字节跳动 Agent 开发一面:Harness 没答上来,居然还能过?
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 你们 Agent 项目的整体架构是怎么设计的?
- Harness 和 LangChain 的本质区别是什么?
- Harness 里面怎么管理状态?
- Agent Loop 是怎么实现的?Plan / Executor / Checker 怎么分工?
- ReAct 和 Plan 模式有什么区别?分别适合什么场景?
- 上下文超过模型限制怎么处理?
- Agent 出现路径震荡怎么优化?
- Context 和长期 Memory 有什么区别?
- 大量工具描述导致 Prompt 过长怎么办?
- 多个 Agent 同时修改文件怎么避免冲突?
- Agent 长任务从 5 分钟变成 20 分钟,怎么排查?
- 工具调用参数错误、超时、重试怎么设计?
- LLM 返回 tool call 格式不合法怎么容错?
- 工具返回 50MB 数据,上下文炸了怎么办?
- 多 Agent 通信为什么不用网络通信?怎么交互?
- 记忆管理怎么做的?超出上下文怎么处理?
- 模型是自己部署的吗?
- HTTPS 为什么能实现加密通信?
- 根证书有什么用?
- 进程和线程的区别?进程间怎么通信?
- Agent 怎么判断任务已完成并停止?
- 长程任务怎么防止行为漂移?
- 用户中途取消任务怎么实现?
- Agent 运行中 message 分几类?
- 短期 Memory 和长期 Memory 分别怎么实现?
- ThreadLocal 线程安全吗?有什么内存泄漏风险?
- BeanFactory 和 ApplicationContext 有什么区别?
- MySQL 去重语句有哪些?ROW_NUMBER() 怎么用?
- Linux 怎么查看进程和端口?
- 哈希表怎么解决哈希冲突?
- 手撕:合并嵌套 JSON。给定两个嵌套结构 JSON,实现合并函数;规则是字典递归合并相同 key、仅在一个字典中的 key 直接保留、列表拼接。
具体项目追问
- 你项目中说到了面试评分、简历评分,这些评分内容如何结构化输出?从哪几个维度评分?
- 项目中的 RAG 知识用了哪些?
- 离线上传和在线问答环节如何进行?
《参考解析》
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) 的返回值);要深拷贝输入而不是原地修改(否则会污染调用方数据)。用栈或队列做迭代版本也可以,但递归更清晰;如果语言支持不可变结构,更好的做法是返回新结构而不是就地改。