聊一聊最近碰到的一些 Agent 面试题(一)

一面 | Agent 生态与工程化

面试题 1:请解释 ACP(Agent Communication Protocol)协议的设计思路,它解决了什么问题?

参考答案

ACP 解决的核心问题:

目前各家的 Agent 框架(LangChain、CrewAI、AutoGen 等)各自为政,Agent 之间无法互通。A 公司用 LangChain 写的 Agent 没法直接和 B 公司用 AutoGen 写的 Agent 协作。ACP 要做的就是 Agent 之间的 HTTP——一个开放的、框架无关的通信标准,让不同技术栈的 Agent 能互相发现、互相对话、协同完成任务。

核心设计:

ACP 是一个 RESTful 协议,基于标准 HTTP 构建,这意味着任何能发 HTTP 请求的语言和框架都能接入,不需要特定 SDK。

几个关键概念:

  • Agent Card(代理名片):每个 Agent 对外暴露一份结构化的元数据描述,包含自己的能力、接受的输入格式、支持的交互模式等。其他 Agent 或编排系统通过读取 Agent Card 来发现和理解这个 Agent 能干什么——类似于 API 的 OpenAPI Spec,但描述的是一个"智能体"而非一组接口。
  • Task(任务):Agent 之间协作的基本单位。一个 Agent 向另一个 Agent 发送一个 Task,Task 有完整的生命周期——提交(submitted)、处理中(working)、完成(completed)、失败(failed)。调用方可以查询 Task 状态,实现异步协作。
  • Message & Artifact:Message 是 Agent 之间交互过程中的对话消息,Artifact 是任务产生的结构化输出(比如生成的文件、处理后的数据)。两者分离的好处是:过程信息和最终交付物不混在一起,消费方可以直接取 Artifact 而不用从一堆对话中提取结果。

通信模式:

ACP 同时支持同步和异步两种模式。简单快速的请求走同步(发请求、等响应);耗时长的任务走异步(提交任务、拿到 task_id、轮询或通过 SSE 流式获取进度)。这个设计很务实——现实中 Agent 任务从毫秒级到分钟级都有,一种模式不可能覆盖所有场景。

多模态支持:

消息内容用 MIME Type 标识格式,可以是纯文本、JSON 结构化数据、图片、音频、甚至向量嵌入。这让 ACP 不局限于文本 Agent,多模态 Agent 也能用同一套协议通信。

追问 Q&A

Q:ACP 和 MCP 是什么关系?会不会冲突?

A: 不冲突,解决的是不同层面的问题。MCP 解决的是 Agent 和工具之间的连接——让一个 Agent 能调用搜索引擎、读数据库、操作文件系统等外部能力。ACP 解决的是 Agent 和 Agent 之间的通信——让多个 Agent 能互相协作完成复杂任务。打个比方:MCP 是"手",让 Agent 能操作外部世界;ACP 是"嘴",让 Agent 能跟其他 Agent 说话。一个完整的多 Agent 系统中,两个协议完全可以共存:每个 Agent 内部通过 MCP 连接自己的工具,Agent 之间通过 ACP 通信协作。

Q:ACP 选择 REST 而不是 gRPC 或 WebSocket 作为底层协议,怎么看这个设计决策?

A: 这是一个可达性优先的决策。REST/HTTP 是目前互联网上部署最广泛、基础设施支持最完善的协议。任何语言、任何平台、任何云服务都能直接发 HTTP 请求,不需要额外的客户端库。gRPC 性能更好但需要 proto 定义和特定客户端;WebSocket 适合双向实时通信但穿越防火墙和负载均衡器更复杂。ACP 的目标是成为"所有 Agent 都能说的语言",所以选择了门槛最低的 HTTP。对于实时性需求,ACP 用 SSE(Server-Sent Events)作为补充,SSE 也是基于 HTTP 的,不会引入额外的协议复杂度。这个选择牺牲了一些极端场景下的性能,但换来了最大的生态兼容性——对于一个想成为"标准"的协议来说,这个取舍是合理的。

面试题 2:对比 MCP(Model Context Protocol)和 Agent Skills 的设计差异,什么场景该用哪个?

参考答案

本质区别一句话:MCP 向外连接外部能力,Skills 向内注入行为指令。

MCP 的设计思路:

MCP 是一个标准化协议,让 LLM/Agent 连接到外部工具和数据源。它的架构是 Client-Server 模式:Agent 作为 Client,每个工具封装成一个 MCP Server,两者通过 JSON-RPC 通信。关键设计是进程隔离——每个 MCP Server 运行在独立进程中,有自己的凭证和权限边界,Server 之间互相不可见。这意味着一个搜索工具的 Server 无法访问数据库工具的 Server 的凭证,安全边界非常清晰。

Skills 的设计思路:

Skills 本质上就是一个 Markdown 文件(SKILL.md),里面用自然语言描述了"这个技能是什么、什么时候触发、执行时应该遵循什么规则和步骤"。Agent 加载 Skill 后,这些指令成为它的 system prompt 的一部分,指导它在特定场景下的行为模式。Skills 可以附带资源文件和脚本,但核心是那份自然语言描述。它没有独立进程、没有 JSON-RPC,运行在 Agent 自身的上下文环境里。

架构差异核心:

运行方式

独立进程,跨进程通信

进程内,作为 prompt 注入

安全模型

进程隔离,凭证分离,Server 间不可见

无隔离,共享 Agent 运行环境

能力边界

连接外部系统(API、数据库、文件系统)

定义 Agent 行为模式和工作流程

动态性

需要配置和启动 Server

加载一个文件即可,Agent 甚至可以自己编写 Skill

适合谁

企业级、多团队、需要合规审计

个人开发者、快速实验、本地场景

选型建议:

需要对接外部系统(搜索引擎、数据库、第三方 API)且有安全合规要求——用 MCP。需要定义 Agent 在特定场景下的行为规范(代码审查规则、写作风格、特定工作流程)——用 Skills。很多时候两者配合使用:Skill 定义了 Agent "该做什么",MCP 提供了 Agent "用什么去做"。

追问 Q&A

Q:Skills 没有进程隔离,安全风险具体体现在哪里?

A: 核心风险是 Skill 和 Agent 共享同一个执行环境。如果 Agent 有文件系统访问权限,那么所有加载的 Skills 都隐式拥有这个权限。一个恶意的 Skill(比如从不可信来源安装的第三方 Skill)可以通过自然语言指令诱导 Agent 去读取敏感文件、泄露环境变量中的密钥、或者执行破坏性操作。MCP 不存在这个问题,因为每个 Server 运行在自己的沙箱里,凭证由各自独立管理。所以社区对 Skills 的共识是:只加载你信任的 Skill,就像你只会 source 你信任的 shell 脚本一样。在企业环境中,通常需要一个 Skill 审核机制——类似 App Store 的审核流程。

Q:未来 MCP 和 Skills 会不会合并成一个标准?

A: 大概率不会合并,但会更好地互补。它们解决的是两个正交问题:MCP 是"能力连接层",Skills 是"行为定义层"。类比 Web 开发:MCP 像后端 API,Skills 像前端路由配置——没人会想把它们合成一个东西。更可能的演进方向是:Skills 规范会增加权限声明和安全约束(借鉴 MCP 的隔离思想),MCP 会更好地支持动态发现和热插拔(借鉴 Skills 的轻量理念)。两个协议都还在快速迭代期,最终形态取决于社区的实际需求。

面试题 3:Agent 的 Memory 系统应该如何设计?不同类型的记忆各自解决什么问题?

参考答案

为什么 Agent 需要 Memory?

LLM 本身是无状态的——每次调用都是独立的,它不记得上一次对话说了什么。但一个真正有用的 Agent 需要在任务内保持连贯、跨任务积累经验。Memory 系统就是解决这个问题的。

三种记忆类型:

短期记忆(Working Memory):就是当前对话的上下文窗口。存放本次任务的推理链条、中间结果、用户的实时指令。特点是容量有限(受窗口大小约束)但访问速度最快(直接在 prompt 里)。核心挑战是窗口溢出管理——多步任务中上下文越来越长,需要通过摘要压缩、关键信息提取等手段控制长度。

长期记忆(Long-term Memory):跨会话持久化的信息,通常存储在向量数据库中。包括用户偏好("这个用户喜欢简洁的回复风格")、历史决策("上次处理类似问题用了方案 A 效果不好")、领域知识等。每次会话开始时,根据当前任务做相似性检索,把相关记忆注入到上下文中。核心挑战是检索质量——记了很多但检索到的不相关,反而会干扰当前推理。

情景记忆(Episodic Memory):记录的是完整的"任务执行经历"——某次任务的完整推理过程、用了哪些工具、遇到了什么问题、最终是否成功。和长期记忆的区别是:长期记忆存的是"知识点",情景记忆存的是"完整的故事"。它的价值在于让 Agent 能做类比推理——遇到相似任务时,回忆起以前的完整处理过程作为参考,而不是只检索到碎片化的知识。

三者的协作模式:

Agent 接到新任务时,先用任务描述去检索长期记忆和情景记忆,把相关内容注入到短期记忆(上下文)中。任务执行过程中,所有推理过程在短期记忆中流转。任务结束后,对本次经历进行评估,有价值的结论写入长期记忆,完整过程可选择性写入情景记忆。

追问 Q&A

Q:记忆写入时如何防止"记忆污染"——把错误的信息写进长期记忆?

A: 这是 Memory 系统最容易被忽视但最致命的问题。一旦错误结论进入长期记忆,Agent 在后续任务中会反复引用错误信息,造成连锁错误。

防御策略分三层。第一层:写入门槛。只有任务成功完成时才触发记忆写入,失败的任务不写入或标记为"负面经验"。第二层:质量评估。写入前用一个独立的 LLM 调用评估这条记忆是否准确、是否有价值、是否与已有记忆矛盾。如果与已有记忆冲突,需要人工审核或进一步验证。第三层:衰减机制。记忆不是永久有效的,给每条记忆设置置信度分数,长期不被检索到的记忆逐渐降低权重,被多次成功引用的记忆提升权重。这类似人类的遗忘曲线——不重要的记忆自然淡化。

Q:向量检索有时候召回的记忆不相关,怎么优化检索质量?

A: 纯向量相似性检索的问题在于它只看语义距离,不考虑上下文。优化思路有几个方向:

混合检索:不只用向量检索,同时用关键词检索(BM25 之类),两路结果做融合排序。向量捕捉语义相似,关键词捕捉精确匹配,互补。

记忆结构化:存储记忆时不只存一段文本和它的向量,还存储元数据标签——任务类型、涉及的工具、时间戳、成功/失败等。检索时可以先用元数据做粗筛("只看同类型任务的记忆"),再用向量做精排。

检索后重排:向量检索拿回 top-K 候选后,用一个 LLM 做二次排序——"以下哪条记忆对当前任务最有帮助?"这步成本不高(候选数量少),但能显著提升相关性。

反馈闭环:记录每次检索到的记忆是否真的被 Agent 使用了。如果某条记忆反复被检索到但从不被引用,说明它的检索信号有误,需要调整它的向量表示或元数据。

面试题 4:请系统性地解释 RAG 的架构设计,以及从原型到生产级的关键优化点。

参考答案

RAG 解决的核心问题:

LLM 的知识截止于训练数据,且无法直接访问私有数据。RAG(Retrieval-Augmented Generation)的做法是:回答问题前,先从外部知识库中检索相关文档,把检索结果塞进上下文,让 LLM "看着资料回答"。这样既保留了 LLM 的语言能力,又让它能用最新的、私有的信息。

基础架构三阶段:

索引阶段:把文档切分成合理大小的块(chunking),对每个块生成向量嵌入(embedding),存入向量数据库。这个阶段是离线的,提前完成。

检索阶段:用户提问时,把问题也生成向量,在向量数据库中做相似性检索,拿到 top-K 个最相关的文档块。

生成阶段:把检索到的文档块和用户问题一起作为 prompt 输入 LLM,生成最终回答。

从原型到生产的关键优化点:

1. Chunking 策略

原型阶段通常是固定长度切分(比如每 512 token 一块),但这会切断语义完整性。生产级要做语义感知切分——根据文档结构(段落、章节、标题)切分,确保每个块是一个完整的语义单元。对于代码、表格等特殊内容,需要专门的切分策略。chunk 的大小也是一个权衡:太小则缺乏上下文,太大则引入噪声并占用宝贵的上下文窗口。

2. 检索质量优化

最关键的环节。纯向量检索的问题前面在 Memory 题里讨论过——语义相近不等于真正相关。生产中常见的优化:

  • 混合检索:向量 + 关键词,两路融合
  • Query 改写:用户的问题往往不适合直接做检索查询。先用 LLM 将用户问题改写成更适合检索的形式,或者分解成多个子查询分别检索
  • 重排序(Reranker):向量检索拿回粗排结果后,用一个 Cross-Encoder 模型对 query-document pair 做精排。粗排靠向量点积快速筛选,精排靠交叉注意力精确评估相关性
  • 元数据过滤:按文档来源、时间、类型等维度做前置过滤,缩小检索范围

3. 上下文组装

检索到的文档块怎么塞进 prompt 也是学问。直接把所有 chunk 拼接可能超窗口、也可能互相矛盾。生产中会做:按相关性排序放置(最相关的放最靠近问题的位置,因为 LLM 对位置敏感)、去重(不同 chunk 可能包含重复内容)、冲突检测(如果两个 chunk 信息矛盾,要明确标注让 LLM 注意)。

4. 忠实性保障

RAG 最大的坑是 LLM 拿到了正确的资料却还是"编"——要么无视检索结果凭内部知识回答,要么对检索结果做了错误的推理。应对方式:prompt 中明确要求"只根据提供的资料回答,如果资料中没有答案请说明";让 LLM 在回答时标注引用来源("根据文档 X 第 Y 段"),方便验证;做后处理校验——检查回答中的关键声明是否能在检索到的文档中找到支撑。

追问 Q&A

Q:RAG 和微调(Fine-tuning)分别适合什么场景?能不能结合?

A: 两者解决的问题不同。RAG 解决的是知识层面的不足——模型没见过的数据、需要实时更新的数据、私有数据。微调解决的是能力层面的不足——模型的输出风格、格式、对特定领域术语的理解、推理模式等。

举例:如果你想让模型回答公司内部知识库的问题——用 RAG;如果你想让模型始终以特定的 JSON schema 输出、或者理解你们公司内部的术语缩写——做微调。

两者完全可以结合,而且这是生产中的最佳实践:先微调让模型适应你的领域和输出要求,再用 RAG 补充实时知识。微调后的模型对检索结果的理解和利用能力通常更强,因为它已经"懂"了这个领域的语言。

Q:如何评估一个 RAG 系统的效果?

A: 需要分层评估,不能只看最终回答对不对。

检索层评估:检索到的文档是否包含回答问题所需的信息?用 Recall@K(前 K 个结果中包含正确答案的比例)和 MRR(正确答案首次出现的排名倒数)来衡量。这一层不及格,后面生成再好也没用。

生成层评估:LLM 是否忠实地利用了检索到的文档?有没有添加文档中不存在的信息(幻觉)?有没有漏掉文档中的关键信息?这里有两个核心指标:忠实度(回答是否有文档支撑)和相关度(回答是否真正解答了用户问题)。

端到端评估:最终答案对用户有没有用。可以用人工评测打分,也可以用 LLM-as-Judge(让另一个模型评估回答质量)做自动化评估。

一个常见的错误是只做端到端评估——结果不好时根本不知道是检索的问题还是生成的问题,优化无从下手。分层评估才能精确定位瓶颈。

Q:多轮对话场景下 RAG 有什么特殊挑战?

A: 核心挑战是查询依赖上下文。用户第一轮问"特斯拉最新的财报怎么样",第二轮说"那它的竞争对手呢"——"它"指的是特斯拉,"竞争对手"需要从第一轮的汽车领域上下文推导。如果直接用第二轮的原始问题"那它的竞争对手呢"去检索,不可能拿到有用的文档。

解法是在检索前做查询重构:把对话历史和当前问题一起交给 LLM,让它生成一个自包含的、不依赖上下文就能理解的查询(比如改写为"特斯拉在电动车领域的主要竞争对手的最新财务表现")。这步改写的质量直接决定了多轮 RAG 的效果。

#面试问题记录##面试##Agent##AI求职记录#
全部评论

相关推荐

评论
5
19
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务