Skip to content

02 核心框架(AI Agent 面试八股文 · 模块二) ​

系统梳理主流 Agent「推理—行动—编排」框架。建议先理解 ReAct 的「一步想、一步做」,再对比 Plan-and-Execute 的「先想全局、再分步做」,最后把 LangChain / LangGraph / 多 Agent 当作「工程落地方式」来记忆。

目录 ​

  1. ReAct 框架
  2. Plan-and-Execute 框架
  3. Reflexion 框架
  4. LATS(Language Agent Tree Search)
  5. LangChain Agent 实现
  6. LangGraph 状态机
  7. AutoGen / CrewAI 等多 Agent 框架
  8. 模块综合:15+ 道高频面试题速查

1. ReAct 框架(重点中的重点) ​

概念解释 ​

ReAct 的全称是 Reasoning + Acting(推理 + 行动)。可以把它想象成:一个会做题的学生,不是一口气写完答案,而是边想边做——先在心里说一句「我接下来要干什么」(推理),然后真的去查资料、用计算器、调 API(行动),看到结果后再继续想下一步。

ReAct 要求模型在文本里显式交替写出:

  • 推理(Thought):为什么要这么做、下一步选什么工具、预期看到什么。
  • 行动(Action):调用某个工具(如搜索、代码执行),并给出参数。
  • 观察(Observation):环境/工具返回的结果。

循环多次,直到模型给出 Final Answer。

一句话:ReAct = 把「思考过程」和「工具使用」写进同一条轨迹里,让推理可监督、可纠错、可复现。

原理详解 ​

单轮问答时,模型容易「幻觉」事实;ReAct 通过行动把模型锚定在外部证据上。其关键不是「更会想」,而是想与做的闭环:

用户问题
→ Thought:拆解子目标
→ Action:选择工具并执行
→ Observation:获得外部反馈
→ Thought:根据观察修正计划
→ ...
→ Final Answer
用户问题
→ Thought:拆解子目标
→ Action:选择工具并执行
→ Observation:获得外部反馈
→ Thought:根据观察修正计划
→ ...
→ Final Answer

解析要点(面试常问):

  • Thought / Action / Observation 通常用固定前缀或结构化格式(如 JSON)便于程序解析。
  • Observation 只能来自工具,不能由模型自己编造(工程上要校验)。
  • 停止条件:出现 Final Answer,或步数上限,或检测到重复无效循环。

设计要点:

  • 工具清单与参数格式要写清,减少模型胡写工具名。
  • 强调「Observation 由系统填充」,避免模型在提示里自己续写假 Observation。
  • Few-shot:给 1~3 个完整轨迹示例,能显著提高格式遵从率。

面试问题(Q)+ 标准答案(A) ​

  • Q1:ReAct 和「普通 CoT 提示」有什么本质区别?
    • A: 普通 CoT 只在模型内部展开推理链,不强制与外部环境交互;ReAct 把推理与可执行行动绑定,每一步行动后都有真实 Observation 反馈,从而用工具结果约束生成,降低闭卷幻觉。
  • Q2:ReAct 为什么要显式写出 Thought?
    • A: 显式 Thought 有三类价值:可解释性(便于人类审计)、可调试性(定位哪一步选错工具)、学习信号(可做监督微调或评估中间步骤质量)。在工程上,Thought 也帮助模型在下一步更稳定地选择 Action。

追问及应对 ​

追问应对要点
Observation 造假怎么办?由执行器生成 Observation,模型只负责 Thought/Action;可加校验与重试。
成本高吗?每步一次 LLM 调用 + 工具调用,延迟与费用随步数上升;可用步数上限、小模型路由、工具结果缓存控制。
适合哪些任务?需要外部知识或可执行验证的任务(搜索、数学、代码、数据库)。

代码示例(Python,简化版 ReAct 循环) ​

python
from dataclasses import dataclass
from typing import Callable, Dict, List, Tuple

@dataclass
class Tool:
    name: str
    run: Callable[[str], str]

def build_prompt(question, history, tool_names):
    lines = [
        "You solve tasks with tools. Use EXACTLY this format each turn:",
        "Thought: ...",
        f"Action: one of {tool_names}",
        "Action Input: ...",
        "Stop when you can answer:",
        "Final Answer: ...",
        "",
        f"Tools available: {tool_names}",
        "",
        f"Question: {question}",
        "",
    ]
    for thought, action, obs in history:
        lines += [f"Thought: {thought}", f"Action: {action}",
                  f"Observation: {obs}", ""]
    return "\n".join(lines)

def parse_action(text):
    action = action_input = None
    for line in text.splitlines():
        if line.startswith("Action:"):
            action = line.split("Action:", 1)[1].strip()
        if line.startswith("Action Input:"):
            action_input = line.split("Action Input:", 1)[1].strip()
    return action, action_input

def react_loop(question, tools, llm, max_steps=6):
    tool_names = "[" + ", ".join(tools.keys()) + "]"
    history = []
    for _ in range(max_steps):
        prompt = build_prompt(question, history, tool_names)
        out = llm(prompt)
        if "Final Answer:" in out:
            return out.split("Final Answer:", 1)[1].strip()
        thought = ""
        for line in out.splitlines():
            if line.startswith("Thought:"):
                thought = line.split("Thought:", 1)[1].strip()
        action, action_input = parse_action(out)
        if not action or action not in tools:
            obs = f"ERROR: invalid Action. Must be one of {list(tools.keys())}."
        else:
            obs = tools[action].run(action_input or "")
        history.append((thought, f"{action}[{action_input}]", obs))
    return "Failed: max steps exceeded."
from dataclasses import dataclass
from typing import Callable, Dict, List, Tuple

@dataclass
class Tool:
    name: str
    run: Callable[[str], str]

def build_prompt(question, history, tool_names):
    lines = [
        "You solve tasks with tools. Use EXACTLY this format each turn:",
        "Thought: ...",
        f"Action: one of {tool_names}",
        "Action Input: ...",
        "Stop when you can answer:",
        "Final Answer: ...",
        "",
        f"Tools available: {tool_names}",
        "",
        f"Question: {question}",
        "",
    ]
    for thought, action, obs in history:
        lines += [f"Thought: {thought}", f"Action: {action}",
                  f"Observation: {obs}", ""]
    return "\n".join(lines)

def parse_action(text):
    action = action_input = None
    for line in text.splitlines():
        if line.startswith("Action:"):
            action = line.split("Action:", 1)[1].strip()
        if line.startswith("Action Input:"):
            action_input = line.split("Action Input:", 1)[1].strip()
    return action, action_input

def react_loop(question, tools, llm, max_steps=6):
    tool_names = "[" + ", ".join(tools.keys()) + "]"
    history = []
    for _ in range(max_steps):
        prompt = build_prompt(question, history, tool_names)
        out = llm(prompt)
        if "Final Answer:" in out:
            return out.split("Final Answer:", 1)[1].strip()
        thought = ""
        for line in out.splitlines():
            if line.startswith("Thought:"):
                thought = line.split("Thought:", 1)[1].strip()
        action, action_input = parse_action(out)
        if not action or action not in tools:
            obs = f"ERROR: invalid Action. Must be one of {list(tools.keys())}."
        else:
            obs = tools[action].run(action_input or "")
        history.append((thought, f"{action}[{action_input}]", obs))
    return "Failed: max steps exceeded."

优缺点分析 ​

优点

  • 可解释:轨迹可读,便于调试与评测中间步骤。
  • 接地:通过工具把答案锚定在可验证数据上。
  • 通用:与具体工具解耦,易于替换搜索/代码/SQL 等。

缺点

  • 多轮调用:成本高、延迟大。
  • 格式脆弱:模型若偏离模板,需要解析器与重试策略。
  • 规划能力有限:逐步贪心,复杂任务上可能缺「全局最优计划」(对比 Plan-and-Execute)。

与 Chain-of-Thought(CoT)的区别 ​

维度CoTReAct
是否有外部环境通常无有(工具/Observation)
输出内容推理文字为主Thought + Action + Observation 交替
纠错方式主要靠模型自省主要靠外部反馈
典型目标提升推理深度推理 + 行动闭环

一句话总结:CoT 让模型「更会想」;ReAct 让模型「在想的同时能动手,并用真实结果纠正自己」。


2. Plan-and-Execute 框架 ​

概念解释 ​

Plan-and-Execute 是两阶段:先制定计划(Planner),再逐步执行(Executor)。像旅行前先列行程单,再按天去玩;执行中若发现「景点关门」,再改行程(Re-planning)。

与 ReAct 的差别:ReAct 常常是「走一步看一步」;Plan-and-Execute 先有一张「总蓝图」,再落地,适合步骤多、依赖关系清晰的任务。

原理详解 ​

两阶段模式:

输入任务
→ Planner:输出计划 P = [step1, step2, ...]
→ Executor:for each step:
    执行(可调用工具/子 Agent)
    更新状态 state
    若失败或信息不足 → 触发 Re-planning
→ 输出最终结果
输入任务
→ Planner:输出计划 P = [step1, step2, ...]
→ Executor:for each step:
    执行(可调用工具/子 Agent)
    更新状态 state
    若失败或信息不足 → 触发 Re-planning
→ 输出最终结果
  • Planner 组件设计:输入 = 用户目标、约束(时间/预算/格式)、当前已知上下文;输出 = 结构化计划(步骤列表、每步子目标、依赖、所需工具类型)。技巧:计划粒度适中,过细易 brittle,过粗难执行。
  • Executor 组件设计:输入 = 当前步骤、state(已完成结果、中间变量);输出 = 步骤产物 + 新 state。每一步可选用不同工具。
  • 重规划(Re-planning)机制:
    • 触发条件:工具失败、返回空、超时;Observation 与假设冲突;新信息使原计划步骤多余或顺序错误。
    • 做法:局部修复(只替换失败步骤之后的子计划);全局重规划(回到目标重新生成计划,成本高但更稳)。

面试问题(Q)+ 标准答案(A) ​

  • Q3:Plan-and-Execute 相比 ReAct 什么时候更占优?
    • A: 当任务步骤多、结构清晰、需要全局分解(如多文件代码改动、数据分析流水线、复杂调研提纲)时,Planner 先给出路线图能减少「短视」;ReAct 更擅长动态工具交互、逐步探索。
  • Q4:Re-planning 会不会导致「计划抖动」?怎么缓解?
    • A: 会。频繁重规划可能让执行轨迹不稳定。缓解方式包括:限制重规划次数、局部重规划优先、在 state 中保留已验证事实、对计划变更加一致性检查(新旧计划差异说明)。

追问及应对 ​

追问应对要点
Planner 输出不可靠?加结构化输出(JSON schema)、自检清单、必要时用更强模型只做规划。
和「分层 Agent」关系?Plan-and-Execute 常作为上层模式;Executor 内部可再接 ReAct 或子 Agent。

与 ReAct 的对比 ​

维度ReActPlan-and-Execute
规划隐式、逐步显式、先全局后局部
灵活性高(随时改工具)中(依赖重规划机制)
成本步数多时可很高规划一次可能省执行盲目性
风险短视计划错误会波及全局

适用场景小结:

  • ReAct:工具交互密集、环境反馈关键、路径不确定。
  • Plan-and-Execute:任务可分解、流程强、需要可审计的计划书。

3. Reflexion 框架 ​

概念解释 ​

Reflexion 的核心是:做完不等于结束——还要评估做得好不好,把教训记下来,下次带着教训重试。像考试做错后写错题本,而不是盲目刷同一道题。

它强调语言化反思(自然语言反思条目),而不是只改参数;反思作为记忆,影响后续尝试的策略。

原理详解 ​

典型角色分工(概念上):

  • Actor:生成行动/答案(可接工具)。
  • Evaluator:给反馈(对/错、评分、缺失项)。
  • Reflector:根据反馈写反思文本(指出错误原因与改进策略)。

反思不是泛泛的「我要更仔细」,而是可执行的指导,例如:「应先确认单位换算」「应先检索最新数据而非凭记忆」。

反思记忆的存储与使用:

  • 短期:同一任务多轮尝试中维护 reflections: List[str]。
  • 长期:写入向量库/键值库,按任务类型检索相似反思。

工作流程:Action → Evaluation → Reflection → Retry

面试问题(Q)+ 标准答案(A) ​

  • Q5:Reflexion 和「让模型自己检查一遍」有什么不同?
    • A: 自检往往是一次性的;Reflexion 把评估与反思显式化、结构化,并跨尝试复用反思文本,形成可累积的「策略记忆」。工程上更易控制与评测。

追问及应对 ​

追问应对要点
Evaluator 从哪来?规则、更强模型、单元测试、外部工具验证(因任务而异)。
反思会不会冗长?限制条数与长度;合并相似反思;只保留高信息密度条目。

适用场景 ​

  • 可验证任务:代码、数学、有测试用例的生成。
  • 易犯系统性错误的任务:格式、约束、工具选择。
  • 预算允许多轮尝试的场景(反思会增加调用次数)。

概念解释 ​

LATS 把 Agent 的决策看成在树上搜索:每个节点是一种「状态/中间思路」,分支是不同行动。任务复杂、存在多条可能路径时,与其一次走到底,不如探索多条路,用评估函数判断哪条路更有希望。

它常与蒙特卡洛树搜索(MCTS)思想结合:通过选择—扩展—模拟—回传在探索与利用之间折中,把「语言推理」嵌进搜索节点。

原理详解 ​

  • 节点:包含当前上下文、已执行动作历史、可选下一步。
  • 边:一次 Thought/Action 或一个子目标步骤。
  • 叶节点评估:是否完成任务、奖励分数、是否需继续扩展。

MCTS 四步(面试版描述):

Select:从根沿策略选到叶(UCB 等平衡探索/利用)
Expand:生成若干可能的下一步(语言分支)
Simulate/Rollout:用启发式或模型快速评估结果潜力
Backpropagate:把评估回报回传到路径上的节点统计量
Select:从根沿策略选到叶(UCB 等平衡探索/利用)
Expand:生成若干可能的下一步(语言分支)
Simulate/Rollout:用启发式或模型快速评估结果潜力
Backpropagate:把评估回报回传到路径上的节点统计量

面试问题(Q)+ 标准答案(A) ​

  • Q6:LATS 相比单次 ReAct 多在哪里成本?换来什么收益?
    • A: 成本主要来自多分支扩展与多次评估/模拟。收益是更系统的探索,降低「一条路径走到黑」的局部最优风险,适合决策点多的任务。

追问及应对 ​

追问应对要点
和束搜索(Beam Search)区别?Beam 偏序列生成;LATS/MCTS 更强调节点价值估计与探索策略(UCB)。
工程难点?分支爆炸、评估器设计、延迟控制;需要强剪枝与缓存。

适用场景 ​

  • 策略游戏、规划 puzzle、代码修复(多方案补丁)。
  • 研究型问题:需要先提出多种假设再验证。

5. LangChain Agent 实现 ​

概念解释 ​

LangChain 把 LLM、提示模板、工具、记忆、解析器等拼成可运行程序。Agent 在这里通常指:由 LLM 决定下一步调用哪个工具的循环执行体;AgentExecutor 负责「跑这个循环直到结束」。

原理详解 ​

核心抽象(面试口径):

  • Tools:对外部能力的封装(name、description、args schema、执行函数)。
  • LLM / ChatModel:生成下一步决策与内容。
  • Agent(推理策略):如何把工具、提示、中间步骤组合起来(ReAct、OpenAI tools 等)。
  • AgentExecutor:驱动循环——调用 Agent → 若有 tool_calls 则执行工具 → 回填消息 → 直到停止。

AgentExecutor 工作原理:

inputs → AgentExecutor
loop:
    agent.plan(messages/tools) -> next message / tool_calls
    if final answer: return
    else: run tools -> append tool messages
    (optional) trim memory / handle parsing errors
inputs → AgentExecutor
loop:
    agent.plan(messages/tools) -> next message / tool_calls
    if final answer: return
    else: run tools -> append tool messages
    (optional) trim memory / handle parsing errors

自定义 Agent 的步骤(通用 checklist):

  1. 定义 Tools(清晰 description 与 schema)。
  2. 选择提示模板(ReAct JSON / OpenAI tool calling)。
  3. 选择模型与输出解析器(防止格式漂移)。
  4. 组装 Agent + AgentExecutor(设置 max_iterations、handle_parsing_errors)。
  5. 评测与加固(日志、重试、工具超时)。

面试问题(Q)+ 标准答案(A) ​

  • Q7:LangChain 里 AgentExecutor 解决的核心问题是什么?
    • A: 把「模型决策 → 工具执行 → 结果回填 → 再决策」的控制流标准化,统一处理迭代限制、错误处理、中间消息结构,让开发者专注工具与提示。
  • Q8:工具描述为什么重要?
    • A: Agent 依赖描述进行工具选择;描述不清会导致错选工具或参数幻觉。应包含用途、输入输出、边界条件、示例。

追问及应对 ​

追问应对要点
LangChain Agent 和自写 ReAct 差别?LangChain 提供工程封装与生态整合;底层仍是提示+解析+循环。
版本迁移问题?面试中强调理解 Executor 循环与 tool calling 模式即可,不必背每个 API 名。

6. LangGraph 状态机 ​

概念解释 ​

如果把 LangChain Agent 看成「一套默认的循环」,LangGraph 则是把 Agent 工作流画成图:节点是处理步骤(调用模型、调工具、审核),边是流转关系。复杂业务往往需要分支、循环、人工确认——用图更直观。

原理详解 ​

  • Graph / StateGraph:节点函数读取共享 state,返回 state 更新。
  • Node:state -> partial_state_update。
  • Edge:A -> B 表示执行完 A 后执行 B。
  • 条件边(Conditional Edge):根据 state 决定下一步去哪个节点,例如 if needs_human_review(state): goto human; elif tool_error(state): goto repair; else: goto continue。
  • 状态管理:通常定义 TypedDict 或 dataclass 描述 state schema;多节点可增量合并更新(reducer),避免全局覆盖冲突。

与 LangChain Agent 的区别(面试高频):

维度LangChain AgentLangGraph
控制流偏固定循环显式图、分支/循环更自然
可观测性日志为主结构化的节点轨迹
人机协同需要额外封装容易加 human 节点
适用标准工具 Agent复杂业务流程、审查、重试拓扑

面试问题(Q)+ 标准答案(A) ​

  • Q9:什么时候选 LangGraph 而不是 AgentExecutor?
    • A: 当流程不是「单一工具循环」,而是需要多阶段流水线、条件路由、回环修复、人工审核节点、并行任务时,用图编排更清晰可维护。
  • Q10:LangGraph 的状态更新为什么要谨慎设计?
    • A: 多节点写入同一字段可能冲突;需要 schema 约束、归约策略(append vs replace)、明确每个节点的写入职责。

追问及应对 ​

追问应对要点
图会不会变复杂?用子图/模块化节点;把业务阶段分层。
调试怎么做?节点级日志、导出每一步 state、可视化执行路径。

7. AutoGen / CrewAI 等多 Agent 框架 ​

概念解释 ​

多 Agent 框架把任务拆给多个「角色」:有人负责写代码,有人负责审查,有人负责检索。它们通过对话或结构化消息协作。AutoGen 偏可编程的对话与工具;CrewAI 偏角色驱动的团队流程(Crew)。

原理详解 ​

核心设计理念:

  • 分权:降低单模型负载,让角色专注子任务。
  • 对抗/互补:审查者发现生成者问题,提高质量。
  • 可组合:工作流可由对话路由或 DAG/图编排。

角色定义与对话:

  • 角色(Role):system prompt + 工具权限 + 目标。
  • 对话拓扑:一对一、群聊、星型(manager)、分层。

适用场景:

  • 内容生产流水线(调研→写作→校对)。
  • 软件工程(需求→设计→实现→Code review)。
  • 需要强分工与过程质量控制的组织化任务。

面试问题(Q)+ 标准答案(A) ​

  • Q11:多 Agent 一定比单 Agent 更强吗?
    • A: 不一定。更多 Agent 可能带来协调成本、错误级联、对话冗长。当任务可清晰分工且有评估机制时收益大;否则单 Agent + 强工具可能更简单高效。
  • Q12:如何避免多 Agent「互相附和」?
    • A: 引入独立审查角色、基于规则的检查、外部工具验证(测试、检索),并明确停止条件与异议处理流程。

追问及应对 ​

追问应对要点
AutoGen vs CrewAI 怎么选?看团队更偏对话编排/代码优先(AutoGen 系)还是角色/任务流水线(Crew 风格);最终以项目 PoC 为准。
成本?多角色多轮对话显著增加 token;需要缓存、摘要、限轮。

8. 模块综合:15+ 道高频面试题速查 ​

  • Q13:请用一句话解释 ReAct。
    • A: 让模型交替输出推理与可执行行动,并用工具返回的 Observation 闭环纠错,从而把推理接地到外部环境。
  • Q14:ReAct 轨迹里,哪一部分必须由系统生成?为什么?
    • A: Observation 必须由工具/环境生成,防止模型伪造证据导致「看似合理但错误」的答案。
  • Q15:Plan-and-Execute 的最大风险是什么?如何缓解?
    • A: 风险是错误计划污染全局;缓解是可验证子步骤、重规划、强 Planner 约束输出与执行期监控。
  • Q16:Reflexion 的关键产出是什么?它如何提升下一轮?
    • A: 关键是高质量反思文本;它作为记忆进入下一轮提示,指导 Actor 改变策略而非重复错误。
  • Q17:LATS 与 ReAct 在「探索能力」上如何对比?
    • A: ReAct 通常主路径贪心推进;LATS/MCTS 通过多分支搜索与价值回传更系统探索决策空间(成本更高)。
  • Q18:LangChain AgentExecutor 中为什么要限制 max_iterations?
    • A: 防止工具循环、解析失败导致的无限循环,并控制成本与延迟。
  • Q19:描述 LangGraph 的条件边解决的业务问题。
    • A: 根据中间状态动态路由,例如失败重试、需要人工审核、不同客户等级走不同流程。
  • Q20:什么时候更建议「单 Agent + 强工具」,而不是多 Agent?
    • A: 任务边界清晰、无需组织化分工、协调成本可能大于收益时;或延迟/成本敏感场景。
  • Q21:多 Agent 系统的「评估器」可以有哪些实现?
    • A: 单元测试/静态规则、更强模型评审、人工审核节点、外部检索核对事实等。
  • Q22:ReAct Prompt 为什么要给 few-shot 示例?
    • A: 提升模型对固定格式的遵从度,降低解析失败率,稳定工具调用。
  • Q23:Re-planning 与 Reflexion 都「改正错误」,区别是什么?
    • A: Re-planning 偏计划结构的调整(下一步怎么走);Reflexion 偏策略/经验的语言化总结并跨轮复用。
  • Q24:LangGraph 相比普通脚本编排的核心收益?
    • A: 把流程显式化为图,分支/回环/人机节点一等公民,更易维护与观测。
  • Q25:如果工具返回噪声很大,ReAct 可能出什么问题?怎么改进?
    • A: 模型可能被噪声误导;改进包括工具侧清洗/结构化输出、二次检索、在 Thought 里强制引用证据片段、增加校验工具。
  • Q26:你如何为一个企业场景选择 ReAct vs Plan-and-Execute?
    • A: 看任务是否强流程、是否需要可审计计划书、是否允许前期规划成本;需要强工具交互与动态环境用 ReAct,强分解与多步骤交付用 Plan-and-Execute。
  • Q27:为什么说「工具描述」是 Agent 的接口设计?
    • A: LLM 靠描述做路由与填参;描述就是人机接口,直接影响成功率。

附录:对比速记表 ​

框架/概念关键词典型循环
ReAct推理+行动交替Thought→Action→Observation
Plan-and-Execute先计划后执行Plan→Execute→(Replan)
Reflexion反思记忆Act→Eval→Reflect→Retry
LATS树搜索 / MCTSSelect→Expand→Evaluate→Backprop
LangChain AgentExecutor 循环decide→tool→observe
LangGraph图编排node→conditional edge
多 Agent角色协作对话/流水线