详情

首页手游攻略 腾讯面试官:“你做了一个终端Agent,那谈谈 LLM 和 Agent的区别,ReAct、MCP、Tool、Memory、Skills?”我胸有成竹开始答了

腾讯面试官:“你做了一个终端Agent,那谈谈 LLM 和 Agent的区别,ReAct、MCP、Tool、Memory、Skills?”我胸有成竹开始答了

佚名 2026-07-29 08:32:57

大家好,我是二哥呀。

接下来是一份硬核面经,写给那些相信努力与过程、愿意一步一个脚印前进,也相信自己能在 AI 时代分一杯羹的人,希望你能认真读完。

全文写得比较肝,但保证大家能学到很多很多;系好安全带,我们粗粗发~

content

01、LLM 和 Agent 的联系与区别

老王先抛出一道概念题:讲讲 LLM 和 Agent 有什么联系,又有哪些区别。

先谈联系:Agent 作出的每一次决策,都来自 LLM。

是否调用工具、选择哪个工具、参数怎样填写以及任务是否完成,都由模型决定,Agent 框架自身并不负责判断。

二者的区别体现在职责边界上。LLM 是无状态的文本生成服务,一次调用接收一段上下文并输出一段文本;调用结束后既不会保留记忆,也无法改变外部世界。

Agent 则是以 LLM 为核心搭建的执行系统,为模型补齐了三种欠缺的能力:

  • 工具:把模型输出转成真实动作,包括读取文件、执行命令和查询网页
  • 循环:把单次调用无法解决的任务拆为多轮推理和行动,持续推进直至完成
  • 记忆:在轮次之间及会话之间保存状态,让系统记住此前发生的事情

概括来说,LLM 负责思考,Agent 则把思考结果真正付诸行动。

老王接着问:网页版对话助手能算 Agent 吗?

关键要看是否存在 ReAct 循环。单纯问答只调用一次,输入一段话、输出一段话,因此不算;如果它能自主联网检索、运行代码,并依据中间结果继续推动任务,就已属于轻量级 Agent。

判断时不看产品形态,而要确认是否形成决策、行动、观察结果、再次决策的闭环。ReAct 怎样具体运转,正好留到下一题展开。

02、ReAct Agent 由哪几部分组成

老王点头后问:你了解 ReAct Agent 吧?它包含哪些部分?

ReAct 指推理加行动(Reasoning + Acting)构成的循环。以我编写的 PaiCLI-Python 为例,可以拆成五部分,而且每部分都有对应的具体模块:

  • 模型客户端:负责与 LLM 通信,以流式方式接收文本、思考过程及工具调用请求
  • 工具注册表:汇总全部可用工具,每项工具均附有一份 JSON Schema 描述
  • 工具执行器:收到模型调用请求后,实际执行任务的模块
  • 循环控制:判断继续运行还是退出,我设置的最大轮数为 20
  • 上下文管理:逐轮检查消息总量,在接近预算时执行压缩

它如何完成用户提交的问题

老王又追问:用户交给它一个问题后,完整流程具体怎样运行?

开始时先完成两项准备:将匹配到的 Skill 候选列表注入上下文,再核查消息总量是否需要压缩。

随后启动循环,把消息历史连同工具列表发送给模型。模型以流式方式返回内容,可能直接输出文本答案,也可能提出工具调用。

若模型选择后者,执行器运行工具,并把结果作为 tool 消息加入历史,然后再次调用模型。模型读取工具结果后继续决策,或继续调用,或给出最终答案。

退出有两个条件:模型不再要求调用工具时正常结束,或者达到 20 轮上限后强制收尾。

执行层面还有两点:只读工具最多支持 4 个并发,写操作则必须严格串行,以免相互覆盖;流式场景中的工具调用参数会分片到达,需要依照序号完整拼接参数片段,再解析为 JSON 交给执行器。若过早拼接,得到的只是半截 JSON,会直接导致解析失败。

03、设计 Agent 框架时如何划分模块

老王靠向椅背问:假如从零开始设计 Agent 框架,你会怎样划分模块?

核心可以划为六层:

  • 入口层:包含命令行与交互式会话,负责参数解析和结果渲染
  • Agent 层:提供 ReAct 循环、计划执行和多 Agent 协作三种执行模式
  • 模型层:使用统一的 OpenAI 兼容客户端,处理流式解析、token 用量及计费
  • 工具层:由注册表、执行器及十七个内置工具组成
  • 记忆与上下文层:涵盖短期消息历史、长期记忆库以及上下文压缩
  • 安全层:设置命令黑名单、路径守卫、高危操作人工确认及审计日志

安全层很容易被忽略,因此值得单独说明。Agent 会真实执行命令,黑名单针对的都是高风险对象,sudo、rm -rf 等命令会被直接拦截。

写文件和执行命令要么标注危险等级,要么强制进行人工确认,并将全部执行记录写入审计日志。系统能力越强,越应提前设计好约束机制。

模块之间的交互方式

系统启动时完成组装,由入口层将内置工具和 MCP 工具合并注册到同一张工具注册表,再交给 Agent。

运行过程中,Agent 保存消息历史;每轮将历史交给模型层,再把模型返回的调用请求交由工具层执行,执行结果回填历史,如此循环。

设计中的关键决定,是要求所有模块对外仅输出统一格式的流式事件。无论文本增量、思考增量、工具调用还是用量统计,都统一表示为事件,入口层只负责渲染,不参与业务逻辑。

这种设计让各层都能独立替换:更换模型只改模型层,增加工具只调整注册表,修改界面只需处理入口层。

04、MCP 与 tool 的联系和区别

老王在本子上做了记录,接着让我谈谈 MCP 和 tool 之间的联系与区别。

区别主要看归属。tool 是应用内部的函数,由我编写并注册,随代码运行,无法直接供其他应用使用。

MCP 将工具从应用内部剥离,使其成为独立服务进程,任何支持 MCP 的客户端都能连接使用,从而解决 M 个应用与 N 个工具对接时的组合爆炸问题。

二者的联系在于最终形态一致。MCP 工具接入后,会被包装成与内置工具相同的形式,登记到同一张工具注册表中,再统一以函数调用(Function Calling)格式提供给模型。

模型既不知道,也不必知道某项工具究竟属于本地函数还是远端服务。

具体实现中,我完成了三件事:

  • 传输支持 stdio 和 Streamable HTTP 两种
  • 给远端工具名增加服务名前缀,利用命名空间隔离避免与内置工具重名
  • 权限判断参考远端声明的只读提示,所有非只读 MCP 工具都须经人工确认才能执行

配置采用分层合并:用户目录保存全局配置,项目目录保存局部配置;服务同名时由后者覆盖前者,路径支持展开环境变量。

如果某个 server 无法连接,就对其单独隔离并记录错误,不让其他工具的正常注册受到影响。

“还有个容易被忽略的点。MCP 除了工具还有资源和提示词模板,我把它们也映射成了虚拟工具,列资源、读资源和调用普通工具走的是同一条路径,模型侧不用学新动作。”

05、短期记忆与长期记忆怎样实现

老王翻到简历下一页,问项目中的智能问答如何处理短期记忆和长期记忆。

短期记忆就是当前会话的消息历史,以列表保存,上限为 100 条,并与上下文压缩配合运行。

当内容达到可用输入预算的 80%时触发压缩,并压到 55%;最近 6 条消息保持原样,更早轮次采用提取式摘要。分割边界设在用户消息处,从而保证工具调用与结果成对保留。

长期记忆则存入用户目录下的 SQLite,可跨会话生效,并按照项目路径隔离作用域。其中有几项设计细节值得展开:

  • 去重:先将内容归一化再计算哈希,同一作用域中相同哈希仅保存一条
  • 淘汰:容量上限为 1000 条,超限后按照重要性、置信度和访问次数由低到高淘汰
  • 过期:支持 TTL,临时事实到期后自动失效
  • 召回:以词法匹配为主,再对重要性、新鲜度及访问频次加权;默认召回 6 条,未达到分数阈值的内容不会进入上下文

还要守住一条边界:压缩产生的摘要只供当前会话使用,因为它属于模型生成的二手信息,不会升级为长期记忆。

长期记忆只接受用户明确要求保存的事实。一旦放松这一界限,模型自己的转述很快就会污染记忆库。

业界主流的三层记忆体系

老王继续问:业界主流的三层记忆系统如何划分,每一层分别保存什么?

主流方案按照作用域划分为三层:

层次存储内容PaiCLI-Python 中的实现
会话层当前对话消息内存中的消息列表,上限 100 条
项目层仓库规范与构建命令项目根的 PAI.md,跟着 Git 走
全局层跨项目个人偏好用户目录中的记忆库及全局配置

文件记忆还设有本地覆盖层 PAI.local.md,用于存放仅属于本机且不进入版本库的配置。加载过程同样受预算约束:单文件截断至 6000 字符,合并内容总量限制为 16000 字符,避免记忆过度占用窗口。

建议保存这张表,回答记忆类问题时基本都能套用。

06、是否了解 Skill 的渐进式加载机制

老王提出下一题:是否了解 Skill 的渐进式披露(progressive disclosure)机制?

了解,核心可以概括为八个字:索引常驻,正文按需。整个过程分为两段。

第一段发生在每次用户输入时,只向上下文注入匹配度最高的 5 个 Skill 名称和描述。每条描述最多保留 300 字符,索引总量不超过 4000 字符。此时模型只知道有哪些技能可以使用,正文内容尚未加载。

第二段中,模型判断任务与某个 Skill 匹配后,主动调用加载工具,此时才读取 SKILL.md 正文,上限为 5000 字符。正文不会立即进入当前轮,而会先放入缓冲区,并在下一轮随工具结果一同注入;缓冲区仅保留最近 3 条,以免持续累积。

Skill 目录自身也分为内置、用户级和项目级三层;出现同名内容时,项目级覆盖用户级,这与记忆文件的分层逻辑相同。

这套机制带来的收益可以量化:若将 20 个 Skill 按每篇 5000 字符的上限全部加载,总量达到 10 万字符;采用渐进式披露后,常驻成本仅为 4000 字符索引,相差 25 倍。

老王又问:候选项是怎样匹配出来的?

通过加权评分完成。用户明确点名某个 Skill 时直接赋予最高分;否则根据命中位置计算,名称命中权重最高,标签其次,描述最低。针对中文,还采用二元、三元分词提高召回。

直白地说,它就是一个微型搜索引擎,只是检索对象由网页变成了技能。

07、使用 AI 时如何保障输出质量

老王提出最后一道正式问题:使用 AI 时,应当怎样保障输出内容的质量?

我按三层回答,先介绍自己已经实现的部分。

  • 写后自检:写入或修改 Python 文件后立即执行语法编译检查,把报错附加在工具结果中返回模型,使其能在当轮修正
  • 审查重试:多 Agent 模式设置专职审查者,产出不符合要求就退回重做,每个步骤最多重试 2 次
  • 安全兜底:配置危险命令黑名单、路径守卫、高危操作人工确认及全程审计日志,并在任务前后分别创建一次快照,以便随时回滚

老王追问。“这些都是工程手段,提示词层面呢?”

“三条实践。把验收标准直接写进提示词,让模型知道什么叫合格;复杂任务要求模型先复述一遍理解再动手,提前暴露偏差;重要产出让模型对照标准自查一轮再交付。”

也要坦白说明,通用钩子机制和结构化输出校验尚未完成,主循环同样没有自动重试。面试中最忌讳把没做过的功能说成已经实现;质量保障的首要原则,就是先确保自己的陈述真实。

老王笑了笑,把本子合上。

怎样把 PaiCLI 写进简历?

项目名称:PaiCLI-Python

项目简介:一款对标 Claude Code 的 Python Agent 命令行工具,提供 ReAct、计划执行、多 Agent 三种模式

技术栈:Python、asyncio、httpx、MCP、SQLite

核心职责:

  • 基于函数调用搭建 ReAct 主循环,以流式方式拼接工具调用参数分片;只读工具支持 4 路并发执行,通过 20 轮硬上限防止失控
  • 构建三层记忆体系,包括会话内消息历史、用户级与项目级分层文件记忆以及 SQLite 长期记忆,并支持哈希去重、TTL 过期和 1000 条容量淘汰
  • 实现可随窗口自适应的上下文压缩:预算达到 80%时触发并压缩至 55%,将分割边界置于用户消息处,确保工具调用和结果完整成对
  • 接入 MCP 官方 SDK,同时支持 stdio 和 Streamable HTTP 双传输,实现服务级配置的分层合并、故障隔离以及远端工具统一命名空间注册
  • 搭建 Skill 渐进式披露机制,使 4000 字符索引常驻、正文按需加载,将常驻上下文成本降低 25 倍

反问

08、结合面试表现,如何学习后端和 Agent

面试进入收尾环节,轮到我提问:结合刚才的表现,能否给一些后端和 Agent 方面的学习建议?

老王思考后给出了信息量很大的建议,实在太用心了,兄弟,我都想向他鞠个躬。把原话逐项拆开,就是一份完整的自查清单:

  • 模型怎样运行:在 ReAct 主流框架下,模型和框架分别承担什么职责,边界位于何处
  • 模型缓存机制:前缀缓存命中与未命中的成本差异,以及怎样组织上下文以利用这一收益
  • 如何提高输出稳定性:温度参数、结构化提示及约束性描述
  • Skill 的运行逻辑:索引注入和按需加载的两段式流程,以及预算如何确定
  • MCP 与 tool use 的机制:协议、传输方式、命名空间和权限控制
  • 上下文管理:压缩触发线、内容保留策略及消息边界完整性
  • 参考实现:上述机制都能在 Claude Code 的开源生态中找到对照
  • RAG 的知识管理与召回:切块策略、混合检索和重排序,以及怎样提升召回的准确度与精度

清单中的每一项,都可以结合一个真实项目的源码完整过一遍。

ending

过去后端面试比拼并发和中间件,如今还要比拼对模型、工具调用、记忆及上下文的理解。

我们有机会置身 AI 发展的风口浪尖,把 Agent 从名词清单变成写在简历上、经得起追问的项目。挑战固然不少,但可能性同样无限。

兄弟姐妹们,加油吧。

下期再见。

相关资讯
点击查看更多
游戏推荐
推荐专题
热门阅读
推荐下载