
面试官问:"ReAct 和 Plan and Execute 你选哪个?"——这道题没有标准答案,但回答的方式直接暴露你对 Agent 架构的理解深度。选 ReAct 的人被认为缺乏全局观,选 Plan and Execute 的人被质疑没有灵活性,那到底怎么站队?
本文整理自近期多场真实面试中的 AI 相关问题,从 Agent 架构之争出发,串联 Function Call、MCP 协议、RAG、上下文管理、文档解析六大核心话题。不只是"背答案",更要知道"为什么这么做"。
🙋♂️候选人:Agent 就是让大模型不只是"说话",还能"做事"——通过工具调用、规划推理来主动完成复杂任务。ReAct 是边想边做,Plan and Execute 是先规划再执行。
👔面试官:那你觉得什么场景该用 ReAct,什么场景该用 Plan and Execute?
🙋♂️候选人:如果任务步骤不确定、需要根据中间结果灵活调整,用 ReAct;如果步骤之间有强依赖、执行顺序基本固定,用 Plan and Execute。
👔面试官:那你就不能两个都用吗?
Agent = LLM + 工具 + 记忆 + 规划。ReAct 和 Plan and Execute 不是二选一的关系,而是两个不同粒度的策略——ReAct 是"一步一想",Plan and Execute 是"先全局规划,再逐步执行"。实战中最好的做法是混合使用:Plan and Execute 做全局规划,ReAct 做每步内的灵活执行。

Agent 不是一个单一的技术,而是一个架构模式。它的四个核心组件:
维度 | ReAct | Plan and Execute |
|---|---|---|
核心思路 | 每一步都 Thought → Action → Observation 循环 | 先生成完整计划,再逐步执行计划 |
灵活性 | 高,每步可根据观察调整下一步 | 低,计划一旦生成就按顺序执行 |
一致性 | 可能跑偏,缺乏全局视角 | 全局规划,步骤间依赖关系清晰 |
适用场景 | 开放式探索、工具调用不确定 | 流程型任务、步骤有强先后依赖 |
典型案例 | "帮我查下北京天气,如果下雨推荐室内活动" | "帮我完成一个数据分析报告" |
ReAct 的执行流程:

ReAct 的优势是实时感知——每一步执行完都能根据结果调整策略。但缺点也很明显:如果某一步推理出错,后续步骤可能连锁崩溃,而且没有全局规划容易"走弯路"。
Plan and Execute 则是在开始执行前先让 LLM 生成一个完整的步骤列表,然后按列表逐个执行。适合那种"你很清楚要干什么,只是需要一步步来"的场景。比如数据分析:先获取数据 → 清洗数据 → 统计分析 → 生成可视化 → 写总结报告,这些步骤的依赖关系是固定的。
实战建议:复杂项目中,可以考虑混合策略——先用 Plan and Execute 做全局规划,每个步骤内部用 ReAct 做灵活执行。这样既有全局视角,又有局部灵活性。面试中被逼二选一的时候,说出这个混合方案,基本就能让面试官意识到你不止停留在"用过"的层面。
🙋♂️候选人:我们用的是经典的 RAG 流程——文档解析、分块、向量化、检索、生成。切分策略上,主要基于语义段落和重叠窗口。
👔面试官:重叠窗口的 overlap 设多少?为什么不是0?
🙋♂️候选人:overlap 设的是 chunk_size 的 10% 左右,避免语义在切分边界处断裂。
RAG 的核心是把"检索"和"生成"解耦,用向量检索从知识库中找到相关片段,再交给大模型基于这些片段生成回答。文档切分是 RAG 效果的地基,切不好,后面再怎么优化都是白搭。

一个完整的 RAG 流程分为离线索引和在线检索生成两个阶段:
切分是 RAG 里最容易被忽视、但对效果影响最大的环节。常见的几种策略:
切分策略 | 原理 | 优点 | 缺点 |
|---|---|---|---|
固定长度切分 | 按字符/Token数固定切割 | 实现简单,通用性强 | 容易切断句子和段落 |
语义段落切分 | 按段落、标题、换行等自然边界切 | 语义完整性好 | 块大小不均匀,小块信息量不足 |
递归字符切分 | 先按大分隔符切,切不开再按小的切 | 兼顾语义和长度控制 | 需要调参,分隔符选择影响大 |
语义切分 | 用 Embedding 计算相邻句子相似度,相似度骤降处切割 | 语义边界最精准 | 计算成本高,需要额外调用模型 |
实际项目中,递归字符切分 + overlap 是性价比最高的组合。overlap 的作用是让相邻块之间有一段重叠文本,防止关键信息恰好落在切分边界上导致检索不到。
常见误区:很多同学觉得切得越细检索越精准。实际上切得太细会导致每个块信息量不足,模型拿到的上下文碎片化,生成质量反而下降。一般建议 chunk_size 在 512~1024 Token,overlap 在 50~100 Token。
向量检索的本质是语义匹配——把文本映射到高维向量空间,语义相近的文本在空间中距离更近。相比关键词检索,向量检索能理解"同义词"和"语义关联",比如用户问"怎么退款",能检索到包含"退货流程"的文档。
🙋♂️候选人:Function Call 就是让大模型在生成回答时,能识别出需要调用外部工具,然后输出一个结构化的工具调用请求,由应用层执行后把结果喂回模型继续生成。
👔面试官:那模型本身会执行工具吗?
🙋♂️候选人:不会。模型只负责"决定调什么、传什么参数",真正的执行是应用层完成的。
Function Call 的本质是让 LLM 输出结构化的"工具调用意图",而不是直接执行工具。整个流程是:模型决策 → 应用层执行 → 结果回传 → 模型继续生成。模型永远不直接接触外部世界。

关键步骤拆解:
第一步:注册工具定义
你需要在请求中告诉模型"你有哪些工具可以用",这是一个 JSON Schema 格式的描述:
{
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
}
]
}
第二步:模型决策
模型接收到用户消息和工具定义后,会判断是否需要调用工具。如果需要,它不会生成普通文本,而是返回一个 tool_calls 结构,包含工具名和参数。
第三步:应用层执行
这是很多同学搞混的地方——模型不会自己执行工具。你的应用代码拿到 tool_calls 后,需要自己调用对应的函数/API,然后把执行结果以 tool 角色的消息格式回传给模型。
第四步:模型生成最终回答
模型拿到工具返回的结果后,结合原始问题和工具结果,生成最终的自然语言回答。
关键点:Function Call 可以嵌套多轮——模型可能在第一轮调了一个工具,拿到结果后发现还需要调另一个工具,这个过程会自动循环直到模型认为信息足够给出最终回答。你需要在应用层实现这个循环逻辑,设置最大轮数防止无限循环。
🙋♂️候选人:可以做上下文压缩或者滑动窗口……
👔面试官:具体怎么做?压缩的精度怎么保证?
上下文限制的处理不是单一方案能解决的,需要组合使用:滑动窗口保留近期对话、摘要压缩历史内容、向量检索召回关键信息。核心原则是——让模型"忘掉细节,记住要点"。
这是 AI 应用开发中非常实际的问题。GPT-4 的上下文窗口是 128K,Claude 是 200K,看起来很大,但在多轮对话尤其是 Agent 场景下,Token 消耗远比你想象的快——一次工具调用可能就吃掉几千 Token。
策略 | 原理 | 优点 | 缺点 |
|---|---|---|---|
滑动窗口 | 只保留最近 N 轮对话 | 实现简单,延迟低 | 丢失早期上下文 |
摘要压缩 | 用 LLM 把历史对话压缩成摘要 | 保留关键信息 | 额外调用 LLM 有成本,压缩有信息损失 |
向量检索 | 把历史对话存入向量库,按需检索 | 可检索任意历史 | 检索可能不精准,需要额外存储 |
Token 预算分配 | 给系统提示/历史/当前问题分配 Token 预算 | 精细控制 | 需要实时计算 Token 数 |

具体实现思路:
很多同学直觉上认为:直接把所有历史对话都做摘要就好了。但摘要本身也是有损压缩,你每做一次摘要,就丢失一些细节。所以更好的做法是分层——近期对话原样保留(保真),远期对话摘要压缩(保要),超远期向量检索(按需)。
🙋♂️候选人:MCP 是 Model Context Protocol,是 Anthropic 提出的一个开放协议,用来标准化大模型与外部工具之间的连接方式。
👔面试官:那它和 Function Call 是什么关系?有了 Function Call 为什么还需要 MCP?
MCP 是工具接入的标准化协议,Function Call 是模型调用工具的机制。Function Call 解决的是"模型怎么调工具",MCP 解决的是"工具怎么接入"。没有 MCP,你每接入一个新工具就要手写 Schema、对接 API;有了 MCP,工具提供方自己实现 MCP Server,你的应用直接连就行。

MCP 采用了 Client-Server 架构:
没有 MCP | 有 MCP |
|---|---|
每个工具手写 Function Schema | Server 自描述,自动生成 Schema |
工具实现耦合在应用代码里 | 工具逻辑独立在 Server 进程中 |
换一个 AI 应用就要重新对接工具 | 同一个 Server 可被多个 Host 复用 |
工具鉴权、安全策略各自实现 | 协议层统一处理权限控制 |
说白了,MCP 做的事情类似于 USB 协议——在 USB 出现之前,键盘、鼠标、打印机各有各的接口;USB 统一了接口标准后,设备厂商只需要实现 USB 协议就能接入任何电脑。MCP 对 AI 工具接入做了同样的事。
以实际使用场景举例,常见的 MCP Server 包括:
注意:MCP 不是 Function Call 的替代品,而是 Function Call 的上游。流程是:MCP 负责发现和描述工具 → 应用把 MCP 的工具描述转换为 Function Call 的 Schema → 模型通过 Function Call 决定调用哪个工具 → 应用层通过 MCP 协议实际执行调用。
🙋♂️候选人:我们用 PyMuPDF 解析 PDF 文本,然后用递归字符切分器做分块……
👔面试官:PDF 里有表格和图片怎么办?表格被切散了怎么处理?
PDF 解析的难点不在提取文字,而在保持文档的结构语义——表格、图片、布局信息在纯文本提取时都会丢失。工程上需要根据文档类型选择不同的解析策略,并在分块时尽量保持语义单元的完整性。
层次 | 方法 | 能力 | 局限 |
|---|---|---|---|
基础文本提取 | PyMuPDF、pdfplumber | 提取纯文本,速度快 | 丢失表格结构、图片内容 |
结构化解析 | pdfplumber 表格提取、Unstructured | 保留表格、标题层级 | 复杂布局识别差 |
视觉理解 | 多模态模型(GPT-4V、Qwen-VL) | 理解布局、图片、公式 | 成本高、速度慢 |
实际项目中的分层策略:
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100,
separators=["\n\n", "\n", "。", "!", "?", ".", " "],
)
关键参数说明:
表格切分的实战经验:在递归切分之前,先用正则或 pdfplumber 标记表格区域的起止位置,然后在切分时将整个表格作为一个原子单元。如果表格超过 chunk_size,就把表格单独成块,不与前后文本合并。这样做虽然单个块可能偏大,但至少表格的行列关系不会被打散,检索出来的内容对模型是有意义的。