Part 9 · 1 chapters · ~12 min
Agent Architecture
Agents as models in a bounded loop: tool calling with validated arguments, the four limits every loop needs, explicit state as a graph with conditional edges, checkpoints for resumption and replay, interrupts before consequential actions, and choosing between a chain, a graph, a free loop and multiple agents.
10
Tools, state, limits and the interrupt
code
// a bounded agent loop: validated tools, limits, and an interrupt before writes
const tools = {
searchDocs: { schema: z.object({ q: z.string().max(200) }), write: false, run: ({ q }) => retrieve(q, 'loans') },
draftLetter: { schema: z.object({ customerId: z.string() }), write: false, run: draftClearanceLetter },
sendEmail: { schema: z.object({ to: z.string().email(), body: z.string() }), write: true, run: sendEmail },
} as const;
async function runAgent(goal: string, ctx: { approve: (call: ToolCall) => Promise<boolean> }) {
const state: Msg[] = [{ role: 'user', content: goal }];
const seen = new Set<string>();
for (let step = 0; step < 8; step++) { // max steps
const out = await model.respond(state, { tools: describe(tools), maxTokens: 800 });
if (out.type === 'answer') return { done: true, answer: out.text, steps: step };
const tool = tools[out.call.name as keyof typeof tools];
const args = tool?.schema.safeParse(out.call.args);
if (!tool || !args?.success) { state.push(toolError(out.call, 'invalid call')); continue; }
const key = out.call.name + JSON.stringify(args.data);
if (seen.has(key)) return { done: false, reason: 'repeated call', steps: step }; // loop detection
seen.add(key);
if (tool.write && !(await ctx.approve(out.call))) { state.push(toolError(out.call, 'rejected by human')); continue; }
state.push(toolResult(out.call, await tool.run(args.data as any)));
await checkpoint(state); // resume and replay
}
return { done: false, reason: 'step limit', steps: 8 };
}| shape | use when | example |
|---|---|---|
| chain | the steps are known and fixed | classify → retrieve → answer → check |
| graph | branches vary by input; some need a human | M phase 2 in LangGraph; a clearance-letter flow with approval |
| free loop | open-ended research with read-only tools | "find every place this fee is documented" |
| multi-agent | one context cannot hold the task | a planner with separate implementer and reviewer agents |
the link to state machines
An agent graph is the FSM pattern from the loan flow with some transitions chosen by a model. Keep the states and the allowed transitions in code, so the model can only choose among edges you have drawn.
AGENT ARCHITECTURE: TOOLS, STATE AND GRAPHS
from one prompt to a bounded loop: tool calling, explicit state, graphs with checkpoints, and a human in the right place
swipe the figure sideways, or tap expand for full screen
1/6
tool calling
Tool calling: each tool has a name, a description the model reads, and a JSON schema for its arguments. The model returns a tool call; your code validates the arguments, runs the tool and returns the result. The model never executes anything itself. Tool descriptions are prompts: write them like API documentation.