面灵AI→

字节AI Agent开发一面:三层编排、上下文隔离与GRPO

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

《面试题目》

  1. 先自我介绍,挑一个你主导的 Agent 项目讲。
  2. 为什么非得三级架构,单层不行吗?编排层单独拆成 Agent 图什么?
  3. 主 Agent 跟子 Agent 上下文怎么传?怎么保证不漏掉关键信息?
  4. 那 Agent 上下文超长怎么压?
  5. RAG 的召回率一般从哪些角度去提?父子文档索引解决了什么?
  6. 手撕:把两个多层嵌套的 JSON 做深度合并,key 冲突且类型不同怎么办?
  7. 评测 Agent 你怎么搭 benchmark?
  8. 多个 Agent 之间上下文和状态怎么做到互不串?
  9. GRPO 跟 PPO 在奖励归因上差在哪?为什么 GRPO 不用 critic?

《参考解析》

为什么拆三级编排:单层 Agent 处理复杂任务时,所有子任务的上下文都堆在一条对话历史里,结果有两个:一是上下文迅速膨胀,关键信息被淹没、推理质量下降;二是职责混在一起,没法给不同子任务配不同的工具集和权限。拆成「主 Agent 编排 + 编排层 + 执行子 Agent」的价值在于三件事:上下文隔离(每个子 Agent 只拿到自己那部分输入,互不污染)、权限收敛(执行层按角色拿最小权限工具,编排层只做调度不碰生产写操作)、以及可评测(每个子 Agent 能单独跑测试集,端到端失败时能定位到具体哪一环)。要向面试官说清的是「拆的收益必须大于协调成本」——如果任务本身是线性的、步骤可枚举,那单层加工具就够了,硬拆只会让延迟和 token 成本翻倍、错误在层间被放大。

主 Agent 到子 Agent 的上下文传递:关键是「传结构化的事实,不传整段对话」。可行的做法是把子任务描述定义成固定 schema:目标、输入数据(实体与字段值)、硬约束(预算、时限、禁止动作)、期望输出格式、以及已知的前置结论。这样字段级别明确,摘要压缩时也知道哪些字段不能丢。纯自然语言摘要的问题是模型会把数字、ID、枚举值这类「看起来不重要」的内容压掉,所以工程上要么把关键字段单独抽出来以结构化形式随消息一起传(摘要负责叙事,字段负责事实),要么在 schema 里标记必填字段并在子 Agent 侧做入参校验,缺字段就打回请求补全而不是让它猜。再进一步是共享一个只读的「任务黑板」,子 Agent 需要细节时按 key 回捞原文,而不是把原文塞进 prompt。

上下文超长的压缩:主流三条路。滑动窗口只保最近 N 轮,最省事但会丢早期约束;摘要压缩把历史压成一段话,能保主线但细节有损,而且摘要本身要花一次模型调用;结构化状态外置是更稳的做法——把对话里的实体、事件、结论、待办拆成字段存到外部状态里,prompt 里只放当前必要的那部分,其余按需检索回填。实践中把它们组合起来:近期原文 + 中期结构化摘要 + 远期只保留结论与实体索引。压缩策略要选「不可逆性最低」的那一层压——数字、ID、链接、用户显式约束永不绝压缩,宁可原文保留。

RAG 召回率怎么提:分三段找抓手。索引段:切块策略(按语义边界切、保留父子结构、代码块与表格不切)、embedding 模型选型与领域微调、给每块补上标题与上下文摘要(contextual retrieval)让孤立片段带上全局信息。检索段:混合检索(BM25 + 向量,各补对方短板)、查询改写与扩展(把口语 query 扩成多角度表述)、HyDE(先生成假设答案再检索)、多路召回后用 RRF 融合。排序段:Cross-Encoder 精排把真正相关的顶上去,做 Top-K 截断而不是把几十条都塞给模型。度量上必须能报数:Recall@k 看召回到了没有、MRR 和 nDCG 看排序质量,再配合端到端的「有依据率」判断检索是否真的帮到生成。

父子文档索引解决什么:它解决「检索要小块、生成要大块」的矛盾。检索时用小的子块(句子或段级)做向量匹配,因为小块语义集中、相似度更准;命中后不把小块本身送进模型,而是沿父子关系返回它所属的父块(或父块加相邻子块),让模型拿到完整上下文。这样召回精度和上下文完整性各取所需。代价是索引结构更复杂(需要维护两级映射)、同一父块被多条子块命中时要去重、以及父块过大时仍要二次截断。同族的做法还有句子窗口检索(命中句子后带前后 N 句)和小块检索 + 邻近扩展,思路一致。

多层嵌套 JSON 的深度合并:递归处理,规则要先明确再写代码。一是键在两个对象里都存在:如果两边都是对象,递归合并;如果两边都是数组,按业务约定选「拼接」或「按索引逐位合并」(多数配置合并场景选拼接);如果类型不同(一边对象一边标量、或数组对标量),不能静默覆盖,要么后者覆盖前者并记一条冲突日志,要么按既定优先级(比如以左侧为准)保留并向调用方返回冲突列表。二是键只在一侧存在:直接纳入结果。三是递归深度很大时要防栈溢出,可以改成显式栈的迭代实现。手撕时最容易丢分的两点:没有先把冲突策略讲清楚就直接写;以及把数组也当对象递归,导致 [1,2] 和 [3] 合出 {"0":3,"1":2} 这种荒唐结果。

Agent benchmark 怎么搭:分四层。用例集要分层设计——冒烟(十几条主干路径,秒级反馈)、回归(覆盖历史 bug 与边界)、对抗(诱导走错路径、参数注入、超长输入)、以及从线上 badcase 沉淀的真实长尾。判定方式要分确定性断言与 LLM 评分两档:能代码判定的全用代码(文件是否生成、命令退出码、SQL 结果集、JSON 是否符合 schema、是否调用了指定工具、调用次数是否超预算),不确定的才用 judge 加评分细则,并且要用人工标注集测 judge 与人的一致率。指标除了任务成功率,还要看工具选择准确率、平均交互轮数、token 成本、P95 延迟、失败类型分布,并对同一用例做多次采样(pass^k)抵消模型随机性。最后要把 benchmark 接进 CI 做门禁,并对测试集做版本化和冻结——否则调 prompt 的过程会把它慢慢过拟合掉。

多 Agent 上下文与状态隔离:三条边界一起守。上下文隔离:每个 Agent 独立上下文窗口,彼此只通过显式消息传递,绝不共享对话历史——共享历史最典型的故障是 A 的中间推理被 B 当成指令。状态隔离:全局状态(任务进度、已完成子任务、中间产物)集中存放且对执行 Agent 只读,所有写操作经编排层串行化,避免并发写互相覆盖。资源隔离:每个 Agent 独立的沙箱与工作目录,工具凭据按角色最小化下发。文件级冲突用版本号乐观锁或分段锁处理。把这三条讲清楚,比笼统说「用 session 隔离」得分高得多。

GRPO 与 PPO 的差别:PPO 是 actor-critic 结构,除了策略网络还要训一个价值网络(critic)来估计状态价值、算优势函数,再用裁剪的目标函数限制每步更新幅度。GRPO 去掉了 critic:对同一个 prompt 采样一组(group)输出,用组内的平均奖励作为基线,每个样本的优势就是「自己的奖励减组内均值再除以组内标准差」,也就是用组内相对排名代替价值网络估计。好处很直接——省掉一个和策略同量级的模型,显存和训练成本大幅下降,而且避免了 critic 估计不准带来的偏差;代价是必须一次性采样多条输出(采样成本上升),组内奖励方差过大或全部相同时优势信号会退化。归因上的差异是:PPO 的奖励归因依赖 critic 对每个中间状态的价值估计,GRPO 只做整条输出的相对比较,所以 GRPO 更适合「结果可打分、过程难评估」的任务(数学、代码、可验证奖励),PPO 更适合有稠密过程奖励的场景。