字节跳动 AI Agent 开发一面:90 分钟共享屏幕看代码
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍,重点讲你最近半年做的最复杂的 Agent 项目。
- 你这个 Agent 的调度层 Planner/Executor 是怎么实现的?为什么用异步不用同步?异步任务状态怎么持久化?
- 你提到用了 ReAct,具体怎么实现的?Thought、Action、Observation 在你的代码里怎么体现?每一步输入输出格式是什么?
- LLM 返回的 tool call 格式不合法或参数类型不对,你的系统怎么处理?有没有做校验和重试?重试几次?
- Agent 执行长任务时,中间某一步工具调用了 3 秒还没返回,你怎么处理?超时时间怎么设?
- 上下文管理怎么做的?对话超过 100 轮怎么控制 token 消耗?
- 你说做了上下文压缩,具体怎么压缩的?压缩提示词怎么写的?压缩后丢失关键信息怎么办?
- 如果第 3 步调用的工具返回了 50MB 的数据,上下文窗口直接炸了,你的系统怎么处理?不要跟我说摘要,我要听具体的工程实现。
- 多 Agent 同时修改同一个文件,怎么防止冲突?有没有用分布式锁?锁的粒度是什么?
- 你说 Agent 有断点续传,服务重启后怎么恢复未完成的任务?存了哪些状态?存在哪里?恢复后怎么保证状态一致性?恢复失败了怎么办?
- Agent 出现路径震荡(反复失败)的原因是什么?怎么优化?
- 长周期任务中 Agent 容易行为漂移,你怎么检测和纠正?
- 多 Agent 之间怎么通信?用过消息队列吗?子 Agent 挂了怎么处理?
- 你怎么评测一个 Agent 系统的好坏?关注哪些指标?端到端成功率多少?
- 你说做了 Agent 评测,评测集怎么构建的?覆盖了哪些场景?多少条?怎么保证覆盖所有场景且可用?
- 人工归因的标准是什么?case 错误率多少?回归验证结果如何?
- 用模型自动化生成评测集时,怎么保证用到正确的信息?
- 你怎么理解 Harness?一个标准的 Harness 包含哪些核心模块?
- Harness 和 orchestrator 有什么区别?
- 你们项目为什么不用 LangChain?自己封装的原因是什么?
- 不依赖开源 Agent 框架时,你需要自己实现哪些核心模块?
- 你怎么管理 Agent 的长期记忆?存了什么?怎么检索?记忆冲突怎么处理?
- 短期记忆和长期记忆怎么区分?哪些信息适合长期保存?
- 用户偏好信息怎么处理和存储?为什么用异步?
- 你怎么防止 Agent 被 Prompt Injection 攻击?用户诱导 Agent 泄露 System Prompt 怎么办?
- Agent 对工具调用不做限制会产生哪些风险?怎么防范?
- 你怎么保证 Agent 生成代码的安全性?有没有在沙箱里执行?沙箱怎么设计的?
- 你说用了 MCP,MCP 解决了什么问题?和直接调 API 比优势在哪?
- 如果 Agent 有 100 个工具,接口数量太多,你怎么管理?工具注册中心怎么设计的?
- 你怎么控制 Agent 的 Token 成本?有哪些具体优化策略?
- 如果这个 Agent 要支持每天 10 万次请求,平均每个任务调用 5 个工具,每次工具调用 200ms,大模型推理 800ms,你需要多少并发资源?怎么设计调度?
- 你刚才说你们用了向量检索,RAG 的完整流程讲一下?文档切分策略是什么?chunk size 怎么选?
- 如果 Markdown 文档没有标题,你怎么切分?有没有试过按语义切分?
- BM25 和向量检索的结果怎么融合?RRF 的 k 值怎么设?
- 你做的 Agent 和普通 AI 应用的本质区别是什么?
- 手撕:给定两个嵌套结构的 JSON 数据,实现合并函数。规则是键值对递归合并相同 key,仅在一个字典中的 key 直接保留,列表拼接。追问:如果 Key 冲突且类型不同怎么办?如果嵌套深度超过 1 万层怎么办?
《参考解析》
Planner/Executor 与状态持久化:异步的意义在于一个任务里既有秒级完成的工具调用,也有几十秒的模型推理和外部等待,同步串行会让吞吐被最慢的一环钉死,也不好做超时与取消。工程上通常把任务建成有向图或步骤队列:Planner 产出带依赖关系的步骤,Executor 用线程池或事件循环并发执行无依赖步骤,每一步的结果回写共享状态。状态持久化要落在数据库而不是内存:一张任务表(任务 ID、目标、状态机状态、重试次数、截止时间)+ 一张步骤表(步骤 ID、依赖、输入参数哈希、结果引用、执行状态、耗时与错误),状态迁移用带版本号的 CAS 更新避免并发覆盖。这样才能做到崩溃后可恢复:重启后扫描处于运行中的任务,按步骤状态重放未完成的部分,已成功的步骤直接用已存结果,不重复产生副作用。
ReAct 的实现与工具调用健壮性:ReAct 是一个循环:把当前观察和工具清单拼进上下文,让模型输出 Thought 与 Action,系统解析 Action 并真正调用工具,把 Observation 追加回上下文再进入下一轮,直到模型给出 Final Answer 或触发终止条件(步数上限、时间上限、重复动作检测)。工程上必须用结构化的方式约束输出(JSON schema 或函数调用格式),每步的输入输出都记进 trace 便于复盘。工具调用的健壮性分三层:解析层用 schema 校验参数类型与必填项,非法就直接把校验错误回灌给模型让它重写,重试次数设上限(常见 2 到 3 次)并逐次收紧提示;语义层对参数做业务校验(ID 是否存在、权限是否允许);执行层给每次调用带幂等键,超时后先查状态再决定是否重试,避免重复下单类的副作用。
上下文管理与大结果处理:控制 token 不能只靠摘要。可行的分层是:把关键事实(任务目标、已确认的事实、待办、用户偏好)抽成结构化 state 常驻在短提示里,历史对话按轮次做滑动窗口 + 向量检索式回捞,被淘汰的部分才做摘要归档;工具清单和长文档按需检索加载,而不是全量塞进 prompt。压缩提示词要明确写出「保留哪些字段、丢弃哪些、用什么格式输出」,并要求输出结构化 JSON 以便程序消费,压缩后还要用关键字段回填校验,防止压缩把决定性细节抹掉。遇到 50MB 的工具返回,正确做法是根本不进上下文:先落对象存储或本地文件,只把「引用 ID + 结构摘要 + 可查询方式」交给模型,需要细节时按分页或过滤条件回查;同时在做大结果返回的工具契约里就约定分页参数、最大返回条数和字段裁剪,从源头控制体积。
长任务可靠性:超时、续传、震荡与漂移:超时值要分层设定:单次工具调用按下游 P99 加余量(并通过异步等待而非阻塞),整体任务设总时长与最大步数,超时后进入可恢复状态而不是直接失败。断点续传的前提是状态可持久化且步骤幂等:恢复时先校验状态一致性(版本号、时间戳、外部副作用是否已发生),对状态可疑的任务走人工核对或重新规划,恢复失败要有死信队列与告警,绝不能静默丢弃。路径震荡(反复失败、来回试同一个动作)的常见原因是观测信息不足、工具错误信息不可读、以及缺少失败记忆;优化手段是记录已尝试动作与失败原因并注入上下文、让工具返回可操作的错误、加重复动作检测与强制换策略、必要时降低自主度改为向用户提问。行为漂移的检测靠护栏:每 N 步做一次目标一致性校验(用模型或规则检查当前计划是否仍服务于原目标)、设预算与进度检查点,偏了就重规划或中止。
多 Agent 协作、框架取舍与 Harness 理解:多 Agent 同时改同一份资源,冲突控制不能只靠一把全局锁(会把并发度锁死)。常见做法是锁到资源粒度(文件级或符号级),配合乐观并发:写前带版本号、提交时校验,冲突就走重试或合并;更彻底的是让多个 Agent 不直接改同一文件,而是各自产出补丁,由单一的合并者串行应用。Agent 间通信推荐走消息队列或事件总线,好处是解耦、可重放、天然支持子 Agent 挂掉后的重新入队与超时接管,但要求消息幂等并对乱序有处理。至于为什么不用 LangChain 这类框架:核心诉求是控制力(提示与解析细节、状态与恢复、可观测与评测)和依赖稳定性,框架抽象会藏掉关键行为、版本升级还会带来破坏性变更;代价是自研的调度、记忆、工具注册、重试与追踪都要自己写。Harness 可以理解为模型之外的整套运行时骨架——工具注册与调用、上下文与记忆、循环与终止、权限与沙箱、可观测与评测、错误恢复;orchestrator 更多指其中的调度编排那一层。MCP 的价值在于把工具接入标准化,一次实现多处复用,比每个应用各写一套 API 适配层更容易治理。
评测、成本与安全:Agent 评测要同时有机器可判的硬指标和语义判断:端到端任务成功率、工具调用准确率与参数正确率、平均步数、超时与重试率、Token 消耗与单任务成本、P95 时延,再由模型评审回答质量,并定期用人工标注校准。评测集的建设要从真实 trace 和 oncall 工单里来:按场景矩阵(工具组合、任务难度、边界与对抗样本)分层采样,每条 case 带输入、期望结果与约束,人工归因后去重标注,核心回归集要小而稳、每次必跑。用模型自动扩样时必须给足可信来源(真实文档、真实工具返回),并抽样人工复核,否则会引入错误期望。成本控制的主要抓手是提示与上下文裁剪、工具结果压缩、结果缓存与去重、小模型分流简单步骤、批量化调用。容量估算要用排队论:单任务平均占用时长 = 工具数 × 工具耗时 + 推理耗时(可并行部分要另算),每日 10 万次请求折算成到达率,用 Little’s Law(并发 = 到达率 × 平均服务时间)估并发,再留 30% 以上余量并做限流与优先级队列。安全上要防提示注入(外部内容当不可信数据、与指令隔离、工具权限最小化与白名单)、防 System Prompt 泄露(不依赖保密而是假设可见)、防危险工具滥用(沙箱执行、网络与文件访问受限、危险操作二次确认)。手撕的 JSON 合并是标准递归:字典递归合并同名 key、单边 key 直接保留、列表拼接;类型不同时给出明确策略(报错或按优先级覆盖,不要静默丢数据),深度上万层必须改成显式栈迭代或加深度上限,否则递归会爆栈。