Interview Bank
328 questions total; 11 shown with current filters.
126 more tagsShow fewer tags
From Frontend Engineer to Agent Engineer in 30 Days
D2 How Tool Calling Works: JSON Schema, the tool_use Loop; Hand-Writing an Agent Loop With No Framework
How do you keep an agent loop from running forever — is a max-step counter enough?怎么防止 Agent 循环停不下来?只加一个最大步数够吗?
Common in ChinaCommon overseasDeep dive#agent-loop#reliability#costHow to reason about it · think before answering
- The second half is an open trap. 'Add a counter' is the passing grade; what they want is whether you know what a counter cannot catch.
- Explain why it runs away first: the finish reason stays tool_calls because the tool results are not moving the model forward — empty results, fields that do not answer the question, error text that never says what correct looks like. So the first line of defense is not a guard rail at all; it is writing tool results and error messages that carry information.
- Then three complementary hard limits: a step cap is the obvious one; a token and cost budget catches 'few steps, all of them expensive'; a per-step wall-clock timeout catches 'one call hung for two minutes'. A system with only a step cap can still blow its budget on a single enormous context.
- Add a semantic guard: detect repeats. The same tool with identical arguments twice in a row is almost always spinning. Cut it short and tell the model so — 'you already called this tool with exactly these arguments' — which usually converges faster than waiting for the counter to run out.
- Hitting the cap needs an honest ending: never return an empty string, give the user a sentence they can act on, and record cap hits as a metric. A rising cap-hit rate usually means a tool's description or return value needs fixing, not that the cap should be raised.
- Expect: what number do you pick? There is no universal one. Chat-style tasks usually fit in five to ten steps; retrieval-heavy tasks need more. Read the production distribution, take p99 plus headroom, and remember that the tighter the cap, the closer your system sits to a fixed workflow rather than an agent.
分析过程 · 先想清楚再作答
- 后半句是明摆着的陷阱。只答「加一个计数器」是及格线,面试官真正想听的是你知道计数器拦不住什么。
- 先解释它为什么会停不下来:停止原因一直是 tool_calls,通常是因为工具返回的东西没帮模型前进——结果为空、字段答非所问、错误文案没说清该怎么改,于是它换个参数一试再试。所以第一层其实不是护栏,是把工具的返回值和错误文案写得有信息量。
- 再给硬护栏,三条互补:步数上限最直接;token 与成本预算拦的是「步数不多但每步都很贵」;单轮的墙上时钟超时拦的是「一步就卡了两分钟」。只有步数上限的系统,照样会被一次超长上下文的调用打爆预算。
- 语义层面再加一条:检测重复调用。同一个工具、同一份参数连续出现两次以上,几乎可以断定它在原地打转,直接截断并把「你已经用完全相同的参数调过这个工具了,换个思路或者告诉用户你做不到」回传给模型,往往比等步数耗尽更快收敛。
- 触顶之后必须有交代:不能静默返回空字符串,要给用户一句能理解的话;同时把触顶记成一个指标,触顶率上升通常意味着某个工具的描述或返回值该改了,而不是把上限调大。
- 可以预期的追问:上限设多少?没有普适值。聊天类任务 5 到 10 步通常够,需要多轮检索的任务可以更高。正确做法是看线上的步数分布,取 p99 再留一点余量,而不是拍脑袋——上限设得越死,你的系统就越靠近固定流程那一端,越不像一个 Agent。
Key points
- The root cause is usually uninformative tool results or error text, so fix that layer before adding guards
- Three complementary hard limits: max steps, a token and cost budget, and a per-step wall-clock timeout
- Add a semantic guard: identical tool plus identical arguments twice in a row means it is spinning — cut it and tell the model
- Give the user an honest message when the cap is hit, and track the cap-hit rate as a signal that a tool needs fixing
- Size the cap from the production step distribution, not intuition; a tighter cap makes the system a workflow rather than an agent
答题要点
- 根因通常是工具返回值或错误文案没信息量,模型无法前进只能反复重试,先把这层写好
- 三条硬护栏互补:最大步数、token 与成本预算、单步墙上时钟超时,只有步数上限并不够
- 语义护栏:同一工具加同一份参数连续重复调用即判定原地打转,截断并把这个事实回传给模型
- 触顶要给用户一句交代,不能静默返回空;同时把触顶率当指标,上升说明工具该改而不是把上限调大
- 上限值按线上步数分布取 p99 加余量;上限越死越接近固定流程,越不像 Agent
D14 Deployment and Operations: Multi-Worker Compose, Heartbeats, Health Checks, Graceful Shutdown, Dev/Prod Isolation; Week Two Retrospective
System design: design an IM agent platform where users chat with an AI assistant inside a messaging app. The assistant calls tools, remembers long-term preferences, and proactively pushes scheduled messages. Target 100k daily active users.系统设计:请设计一个 IM Agent 平台——用户在即时通讯软件里和一个 AI 助手对话,助手能调用工具、记住长期偏好、还能定时主动推送。要求支撑十万日活。
Common in ChinaCommon overseasDeep dive#system-design#distributed-systems#cost#operationsHow to reason about it · think before answering
- Do not start drawing. The most common way to fail a design question is to hear the prompt and immediately sketch boxes, only for the interviewer to realise twenty minutes later that you solved a different problem. Spend three to five minutes on four questions: traffic shape (how many concurrent sessions does 100k DAU imply, and what is the peak-to-trough ratio), latency (how fast must first byte be, is streaming required), the nature of the tools (read-only lookups, or writes with side effects), and the compliance boundary on proactive pushes (may you push at night, what is the daily cap). All four change the architecture materially, so asking them is itself worth points.
- Then state the trunk in one sentence: stateless ingress, a message bus for decoupling, stateful workers sharded by user, all state in the database. Walk the data flow: the messaging platform's webhook hits ingress, which does only auth, rate limiting, persistence and publish, and returns 202 immediately; the execution side pulls work, runs the agent loop, and streams output fragments back; proactive pushes come from a central scheduler publishing onto the same bus. The load-bearing argument is that ingress latency is bounded while execution latency is not, so putting them in one process means one slow model call occupies a connection that should have returned in milliseconds — say this out loud, it is the premise of the whole answer.
- Then justify each module. Storage: sessions, runs and messages, with runs existing separately because only it can answer whether this attempt actually finished; idempotency comes from a unique constraint on runs, not from check-then-insert. Bus: Redis Streams consumer groups for fan-out, at-least-once semantics, with exactly-once manufactured by consumer-side idempotency, and messages that fail three times moved to a dead-letter stream. Ordering: the consumer group's unit of assignment is one message while the business requires serialisation per user, so hash userId into a fixed set of shards and let exactly one worker hold each shard's lease. Memory: embeddings in pgvector, retrieval wrapped as a tool the model chooses to call, with no identity parameter — identity only ever comes from the session.
- Treat proactive push as its own section, because it is what separates this from an ordinary chat service. The central scheduler publishes one message on a time match and the execution side is unchanged; the idempotency key is anchored to the scheduled minute, so replaying after a scheduler restart cannot double-send. For compliance you need timezone, quiet hours and a daily cap — and all three must be evaluated before publishing rather than at send time, or you have already paid for the model call before discovering you should not have pushed.
- Then volunteer capacity and cost numbers, which is what separates senior candidates. 100k DAU at ten turns each is a million model calls; at roughly a thousand tokens in and out, with input at $0.15 and output at $0.60 per million tokens, that is about $750 a day. That number immediately implies three requirements: meter token usage per call and convert to dollars (otherwise you cannot tell which user or feature is burning money), build tiered degradation (push over-budget users to a cheaper model rather than refusing them), and recognise that context length is the dominant cost lever (so compress history and cap retrieved items).
- Land on operability, which is this week's payoff: multiple replicas, heartbeats to surface zombies, readiness probes that only check their own hard dependencies, graceful shutdown so deploys do not cut conversations, and dev/prod isolation via key prefixes. Pair every mechanism with what happens when it fails — leases can split-brain so you need a self-fencing rule and fencing tokens, heartbeats produce false positives so a red dashboard alerts a human rather than auto-draining, shutdown can time out so the wait needs a ceiling. A mechanism without a stated failure mode reads as something you only read about.
- Expect, in rough order of frequency: where are the single points (the scheduler is stateless and restartable; Redis and Postgres rely on managed primary/replica); how do you roll out safely (old and new workers coexist and a version field in the message selects the prompt set); what if the user sends another message mid-reply (merge a change of mind within thirty seconds into the same execution rather than running two concurrently); and how would you halve the cost (cache frequent answers, compress history, route simple intents to a smaller model).
分析过程 · 先想清楚再作答
- 先别画图。系统设计题最常见的死法是听完就开始画框,二十分钟后面试官发现你解的是另一道题。花三到五分钟问清四件事:一是流量形状(十万日活对应多少并发会话、峰谷比多少),二是延迟要求(首字节要多快,是否必须流式),三是工具的性质(只读查询还是有写操作和副作用),四是主动推送的合规边界(能不能在深夜推、每天上限几条)。这四个答案会实质改变架构,问它们本身就是分数。
- 然后给主干,一句话先定形状:**接入层无状态、消息总线解耦、Worker 有状态且按用户分片、状态全在数据库**。接着按数据流走一遍:IM 平台的 webhook 打到接入层,接入层只做鉴权、限流、落库、投递四件事,立刻返回 202;执行侧从总线取活、跑 Agent 循环、把输出片段回传;主动推送由一个中心调度器按时间投递进同一条总线。**关键论点是接入层耗时确定、执行层耗时不确定,把它们放在一个进程里意味着一次慢的模型调用会占住一个本该毫秒级返回的连接**——这是整道题的立论基础,要主动说出来。
- 再逐个模块给出选择和理由。存储:sessions / runs / messages 三张表,runs 单独存在是因为只有它能回答「这次到底跑完没有」,幂等靠 runs 上的唯一约束而不是先查后插。总线:Redis Streams 的消费组做分摊,语义是至少一次,恰好一次靠消费端幂等做出来;反复失败的消息投递三次后进死信流。顺序:消费组的分配单位是一条消息而业务要求的串行单位是一个用户,所以按 userId 哈希到固定数量分片,每个分片同一时刻只有一个 Worker 持有租约。记忆:pgvector 存 embedding,检索包成一个工具交给模型自己决定要不要查,且不给它身份参数——身份只能来自会话。
- 主动推送这一块要单独讲透,因为它是这道题区别于普通聊天服务的地方。中心调度器命中时间点后只投一条消息,执行侧照旧;幂等键锚在「计划触发的那一分钟」,所以调度器崩溃重启后回看重放不会重复推送。合规上要有时区、静默时段、每日上限三道闸,而且这三道闸必须在投递前判断而不是在推送时判断——否则你已经花了模型调用的钱才发现不该推。
- 然后主动给出容量和成本的数字感,这是高级候选人的分水岭。十万日活、人均十轮对话是一百万次模型调用;按输入输出各一千 token、每百万 token 输入 0.15 美元输出 0.60 美元估算,一天大约七百五十美元。这个数字立刻推出三件事必须做:token 用量要按调用记账并换算成美元(否则你无法定位是哪个用户或哪个功能在烧钱)、要有分层降级(超预算的用户切便宜模型而不是直接拒绝)、以及上下文长度是主要成本杠杆(所以要压缩历史、控制检索条数)。
- 最后收在可运维性上,也就是这一周的落点:多副本部署、心跳发现假死、就绪探针只查自己必需的依赖、优雅停机让发版不掐断对话、dev 与 prod 用键名前缀隔离。**每个机制都要配一句「它失效时会怎样」**——租约会脑裂所以要有自杀规则和护栏令牌、心跳会误判所以面板转红只告警不自动摘流量、停机会超时所以等待要有上限。说不出失效模式的机制,面试官会认为你只是读过。
- 可以预期的追问,按出现频率排:单点在哪(调度器无状态可重启,Redis 和 Postgres 靠托管服务的主备);怎么灰度(新旧 Worker 同时在线,靠消息里的版本字段决定走哪套提示词);用户在助手回复中途又发一句怎么办(三十秒内的改口合并进同一次执行,而不是并发开两个);成本再降一半怎么做(缓存高频问答、压缩历史、把简单意图路由到小模型)。
Key points
- Spend three to five minutes clarifying four things: traffic shape, latency targets, whether tools have side effects, and the compliance boundary on proactive pushes
- State the trunk in one sentence: stateless ingress, bus for decoupling, stateful workers sharded by user, all state in the database — premised on bounded ingress latency versus unbounded execution latency
- Storage is sessions/runs/messages with idempotency from a unique constraint on runs; the bus is Redis Streams consumer groups, at-least-once plus consumer idempotency, dead-lettering after three failures
- Ordering comes from hashing userId into shards plus leases: the consumer group assigns per message while the business serialises per user
- Memory is pgvector exposed as a tool the model may call, with no identity parameter — identity comes only from the session
- Proactive push flows through a central scheduler with the idempotency key anchored to the scheduled minute; timezone, quiet hours and daily caps are enforced before publishing
- Bring numbers: 100k DAU at ten turns is ~1M calls and ~$750/day, which implies metering, tiered degradation, and context length as the main cost lever
- Land on operability: replicas, heartbeats for zombies, readiness probes scoped to own dependencies, graceful shutdown, dev/prod prefix isolation
- Pair each mechanism with its failure mode — leases split-brain, heartbeats false-positive, shutdown times out; a mechanism without one reads as book knowledge
答题要点
- 先用三到五分钟问清四件事:流量形状、延迟要求、工具是否有副作用、主动推送的合规边界——它们会实质改变架构
- 主干一句话:接入层无状态、消息总线解耦、Worker 有状态且按用户分片、状态全在数据库;立论是接入层耗时确定而执行层不确定
- 存储 sessions / runs / messages 三张表,幂等靠 runs 上的唯一约束;总线用 Redis Streams 消费组,至少一次加消费端幂等,三次失败进死信
- 顺序靠 userId 哈希分片加租约:消费组的分配单位是一条消息,而业务要求的串行单位是一个用户
- 记忆用 pgvector 并包成工具交给模型自己决定是否检索,不给身份参数——身份只能来自会话
- 主动推送由中心调度器投递,幂等键锚在计划触发的那一分钟;时区、静默时段、每日上限三道闸必须在投递前判断
- 给出成本数字感:十万日活人均十轮约一百万次调用、一天约七百五十美元,由此推出计量记账、分层降级、压上下文三件事
- 收在可运维性:多副本、心跳查假死、就绪探针只查自己的依赖、优雅停机、dev/prod 前缀隔离
- 每个机制都配一句失效模式:租约会脑裂、心跳会误判、停机会超时——说不出失效模式等于只是读过
D21 Evaluation and Observability: a Golden Set, LLM-as-Judge, Tracing, a Failure-Rate/Cost Dashboard; Pi vs. LangGraph Summary; Week Three Retrospective
System design: a multi-agent support platform is live, the team edits prompts several times a week, nobody can say whether quality is improving, and cost is only known as a month-end total. Design its evaluation and observability system.系统设计:一个多 Agent 客服平台已经上线,团队每周改几次提示词,但没人说得清质量是变好还是变差,成本也只有一个月底的总数。请为它设计一套评估与可观测体系。
Common in ChinaCommon overseasDeep dive#system-design#evaluation#observability#costHow to reason about it · think before answering
- Do not draw an architecture diagram yet. The trap is that this sounds like build monitoring, so many candidates open with Prometheus and Grafana — that answers infrastructure, not this question. Spend three to five minutes on four things: how often prompts change and how they ship (weekly cadence, canary, rollback); how problems surface today (user complaints, or someone happening to notice); what history exists (how long conversations are retained, whether they can be replayed); and who consumes this (engineers debugging, or an executive watching spend). All four materially change the design, so asking them scores.
- Then the trunk, in one sentence: one dataset, two readings. Instrument once, as spans; read across for a single request's call tree (debugging) and stack them for a dashboard (trends and cost). This is the foundation — two data sources will eventually disagree and then nobody trusts either. Many candidates fork here into a monitoring system and an evaluation system, which is the source of every later problem.
- Then three layers. Layer one, offline regression: a small stable golden set (15 to 50), covering three things — every route exercised, one item per failure mode (low-confidence fallback, tool budget exhaustion, downstream outage), and the cases behind real past incidents. Each item declares its expected route and a checklist of required facts. The maintenance rule is add, never edit: changing an expectation voids all historical scores. Score with an LLM-as-judge using a different model, and version the rubric, storing that version on every record. This layer runs in CI on every prompt change and emits a number comparable to last time.
- Layer two, online observability: every request writes a span tree recording the routing rationale (a model decision, lost forever if not captured), per-node tokens and latency, and degradation and fallback events. The dashboard answers four questions: how much is wrong, where it is slow, what it cost, and which role spent it — that last one is multi-agent specific and the most actionable.
- Layer three, online sampled evaluation: fifteen offline cases cannot cover the real traffic distribution, so sample a fraction of live requests (say 1%) through the same judge to get a true quality curve. This layer bridges the other two: offline tells you whether you broke something known, online tells you what real users encountered.
- Bring numbers on cost, which is what separates levels. A multi-agent request can produce five to ten model calls, so per-call price is an order of magnitude below the real unit cost and you must price per request. Give the arithmetic: 10k DAU at three sessions each and five calls per session is 150k calls a day; at 2000 input and 500 output tokens, $0.15 and $0.60 per million, that is roughly $90 a day. That number implies two things: per-node attribution shows where to optimise, and evaluation's own cost must be tracked separately, since judge calls are the same order as the system itself and decide whether you evaluate per commit or nightly.
- Close on adoption, which many candidates omit: wire evaluation into the release process (block a deploy when pass rate drops below threshold), keep the rubric and golden set in the repository under code review, and pair every mechanism with a failure mode — judges favour same-family models, golden sets get gamed (someone tunes prompts to make it green, and at that moment it is worthless), sampling misses the long tail. A proposal with no stated failure modes reads as book knowledge.
- Expect, by frequency: which model judges (one tier above the system under test, and necessarily a different family); where the golden set comes from (start with human-labelled production samples, then append every incident); what happens when this system itself misbehaves (the dashboard refuses to aggregate mixed rubric versions rather than emitting a meaningless average); and how long to build (layer two in a week, layer one in two, layer three in a month since it depends on both).
分析过程 · 先想清楚再作答
- 先别画架构图。这道题的陷阱是它听起来像「搭一套监控」,于是很多人上来就报 Prometheus 加 Grafana——那答的是基础设施,不是这道题。花三到五分钟问清四件事:一是**改提示词的频率和发布方式**(每周几次、有没有灰度、能不能回滚);二是**现在出问题是怎么发现的**(用户投诉?还是有人偶然看到?);三是**有没有历史数据**(线上对话存了多久、能不能回放);四是**谁来看这套东西**(工程师排障,还是老板看成本)。这四个答案会实质改变设计,问它们本身就是分数。
- 然后给主干,一句话定形状:**一份数据、两种读法。** 埋点只做一套(span),横着读是一次请求的调用树(排障用),竖着堆是面板(趋势和成本用)。**这条是地基**——两套数据来源迟早对不上,然后没有人相信任何一个。很多候选人在这里就分叉成「监控系统」和「评估系统」两套,那是后面所有麻烦的源头。
- 接着按三层展开。**第一层,离线回归**:建一个小而稳的 golden set(15 到 50 条),三层覆盖——每条路由都有人走、每种失败模式各一条(置信度不足落兜底、工具预算耗尽降级、下游挂掉)、以及历史上真出过事故的那几条。每条写清期望路由和必备信息清单。维护规矩是**只增不改**:改一条期望,历史分数全部作废。用 LLM-as-judge 对照清单打分,**judge 换一个模型、rubric 版本化并随每条记录存下来**。这一层挂在 CI 上,每次改提示词跑一遍,产出一个能和上次比的数字。
- **第二层,在线观测**:每次请求落一棵 span 树,必须记路由理由(模型做的决策,当时不记就永远丢了)、每个节点的 token 与耗时、以及降级和兜底事件。面板回答四个问题:错了多少、慢在哪、花了多少、**钱花在哪个角色身上**。最后一个是多 Agent 特有的,也最有用。
- **第三层,在线采样评估**:离线的 15 条覆盖不了真实流量分布,所以按比例采样线上请求(比如 1%)跑同一套 judge,得到一条真实质量曲线。**这一层是前两层的桥**:离线告诉你有没有改坏已知的东西,在线告诉你真实用户遇到了什么。
- 成本这块要给数字感,这是区分层级的地方。**多 Agent 一次用户请求可能产生 5 到 10 次模型调用**,所以「每次调用多少钱」比真实单价小一个数量级,**必须按请求算钱**。给个算式:日活一万、人均三次会话、每次 5 次调用就是 15 万次调用;按输入 2000 输出 500 token、$0.15/$0.60 每百万算,一天约 90 美元。这个数立刻推出两件事:按节点分摊能定位省钱的地方,以及**评估本身的成本要单独记**——judge 调用和被评估系统一个量级,它决定你每次提交都跑还是每天跑一次。
- 最后收在「怎么让它真的被用起来」,这是很多人漏的一层:把评估结果接进发布流程(通过率跌破阈值就挡住发布)、把 rubric 和 golden set 放进代码仓库走 code review、以及**给每个机制配一句失效模式**——judge 会偏向同源模型、golden set 会被针对性优化(有人为了让它绿而调提示词,那一刻它就失去了意义)、采样会漏掉长尾。说不出失效模式的方案,面试官会认为你只是读过。
- 可以预期的追问,按频率排:judge 用什么模型(比被评估的强一档,且必须异源);golden set 从哪来(先从线上捞一批人工标注,再逐次把事故补进去);这套东西自己出问题怎么办(面板发现 rubric 混版直接拒绝聚合,而不是给一个没含义的平均分);多久能上线(第二层一周、第一层两周、第三层一个月,因为它依赖前两层)。
Key points
- Spend three to five minutes clarifying four things: prompt change cadence and release process, how problems surface today, what replayable history exists, and who the audience is
- The trunk is one dataset, two readings: instrument once as spans, read across for a call tree and stack for a dashboard; two sources will disagree
- Layer one, offline regression: a small stable golden set covering every route, every failure mode and past incidents, add-never-edit, wired into CI
- Layer two, online observability: span trees recording routing rationale, per-node tokens and latency, degradation events; the dashboard answers wrong/slow/cost/which-role
- Layer three, sampled online evaluation through the same judge, covering the real distribution the offline set cannot
- Price per request, not per call: five to ten calls per request, with arithmetic showing ~$90/day at 10k DAU; track evaluation's own cost separately
- Close on adoption: block releases when pass rate drops, keep rubric and golden set in the repo under review
- Pair every mechanism with a failure mode: judge self-preference, golden set gaming, sampling missing the tail — omitting these reads as book knowledge
答题要点
- 先用三到五分钟问清四件事:改提示词的频率与发布方式、现在问题怎么被发现、有无历史数据可回放、这套东西给谁看
- 主干是「一份数据、两种读法」:埋点只做一套 span,横着读是调用树、竖着堆是面板;两套数据源迟早对不上
- 第一层离线回归:小而稳的 golden set,三层覆盖(每条路由、每种失败模式、历史事故),只增不改,挂 CI
- 第二层在线观测:span 树记路由理由、每节点 token 与耗时、降级兜底事件;面板回答错了多少/慢在哪/花了多少/钱花在哪个角色
- 第三层在线采样评估:按比例采样线上请求跑同一套 judge,补上离线覆盖不到的真实分布
- 成本必须按请求算而非按调用:一次请求 5 到 10 次调用,给出日活一万约 90 美元一天的算式;评估自身成本单独记
- 收在落地:通过率跌破阈值挡发布、rubric 与 golden set 进仓库走 review
- 每个机制配失效模式:judge 偏向同源、golden set 会被针对性优化、采样漏长尾——说不出失效模式等于只是读过
D25 The Frontend Agent Experience: Streaming Rendering, Visualizing Tool Calls, Interrupt/Retry, SSE Hooks
The user hits Stop and the frontend calls AbortController.abort(). What is the backend doing at that moment?用户点了「停止生成」,前端调用 AbortController.abort() 之后,后端在做什么?
Common in ChinaCommon overseasDeep dive#streaming#cancellation#costHow to reason about it · think before answering
- This is the core question of the chapter and a deliberate trap: the prompt states the abort as a given and waits for you to say 'so it stopped'. Saying that ends the conversation.
- The correct answer in one line: the backend knows nothing and is still running — still calling the model, still writing messages, still billing tokens. abort only stops your end from reading; at most it drops the TCP connection, and whether the backend notices, or acts on noticing, is a separate matter.
- Decompose by drawing who knows what: the user knows, the frontend knows, the chain breaks, the backend does not know. That broken link must be closed with an explicit request: POST /runs/:id/cancel. So stopping is two steps, not one.
- A quantified contrast lands best: on the same 70-character reply interrupted at character 5, the two-step version stops the backend at 5/70 while abort-only runs to 70/70. That is 14x the tokens, and those 65 characters also land in conversation history and get resent as context next turn, billing you twice.
- Production addendum: on cancel, do not hard-kill. Move the run to a cancelled state and let the current step finish, or you leave half-written messages and gaps in the sequence numbers. Also make cancel idempotent, because you will retry it when the network flakes.
- Expected follow-up: can the backend just detect the dropped connection and stop by itself? It can and should, as a safety net, but not as the only mechanism. Proxies and load balancers often hold connections open, so detection can lag by tens of seconds, and if the client auto-reconnects the connection never drops at all. The net is a net; the explicit cancel is the main path.
分析过程 · 先想清楚再作答
- 这题是本章题眼,也是一道**陷阱题**:题干里已经把「前端 abort 了」当成既成事实,等你顺着说「那就停了」。答「停了」的直接出局。
- 正确答案一句话:**后端什么都不知道,它还在跑。** 还在调模型、还在往库里写消息、还在按 token 计费。`abort` 只是让你这一端不再读了,它顶多让 TCP 连接断开,而后端是否感知得到连接断开、感知到之后做不做事,是另一回事。
- 怎么拆:把「谁知道这件事」画出来。用户知道 → 前端知道 → **中间断了** → 后端不知道。断掉的这一环必须用一个显式的请求补上:`POST /runs/:id/cancel`。所以打断是两步,不是一步。
- 给一个量化的对照最有说服力:同一段 70 个字的回复,在第 5 个字打断——两步打断的后端停在 5/70,只 abort 的后端照跑到 70/70。差 14 倍的 token,而且那 65 个字还会落进会话历史,下一轮当上下文重新发一遍,付第二遍钱。
- 生产视角的补充:cancel 收到之后**不要硬杀**,把 run 迁到 cancelled 状态、让当前这一步跑完再退出——硬杀会留下半写的消息和对不上的序号。而且 cancel 本身必须幂等,因为网络抖动时你会重试它。
- 可预期的追问:那能不能靠后端检测连接断开来自动停?可以做,而且应该做(作为兜底),但不能只靠它——反向代理和负载均衡常常会把连接维持一段时间,后端感知到断开可能已经是十几秒之后;而且用户点停止之后如果自动重连,连接根本没断。**兜底归兜底,显式 cancel 才是主路径。**
Key points
- The backend has no idea: still calling the model, still writing, still billing. abort only stops your side reading.
- Stopping is two steps: abort for instant UI response, plus POST /runs/:id/cancel to actually halt the run.
- Quantified: interrupting the same 70-character reply at character 5 gives 5/70 with both steps versus 70/70 with abort alone.
- On cancel, transition the run to cancelled and let the current step finish rather than hard-killing; make cancel idempotent.
- Backend disconnect detection is only a safety net — proxies hold connections open and auto-reconnect means no disconnect at all.
答题要点
- 后端完全不知情:还在调模型、还在写库、还在计费。abort 只让前端这一端停止读取。
- 打断必须两步:abort(界面立刻响应)+ POST /runs/:id/cancel(后端真的停)。
- 量化差别:同一段 70 字的回复在第 5 个字打断,两步是 5/70,只 abort 是 70/70。
- 后端收到 cancel 不要硬杀,迁到 cancelled 状态让当前步跑完;cancel 必须幂等。
- 靠后端检测连接断开只能当兜底:代理会维持连接、自动重连时连接根本没断。
Context Engineering in 5 Days
D4 Long-Running Sessions: Compression, Notes and Memory Files, Subagent Isolation and Handoff Summaries
Why does a subagent return only a summary instead of its full transcript, and how should the lead agent specify the handoff?子代理为什么只回传摘要而不回传全过程?主代理该怎么写交接要求?
Common in ChinaCommon overseasDeep dive#subagents#handoff#costHow to reason about it · think before answering
- This tests architectural intent. Saying it saves tokens is only half right, and the lesser half: multi-agent setups are more expensive overall, not cheaper.
- State the purpose. Subagent isolation buys a clean main context, not a smaller bill. A subagent can burn tens of thousands of tokens exploring in its own window while the main thread gains only a condensed result of one or two thousand tokens. It is separation of concerns applied to context.
- Put the cost on the table, which is where engineering experience shows: agentic applications use roughly four times the tokens of chat, and multi-agent systems roughly fifteen times. So the fit is narrow: heavy exploration with a condensable result, independent parallelizable subtasks, and a main thread that genuinely does not need the intermediate steps. Missing any one, fall back to compaction.
- Conclusion: specify a handoff contract of three sections (settled conclusions, open items, hard constraints), with every conclusion carrying a source identifier such as a file path, order id, or URL. Without identifiers the main thread can only trust everything or redo everything; with them it can spot-check the one claim it doubts. Require the constraints section even when empty, or the main thread cannot tell absent from forgotten.
- Expect the follow-up about the lead agent's own plan: write it outside the window too, since truncation or compaction late in a long task tends to eat the original plan first.
分析过程 · 先想清楚再作答
- 这题在考架构意图。答「为了省 token」只对了一半,而且是次要的那一半——子代理架构整体上是更贵的,不是更省的。
- 怎么拆:先说清目的。子代理隔离买的不是省钱,是主线上下文的干净。子代理可以在自己独立的窗口里烧掉几万 token 反复探索,主线只多了一两千 token 的浓缩结论,中间过程一个字都没进主线。这是关注点分离在上下文层面的落地。
- 把代价摆出来,这是最能体现做过工程的地方:Agent 类应用本来就比聊天多用约 4 倍 token,多 Agent 系统约 15 倍。所以适用面很窄——探索量大但产出能浓缩、子任务彼此独立可并行、主线确实不需要看中间过程,三条缺一就该退回压缩。
- 结论给交接契约:三段式(已定结论、待办事项、硬约束),且每条结论必须带来源标识(文件路径、订单号、URL)。原因是没有标识的结论不可复查,主线只能全盘相信或全盘重做;带标识之后主线可以只对存疑的那条做定点核实。硬约束那一段没有也要写「无」,不能省略,否则主线分不清是没有还是忘了写。
- 可预期的追问:主代理自己的计划怎么办?也该写到窗口外面。长任务后期一旦触发截断或压缩,最先丢的往往就是最初那份计划,而它恰恰最不该丢。
Key points
- Isolation buys a clean main context, not savings; multi-agent is more expensive overall.
- Magnitudes: agents use about four times chat tokens, multi-agent about fifteen times.
- Fits when exploration is heavy but condensable, subtasks are independent and parallel, and the main thread does not need intermediate steps.
- Handoff contract in three sections, every conclusion carrying a source identifier, and an explicit none when constraints are empty.
- Persist the lead agent's plan outside the window, since it is the first casualty of truncation late in long tasks.
答题要点
- 隔离买的是主线上下文的干净,不是省钱;多 Agent 整体更贵。
- 代价数量级:Agent 约为聊天的 4 倍 token,多 Agent 约 15 倍。
- 适用三条:探索量大且产出可浓缩、子任务独立可并行、主线不需要中间过程;缺一就退回压缩。
- 交接契约三段式,每条结论必须带来源标识,硬约束段即使为空也要显式写「无」。
- 主代理自己的计划也要写到窗口外,长任务里它最容易被截断或压缩吃掉。
RAG in 14 Days: From Retrieval to Trustworthy Answers
D1 Why Retrieve at All: Hallucination, Knowledge Cutoffs, and the Cost of Long Context; a Minimal Keyword-Only RAG
Context windows are now in the millions of tokens. Does that make the retrieval step obsolete?上下文窗口已经做到上百万 token 了,检索这一步会被淘汰吗?
Common in ChinaCommon overseasDeep dive#long-context#cost#system-designHow to reason about it · think before answering
- This is a position question and it is easy to answer as a binary. The signal is whether you separate what fits technically from what is worth paying for on every request.
- Concede the valid half first: bigger windows genuinely absorb part of the use case. For an internal tool over a few dozen stable documents with low traffic, stuffing everything in is the right call and building a retrieval stack would be over-engineering.
- Then give three reasons it does not absorb the rest. Cost is the first: context is billed per request, so the same corpus is paid for on every one of ten thousand queries, whereas retrieval only pays for the passages it returns. Prompt caching softens this but does not remove it.
- Scale is the second: enterprise corpora run to hundreds of thousands of documents and no window holds them. Attribution and access control are the third: pointing an answer at a specific passage, and showing each user only what they are permitted to see, both have to happen before the material reaches the model.
- Add the empirical point: as the supplied material grows, models become less reliable at locating the one relevant fact inside it. More context is not automatically better; fewer and more precise passages often win.
- Expected follow-up: does retrieval change shape? Yes. Larger windows allow bigger chunks and more of them, which relieves pressure on reranking and compression. Retrieval gets coarser, it does not disappear.
分析过程 · 先想清楚再作答
- 这是一道立场题,容易答成非黑即白。判断你有没有做过的地方在于:会不会区分「技术上能不能塞进去」和「工程上该不该每次都塞」,只谈前者的答案一听就是纸上谈兵。
- 先承认对方有道理的部分:窗口变大确实吃掉了检索的一部分场景。几十篇文档、更新不频繁、调用量不大的内部工具,直接全塞是最省事的选择,为它建一套检索系统是过度设计。
- 再给三条它吃不掉的理由。第一是成本:材料是按次计费的,同一份材料被问一万次就要付一万次,而检索只付取回的那几段;预填充缓存能缓解但不能消除,缓存也有有效期和命中率。
- 第二是规模:企业知识库动辄几十万篇,再大的窗口也塞不下,检索是唯一的入口。第三是归因与权限:答案要指回具体某一段,以及不同的人只能看到自己有权访问的材料——这两件事必须在把材料喂给模型之前完成,窗口再大也不解决。
- 还要补一条经验事实:材料变多之后,模型在长上下文里定位关键信息的稳定性会下降,出现「读了但没读到」。所以「全塞」并不总是等于「效果更好」,很多时候少而准反而更好。
- 可预期的追问:那检索的形态会不会变?会——窗口变大之后,取回的块可以更大、条数可以更多,重排与压缩的压力变小,检索从「精挑几句」变成「粗筛一批」。趋势是检索的粒度变粗,不是检索消失。
Key points
- Separate whether it fits from whether it is worth paying for on every request.
- Small, stable, low-traffic corpora can legitimately be stuffed whole; building retrieval for them is over-engineering.
- Three reasons retrieval survives: per-request cost, corpora too large for any window, and attribution plus access control that must happen before the model sees the material.
- More supplied context reduces the reliability of locating a single fact, so stuffing everything is not automatically better.
- The trend is coarser retrieval — bigger chunks, more of them, less reranking pressure — not the removal of retrieval.
答题要点
- 先区分「能不能塞进去」和「该不该每次都塞」,前者是技术问题,后者是成本问题。
- 小规模、低频、少变的语料确实可以直接全塞,为它建检索系统是过度设计。
- 检索不会被淘汰的三个理由:按次计费的成本、几十万篇塞不下的规模、必须在喂给模型之前完成的归因与权限过滤。
- 材料越多,模型定位关键信息的稳定性越差,全塞不等于效果更好。
- 趋势是检索粒度变粗——块更大、条数更多、重排压力变小,而不是检索消失。
D4 Chunking Strategies: Five Approaches — Fixed, Recursive, Structure-Based, Parent-Child, and Semantic — and Choosing by Evaluation, Not Intuition
Semantic chunking costs considerably more than recursive splitting. How would you prove to your team that the money is well spent?语义切分比递归切分贵不少,你怎么向团队证明这笔钱值得花?
Common in ChinaCommon overseasDeep dive#chunking#evaluation#costHow to reason about it · think before answering
- This looks like a technical question but it tests whether you can run a controlled technical argument. Launching into how semantic chunking works answers a different question.
- Step one is to concede that it may well not be worth it. The gain comes from documents that have no usable structure; if your knowledge base is well-formed documents, the authors' heading hierarchy already did the semantic split for free and the money is likely wasted.
- Step two is translating 'worth it' into three measurable numbers: how much the metric moved (hit rate on the same golden set under the same token budget), how much latency moved (chunking is offline, but the end-to-end update path changes), and how much it costs (the initial full embedding pass plus recomputation amortised over update frequency).
- Step three is the control. Recursive splitting is the baseline, semantic chunking the treatment, and they must share the corpus, the questions, the context budget and the retriever. Change one variable only; a two-variable experiment proves nothing.
- Step four is a decision threshold rather than an impression. For example: below three points of hit-rate gain, no; above five points with recomputation inside the monthly budget, yes; in between, roll it out on one document class first. Fix the threshold before you run the numbers, or you will quietly bend it to fit them.
- Expect the follow-up: is there a cheaper way to the same gain. Yes — try structural splitting first, since it is free and often nearly as good, and if the structure really is unusable, apply semantic chunking only to the high-value subset rather than the whole corpus.
分析过程 · 先想清楚再作答
- 这题表面问技术,实际考的是你会不会做一次带对照组的技术论证。上来就讲语义切分原理的人,答的是另一道题。
- 第一步是先承认它可能不值。语义切分的收益来自「文档没有可用的结构」;如果知识库是结构良好的文档,作者的标题层级已经免费替你做完了语义切分,这时候花的钱大概率打水漂。**先说清适用前提,再谈证明,这一步就把大多数候选人区分开了。**
- 第二步是把「值不值」翻译成可测的三笔账:指标涨了多少(同一批标准问题、同一个 token 预算下的命中率)、延迟涨了多少(切块是离线的,但更新链路的端到端时间会变)、钱涨了多少(首次全量 embedding 的费用,加上按更新频率折算的重算费用)。只报第一笔的论证不成立。
- 第三步是设计对照。递归切分是基线,语义切分是实验组,两组必须用同一份语料、同一批问题、同一个上下文预算、同一个检索器,只改切法这一个变量。改两个变量的实验,结论一文不值。
- 第四步是给决策一个门槛,而不是给一个感想。比如:命中率相对基线提升低于三个百分点就不上;提升超过五个百分点且重算成本在月度预算内就上;中间地带先在一类文档上灰度。**门槛要在跑数字之前定好**,否则你会不自觉地去迁就已经跑出来的结果。
- 可预期的追问是「有没有更便宜的办法拿到同样的收益」。答有:先试按结构切,它零成本且效果常常接近;结构确实不可用时,再考虑只对高价值的那一部分文档做语义切分,而不是全量上。
Key points
- Start with the precondition: the gain comes from documents without usable structure, so on well-formed documents it usually is not worth it.
- Translate 'worth it' into three numbers — hit rate, latency, and cost. Reporting only the first is not an argument.
- Run a controlled comparison: same corpus, same golden set, same context budget, same retriever, with the splitting strategy as the only variable.
- Fix the decision threshold before running the numbers so you cannot bend it to fit the result afterwards.
- Try free structural splitting first, and if semantic chunking is genuinely needed, apply it to the high-value subset rather than the entire corpus.
答题要点
- 先讲适用前提:语义切分的收益来自文档没有可用结构,结构良好的文档上它大概率不值。
- 把「值不值」翻译成三笔账:命中率涨多少、延迟涨多少、钱涨多少,只报第一笔不算论证。
- 做对照实验:同语料、同问题集、同上下文预算、同检索器,只改切法一个变量。
- 决策门槛必须在跑数字之前定好,避免事后迁就结果。
- 先试零成本的按结构切;确需语义切分时也优先只覆盖高价值文档,而不是全量上。
D11 Advanced Indexing: Parent-Child Documents, Summary Indexes, Contextual Retrieval, and the Trade-Offs of Tree Aggregation vs. Graph Retrieval
Contextual retrieval needs one model call per chunk. How do you estimate that one-off cost, and what levers bring it down?上下文检索要给每个块调一次模型,这笔一次性成本怎么估?有哪些办法能压下来?
Common in ChinaCommon overseasDeep dive#contextual-retrieval#prompt-caching#costHow to reason about it · think before answering
- This checks whether you have actually done the arithmetic. Saying 'prompt caching makes it cheap' without knowing which line item it touches is a tell.
- Split the bill first: one-off = per-chunk input + output + full re-embedding; per-query = the header read twice, once by the reranker and once in the context. Keep them separate, because they scale with completely different things.
- The dominant term on the one-off side is how many times the same document is re-read. A doc split into n chunks is read n times. Prompt caching attacks exactly that: put the whole document first and mark it cacheable, pay a cache write once, then cache reads for the remaining n-1, typically an order of magnitude cheaper than input.
- Order matters. Caching is prefix-matched, so the document must come first and the chunk after. Put the varying part first and the prefix changes every call — zero cache hits. This is the most common way people get it wrong.
- Our measurement: 30 docs, 134 chunks. Without caching, 103017 input tokens; with caching, 17340 written plus 60137 read, cutting the one-off cost by roughly 29%. The finer the chunks, the bigger the saving, because re-reads multiply.
- The counter-intuitive part is the useful part: the one-off cost amortizes below 10% of per-query cost after about 217 queries. The lasting bill is the extra tokens every query carries (we measured +12.3%). So the first lever is not cheaper index building — it is keeping the header out of the context, keeping it short, and not generating it for the whole corpus indiscriminately.
- A bonus point: before spending any of it, confirm your evaluation setup can actually detect the benefit. In our offline harness the vector route contributed exactly zero unique answer documents, so it cannot answer whether headers help embeddings at all — an A/B run there hands you a wrong conclusion that looks numerically supported.
分析过程 · 先想清楚再作答
- 这题考的是你有没有真的算过账。只会说『用提示词缓存就便宜了』属于听过没做过——面试官会追问缓存到底省在哪一项上。
- 先把成本拆开:一次性 = 每块的输入 + 输出 + 全量 embedding;每次查询 = 块头在重排和上下文里各被读一遍。**这两笔要分开记**,因为它们随业务量的增长方式完全不同。
- 一次性那笔的主项是『同一篇文档被重复读了多少遍』。一篇切成 n 块就要读 n 遍,这是成本的大头。提示词缓存省的正是这一项:把整篇放在提示词最前面并标记为可缓存,第一块付一次缓存写入,后面 n-1 块只付缓存读取,而读取价通常比输入价低一个数量级。
- 顺序不能反:缓存按前缀匹配,整篇必须在前、块内容在后。把变化的块放前面,前缀次次都变,缓存一次都不会命中——这是最常见的翻车点。
- 我们的实测:30 篇、134 块,不开缓存输入 103017 token,开缓存后拆成写入 17340 加读取 60137,一次性成本降约 29%。**块切得越碎这个比例越高**,因为重复读的次数更多。
- 结论反直觉但很实用:一次性那笔是小钱,摊到 217 次查询就降到每次查询成本的一成以下;真正的长期账是每次查询多出来的那几十个 token(我们量到 +12.3%)。所以压成本的第一优先级不是压建索引,而是让块头别进上下文、别过长、别对全库无差别地生成。
- 最后一条是加分项:花这笔钱之前先确认你的评估环境**测得出**收益。我们的离线环境里向量路对召回的独立贡献实测为 0,所以它根本没法回答『块头对向量侧有没有用』——在这种环境里做的 A/B 会给你一个看起来有数字支撑的错误结论。
Key points
- Split into one-off (per-chunk input/output plus re-embedding) and per-query (header read by both reranker and generator).
- The one-off is dominated by re-reading each document n times; caching turns that into one write plus n-1 reads.
- Caching is prefix-matched: the full document must come first, the chunk after, or you get zero hits.
- Measured on 30 docs / 134 chunks, caching cut the one-off cost by about 29%, and finer chunks save more.
- The lasting cost is per query: keep headers out of the context window, keep them short, and generate them selectively.
答题要点
- 把账拆成一次性(每块的输入输出 + 全量 embedding)和每次查询(块头在重排与上下文里各读一遍)两笔。
- 一次性的大头是同一篇被重复读 n 遍;提示词缓存把它压成一次写入加 n-1 次读取。
- 缓存按前缀匹配,整篇必须放在提示词最前面,块内容在后,顺序反了一次都不会命中。
- 实测 30 篇 134 块,一次性成本降约 29%,块越碎省得越多。
- 长期账在每次查询:块头别进上下文、控制长度、只对真正需要的文档生成。
What kind of question actually requires graph retrieval? Give one concrete case where it is justified and one where it is not.什么样的问题必须上图检索?给一个该上的具体例子和一个不该上的例子。
Common in ChinaCommon overseasDeep dive#graph-rag#multi-hop#costHow to reason about it · think before answering
- This one tests whether you reach for tools you don't need. If the answer is 'multi-hop questions need a graph', the interviewer knows you haven't shipped one — multi-hop is necessary, nowhere near sufficient.
- Anchor the criterion on something observable: does the second required document share any lexical or semantic overlap with the query? If it does, ordinary hybrid retrieval will surface it and the hop is illusory. If it shares nothing, only a relation edge gets you there — that is graph territory.
- Justified case: 'who must sign off on a production failover, and what is that person's name?' One doc says the platform lead must approve; another says who the platform lead is. The second shares not one term with the query. Across all five index structures we tested, it never once appeared in a 20-item candidate pool — rechunking, headers and parent backfill all failed.
- Unjustified case: 'which process covers a capacity change, and how many working days ahead must the ticket be filed?' Also two documents, but both overlap the query lexically; hybrid retrieval ranked them second each, and one pass collected both. Building a graph for this buys a solved problem at several times the cost.
- Then state the cost, which is what makes the answer sound operational: graph building is not one extraction call. Entities need disambiguation, relations need dedup, updates force recomputing affected subgraphs, and you now run a graph store and its update pipeline.
- Expect 'what else could you do instead'. Hand multi-hop to agentic retrieval: let the model retrieve the intermediate entity first, then issue a second query with it. Near-zero build cost, paid back in latency and call count per query. Try that before you build a graph.
分析过程 · 先想清楚再作答
- 这题在考你会不会为了用而用。只要答案里出现『多跳问题就要上图检索』,面试官基本就知道你没落地过——多跳只是必要条件,远不是充分条件。
- 判据要落在一个可观察的现象上:**答案的第二篇文档和查询之间,有没有字面或语义上的重合**。有重合,普通的混合检索就能捞到它,多跳是假的;完全没有重合,只能靠一条关系边走过去,这才是图检索的领地。
- 该上的例子:问『生产库主备切换必须谁书面审批、这个人叫什么』。一篇写着须平台组组长审批,另一篇写着平台组组长是某人。第二篇跟查询一个词都不重合,我们在五种索引结构下测了一遍,它在 20 条候选池里一次都没出现过——换切法、加块头、父子回填全都无效。
- 不该上的例子:问『扩容要走哪个流程、最晚提前几个工作日提单』。同样跨两篇文档,但两篇都跟查询有明显字面重合,混合检索把它们分别排在第 2 名,一次检索就凑齐了。为它建图是拿几倍成本买一个已经解决的问题。
- 然后说代价,这一段决定了你像不像做过:建图不止一次抽取调用,实体要消歧、关系要去重、文档更新时受影响的子图要重算,还要多维护一套图存储和一套更新链路。
- 可预期的追问是『不上图检索还有什么办法』。答案是把多跳交给 Agentic 检索:让模型先查出中间实体,再拿这个实体发起第二次检索。它的一次性成本几乎为零,代价换成了每次查询的延迟与调用次数——先试这条,试不通再考虑建图。
Key points
- The test is not 'is it multi-hop' but 'does the second document overlap the query at all' — only zero overlap earns a graph.
- Justified: the approver question, where an intermediate entity is the only bridge and the second doc never enters the candidate pool.
- Not justified: a multi-hop question whose documents both overlap the query — hybrid retrieval collects them in one pass.
- Real graph cost is entity disambiguation, relation dedup, incremental subgraph recomputation and a whole extra store — not a single extraction call.
- Try two-pass agentic retrieval first; build the graph only when that fails.
答题要点
- 判据不是『是不是多跳』,而是『第二篇文档跟查询有没有字面或语义重合』——没有重合才轮得到图检索。
- 该上:审批人那类问题,中间实体是唯一的桥,第二篇文档在候选池里一次都不出现。
- 不该上:两篇都跟查询有重合的多跳题,混合检索一次就能凑齐。
- 建图的真实成本是实体消歧、关系去重、增量重算和一套额外的图存储,不是一次抽取调用。
- 先试 Agentic 检索的两次查询,走不通再考虑建图。
Build an AI Short-Drama Production Pipeline With Agents in 14 Days
D3 Character Consistency: Character Sheets, Reference Images, and Style Locking — Keeping the Same Person the Same Person in Every Shot
How would you design the cache key for reusing generated assets so that you save money without serving the wrong asset?生成类资产要做复用,缓存键你会怎么设计,才能既省钱又不会串戏?
Common in ChinaCommon overseasDeep dive#caching#cost#image-generationHow to reason about it · think before answering
- This question is about two kinds of cache error with wildly asymmetric cost. A miss only costs money; a wrong hit puts last episode's prop into this one. The first is a number, the second is a content incident.
- The derivation is one sentence: the key must be computed from every input that changes the artifact, and nothing else. Include something irrelevant, like the output path, and one directory refactor invalidates everything and you pay again; omit something relevant, like the prompt, and a changed description silently serves the old image.
- Concretely, hash the asset kind, the owning entity id, the variant name, the full prompt, the reference image identity and the seed. Take a short digest as the id, and store those fields verbatim in the metadata so any artifact can be reproduced.
- Then name the boundaries yourself: does the model id and version belong in the key? Yes. What if the style template changes? It is part of the prompt, so it invalidates everything by construction — which is why templates should carry a version number, letting you choose the blast radius.
- One more production note: never cache failed generations, or you will faithfully reuse an empty result that safety review rejected. Cache hits also belong in the cost ledger, flagged as hits, otherwise you cannot report how much caching saved.
- Expect the follow-up: should the cache expire? Content assets usually should not expire on time; invalidate explicitly by version instead, because a time-based expiry regenerates a whole episode at the least convenient moment.
分析过程 · 先想清楚再作答
- 这题考的是缓存的两类错误,而且两类的代价完全不对称。少命中只是多花钱,错命中会把上一集的道具塞进这一集——前者可量化,后者是内容事故。
- 推导链只有一句:**键必须由所有会改变产物的输入算出来,一项不多一项不少。** 多算了不该算的(比如输出路径),改一次目录结构缓存全部失效,白花一遍钱;少算了该算的(比如提示词),换了描述还命中老图,就是串戏。
- 落到这个场景,参与哈希的是:资产类别、归属对象、变体名、完整提示词、参考图标识、随机种子。用 sha1 之类取个短摘要当 id,元数据里再把这几项原样存一份,出问题能照着复现。
- 然后主动把边界说清楚,这是加分项:模型 id 与版本要不要进键?要。风格模板改了怎么办?它是提示词的一部分,进键之后天然全部失效——所以模板要谨慎改,或者给它一个版本号,让你能决定失效的范围。
- 生产视角还有一条:失败的生成不要写进缓存,否则你会稳定复用一张被审核拦下的空结果。命中缓存的那条路径也要记台账并标成命中,不然你算不出缓存到底省了多少钱。
- 可以预期的追问:缓存要不要过期?答案是内容型资产通常不设时间过期,而是靠版本号显式失效;时间过期会在你毫无预期的时候让一整集重新生成一遍。
Key points
- Derive the key from everything that changes the artifact: asset kind, owner id, variant, full prompt, reference image identity, seed, plus model id and version
- Keep output paths and filenames out of the key, or one directory refactor invalidates the whole cache and you pay twice
- Omitting inputs like the prompt causes wrong hits, which are content incidents and far costlier than misses
- Store the hashed fields verbatim in metadata so any artifact is reproducible, and never cache failed generations
- Record cache hits in the cost ledger flagged as hits, and invalidate explicitly by version rather than by time
答题要点
- 键由所有会改变产物的输入算出:资产类别、归属对象、变体名、完整提示词、参考图标识、随机种子,再加模型 id 与版本
- 不要把输出路径或文件名放进键,改目录结构会让缓存整体失效,白付一遍钱
- 少算提示词这类输入会导致错命中,那是内容事故,代价远高于少命中
- 元数据里原样保存参与哈希的各项,出问题能复现;失败的生成不写缓存
- 命中缓存也要记台账并标成命中,否则算不出缓存省了多少;失效靠显式版本号而不是时间过期
D4 From Shot to Footage: Image-to-Video, Polling Async Tasks, and Retrying Failures
When a generation API returns a failure, how do you decide whether to retry, and what happens after the retries run out?生成类接口返回失败,你怎么判断该不该重试?重试几次之后该做什么?
Common in ChinaCommon overseasDeep dive#error-handling#retry#costHow to reason about it · think before answering
- The hinge is 'decide'. Bucketing by the leading digit of the HTTP status is the classic wrong answer, because generation APIs often return HTTP 200 with a business error code in the body.
- Give a reusable test instead of reciting a code table: ask three questions — will waiting help, will changing the input help, or does a human have to step in? They map onto three dispositions: back off and retry, fix the request, alert immediately.
- Concretely: rate limits and server errors are the first bucket and the program handles them; invalid parameters and content moderation are the second, where retrying repeats the same error and burns rate-limit budget that genuinely retryable tasks needed; auth failure and insufficient balance are the third, where retrying only delays the alert.
- Handle timeout separately — this is the line that signals experience. A timeout is unknown, not failed: the job may still be running, or may have finished. So never resubmit blindly; look up the idempotency key for an existing artifact first.
- When retries are exhausted, do three things: mark the item failed with the last error code and the exact request parameters, keep processing the rest of the batch instead of aborting it, and aggregate the failures into one readable alert rather than one per item.
- Expect the follow-up: how many retries? Scale it by unit price. The more expensive the call, the fewer automatic retries, and expensive failures should go to a human for review before being redone.
分析过程 · 先想清楚再作答
- 这题的题眼是「判断」。按状态码首位数字一刀切是最常见的错误答案,因为生成类接口的业务错误码往往和 HTTP 状态码不在一个层面上——很多厂商的失败是 HTTP 200 加一个响应体里的业务码。
- 给一条可复用的判据,比背错误码表有用:问三个问题——等一等会不会好、改输入会不会好、还是必须叫人来。三个问题对应三种处置:退避重试、修请求、立刻告警。
- 落到具体:限流和服务端故障属于第一类,程序自己扛;参数无效与内容审核属于第二类,重试一万次都是同一个错,而且会挤占限流额度让真正该重试的排不上号;鉴权失败与余额不足属于第三类,重试只会延迟告警。
- 然后单独处理超时,这是最能体现经验的一条:超时不是失败,是状态未知,对方队列里那个任务可能还在跑甚至已经成了。所以超时之后不能直接重提,要先按幂等键查一遍已有产物。
- 重试用尽之后要做三件事,缺一不可:把这一条标成失败并记下最后一次的错误码与请求参数、继续跑批次里剩下的任务不要中断、把失败清单汇总成一次可读的告警而不是每条发一次。
- 可以预期的追问:重试次数怎么定?按单价定。单价越高,允许的重试次数越少,而且高单价的失败更应该先送人复核再决定要不要重做。
Key points
- Do not bucket by the leading HTTP digit; generation APIs often hide the business error code inside an HTTP 200 body
- Use three questions — will waiting help, will changing the input help, or is a human required — mapping to back off, fix the request, alert
- Rate limits and server errors are retryable; invalid parameters and moderation blocks are not and waste rate-limit budget; auth and balance failures need an alert
- A timeout is unknown rather than failed: check the idempotency key for an existing artifact before resubmitting, or you pay twice
- When retries run out, mark the item failed with its error code and request parameters, keep the batch running, and aggregate failures into one alert; scale retry counts by unit price
答题要点
- 不要按状态码首位一刀切,生成类接口的业务错误码常常藏在 HTTP 200 的响应体里
- 判据是三个问题:等一等会不会好、改输入会不会好、还是必须叫人来,分别对应退避重试、修请求、立刻告警
- 限流与服务端故障可重试;参数无效与内容审核重试无用且会挤占限流额度;鉴权失败与余额不足必须告警
- 超时是状态未知不是失败,重试前先按幂等键查一遍已有产物,否则会重复计费
- 重试用尽后:标记失败并留下错误码与请求参数、不中断整批、把失败汇总成一次可读告警;重试次数按单价定