Dayward AI

Interview Bank

328 questions total; 2 shown with current filters.

Tag
136 more tags
#api-design6#operations6#sse6#deployment5#message-bus5#tool-calling5#agent-loop4#behavioral4#error-handling4#evaluation4#framework-design4#mcp4#routing4#concurrency3#context-engineering3#interview-prep3#langgraph3#llm-basics3#model-routing3#orchestration3#prompt-injection3#protocol3#redis-streams3#scalability3#scheduling3#agent-design2#auth2#checkpointing2#communication2#cost-control2#database2#debugging2#interview-process2#latency2#long-term-memory2#memory2#ordering2#prompt-engineering2#rate-limiting2#react2#resume2#retrieval2#sharding2#state-management2#tool-design2#tool-permissions2#trade-offs2#ux2#agent-basics1#agent-quality1#async1#atomicity1#cancellation1#capacity-planning1#career1#chunking1#compression1#configuration1#consistent-hashing1#context1#context-compression1#context-management1#correctness1#customer-support1#data-modeling1#deliberate-practice1#docker1#documentation1#engineering-tradeoffs1#escalation1#event-driven1#fallback1#fan-out1#fencing-token1#forking1#framework-selection1#frontend1#global-market1#hybrid-search1#interrupt-merge1#isolation1#json-parsing1#jwt1#knowledge-organization1#lease1#least-privilege1#llm-as-judge1#loop-guard1#mobile1#multi-tenancy1#nodejs1#performance1#persistence1#pgvector1#portfolio1#prioritization1#proactive-messaging1#product-engineering1#project-storytelling1#prompt1#provider-abstraction1#quiet-hours1#ranking1#recall1#reconnect1#redis1#reflection1#replay1#reporting1#rerank1#retrieval-quality1#retry1#retry-semantics1#rrf1#sampling1#sandboxing1#schema-design1#secrets-management1#self-assessment1#self-introduction1#self-presentation1#service-architecture1#session-management1#split-brain1#star1#stateless1#storytelling1#structured-output1#system-prompt1#testing1#timezone1#tool-execution1#tools1#tracing1#transport1#vector-database1

From Frontend Engineer to Agent Engineer in 30 Days

D11 The Run State Machine, Streaming Output Back, Ordering by runId, SSE Waiters, Merging Interruptions Within 30 Seconds

  • How would you design the state machine for one agent run, and which failure states must it cover?怎么设计一次 Agent 执行(run)的状态机?需要覆盖哪些异常状态?
    Common in ChinaCommon overseasBasic#state-machine#distributed-systems

    How to reason about it · think before answering

    1. The discriminator is not listing states, it is explaining why a single-process service does not need them at all. Without that, you have only memorized a diagram.
    2. Start from motivation: in one process the call stack *is* the state. Once you split gateway and worker, three parties must answer the same question independently — the gateway decides whether to keep an SSE connection open, the worker decides whether someone already claimed the message, and a reopened browser tab asks whether the previous question is still generating. Different processes, so the answer has to live in a table.
    3. Then the states: pending to running to streaming to done on the happy path, with failed (retries exhausted) and cancelled (superseded by a merge, or user-cancelled) as exits available from anywhere. Volunteer why running and streaming are separate: running means claimed but no token yet, streaming means the first token is out. That boundary is your time-to-first-token probe and the frontend's cue to switch from spinner to typewriter.
    4. Land on the real purpose: the machine exists to reject writes. Terminal states having no outgoing edges is the most valuable row in the table. Under at-least-once delivery, a done run receiving one more chunk is routine, and without the table that chunk lands silently — the user sees half a sentence appended and the logs show nothing wrong.
    5. Add the discipline that separates shipped from read-about: every status write goes through one transition function. One raw UPDATE that bypasses it and the state machine is just a comment.
    6. Expect the follow-up on storage and concurrency: the database row is the single source of truth, and transitions are conditional updates that include the expected current status in the WHERE clause. Zero rows affected means someone moved first — re-read and decide, never blindly overwrite.

    分析过程 · 先想清楚再作答

    1. 这题的区分度不在「能不能列出几个状态」,而在你有没有说出「为什么单进程时代不需要它」。答不出这一点,说明你只是抄过一张状态图。
    2. 先给动机:单进程里「执行到哪一步了」就是那个函数栈,状态存在于进程内存里,不需要名字。拆成 Gateway 与 Worker 之后,至少三方要同时回答同一个问题——接入层要判断还挂不挂 SSE,执行层要判断这条消息是否已被人领走,前端重开页面要判断上次的问题还在不在生成。三方不同进程,只能靠一张表对齐。
    3. 再给状态:pending 到 running 到 streaming 到 done 是正常路径,failed(重试耗尽)与 cancelled(被打断合并或用户取消)是两个随时可以走的异常出口。主动说明为什么 running 和 streaming 要分开:前者是「有人领走了但还没有一个字」,后者是「第一个字已出来」,这条线就是首字延迟的观测点,也是前端决定转圈还是打字机的依据。
    4. 结论要落到「状态机是用来挡写入的」:终态没有出边这一条最值钱。至少一次投递下「已经 done 的 run 又收到一个片段」是常态,没有转换表,那一笔会安静地写进库,用户看到回复末尾多出半句话,而日志里查不出是谁写的。
    5. 补一条纪律,这是有没有落地过的分水岭:所有写状态的地方都必须过同一个转换函数。绕过它直接执行一条更新语句,状态机就退化成注释了。
    6. 可以预期的追问:状态存哪、并发怎么办?答数据库那一行是唯一真相,转换用带条件的更新(更新时把当前状态写进 where 子句),失败说明有人抢先改过,这时候重读再决定,而不是覆盖。

    Key points

    • In one process the call stack is the state; after splitting gateway and worker, three parties need the same answer, so it has to be a table
    • Happy path pending, running, streaming, done; exits are failed (retries exhausted) and cancelled (merged or user-cancelled)
    • Separating running from streaming gives you a time-to-first-token probe and tells the UI when to switch from spinner to typewriter
    • Terminal states with no outgoing edges reject the late chunks that at-least-once delivery guarantees you will get
    • Every status write goes through one transition function, implemented as a conditional update on the expected current status

    答题要点

    • 单进程里状态就是函数栈;拆成 Gateway 与 Worker 后有三方要独立回答「这次执行到哪了」,必须落成一张表
    • 正常路径 pending 到 running 到 streaming 到 done;异常出口 failed(重试耗尽)与 cancelled(打断合并或用户取消)
    • running 与 streaming 分开,是为了观测首字延迟,也让前端知道该转圈还是该开始打字机效果
    • 终态没有出边是核心:至少一次投递下的迟到片段会被当场挡住,而不是安静写进库
    • 纪律:所有状态写入都过同一个转换函数,并用带当前状态条件的更新来处理并发
  • A user sends another message while the agent is still answering the previous one. How should the system handle it?用户在 Agent 还没回复完的时候又发来一条消息,应该怎么处理?
    Common in ChinaCommon overseasIntermediate#interrupt-merge#state-machine#cost

    How to reason about it · think before answering

    1. It reads like a product question but tests whether you have thought through two concurrent runs. 'Queue it' or 'cancel the previous one' are not wrong, just incomplete — they want the criteria and the costs.
    2. Start with what happens if you ignore it: two runs write into the same conversation, so the UI shows two interleaved answers, and the first run was computed from incomplete input, so its answer is already wrong. Those two consequences point straight at merging rather than concurrency.
    3. Then give the actual test — all three must hold: same session, the previous run is running or streaming, and it was created less than 30 seconds ago. On a hit, append the new message to that run's input and flag it for a rerun instead of creating a new run; outside the window, or if the previous run finished, create a new one. Excluding pending is deliberate: that window lasts milliseconds, and excluding it keeps the rule free of races with the worker reading the input.
    4. Two implementation details show hands-on experience. First, the rerun flag does not belong in the business table — it is meaningful only during this execution, and persisting it means a crash mid-flight leaves a dirty flag that makes the run loop forever after restart; an expiring key is the right home. Second, on rerun the sequence must keep counting up rather than resetting, or a reconnecting client resuming from its last id lands in a history that has been invalidated.
    5. Volunteer the arithmetic to kill the 'saves money' answer: at roughly 2000 input and 500 output tokens, one answer costs about $0.0006. Not merging means two full runs, about $0.0012; merging means a first pass cut off a third of the way in (about $0.0004) plus a full second pass ($0.0006), about $0.0010 — a 17% saving, which is two dollars a day even at ten thousand corrections. Merging is a user-experience decision, not a cost optimization.
    6. Expect: where does 30 seconds come from? It is a product judgment, not a derivation — corrections usually arrive 5 to 15 seconds in, too short misses them and too long merges genuinely new questions into old ones. What matters is defining it once and referencing it from both the rule and the UI hint rather than scattering the constant.

    分析过程 · 先想清楚再作答

    1. 这题看起来是产品题,其实考的是你有没有想过「并发两次执行」的后果。答「排队处理」或「直接取消上一条」都不算错,但都不完整——面试官想听的是判据和代价。
    2. 先说清不处理会怎样:两次执行同时往同一个会话里写输出,前端看到两段交错的文字;而且第一次执行是基于不完整的信息跑的,它的答案注定要被推翻。这两条后果一说,方案的方向就定了——要合并,不要并发。
    3. 然后给可执行的判据,三个条件全中才合并:同一个会话、上一次执行正处于 running 或 streaming、距它创建不到 30 秒。命中就把新消息追加进同一次执行的输入并标记为需要重跑,不新建;超窗或上一次已完成就正常新建。把 pending 排除掉是有意的——那段窗口只有几毫秒,排除后判据不必考虑「执行侧正好在这一刻读输入」的竞态。
    4. 两个实现细节最能体现动手过:一是「需要重跑」这个标记不要写进业务表,它只在本次执行期间有意义,写进表里进程崩在半路就留下脏标记、重启后无限重跑,放一个带过期时间的键上更合适;二是重跑时序号必须接着往上加、不能重置,否则重连的客户端按上次收到的号续,会续到一段已经作废的历史上。
    5. 主动算一笔账,把「为了省钱」这个错误理由挡回去:按输入 2000、输出 500 个 token 估,单次约 0.0006 美元;不合并是两次跑完约 0.0012 美元,合并是第一遍被掐在三分之一处约 0.0004 美元加第二遍 0.0006 美元约 0.0010 美元,只省 17%,一天一万次改口也就两美元。所以合并的理由是体验,不是成本。
    6. 可以预期的追问:30 秒怎么定的?答它是产品判断不是推导结果——用户改口通常在 5 到 15 秒之间,窗口太短合并不到、太长会把新问题误并成补充;关键是这个数只在一处定义、被判据与前端提示共同引用,不要在代码里散落三份。

    Key points

    • Without merging you get two interleaved answers in one conversation, and the first was computed from incomplete input
    • Merge only when all three hold: same session, previous run running or streaming, created under 30 seconds ago; otherwise create a new run
    • On a merge, append to the same run's input and flag a rerun, keeping that flag in an expiring key rather than the business table
    • Sequence numbers keep counting on rerun and are never reset, or reconnects resume into an invalidated history
    • The cost saving is small (about 17%); the real reason is to avoid two answers talking over each other

    答题要点

    • 不合并的两个后果:两段输出交错写进同一个会话,且第一次执行基于不完整信息注定被推翻
    • 判据三条全中才合并:同一会话、上一次执行处于 running 或 streaming、距创建不到 30 秒;否则正常新建
    • 命中就把新消息追加进同一次执行的输入并标记需要重跑,标记放带过期时间的键上而不是业务表
    • 重跑时序号继续往上加、绝不重置,否则断线重连会续到作废的历史上
    • 合并省的钱有限(约 17%),真正的理由是不让两个回答同时对着用户说话