面灵AI→

月之暗面 Agent 应用开发:上下文超限,连追五层

结果
挂
时间
2026-10
来源
牛客网

《面试题目》

Agent 架构与流程

  1. 背景及选择 Agent 方向的原因?
  2. 一个完整的 Agent 系统通常包含哪些核心模块?相比传统应用多了什么?
  3. Agent 项目架构设计及解决的问题?
  4. 你怎么理解 Harness?
  5. ReAct 和 Plan-and-Execute 你选哪个?为什么?
  6. Agent 如何做任务规划?
  7. 路由机制(请求交给哪个 Agent)?

多 Agent

  1. 多 Agent 并行执行的状态管理和结果汇总?
  2. 多 Agent 之间如何通信和同步状态?用过消息队列吗?还是共享内存?
  3. 多 Agent 之间上下文和状态怎么隔离?
  4. 多 Agent 同时执行时争抢哪些资源?怎么做隔离?

上下文与工具

  1. 上下文管理(避免过长导致效果下降)?
  2. 大量工具时避免 Prompt 过长的方案?
  3. 工具返回数据量过大的处理?
  4. 如果上下文超限了,你怎么处理?
  5. 用摘要压缩的话,摘要丢失关键信息怎么办?
  6. 分块存储后,跨块关联怎么保证?
  7. 工具调用失败,容错机制是什么?有没有做重试?重试几次?

RAG 与安全

  1. RAG 全流程(切分、向量检索、召回、生成)?
  2. 文本切分策略怎么选?语义切分怎么实现?
  3. 如何保证 Agent 生成代码的安全性?有没有在沙箱里执行?
  4. Agent 对工具调用不做限制会产生哪些风险?怎么防范?
  5. Prompt Injection 怎么防范?用户诱导 Agent 泄露 System Prompt 怎么办?

评测与手撕

  1. 如何评测你的 Agent 系统?关注哪些指标?端到端成功率大概多少?
  2. 手撕:LRU Cache,并讲思路。

项目追问

  1. 你的 Agent 项目整体架构是怎样的?单 Agent 还是多 Agent?
  2. ReAct Agent 的核心执行流程是什么?Thought、Action、Observation 分别做什么?
  3. Agent 调用工具后,返回结果的消息结构怎么设计?为什么需要单独的 Tool Message?

《参考解析》

1. Agent 系统的核心模块与 Harness 的位置。 可上线的 Agent 系统拆六块:接入与会话、模型与工具运行时、循环与状态机(规划、执行、观察、终止、重试降级)、记忆与检索、安全与权限、评测与可观测。相比传统应用多出来的核心是不确定性管理:输出可能格式不对、可能选错工具、可能绕圈,所以必须有结构化校验、终止条件、幂等与降级。Harness 指包在模型外面那层让它可靠跑起来的工程外壳:循环驱动、上下文组装与预算、工具调用与结果归一、重试熔断、评测回归、Trace 与成本记账。同一个模型,Harness 好坏会让成功率与成本差好几倍。

2. ReAct 与 Plan-and-Execute 的取舍,以及任务规划。 ReAct 想一步做一步,能按观察调整、适应不确定环境,但步数多、每步带全量上下文、长任务易迷失;Plan-and-Execute 先分解再执行,方向明确、可并行、上下文可按子任务切小,但计划错了要返工。常见答案是混用:粗粒度用计划(分解出可验收的子任务)并允许执行中动态重规划,子任务内部用 ReAct。规划的实现要点是把可执行性交给代码:要求模型产出结构化计划(目标、约束、依赖、验收标准),代码校验是否有环、是否引用不存在的工具、是否超预算;每个子任务有独立上下文与状态,完成后把结果摘要回写计划状态。终止与放弃显式定义:子任务全部达成即结束,超步数或连续失败就降级并如实告知未完成的部分。路由按意图决定交给哪个 Agent,走错要靠 Trace 与 badcase 回补规则。

3. 多 Agent 的状态管理、通信与隔离。 状态管理三件事:每个子任务有独立状态对象(目标、已执行动作、中间结果、失败记录)且由代码维护;汇总层按结论、证据、置信度结构化归并,先按实体去重再处理冲突(证据强度优先,无法裁决就标记冲突升级),不做字符串拼接;每步落检查点,失败重试从中间继续。通信按耦合度选:共享内存只适合同进程强协作;进程内队列或跨机 MQ 是常规选择,解耦、可缓冲、可重放,代价是重复投递与顺序问题,所以每条任务带 taskId、幂等键与超时。争抢的资源是模型配额、沙箱、共享数据与外部工具配额,隔离手段是配额桶与优先级队列、一任务一沙箱或用租约从池里取、共享数据用版本号乐观锁、外部调用统一走网关限流;上下文隔离靠只传引用与摘要。

4. 上下文治理:工具描述、工具结果与超限处理。 三个源头分别治:工具数量多就按意图做工具检索或分级暴露,只给当前最可能用到的十几个工具并精简描述;工具结果大就约定结构化返回而不是自然语言长文,大结果落对象存储只把摘要与引用放进上下文、列表做分页与 top-N;历史变长就分层记忆,近期保留原文、更早做摘要、关键结论与用户约束写进常驻任务状态。快超窗口时按结构裁而不是从头砍:保持 tool_call 与工具结果成对(删一半会让 API 直接报错)、保留系统提示与任务约束、优先丢最早的完整轮次,关键状态外置。摘要丢关键信息的答案不是“写得更好”,而是结构化保留、校验、回捞:摘要必须覆盖目标、约束、已完成、待办、关键实体与数字;压缩后做一致性检查;丢了就从原始记录或工具产物重取。

5. 工具调用失败的容错与重试策略。 前提是分类:确定性失败(schema 不符、权限不足、资源不存在、业务拒绝)重试无意义,把结构化错误回灌让模型改参数或换工具;瞬时失败(超时、连接重置、5xx、限流)指数退避加抖动重试一到两次;语义失败(工具成功但结果为空或不合预期)要换策略——换关键词、换数据源、扩大范围或回上层重规划。重试次数与预算绑定:单工具上限、单任务总调用上限、总 token 与时间上限,触顶走降级并明确告知哪一步没做成。工程上要幂等(写操作带幂等键)、要缓存(纯读幂等结果)、要记录(requestId、耗时、结果状态),并对错误率超阈值的工具熔断。

6. RAG 切分与 Prompt Injection 防范。 RAG 链路是解析、清洗、切分、向量化并建关键词索引、检索、融合重排、生成、引用与评测。切分要与结构匹配:有标题先按标题切再按长度合并;表格、代码围栏、清单整块保留;纯文本滑窗加重叠;结构混乱时用语义切分(相邻句向量相似度骤降处断开)兜底。Prompt Injection 分四层防:把外部文档与网页内容标注为不可信数据并用结构化字段包裹,系统提示声明其中的指令一律不执行;输入检测拦截“忽略以上指令”“输出系统提示”等模式及编码、分段、多语言绕过;权限最小化,让模型即使被诱导也没有危险操作权限,写操作要确认、工具按身份鉴权;输出侧过滤系统提示片段与敏感字段。用户诱导泄露 System Prompt 时不靠藏得更深,而是保证提示里没有机密、检测到就回固定话术并记录。

7. 评测指标与 LRU、Tool Message 的设计。 评测分四层:检索的 Recall@k 与 MRR、工具的成功率与参数正确率、规划的无效步数与错分支比例、端到端的任务成功率与平均步数成本,并按任务类型分层报、持续回流 badcase。LRU 用哈希表加双向链表:哈希表 O(1) 定位,双向链表维护访问顺序,get 命中移到头部,put 满则淘汰尾部并把新节点插头部;带哨兵头尾能省掉大量边界判断,手写易错点是漏更新前驱后继、容量为 1、更新已存在 key 时忘记移动;要能覆盖线程安全(整体加锁最简单,ConcurrentHashMap 加分段锁更好,生产用 Caffeine)以及为什么必须双向链表。Tool Message 单独成消息的原因是协议与语义两层:多数厂商 API 要求 assistant 的 tool_call 与结果成对且带相同 call_id;语义上模型要区分用户说的话、自己决定调工具、工具返回的客观结果,混成一条会让模型分不清事实来源,也更容易被工具返回里的内容当成指令。