为什么 Agent 能自主干活,又经常翻车:ReAct 与 Plan-and-Execute 拆解

为什么 Agent 能自主干活,又经常翻车:ReAct 与 Plan-and-Execute 拆解

上一篇《给传统 SaaS 增加 AI 能力:3个真实落地场景》结尾提到,ChatBI 的"生成 SQL → 执行 → 自检 → 重试"循环,就是 Agent 的雏形。这一篇把这个雏形彻底拆开:Agent 到底是什么、由哪些零件组成、能干什么,又为什么经常翻车。

先说清它由哪几个零件组成,再手写一个最简单的 ReAct 循环,然后讲 Plan-and-Execute 模式,最后回答那个最扎心的问题:为什么 Agent 能自主干活,又经常翻车。

全文回答三个问题:

  1. Agent 由哪几个零件组成(LLM、工具调用、记忆、循环)
  2. ReAct 和 Plan-and-Execute 两种模式怎么选(附决策树)
  3. Agent 为什么经常翻车、怎么兜底(四类失败原因 + 四道保险)

先给结论:Agent 不是魔法,是三个机制的组合加一个循环。它能自主完成任务,是因为把"想"和"做"拆开了;它经常翻车,是因为没人管它怎么想、怎么做。

这篇文章不会讲 LangChain 怎么调。框架代码看文档就行,翻车了你也看不懂为什么。我们直接写底层循环,看清每一条 Thought 和 Observation 是怎么流转的,再回去用框架,你会突然明白那些参数是干什么的。

从 ChatBI 到 Agent:差的那一步是什么

回放一下 ChatBI 的工作过程。用户问"华东区各品类退货率",系统干四件事:

  1. 把自然语言翻译成 SQL
  2. 在数据库上执行
  3. 拿结果自检,看有没有明显异常
  4. 不对就重新生成,对了就返回

这一步一步的循环,就是 Agent 的骨架。它没有人在中间插手,靠自己的判断走完整个流程。

那 ChatBI 和 Agent 差在哪?差在"执行"的范围。ChatBI 只会调数据库,Agent 什么工具都可能调:查天气的 API、公司的内部接口、发消息、写文件、搜网页。数据库只是工具的一种。

所以 Agent 的通用定义可以写成一句话:一个循环,让 LLM 在"感知 → 决策 → 行动 → 观察"之间反复转,直到完成任务或撞上终止条件。

感知是拿到用户问题和环境信息;决策是判断下一步干什么;行动是调用某个工具;观察是看工具返回的结果,然后带着新信息进入下一轮。

听上去就是个 while 循环。但"简单"不等于"容易做对"。这个循环里的每一步都有各自的翻车方式:感知阶段可能拿错数据,决策阶段可能选错工具,行动阶段可能传错参数,观察阶段可能误读结果。后面会逐一拆。

在展开循环之前,先把 Agent 的零件数清楚。很多翻车,其实是零件本身就装错了。

Agent 的四个零件:大脑、手、记忆、循环

拆开看,Agent 只有四个零件。

零件一:LLM,大脑但不是全部

LLM 负责思考和决策。注意一个常被误解的点:换更强的模型不等于换更可靠的 Agent。

架构的稳定性、状态的清晰度、工具的规范性——这些工程因素比模型参数对 Agent 的可靠性影响更大。一个架构混乱的 Agent,换再强的模型也会在同一个地方反复翻车。

这跟第 2 篇讲 RAG 时的结论一样:瓶颈往往不在模型,在工程。

零件二:工具调用(Function Calling),本质是一份 JSON 约定

工具调用是 Agent 的"手"。但很多人把它想复杂了。它的本质是:你告诉模型"有哪些函数可以调、每个函数收什么参数",模型在回答里输出"我要调哪个函数、传什么参数",然后由你的代码去真正执行。

我见过不少团队在这上面绕弯子:有人以为模型"会"调用 API,有人以为需要给模型装什么运行时。都不是。模型全程只做两件事:读懂工具描述,输出一段结构化文本。剩下的全是你的代码。

关键点在这里:模型本身不执行任何工具,它只是"决定"调用并生成参数。真正干活的是你的代码。这个决定权交接靠一份 JSON Schema 约定。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询城市天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名"}
                },
                "required": ["city"],
            },
        },
    }
]

模型看到这份描述后,会输出类似 {"name": "get_weather", "arguments": {"city": "上海"}} 的结构化结果,你的代码解析它、调用真实函数、把结果回填给模型。

注意:Function Calling 是通用模式,不是某一家厂商的专属能力。各家 API 的字段名略有差异(OpenAI 叫 tools、Anthropic 叫 tools、一些国产模型叫 functions),但骨架一样。想换供应商,用抽象层包一层就行,别把代码写死在某一家的格式上。

还有一点容易被忽略:工具描述写得好不好,直接决定调用准不准。 "查询城市天气"和"根据城市名查询当地实时天气,返回温度和风力,用于出行建议",后者被模型选中的概率明显更高。description 字段是给模型看的文档,值得像写接口文档一样认真写。

零件三:记忆,短期是窗口,长期是向量库

记忆分两层。

短期记忆就是上下文窗口本身。 这轮循环里模型看到了什么,就是它的短期记忆。上一轮的思考、行动、观察结果,都得拼进对话历史里传给下一轮。窗口越大,能记住的中间过程越多,但记住不等于用好。把十轮历史全塞进去,模型反而抓不住重点,这就是后面要讲的 context rot。

长期记忆是向量库。 跨会话、跨任务的经验和知识,靠第 2 篇那套 RAG 底座存起来:文档解析、分块、Embedding、检索。Agent 遇到问题先去向量库查相关资料,再决定怎么干。前面三篇文章打的底子,在这里直接复用,一分钱没白花。

不知道 RAG 底座怎么搭?先看这篇:《RAG 核心技术实战:文档解析、分块策略与检索 Pipeline》

还有一层容易被忽略的:工作记忆。运行中的计划、待办步骤、已经拿到的中间结果,这些应该放在显式的状态对象里,而不是只靠对话历史隐式携带。第 7 篇讲人机协作时会细说,这里先记住一个原则:能结构化存放的状态,别让模型"记住"。

零件四:循环,把前三者串起来

零件齐了不等于会干活。LLM 不会自己循环,工具不会自己调用,记忆不会自己流动。得有一段代码把"决策 → 行动 → 观察"反复串起来,这就是循环,也是整篇文章的主角。

ReAct:边想边做的循环

ReAct(Reasoning + Acting)是 Yao et al.(2022)在论文《ReAct: Synergizing Reasoning and Acting in Language Models》中提出的模式,至今仍是绝大多数 Agent 框架的默认底座。它的思想就一句话:想一步,做一步,看结果,再想下一步。

论文里的核心实验其实很朴素:同样让模型回答需要实时信息的问题,纯提示词(只让模型"思考")答不对,ReAct(思考 + 调用工具 + 观察结果)就能答对。结论是:推理和行动必须交替进行,光想不做是闭门造车。

每一步模型输出三样东西:

  • Thought(思考):分析当前情况,决定下一步
  • Action(行动):调用哪个工具
  • Action Input(输入):给工具传什么参数

工具返回的结果叫 Observation(观察),作为新信息拼进对话历史,进入下一轮。直到模型认为可以收尾,输出最终答案。

手写一个 ReAct 循环

别急着上 LangChain。先手写一个,40 行左右,你会发现循环的本质就这么点东西。

import json
import re

from openai import OpenAI

client = OpenAI(base_url="...", api_key="...")  # 换成你的 API 地址

# 工具注册表:名字 -> (描述, 处理函数)
ToolRegistry = {
    "get_weather": (
        "查询城市天气,参数 city:城市名",
        lambda city: f"{city}:多云,26℃,东风 3 级",
    ),
    "calc": (
        "计算数学表达式,参数 expr:如 (12+8)*3",
        lambda expr: str(eval(expr)),
    ),
}

def build_prompt(history):
    tool_desc = "\n".join(f"- {name}: {desc}" for name, (desc, _) in ToolRegistry.items())
    system = f"""你是一个能调用工具的助手。可用工具:
{tool_desc}

严格按以下格式输出:
Thought: 你的推理
Action: 工具名
Action Input: {{"参数": "值"}}

当你已有答案时,输出:
Thought: 你的推理
Final Answer: 最终答案"""

    messages = [{"role": "system", "content": system}]
    messages += history
    return messages

def run_agent(question, max_steps=5):
    history = [{"role": "user", "content": question}]

    for step in range(max_steps):
        resp = client.chat.completions.create(
            model="qwen-plus",
            messages=build_prompt(history),
        )
        text = resp.choices[0].message.content
        print(f"--- 第 {step+1} 轮 ---\n{text}\n")

        # 解析:有没有 Final Answer?
        if "Final Answer" in text:
            return text

        # 解析 Action 和 Action Input
        m = re.search(r"Action: (\w+)\nAction Input: (\{.*?\})", text, re.S)
        if not m:
            return f"模型输出无法解析,终止。原始输出:{text}"

        name, args_raw = m.group(1), m.group(2)
        if name not in ToolRegistry:
            return f"未知工具 {name},终止。"

        args = json.loads(args_raw)
        fn = ToolRegistry[name][1]
        observation = fn(**args)

        print(f"Observation: {observation}\n")

        history.append({"role": "assistant", "content": text})
        history.append({"role": "user", "content": f"Observation: {observation}"})

    return "达到最大步数,强制终止。"

if __name__ == "__main__":
    result = run_agent("上海天气怎么样?顺便算一下 (12+8)*3 等于多少")
    print("=== 最终结果 ===")
    print(result)

这段代码把 ReAct 循环的核心讲完了:循环体就三件事,让模型想、解析它的行动、执行工具把观察结果回填。

跑一下逻辑,完整的对话轨迹长这样:

用户: 上海天气怎么样?顺便算一下 (12+8)*3 等于多少

第 1 轮
Thought: 用户问了两个问题,先查上海天气
Action: get_weather
Action Input: {"city": "上海"}
Observation: 上海:多云,26℃,东风 3 级

第 2 轮
Thought: 天气拿到了,再算数学题
Action: calc
Action Input: {"expr": "(12+8)*3"}
Observation: 60

第 3 轮
Thought: 两个问题都有答案了,可以汇总
Final Answer: 上海今天多云,26℃,东风 3 级。另外 (12+8)*3 = 60。

每一步的 Observation 都是上一步 Action 的真实结果,不是模型编的。这就是循环的意义。

为什么这个循环让模型从"猜答案"变成"查答案"

没有循环时,LLM 是"闭卷考试":凭训练时见过的东西直接答。问它"上海今天天气",它只能编,这就是最典型的幻觉场景——它不是在撒谎,是它的知识里没有实时信息,只能猜一个像样的答案。

有了循环,变成"开卷考试":不知道就去查,查完再答。回答"上海多云"不是因为模型记得,而是因为它真的调了天气 API 并看到了返回值。

这就是 Agent 和纯 LLM 的分水岭:模型从"记忆的复读机"变成了"环境的观察者"。 它对事实的陈述不再依赖训练数据,而是依赖工具返回的真实观测。

顺带说一句手写 vs 框架的取舍。手写循环适合理解原理、排查问题、做最小 demo;生产环境建议还是用框架,因为框架把并发、重试、流式输出、状态持久化这些都处理好了。但用框架之前先手写一遍,你会知道 max_iterations 这个参数为什么存在,模型输出不按格式来的时候框架到底在帮你做什么。

第一个实战坑:模型不按格式输出

手写循环跑通第一天就会遇到这个坑:模型不总是老实输出 Action: xxx。它可能把 Action 写进 Markdown 代码块里,可能突然输出一段散文,可能多写一个 Final Answer 但前面还要调工具。

我的处理分三层。第一层,解析时用宽松正则,容忍代码块、多余空格;第二层,解析失败就把原始输出原样丢回给模型,追加一句"你的输出格式不对,请严格按照格式重新输出",让它自纠一次;第三层,连续两次解析失败就直接终止,把控制权交回给用户,别死磕。

顺带说一句:模型如果在一个明确的任务上都反复不按格式来,换个更强或更听话的模型,比改一万行解析代码管用。

ReAct 的局限

ReAct 走一步看一步,问题在于看不到全局

任务简单时没问题。任务有 8 个步骤、步骤之间有依赖关系时,模型每一步都要重新判断"现在到哪了、下一步干啥",容易走着走着迷路,来回折腾,token 烧得飞快。

而且 ReAct 的每一步都要调一次 LLM,长链条任务下成本线性上涨。这引出了另一种模式。

Plan-and-Execute:先规划再执行

Plan-and-Execute(计划与执行)的思路完全相反:动手之前,先把整个任务的步骤规划出来,然后按计划执行。

它把 Agent 拆成两个角色:

  • Planner(规划器):只思考,不碰工具。拿到任务后输出一份步骤清单,比如"第一步查 A 数据,第二步查 B 数据,第三步对比,第四步写报告"
  • Executor(执行器):只执行,不临场发挥。按规划器的步骤清单一步步干活,每步可以调工具

这么做有三个好处。

第一,省 token。 规划只做一次,不像 ReAct 每一步都要重新推理"下一步干啥"。ReWOO 这类变体进一步把推理和观察解耦,中间过程的 token 消耗更少。

第二,可审查。 计划在动手前就生成,人可以先看一遍:"这计划靠谱吗?"不靠谱直接改,不用等它跑完再发现方向错了。对敏感任务,这是很大的安全感。

第三,可分工。 规划可以用强一点的模型,执行可以用便宜的小模型。把成本花在刀刃上。

代价是:计划一旦错了,后面全错。 如果任务是探索性的,目标模糊、中间结果会影响后续方向,预先规划反而碍事。比如"帮我调研一下这个新领域的竞争格局",你根本不知道会查到什么,怎么提前列步骤?

所以 Plan-and-Execute 适合步骤可预测的任务:报表生成、多源数据汇总、固定流程的自动化。ReAct 适合不可预测的任务:需要根据中间结果不断调整方向的探索。

进阶的做法是给 P&E 加一个 Replanner(重规划器):执行过程中发现某一步跑不通,或者中间结果和计划假设不符,就停下来重新规划剩余步骤,而不是硬着头皮按原计划走。这样既保留了"先规划"的成本优势,又补上了"计划会错"的短板。很多号称 P&E 的生产系统,实际是"P&E + Replanner"的混合体。

一个可运行的 Planner + Executor 例子

import json
import re

from openai import OpenAI

client = OpenAI(base_url="...", api_key="...")  # 换成你的 API 地址

# 复用 ReAct 那节的工具注册表,P&E 的执行器照样靠它干活
ToolRegistry = {
    "get_weather": (
        "查询城市天气,参数 city:城市名",
        lambda city: f"{city}:多云,26℃,东风 3 级",
    ),
    "calc": (
        "计算数学表达式,参数 expr:如 (12+8)*3",
        lambda expr: str(eval(expr)),
    ),
}

def planner(task):
    prompt = f"""你是规划器。把任务拆成有序步骤,每步一行,不要执行任何工具。
任务:{task}
输出格式:
1. 步骤描述
2. 步骤描述
..."""
    resp = client.chat.completions.create(
        model="qwen-plus",
        messages=[{"role": "user", "content": prompt}],
    )
    return [s for s in resp.choices[0].message.content.split("\n") if s.strip()]

def call_tool(text):
    """解析模型输出里的 Action / Action Input,真正调用工具,返回观察结果。"""
    m = re.search(r"Action: (\w+)\nAction Input: (\{.*?\})", text, re.S)
    if not m:
        return f"无法解析工具调用,原始输出:{text}"
    name, args_raw = m.group(1), m.group(2)
    if name not in ToolRegistry:
        return f"未知工具 {name}"
    args = json.loads(args_raw)
    return ToolRegistry[name][1](**args)

def execute_one_step(step, i):
    """按计划执行第 i 步:让 LLM 决定调哪个工具、传什么参数,再真正调用。"""
    tool_desc = "\n".join(f"- {name}: {desc}" for name, (desc, _) in ToolRegistry.items())
    prompt = f"""你正按计划执行第 {i} 步。可用工具:
{tool_desc}

第 {i} 步任务:{step}

严格按以下格式输出,不要多余内容:
Thought: 你的推理
Action: 工具名
Action Input: {{"参数": "值"}}"""
    resp = client.chat.completions.create(
        model="qwen-plus",
        messages=[{"role": "user", "content": prompt}],
    )
    text = resp.choices[0].message.content
    observation = call_tool(text)
    print(f"第 {i} 步:{step}\n→ {observation}\n")
    return observation

def executor(plan_steps):
    results = []
    for i, step in enumerate(plan_steps, 1):
        results.append(execute_one_step(step, i))
    return results

plan = planner("统计本季度各区域销售额,和上季度对比,输出涨跌结论")
print("计划:", plan)
print("结果:", executor(plan))

ReWOO 和 LLMCompiler 是这条思路的进阶版:前者省 token,后者让没有依赖关系的步骤并行执行。企业项目里直接用它们的框架实现就行,原理都是"先规划再执行"。

选型决策树:三种模式怎么选

选型有个快速判别法,Oracle 的 Agent 集成文档里也聊到过类似思路,下面这张判别树则是我们在几个企业项目里反复验证后浓缩出来的:动手之前,你能列出要调的工具吗?

能列出来 → 任务可预测,用 Plan-and-Execute。列不出来,得先查一下才知道下一步 → 任务不可预测,用 ReAct。

拿我们做过的一个真实需求走一遍。客户要"每天自动生成销售日报":数据源固定(订单库、客户库)、步骤固定(汇总→对比→排版→发送),动手前就能把四步和要调的工具全列出来。这种活 ReAct 也能干,但每天在"下一步干啥"上重复推理纯属浪费,P&E 一次规划到位,还便宜。

另一个需求是"帮销售分析这个客户为什么流失":你得先查聊天记录,再看有没有投诉工单,还要比对历史订单,每一步都可能改变调查方向。这种就得 ReAct,走一步看一步。

完整的决策树长这样:

这个任务适合哪种 Agent 模式?
│
├─ 能提前列出完整步骤和要调的工具吗?
│   ├─ 能 → Plan-and-Execute(规划先行)
│   │        └─ 步骤间无依赖、想省时间 → LLMCompiler(并行执行)
│   │        └─ 想省 token、步骤多 → ReWOO(解耦推理与观察)
│   └─ 不能,得看中间结果才能定下一步 ↓
└─ 任务有明确终点吗(能判断"做完了")?
    ├─ 有 → ReAct(边想边做)
    └─ 没有,容易跑偏 → 混合模式:先规划框架 + 每步校验
         (Planner 出大纲,Executor 逐步执行,每步结果回填 Planner 调整)

实战里最常用的是混合模式:任务开头用一次规划定方向,执行过程中每一步仍走 ReAct 的"行动-观察"循环,发现计划行不通就重新规划。又省 token,又不至于一条道走到黑。

为什么 Agent 经常翻车:架构的锅,不是模型的锅

2025 年有一篇论文(Cemri et al., 2025,《Why Do Multi-Agent LLM Systems Fail?》)系统分析了多智能体系统的失败模式:5 个主流框架、150 多个任务,归纳出 14 种失败模式,分三类:任务规范与系统设计问题、智能体间协调问题、任务验证与终止问题。其中规范和设计类占比最高,接近四成;协调类次之,也接近四成;验证类约两成。

翻译成人话:大部分翻车不是模型蠢,是架构没设计好。 单 Agent 也一样,翻车原因可以归纳成四类。

先看一个具体的翻车现场,你就明白"架构的锅"是什么意思。我们的业务助手接了个"自动汇总三个部门周报"的任务,Agent 第一步拉取 A 部门数据时,接口恰好返回了空列表(那天数据还没同步完)。它没有识别出异常,把"空"当成"A 部门本周无产出"写进了汇总,第二步基于这个结论分析"A 部门业绩下滑原因",一本正经地分析了一整段。结果第二天数据同步完,结论全废。

每一步单独看都合理,错误就出在第一步的异常没有被识别和拦截。这就是典型的架构问题:缺了"观察结果合法性校验"这一环。

错误跨阶段累积

这是最阴险的一种。第一步的结果是错的,但看起来合理;第二步基于这个错结果继续算,错得越来越离谱;第三步已经把错的结果当成事实写进结论。

单看每一步都"合理",最后全盘皆错。而且越到后面越难发现,因为错误的源头被埋在中间步骤里了。

上下文坍缩与状态过期

模型的注意力是有限的,信息塞得越多,中间的越容易被忽略(业界叫 context rot)。循环跑到十几轮,早期关键信息可能已经被模型"忘"了,它开始自相矛盾。前几轮说"A 方案可行",后几轮又基于新信息说"A 方案不可行",浑然不觉自己改过口。

缓解办法不是无脑加大窗口。窗口越大,模型越容易抓不住重点。更实用的是控制每轮塞进去的内容:只传本轮需要的关键信息,中间结果存到结构化状态里,历史太长了就做摘要。别把对话历史当垃圾桶,什么都往里倒。

另一个常见问题:状态过期。 Agent 在第一步读到的数据,到第五步可能已经变了。如果代码不主动重新获取,Agent 会拿着旧数据做新决策。库存类、价格类、订单状态这类易变数据,每次用到都应该重新拉取,或者至少带上"数据获取时间"让模型知道新旧。

死循环与 token 烧穿

Agent 反复做同一件事,永远得不到"完成"的信号。常见场景:工具一直报错,Agent 一直重试;或者任务本身没有明确的完成标准,模型觉得"还能再优化一下"。

没有终止条件的 Agent,就是一个烧钱的永动机。我们自己就见过一个 demo,循环了 30 多轮才被手动掐掉,账单感人。

反模式:无脑 Agent 化

第 4 篇讲过场景选择四标准,这里再强调一遍:不是所有功能都该做成 Agent。

有些功能用规则、用 Prompt、甚至用普通代码就够,硬上 Agent 只会引入不确定性:输出不可预测、延迟变高、还要伺候它偶尔的抽风。判断标准还是那句:高频、数据现成、错误可容忍、不碰核心决策。不满足就别 Agent 化。

举个反例。有团队把"用户改密码"做成了 Agent 流程,让模型决定调哪个接口、要不要发验证码。结果模型偶尔会跳过某些校验步骤,或者多调一个无关接口。这种操作路径完全固定的功能,用代码写死流程比 Agent 可靠一百倍,成本还低一个数量级。

判断方法很朴素:这个流程,一个实习生看一遍文档能不能照着执行? 能,就别用 Agent。Agent 的价值在"需要判断"的地方,不在"需要执行"的地方。

给 Agent 上保险:工程兜底四件套

Agent 一定会犯错,所以工程上要有四道保险。

第一,最大步数限制。 这是最便宜也最有效的保险。循环加个计数器,到上限强制终止,宁可没做完,不能烧穿预算。上面的手写代码里 max_steps=5 就是干这个的。

第二,超时与重试策略。 单次工具调用设超时,超时就返回错误观察,让 Agent 换个思路;外部 API 失败时按指数退避重试,别把瞬时抖动当成永久失败。

第三,人工确认闸门。 写操作、发消息、扣款这类动作,执行前必须暂停等人工确认。第 4 篇的教训这里继续用:AI 出草稿,人拍板。权限校验必须在服务端做,Agent 的每步行动都要过权限检查,不能信它的"自觉"。

具体到实现:工具注册表里给每个工具标一个危险等级,比如"只读""写""对外发送"。写和对外发送的工具,调用前必须等人工确认信号,确认了才真正执行。这一步不能省,Agent 越自主,越需要这个闸门,不然它自主犯错的能力也同步放大。

第四,可观测性。 每一步的 Thought、Action、Observation 全部落日志。翻车不可怕,可怕的是翻车了不知道它当时在想什么。有了完整日志,bad case 才有得复盘,评估集才能持续补充(第 4 篇的回归套路在这里继续用)。

日志别只记"模型输出了什么",还要记"工具返回了什么""耗时多久""花了多少 token"。排查问题时,一份完整的轨迹日志能让你十分钟定位到是第几步出了问题,而不是对着最终结果猜。有条件的话,把每轮轨迹做成可视化的时间线,团队复盘效率会高很多。

几个高频疑问一次性回答

ReAct 和 Plan-and-Execute 到底有什么区别?

一句话:ReAct 走一步想一步,计划在执行中动态生成;P&E 先把计划定下来再执行。前者灵活,后者省 token 且可提前审查。任务能提前列出步骤就用 P&E,列不出来就用 ReAct。

Function Calling 和 Tool Use 是一回事吗?

是同一个东西的两个叫法。本质都是"模型根据工具描述输出结构化调用指令,代码去执行"。别被厂商的营销词绕晕。

Agent 的短期记忆和长期记忆分别存在哪里?

短期记忆在上下文窗口里,随对话历史流动;长期记忆在向量库里,靠检索取用。工作记忆(计划、中间结果)建议放显式状态对象,别全丢给上下文。

什么时候不应该用 Agent?

操作路径固定、不需要判断的功能,用代码写死流程。一个实习生看一遍文档能照着执行的活,就别上 Agent。

Agent 会死循环吗?

会,而且很常见。工具反复报错、任务没有明确完成标准,都可能导致死循环。所以最大步数限制是所有 Agent 的第一条保险。

总结

Agent 没那么玄。三个机制加一个循环:LLM 负责想,工具调用负责做,记忆负责记住,循环负责把三者串起来。

ReAct 是默认底座,适合不可预测的探索;Plan-and-Execute 先规划再执行,适合步骤固定的流程;实战里大多用混合模式。选型就记一句话:能提前列出工具用 P&E,列不出来用 ReAct。

翻车也不用慌。大部分翻车是架构问题,不是模型问题:错误累积、上下文坍缩、死循环、无脑 Agent 化。对应解法是步数限制、超时重试、人工确认、完整日志。

下一篇讲实战:数据分析 Agent 和业务自动化 Agent 的完整代码。你会看到工具调用怎么组织、多步任务怎么编排,以及——ChatBI 那套教训怎么避免在 Agent 场景里重演。

我们下篇见。


系列文章

  1. 《一套生产级 RAG 知识库:从 Demo 到生产架构的完整复盘》
  2. 《RAG 核心技术实战:文档解析、分块策略与检索 Pipeline》
  3. 《RAG检索优化实战:从67%到92%,我做了这4步》
  4. 《给传统 SaaS 增加 AI 能力:3个真实落地场景》
posted @ 2026-08-25 16:25  汪汪汪?  阅读(5)  评论(0)    收藏  举报