腾讯面试官:“你做了一个终端Agent,那讲讲 LLM 和 Agent的区别,ReAct、MCP、Tool、Memory、Skills?”我信心满满开始答了

作者:袖梨 2026-07-29

大家好,我是二哥呀。

如果你相信努力和过程,愿意一步一个脚印,也相信自己能够在 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 从概念名词变成简历中经得住追问的实际项目。挑战固然不少,可能性也同样无限。

兄弟姐妹们,加油吧。

下期再见。

相关文章

精彩推荐