蚂蚁集团 AI Agent 开发复活赛二面:CR Agent 三级架构深挖
- 轮次
- 二面(复活赛)
- 结果
- 已过
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
项目背景与记忆设计
- 你在 AI Agent 这块具体做了哪些事情?
- 介绍一下项目背景:做了什么、碰到什么问题、怎么解决的?
- 为什么选择用 Markdown 方案做记忆管理?
- 相比 RAG 方案有什么考虑?
- Agent 记忆更新过程中,如何保证语义匹配的准确性?
- 如果匹配错了会如何处理?
Agent 架构与工具调用
- 项目中为什么采用 Agent Teams 架构?
- 相比 Workflow 编排方式有什么优势?
- 如果线上要求 Agent 全流程自动化、不依赖人工审核,怎么保证稳定可靠?
- 一个 Agent 调用多个工具时,执行流程怎么设计?
- 如何管理工具调用的顺序?
- 大模型调用外部工具的底层机制是什么?
- 模型如何决定调用哪个工具?
- Agent 系统通常由哪些核心模块组成?
- 各模块分别承担什么职责?
- 如何理解 Agent 的短期记忆和长期记忆?
- 两者通常有哪些实现方式?
- MCP 是什么?主要解决 Agent 开发中的什么问题?
风控归因 Agent 的三级架构
- 风控归因 Agent 为什么设计成三级 Agent 架构?
- 第二层编排为什么还要单独设计成一个 Agent?
- 主 Agent、编排 Agent、原子子 Agent 的职责分别是什么?
- 各层 Agent 之间如何通信?
- 上下文如何传递?怎么保证不遗漏关键信息?
- 原来的纯 ReAct 方案只是工具调用不稳定吗?还有哪些问题?
- 直接采用 ReAct + Tool 是否也能满足需求?
- 引入多层 Agent 和多个子 Agent 后,执行效率会变慢吗?
- 三级架构是否提升了结果准确率?具体体现在哪些场景?
多模态与文档解析
- 多模态文档解析的流程是怎样的?
- 早融合、中融合、晚融合分别适合什么场景?
- 纯视觉模型改造成 VL 模型,哪些模块必须重新设计?
手撕代码
- 手撕:二叉树的最近公共祖先怎么实现?
《参考解析》
这场面试的风格:顺着一个项目往深里挖。整场没有八股式轮询,而是从「你在 Agent 这块做过什么」开始,围绕同一个项目换四个角度反复追问:先问设计选择(为什么这么做),再问反例与边界(匹配错了怎么办、不依赖人工审核怎么办),最后抽掉项目问通用机制(Agent 有哪些核心模块、模型怎么选工具)。面试官明确说会从很多不同角度深挖、看你有没有思考过,所以准备方式是:简历上的每个技术选择都要能答出「当时的替代方案、为什么没选、代价是什么」,而不是只背实现。
Markdown 记忆与 RAG 的取舍:Markdown / 文件式记忆把事实写成人类可读、可 diff、可版本管理的结构化文本,Agent 直接读全文,天然做到全量覆盖、可审计、可回滚,适合条目量不大但要求精确(规则、偏好、项目结论、配置)的场景,缺点是规模上去后无法全量进上下文、检索只能靠规则。RAG 走向量召回,适合条目多、以语义相似为主的场景,问题是召不回、chunk 切断语义、相似段落互相干扰、且结果难以人工核对。真实系统通常是混合:长期稳定事实落文件,大批量知识走检索;写入时同时落结构化字段与 embedding,检索先精确匹配(实体、ID、时间)再补一路语义召回。
语义匹配准确性与匹配错误的兜底:准确性来自三处——写入时做规范化(实体抽取、别名统一、补时间戳与来源),检索时混合召回(关键词加向量)再 rerank,判决时分档:高置信直接更新、中置信走合并或追问澄清、低置信只新增不覆盖。匹配错误靠两条兜底:写入采用 append-only 加生效时间,任何一次错误合并都能回滚,读取时把「这条记忆来自哪次对话、最近更新于何时」一并交给模型,让它有机会自我怀疑;对有副作用的动作(发消息、下单、改配置)再加幂等键和二次确认,把「记错」的影响限制在建议层而不是执行层。
Agent Teams 与 Workflow:Workflow 是预先写死的确定性流程,链路可枚举时最好用——好调试、成本可控、结果稳定,缺点是分支要人工穷举,遇到未预期情况就断。Agent Teams / 多 Agent 把角色拆开(规划、执行、审阅),由模型在运行时决定下一步和分工,灵活、可扩展、能并行,代价是 token 与延迟上升、结果不确定、必须配更强的可观测性和终止条件。选择判据是流程的开放程度:稳定可枚举走 Workflow,开放或需要动态分解走多 Agent;工程上最常见的是混合——外层用固定流程保证可控,内部节点交给 Agent 自由决策。
全流程自动化的可靠性:不依赖人工审核时,可靠性靠三件事而不是靠「提示词写得更严」。第一是分层校验:每个子 Agent 的输出带 schema,关键字段用确定性规则校验(数值范围、引用是否存在、必填项),不让模型自评替代校验。第二是幂等与可回滚:外部副作用带幂等键、支持 dry-run、灰度放量与一键回滚,先影子跑再放真流量。第三是可观测与熔断:全链路 trace 落盘,按置信度分流,低置信降级为拒绝执行或转人工,并设置最大步数、token 预算、超时与死循环检测。上线前用离线评测集加影子流量做回归,缺一个都会在长尾上翻车。
多工具调用的执行流程与顺序:模型在一轮里可以并行发起多个无依赖的工具调用,有依赖的必须等上一轮结果回来后,由模型基于结果构造下一轮参数,所以「流程」本质是模型决策加调度层约束的配合。调度层要负责的事:解析依赖关系决定并行还是串行、按 schema 校验参数、超时与重试(只有幂等工具能重试)、把冗长的工具输出摘要化再回灌上下文、同参调用去重、限并发与熔断。调用顺序不能全靠模型自由发挥——业务上强顺序的步骤写成编排器或状态机,或者把前置条件写进工具描述里(「必须先调用 X 拿到 id 才能调用本工具」),这比事后纠错便宜得多。
Function calling 的底层机制:请求里带上工具列表,每个工具含名称、自然语言描述和参数的 JSON Schema;模型侧经过专门训练,能在需要时输出一个结构化的 tool_call(工具名加参数),客户端解析后执行真实函数,把返回值作为工具角色的消息拼回上下文,再请求模型继续。所以「模型如何决定调哪个工具」本质是一次基于当前上下文的下一 token 决策——工具名与描述就是提示词,写清「什么时候用、什么时候不要用、返回什么、参数含义」直接决定选择准确率;工具数量多时先做工具检索或按场景分组路由,避免几十个工具同场竞争注意力。
Agent 的核心模块与职责:推理层(模型调用、提示组装、流式与重试)、规划层(任务分解、状态机、进度管理)、记忆层(短期上下文管理与长期外部存储)、工具与环境接口(含 MCP、鉴权与权限边界)、执行控制(循环、终止条件、步数预算、幂等与重试)、可观测与评测(trace、token 与耗时、成功率、评测集回归)。划分职责的原则是「确定性的事交给程序,判断的事交给模型」:路由、校验、状态、重试、限额用代码写死,意图理解、选路、生成、归因交给模型,中间用结构化 schema 衔接。
短期记忆与长期记忆:短期记忆就是上下文窗口里的对话与中间状态,容量受上下文长度限制,管理手段是滑动窗口、摘要压缩、以及把任务清单和中间结果外置成结构化状态(TODO 文件、变量)而不是留在聊天记录里;长期记忆是外部存储(向量库、KV、文件、图数据库),按需检索召回,实现方式包括 embedding 语义检索、关键词或 BM25、结构化字段查询、知识图谱关系查询。真正的难点不在存和取,而在写入策略、冲突覆盖、过期与来源标注——写进去的噪声会一直污染后续所有召回。
MCP 解决什么:MCP(Model Context Protocol)把「有哪些工具和资源、参数长什么样、怎么调用」标准化:服务端按协议暴露 tools / resources / prompts,客户端(Agent 宿主)统一发现与调用。它解决的是每个 Agent 框架各写一套工具适配的重复建设和生态割裂,让一次实现能在多个宿主里复用,同时把鉴权与权限边界收到协议层。要补一句局限:协议不保证工具描述的质量,也不解决远程服务不可信带来的提示注入和越权风险,副作用工具仍要自己加校验、幂等和确认。
三级 Agent 架构为什么这么分:主 Agent 面对用户,负责理解目标、判断该走哪条流程并把最终结论讲清楚;编排 Agent 单独抽出来,是因为它的职责是「分解、调度、收敛、校验」,跟主 Agent 的对话与决策耦合在一起会互相拖累——独立之后编排策略可以单独评测和替换(换模型、换分解模板、单独回归),上下文也更干净。原子子 Agent 每个只做一件确定性的事(查规则、捞数据、跑模型、生成归因结论),输入输出 schema 固定,因此可并行、可复用、失败可局部重试。这样分层的本质是把「长链路的不确定性」收敛到编排层,让每一层都能被单独验证。
层间通信与上下文传递:层间通信建议用结构化消息——JSON schema,包含 task_id、目标、约束、输入引用、期望产物和状态码,而不是自然语言对话(自然语言会丢字段且不可校验)。上下文传递用「引用加摘要」而不是整段透传:上游只把必要事实和产物句柄(文件 id、表 id、片段编号)传下去,下游按需读取全文,这样既控制 token 也避免无关信息干扰。防止遗漏靠机制而不是靠模型自觉:编排层维护任务清单与必填字段清单,每个子 Agent 产出后做 schema 校验与完整性检查,缺字段就打回补齐或标注不确定;同时在最终汇总时列出用到的证据来源,让结论可追溯。
纯 ReAct 的问题与多层架构的收益:ReAct 的「想一步做一步」在短任务上够用,长任务上会暴露几个结构性缺陷:上下文随步数滚动增长、早期关键约束被淹没;一次工具报错会污染后续推理并可能滚雪球;没有全局规划,容易在局部反复试错、步数爆炸;没有中间校验与回滚,副作用不可逆;每次轨迹不同,难以评测和定位。所以引入规划与专用子 Agent,把长链路拆成可验证的短链路。代价是肯定更慢、token 更多(每多一层就多一次模型往返),收益体现在复杂任务上的准确率与可维护性:上下文更短更聚焦、可并行、失败可局部重试、结果可校验;优化方向是并行执行、只传必要上下文、原子任务用小模型、把规则前置到代码里。
多模态文档解析与融合时机:解析流程一般是版面分析(切出文本块、表格、图片、公式区域)→ 按区域裁剪 → 分流识别(OCR、表格结构识别、图表理解)→ 按阅读顺序还原(多栏、跨页、表格跨页要合并)→ 结构化输出成 Markdown / HTML / JSON。融合时机:早融合在编码器早期就把各模态拼进同一个 Transformer,适合模态强关联、需要细粒度对齐的任务,但训练成本高、模态间容易互相干扰;中融合各自编码后用 cross-attention 或适配器交互(CLIP 加 projector 再接 LLM、Flamingo 一类),效果与成本平衡,是当前 VLM 的主流;晚融合各模态独立出结果再合并,实现简单、可以分别升级、延迟可控,适合模态弱耦合或对延迟敏感的场景。选型判据是「模态之间需不需要在特征层面对齐」,而不是哪个更新。
纯视觉模型改造成 VL 需要重设计什么:至少五块要动。一是语言侧从零开始——文本 tokenizer、词表与 embedding 原来根本不存在;二是连接器 / projector,把视觉特征投影到语言模型维度,还要适配 patch 数量变化;三是位置编码,图片是二维、视频是三维,高分辨率和长文档还要求外推能力;四是注意力结构与训练目标,纯视觉只有自监督,改 VL 后要走图文对齐加指令微调两阶段;五是分辨率与 token 压缩策略、以及图文对与 OCR 数据构成的数据 pipeline。可以复用的是视觉编码器的底层特征提取能力,但「接上语言」这一段的训练策略和数据处理基本要重做。
手撕:二叉树的最近公共祖先:递归是最标准的写法——后序遍历,函数返回「子树里是否找到 p 或 q」,若左右子树都返回非空,当前节点就是 LCA,否则把非空的那一侧往上传递,时间 O(n)、空间 O(h)(递归栈)。如果节点带 parent 指针,等价于求两条链表交点:分别从 p、q 走到根得到两条路径,再从后往前找最后一个公共节点。需要多次查询同一棵树时用倍增(二进制 lifting)预处理每个节点向上 2^k 级的祖先,单次查询 O(log n);或者用 Tarjan 离线算法配合并查集把所有查询一次跑完。如果树是 BST,可以按值域判断 p、q 是否分别落在当前节点的两侧,一路下行即可,时间降到 O(h)。