面灵AI→

字节跳动 Agent 开发一面:Harness 没答上来,居然还能过?

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

《面试题目》

  1. 你们 Agent 项目的整体架构是怎么设计的?
  2. Harness 和 LangChain 的本质区别是什么?
  3. Harness 里面怎么管理状态?
  4. Agent Loop 是怎么实现的?Plan / Executor / Checker 怎么分工?
  5. ReAct 和 Plan 模式有什么区别?分别适合什么场景?
  6. 上下文超过模型限制怎么处理?
  7. Agent 出现路径震荡怎么优化?
  8. Context 和长期 Memory 有什么区别?
  9. 大量工具描述导致 Prompt 过长怎么办?
  10. 多个 Agent 同时修改文件怎么避免冲突?
  11. Agent 长任务从 5 分钟变成 20 分钟,怎么排查?
  12. 工具调用参数错误、超时、重试怎么设计?
  13. LLM 返回 tool call 格式不合法怎么容错?
  14. 工具返回 50MB 数据,上下文炸了怎么办?
  15. 多 Agent 通信为什么不用网络通信?怎么交互?
  16. 记忆管理怎么做的?超出上下文怎么处理?
  17. 模型是自己部署的吗?
  18. HTTPS 为什么能实现加密通信?
  19. 根证书有什么用?
  20. 进程和线程的区别?进程间怎么通信?
  21. Agent 怎么判断任务已完成并停止?
  22. 长程任务怎么防止行为漂移?
  23. 用户中途取消任务怎么实现?
  24. Agent 运行中 message 分几类?
  25. 短期 Memory 和长期 Memory 分别怎么实现?
  26. ThreadLocal 线程安全吗?有什么内存泄漏风险?
  27. BeanFactory 和 ApplicationContext 有什么区别?
  28. MySQL 去重语句有哪些?ROW_NUMBER() 怎么用?
  29. Linux 怎么查看进程和端口?
  30. 哈希表怎么解决哈希冲突?
  31. 手撕:合并嵌套 JSON。给定两个嵌套结构 JSON,实现合并函数;规则是字典递归合并相同 key、仅在一个字典中的 key 直接保留、列表拼接。

具体项目追问

  1. 你项目中说到了面试评分、简历评分,这些评分内容如何结构化输出?从哪几个维度评分?
  2. 项目中的 RAG 知识用了哪些?
  3. 离线上传和在线问答环节如何进行?

《参考解析》

Harness 是什么,和 LangChain 差在哪。 面试官问的 Harness 指的是「包在模型外面、让它能稳定跑长任务的那层工程脚手架」:Agent Loop 的调度、工具注册与调用、状态与上下文组装、权限与沙箱、重试与超时、可观测性。LangChain 这类框架解决的是「怎么把 prompt、模型、工具串起来」的编排问题,偏库与抽象;Harness 解决的是「这个循环跑在真实环境里会不会失控」的工程问题,偏运行时与治理。所以回答 Harness 时的抓手是四件事:状态存在哪里、每步的输入怎么裁剪、失败怎么重试与终止、全过程怎么观测与复现。候选人现场没答出这个词却仍然过了,说明面试官更看重后面那些具体问题里体现的工程判断力——概念可以补,判断力补不了。状态管理上,成熟做法是把「会话消息、任务 DAG 与各节点状态、已执行动作集合、产物引用」分开存:消息给模型看,状态机给代码用,产物落外部存储只在上下文里放引用与摘要。

Agent Loop、ReAct 与 Plan 模式。 Agent Loop 的骨架就是「组装上下文 → 调模型 → 若返回工具调用则执行并把结果塞回消息列表 → 否则判定结束」,外面套上最大步数、最大 token、最大重试与超时。ReAct 是边想边做:思考、行动、观察循环推进,适合工具少、路径短、需要根据中间结果临场调整的任务(检索问答、查数),优点是灵活、上下文短;缺点是容易绕圈、难以预估步数。Plan 模式先产出完整计划再逐步执行,适合步骤多、依赖清晰、要给人审阅或要并行的任务(大改造、批量处理),优点是可控可审计,缺点是一旦前提错了整份计划都废,所以实践中多是「Plan 打底 + 执行中局部重规划」,并限制重规划次数。Checker 的角色不是再答一遍,而是拿子任务的成功判据去校验产物:缺什么就结构化地指出缺什么,让 Executor 补,连续打回两次就升级为「证据不足」并降级收尾。

上下文、路径震荡与工具描述治理。 上下文超限的处理顺序是:先按「必须保留」分层(系统约束与当前任务目标常驻,最近若干轮保原文,更早的做摘要或只保留结论与未完成事项),再用检索按需取相关片段,长工具输出落盘只回摘要加引用,最后才是换更长上下文的模型——因为窗口再大也有成本与「中间遗忘」问题。路径震荡的表现是 Agent 在两个动作之间来回切换(改了 A 又改回 B),治理手段是显式化已执行动作集合并去重、给每个方向设尝试预算、检测到同一状态重复出现就强制收敛到某一条路径或直接询问用户。工具描述过长时别把全部 schema 都塞进 prompt:按任务动态筛选相关工具(工具检索、按域分组、子 Agent 只挂自己需要的工具)、只给必需字段并省略长描述、把示例精简成最小可用形式。

多 Agent 协作与长任务排查。 多个 Agent 同时改文件必须有互斥与隔离:同一文件加锁(进程内文件锁或分布式锁)、按文件或目录划分归属、改动走「读—改—写」的原子替换并做版本校验(内容哈希不符就拒绝写入并重读),最外层还要有冲突检测与人工确认。多 Agent 通信通常不走网络而走共享内存/文件/消息总线,理由是延迟低、可审计、无需网络配置与鉴权,且同一进程内可以直接共享状态;跨机器时才升级为 RPC 或 MQ。长任务从 5 分钟变成 20 分钟要按阶段打点排查:看是模型调用变慢(上下文变长、token 数上升、上游限流)、工具变慢(下游接口、检索、编译)、还是重试变多(失败被静默重试)——所以从第一天就要把每步的耗时、token、重试次数做成指标,否则只能靠猜。

工具调用容错与终止条件。 参数错误分两类:可判的(缺字段、类型错、枚举外)用 schema 直接拒并把错误回灌给模型让它改正,不可判的(语义错,比如城市名写错)交给工具返回明确错误码。超时与重试的原则是只重试幂等操作、指数退避加抖动、限制次数,写操作必须带幂等键。tool call 格式不合法的容错分三层:优先用结构化输出或 tool calling 能力做约束;解析时宽容处理(剥 markdown 围栏、截取首个完整 JSON、容忍尾逗号);仍失败就把原始输出与校验错误回灌重试一到两次,最后降级为「该步失败」交给上层决策。工具返回 50MB 数据时绝不能进上下文:落对象存储或临时文件,只把结构摘要、前若干条样例与引用路径给模型,需要细节时再让它按参数分页取。「Agent 怎么判断任务完成」要靠显式判据而不是模型感觉:子任务全部有证据支撑、产物通过校验、且没有待执行的计划项;配合硬性上限(步数、预算、时间)触顶即终止并如实报告未完成。防止长程行为漂移则靠三件套:目标与硬约束在每步重新注入、阶段性产物写外部状态做锚点、每 N 步做一次自检(是否偏离原始目标、是否重复劳动)。

手撕:合并嵌套 JSON。 递归实现最直观:若两个值都是字典,就递归合并——遍历第二个字典的每个 key,若第一个里不存在直接放入,存在则递归合并;若两个值都是列表,做连接(顺序按题面规定在前者之后追加);其余情况用后者覆盖前者。边界要提前想清:类型不匹配(字典对列表)按「覆盖」还是「报错」取决于题面,必须问清或按题面默认;null 值算不算存在(用 key in dict 判断而不是 dict.get(key) 的返回值);要深拷贝输入而不是原地修改(否则会污染调用方数据)。用栈或队列做迭代版本也可以,但递归更清晰;如果语言支持不可变结构,更好的做法是返回新结构而不是就地改。