Overview
An AI agent is a system that takes a goal, plans steps, calls tools, observes results, and repeats until the goal is met. The hard part is not the model — it's the guardrails that keep the loop safe, observable and bounded.
Architecture
We use a supervisor/worker pattern: a planner decides the next action, a tool executor runs it, and an evaluator checks the result before the next step.
Each step is bounded by a budget and a validation gate.
Folder structure
src/agent/
planner.ts # decides next action
executor.ts # runs tools, typed
guardrails.ts # budget + policy checks
memory.ts # conversation + state store
tools/
search.ts
crm.ts
email.ts
eval/
harness.ts # offline evalsCore loop
export async function runAgent(goal: string) {
const state = createMemory(goal);
for (let step = 0; step < MAX_STEPS; step++) {
const action = await planner(state);
await guardrails.assert(action, state.usage);
const result = await executor(action);
if (!(await validator(result))) {
state.log("retry", action);
continue;
}
state.append(result);
if (state.isComplete()) break;
}
return state.final();
}MAX_STEPS and per-run tokens. Unbounded loops are the fastest way to a surprise invoice.Deployment strategy
Run agents as short-lived serverless functions or a queue worker. Persist state to Postgres so a crash mid-run can resume. Emit structured logs for every tool call.
Security considerations
- Scope each tool's credentials to least privilege.
- Never let the model write raw SQL — use typed tool functions.
- Require human approval for payments, deletes and external sends.
Scaling strategy
Decouple planning from execution with a queue. Scale workers horizontally; keep the planner stateless. Cache planner outputs for repeated intents.
FAQ
See the FAQ section above. For implementation help, book a strategy call.