面灵AI→

字节一面 Agent 岗:ReAct、幂等与上下文压缩连环追问

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

  1. 自我介绍,重点讲一个你做过的最复杂的 Agent 项目。
  2. 你这个 Agent 的整体架构是怎样的?画一下架构图,讲清楚每一层负责什么。
  3. 你提到用了 ReAct 模式,具体怎么实现的?Thought、Action、Observation 在你的代码里怎么体现?
  4. 每一步的输入输出格式是怎么约定的?有没有用结构化输出?
  5. 如果 LLM 返回的 tool call 格式不合法,或者参数类型不对,你的系统怎么处理?
  6. 有没有做校验和重试?重试几次?重试会不会导致重复操作?
  7. 工具调用超时后怎么处理?超时时间怎么设?
  8. 幂等怎么设计?幂等 key 怎么生成?为什么不让大模型自己生成 key?
  9. 上下文管理是怎么做的?如果对话超过 100 轮,你怎么控制 token 消耗?
  10. 上下文压缩具体怎么实现?压缩提示词怎么写的?
  11. 压缩完怎么确认 LLM 真的完成了压缩?
  12. 压缩后丢失了关键信息导致任务失败,你怎么回退?
  13. 长流程任务如果中途服务重启了,怎么恢复未完成的任务?
  14. 你存了哪些状态信息?存在哪里?恢复后怎么保证状态一致性?
  15. 多 Agent 之间怎么通信?消息队列还是共享内存?
  16. 子 Agent 挂了怎么办?怎么保证任务不中断?
  17. 多个 Agent 同时修改同一个文件,怎么避免冲突?有没有用分布式锁?
  18. Agent 之间传递的上下文怎么保证完整、不遗漏关键信息?
  19. 如果传给子 Agent 的上下文不完整,导致它做了错误决策,你怎么发现和补救?
  20. 你做过 Agent 评测吗?评测集怎么构建?多少条?
  21. 评测指标关注哪些?准确率、任务完成率、人工介入率?
  22. 如果模型输出 JSON 格式不稳定,怎么校验?Schema 怎么设计?
  23. 如果评测集覆盖不全,怎么发现?
  24. 你平时怎么用 AI 写代码?你的 AI Coding 工作流完整描述一下。
  25. 从拿到需求到提交代码,AI 参与了哪些环节?每个环节你做了什么?
  26. 你如何确保 AI 生成的代码质量?如果 AI 生成的代码能跑但逻辑很烂,哪些问题必须改?
  27. 如果 AI 连续三次没修好一个 Bug,你会怎么处理?有没有遇到过真实案例?
  28. 你最近在关注 Agent 领域的什么新技术?DeepSeek-Harness 和 LangChain 的本质区别是什么?
  29. 手撕:合并嵌套 JSON。给定两个嵌套结构的 JSON 数据,实现合并函数;规则是相同 key 递归合并、仅在一个字典中的 key 直接保留、列表拼接;要求处理 key 冲突且类型不同的情况,写出完整代码并分析时间复杂度。

《参考解析》

ReAct 的工程落地:格式约定比「用了 ReAct」重要

ReAct 的本质是把「想一步 → 做一步 → 看结果」显式化成文本循环:模型输出 Thought(推理)和 Action(工具名 + 参数),运行时执行工具并把 Observation 拼回上下文,进入下一轮,直到模型给出 Final Answer。工程上真正决定成败的是格式约定和终止条件:每一步用固定模板(或直接走模型的 function calling / JSON mode),在 prompt 里给出正例反例;运行时解析失败要有兜底(抽 JSON 片段、修尾逗号、截断补括号);必须设最大步数、最大 token 和整体超时三个硬上限,否则一个打转的循环能烧掉整天的 token。此外要防「原地打转」:对 工具名 + 参数 做哈希去重计数,连续 N 次相同调用或同一工具反复失败就中断、换策略或转人工。

tool call 容错:校验、重试与幂等的三角关系

模型输出永远当成不可信输入:工具名不能直接拿去路由函数(一个幻觉出来的名字可能触发任意调用),参数必须过一遍服务端 JSON Schema / Pydantic 校验。校验失败时把结构化错误回填给模型让它自修正,体验比直接报错好得多,但要设重试上限(2~3 次)并准备降级路径(换工具、追问澄清、转人工)。

重试和幂等是一对:读操作随便重试,写操作必须幂等,否则「超时但其实执行成功了」的重试会变成下两次单。幂等 key 的正确生成方式是业务侧确定性派生——用「会话 ID + 步骤序号 + 工具名 + 规范化参数」的哈希,而不是让大模型自己编一个 key:模型生成的 key 每次调用都可能不一样(温度、上下文变化),等于没有幂等;而且让模型参与生成等于把幂等性建立在不可信输出上。服务端拿 key 去查「是否已执行过」,已执行直接返回上次结果。超时时间的设置要分层:单次工具调用超时(按该工具 P99 的 2~3 倍)、单步 Agent 超时、整个任务超时,三级都要有,并且超时后的错误信息要能让模型判断「能不能换个方式重试」。

上下文压缩与长流程状态恢复

超过 100 轮后 token 必然炸,常见策略按性价比排序:① 固定不可丢弃的部分(系统指令、任务目标、用户核心约束);② 对历史做滚动摘要,把「已确认的事实、已完成的步骤、待办」结构化保留,原始对话丢弃;③ 只保留最近 N 轮原文;④ 把长工具返回落盘,上下文里只留引用和摘要。压缩提示词要写成有 schema 的抽取任务(输出固定字段),而不是「帮我总结一下」。压缩完要验证:检查输出是否是合法结构、关键字段是否为空、是否还含有原始目标中的实体,任何一项不过就重试或退化成「原文保留 + 只丢最早的一批」。

压缩丢信息导致任务失败时,回退靠的是原始记录没有真的删掉——历史消息、工具调用入参出参都持久化在库里,压缩只影响送进模型的那一份视图;出问题可以按任务 ID 重建完整上下文重新跑。同理,服务重启后要恢复未完成任务,前提是把状态存成外部化的、可重放的形式:任务状态机(pending/running/done/failed)、已完成步骤的幂等 key、工具调用记录、模型与 prompt 版本、中间产物引用。恢复时以持久化状态为准做幂等重放,而不是从头再来;一致性靠状态机流转加乐观锁(版本号)保证,恢复失败就落到明确的失败态并告警,绝不静默重头跑。

多 Agent 协作:通信、写冲突与上下文传递

通信选消息队列还是共享内存,看两点:是否跨进程/跨机(跨就是 MQ,进程内共享内存/直接调用即可)、是否需要解耦与削峰(需要就 MQ)。要补一句:MQ 至少一次投递语义意味着消费侧也必须幂等。子 Agent 挂掉的保护手段是心跳 + 超时 + 重试 + 熔断,重试要落到「任务分片」粒度,不能让整个任务重来。

多个 Agent 同时改同一份资源(文件、数据库行、工单)时,别指望靠协调提示词解决,要靠机制:文件级用租约/锁文件或干脆让每个 Agent 只写自己的分片再合并;数据库用行锁 / 乐观锁(版本号 CAS);跨机统一用分布式锁(Redis Redlock 或 etcd lease)并设 TTL 与续约,防止持锁进程挂掉造成死锁。

上下文传递的完整性靠结构化交接单而不是把历史对话整段转发:handoff 时明确写出任务目标、已确认事实、已完成动作及其结果、当前阻塞、期望输出格式,并做一次校验(必填字段非空、引用的中间产物 ID 存在)。子 Agent 判断错误时的发现机制是「回到父级做结果校验」:父级对子任务结果做 schema 校验 + 事实一致性检查(引用的文件/ID 是否真实存在),不一致就带着具体差异重派,而不是笼统地说「再试一次」。

Agent 评测与 AI Coding 工作流

评测集要从真实流量与失败案例里长出来,而不是坐在工位上编:把线上 badcase、人工介入过的会话、边界场景各按比例采样,规模从几十条起步,按能力维度分层(单工具调用、多步规划、长上下文、异常恢复),每条给出标准答案或可判定的成功条件。指标除了准确率,还要看任务完成率、平均步数(成本)、工具调用成功率、人工介入率、超时率、以及端到端的 P95 延迟。覆盖不全的发现办法是分层看指标:整体涨但某一维度跌,就说明新增数据偏科;也可以做「扰动测试」(改输入措辞、注入噪声、删掉一条关键信息)看模型是否还稳。Schema 设计上宁可窄而严:字段类型明确、必填项显式、枚举值穷尽,配 additionalProperties: false,避免模型自由发挥。

AI Coding 工作流要能说清「哪里让 AI 做、哪里人把关」:需求澄清与方案设计人主导,样板代码、测试用例、重构、写文档、翻日志交给 AI,自己负责审关键逻辑(并发、边界、错误处理、安全、性能)和最终验收。AI 生成的代码能跑但逻辑烂时,必须改的是:错误被吞掉(catch 了什么都不做)、资源泄漏、无边界校验、隐式全局状态、复制粘贴出的重复逻辑、以及看不出意图的命名与魔法数。连续三次修不好同一个 bug 时正确动作是停下来换信息源:让 AI 复现并给出根因假设与验证方法,缩小到最小可复现用例,必要时人肉读代码或加日志,而不是继续换措辞重问。

手撕:嵌套 JSON 合并

递归是自然的解法:对两个 dict 的 key 并集遍历,两边都有就递归合并;只有一边有就直接取;两边都是 list 就拼接(注意应该是浅拼接还是逐元素递归合并,取决于业务语义,面试时要问清);类型不同(比如一边 dict 一边标量)时要显式定义策略——常见是「后者覆盖前者」或「报错拒绝」,绝不能隐式强转。复杂度是 O(两个 JSON 的总节点数),空间上递归深度等于最大嵌套深度。如果要求不改动入参,就要在合并时拷贝节点。写完主动补充:嵌套极深时递归会爆栈,改成显式栈的迭代版本;list 拼接要说明是否去重、是否保持顺序。