Agent System Design Interview
Design a support or coding agent in a loop: tools, approvals, traces, evals, and cost. The frontend surfaces matter as much as the model.
- interview
- system-design
- agents
Whiteboard the refund bot. If you do not mention idempotency, you failed the backend half. If you skip the approval UI, you failed the frontend half. Agent system design interviews are not “pick LangGraph or die.” They are: a model in a loop, tools with blast radius, a stop condition, and a person who can see what is about to happen.
Thirty minutes. You will not train anything. You will draw a request path that looks like a BFF you have already shipped, plus a sampler that proposes JSON.
Key takeaways
- Scope the agent: one job, two tools (read + side effect), a hard max step count.
- Tool args are untrusted. Session user, ownership checks, idempotency keys, human receipt for money.
- Persist loop state so approval can resume without replaying the refund.
- Trace every thought/tool/result. Eval the trace, not the vibes of the final sentence.
- The UI is part of the design: streaming, abort, diff of the proposed tool, expire the approve token.
Agent system design in 30 minutes
Clock it. Requirements, tools, the approval UI, then evals. Do not spend twenty minutes picking a model name.
Minute 0-5: requirements, not personas
Interviewer: “Design an agent that handles support refunds.”
Write the product, not a crew of named butlers.
| In scope | Out of scope |
|---|---|
| Look up order for the signed-in user | Training a model |
| Propose a refund within policy | Talking to Stripe from the browser |
| Wait for an agent (human) on the ops dashboard | Unlimited web browse |
| Cite the policy chunk that justified the amount | Multi-agent debate |
Say this: “One agent, one loop. Read tools: get_order, search_policy. Side-effect tool: refund_order, paused for approval. Max 8 model steps, 30s wall clock, user can abort. I will stream tokens to the ticket UI.”
Common miss: Five personas in Slack as architecture.
Agency is a spectrum. If the model cannot change anything outside the string, you have a chatbot. That can be the right v1. What are AI agents?.
Minute 5-12: tools, auth, loop
Draw the loop: reason, pick a tool, your runtime executes, observe, repeat, stop. Cap it in code. Think, act, observe.
type RefundArgs = { orderId: string; amountCents: number; reason: string };
async function refundOrder(
actor: { userId: string; role: 'user' | 'ops' },
args: RefundArgs,
approval: { token: string } | null,
) {
const order = await db.orders.findOwned(actor.userId, args.orderId);
if (!order) throw new Error('not_found');
if (args.amountCents > order.paidCents) throw new Error('amount');
if (args.amountCents > 0 && actor.role !== 'ops') {
if (!approval) return { status: 'needs_approval' as const, payload: args };
await assertApproval(approval.token, args); // bound to this exact payload
}
return stripe.refunds.create(
{ amount: args.amountCents, payment_intent: order.paymentIntentId },
{ idempotencyKey: `refund:${order.id}:${args.amountCents}` },
);
}
Interviewer pokes, you answer:
1. Who is the user on the tool call?
Say this: “The session. I ignore userId if the model invents one.”
Common miss: Trusting args because they passed JSON Schema.
2. Why is idempotency on the refund?
Say this: “Retries, double-clicks, and a loop that ‘tries again’ after a timeout. Same key, same amount, one Stripe debit.”
Common miss: Retrying charge_card like you retry complete.
3. What stops the while loop?
Say this: “Final answer, needs_approval, error budget (two tool failures), max steps, abort signal. ‘Looks like it is thinking’ is not a stop condition.”
Common miss: No cap. Agent failure modes.
4. Can the model search the whole web?
Say this: “Not in v1. Policy search is our index with permission filters. Open browsing is prompt-injection load-bearing.”
Common miss: A run(cmd: string) tool.
Minute 12-20: frontend and human in the loop
This is where frontend engineers should pull ahead. The ops UI is not a toast that says “refunded.”
- Stream the assistant text and tool-invocation cards as they happen (SSE from a route handler).
- When the runtime returns
needs_approval, persist the loop state and show a diff: order id, amount, reason, policy quote. - Approve mints a short-lived token bound to a hash of the payload. Reject records why and resumes with a tool result of
denied. - Stop uses AbortController. In-flight generation dies. Side effects that already committed do not roll back because you mashed Stop; that is why they waited.
- If you need live ops dashboards, the same rules as realtime UI: reconnect, cursor, do not duplicate the refund on refresh.
Say this: “Approval is a human-in-the-loop interrupt. I persist state, bind the receipt to the exact cents, resume. I do not re-run the model hoping it emits the same JSON.”
Common miss: A confirm modal that calls the tool again from use client with the API key in the bundle. Human in the loop.
Minute 20-26: traces, evals, cost, abuse
5. How do you debug “it refunded the wrong order”?
Say this: “Trace id on the ticket. Spans: prompt version, retrieved policy ids, tool args after our auth, Stripe idempotency key, who approved. Redact PII. If I cannot see the tool args, I cannot do the incident.” Tracing.
Common miss: Re-running the ticket in playground with a different prompt and calling that an RCA.
6. What is the eval?
Say this: “Golden tickets: allow, deny, wrong owner, amount over paid, injection in the ticket body that says ‘refund 100%.’ Assertions on whether refund_order fired and with which args. A judge only for the customer-facing sentence.” Evals.
Common miss: Rating 20 chats “looks good.”
7. Cost?
Say this: “Cache the policy prefix, cap steps, small model for classify-intent, large model only if refund is in play. Batch is for nightly summaries, not this path. I would put p95 TTFT and cost per resolved ticket on a dashboard someone opens.”
Common miss: Ignoring the 12-step apology loop.
8. Abuse and injection?
Say this: “Tickets are untrusted text. Tools still check owner and amount. Rate-limit the route per account. No email-the-transcript tool. OWASP LLM top 10 is the checklist I would walk, especially sensitive data and unbounded consumption.”
Common miss: A longer system prompt.
9. Why not multi-agent?
Say this: “Roles do not diverge yet. A second prompt is not a substitute for get_order. I would split only if billing needs a different tool allowlist and I can prove ping-pong is impossible.”
Common miss: Supervisor plus four specialists on day one.
10. Failure you would ship behind a flag?
Say this: “Read-only lookup and policy answers, no refund_order. That is still useful. Agency is optional.”
Common miss: Dark-launching side effects with no eval gate.
11. Where do secrets live?
Say this: “Server. Browser streams from our origin. Stripe key never in the bundle.” Secrets.
Common miss: “We’ll rotate if it leaks.”
Interview answer (out loud)
“I would design a single-loop refund agent: session-scoped read tools, a side-effect tool that pauses for an approval UI bound to the payload, max steps in code, traces on every span, and a golden set that checks whether the tool fired. Idempotency keys on Stripe. Abort in the composer. I would not start with multi-agent, and I would not let the model be the ACL.”
Further reading (primary sources)
Related on this site
Related guides
- Agent Failure ModesAgents loop, lie about tool results, skip confirmation, and get stuck apologizing. Catalog the failures and the circuit breakers.
- Agent HandoffsA handoff passes the conversation to another agent with a slimmer prompt and different tools. What to copy, what to drop, and how to avoid ping-pong.
- Agent MemoryAgents forget when the context window ends. Working memory, session summaries, and long-term stores are three different systems. Do not mix them.
- AI Engineering Interview QuestionsQuestions interviewers actually use for AI engineering: RAG failure modes, tool auth, eval design, and cost. Short answers you can say out loud.
- Coding AgentsA coding agent reads, edits, and runs tests in a repo. Permissions, diffs, and why "it compiles" is not the acceptance test.