Agent开发 1.1 - 从 Chatbot 到 Agent:Agent 解决真实业务的核心机制

2026-10-19 | 40分钟 | yrobot | Agent开发, 大语言模型, 闭环系统, 智能体, 控制流

在刚接触大语言模型开发时,面对一个稍微复杂的业务需求(比如做一个“智能留学选校助手”),最容易产生的直觉往往是:写一段很长、很详细的系统提示词(System Prompt),把所有规则、约束和示范样本都放进去,然后调一次 GPT-4,希望它直接输出最终的规划方案。

但只要一碰真实业务,这种做法就会迅速崩溃。

这不是提示词写得不够好,也不是模型参数不够大,而是单次生成的物理机制决定了它无法胜任复杂业务。要理解 Agent 到底是什么,必须先看清楚 Chatbot 这种“单次开环生成”的物理极限。

为什么“超级 Prompt + 单次生成”必然崩溃?

如果让大模型一次性处理一个多约束任务(例如:“双非 GPA 3.3,软件工程,想申海外 CS 硕士,要求免 GRE、有全奖机会,导师方向偏具身智能”),单次调用会遭遇三个不可逾越的物理限制:

1. 自回归采样的误差累积(Error Compounding)

大模型的生成机制是自回归的(Next Token Prediction),即根据前序文本预测下一个词的概率分布。这种机制没有“回溯”能力。 在生成长文本时,一旦模型在中间某一步推导出了偏差(例如把某所学校记成了免 GRE),它在后续生成中无法推翻自己刚刚输出的文字,反而会把这个错误作为既定事实继续往后编造,导致后续方案全线偏航。

2. 注意力稀释与 Lost in the Middle

当我们在 Prompt 里塞入大量背景信息、规章制度或长篇参考资料时,自注意力机制在长上下文的中间区域会出现明显的权重衰减。模型天然更容易关注最前面和最后面的信息,放在中间的强约束(比如“必须有全奖”)极易被物理性忽略。

3. 参数化记忆的静态失效与谄媚性伪造

模型的知识全在训练截断前的静态权重里,它无法感知今年的最新招生政策变动。更严重的是,受强化学习对齐(RLHF)的影响,模型存在本能的“讨好倾向”:面对不确定的事实,它往往倾向于编造看似合理的假数据(如假死线、假申请条件),而不是明确说明缺少数据。

即便模型拥有几百万 Token 的上下文窗口,把所有招生简章全量塞进去,不仅调用成本极高、速度极慢,动态更新的现实世界(如导师跳槽、名额变动)也根本不可能提前全量静态收集完毕。

软件架构的演进:自主权不断让渡

传统软件 到 Agent,并不是非黑即白的二极管,而是控制流自主权不断让渡:

完全由代码写死 ---------------------- 局部交警分流 ---------------------- 完全由模型决定下一步
[传统确定性代码]                 [路由工作流 Router / Chain]                 [自主推演循环 ReAct Agent]
  流程 100% 穷举                   整体拓扑固定,LLM 选分支                     运行时动态探索工具与路径
  1. 传统确定性代码(零让渡):控制流完全由代码硬编码,所有的分支走向(if/else)都必须在编写代码时穷举。确定性最高,但无法理解模糊的人类自然语言。
  2. 路由与固定工作流(局部让渡,如 LangChain Router / Workflow):整体业务拓扑是代码写死的(比如定义好了 3 条处理分支),但具体走哪一条分支,交给大模型根据语义做判断。这种形态在很多宣传中也被称为“Router Agent”。它在工程上非常实用,因为既利用了模型的语义理解能力,又把执行边界牢牢锁死在几个预定路径内,成本低且确定性强。
  3. 自主推演智能体(高程度让渡,如 ReAct 微内核):开发者不再提前写死“必须走哪几步”,而是给模型提供一个开放的工具箱(搜索、计算、数据库)。模型根据每次执行后的实际反馈(Observation),自主决定下一步是继续查、换个词搜,还是就此终止。

很多团队之所以在选型时感到困惑,把“路由工作流”和“自主循环智能体”统统混称为 Agent。Anthropic 在其官方指南《Building effective agents》中也专门呼吁进行这种区分:很多时候,基于固定流程和模型路由的工作流(Workflows),比完全自由放任的自主智能体(Agents)更加可控、可预测且成本更低。

只要引入了工具与环境反馈,系统的核心逻辑就从“单向开环输出”转变成了“基于环境观察的闭环系统”。

扒开神秘外衣:Agent 到底是怎么跑起来的?

很多讨论把 Agent 描述得像是具备自主意识的数字生命,其实在底层物理实现上,Agent 极其朴素:它就是一段跑在本地或服务器上的普通程序,在一个 while 循环里反复向大模型发请求。

大模型本身不能联网、不能操纵系统、不知道当下时间。它们的分工就像“盲人指挥官”与“侦察兵”:

  • 大模型(指挥官):负责分析逻辑并下达指令,但没有手脚。
  • 本地程序(侦察兵):拥有网络请求、数据库读写、文件操作能力,负责替模型跑腿。

运行全流程拆解

为降低认知负担,整个运行微内核可以用以下状态反馈回路直观呈现:

flowchart TD
    Start["用户提交复杂需求"] --> Init["本地程序初始化消息历史 (User Prompt + Tools Schema)"]
    Init --> LoopStart["进入 while 事件循环"]
    LoopStart --> CallLLM["向大模型发起 API 请求"]
    CallLLM --> CheckResponse{"大模型返回类型判断"}
    
    CheckResponse -- "包含 tool_calls 指令 (信息未完备)" --> Intercept["本地程序拦截指令,替模型执行真实工具 (抓网页/查库)"]
    Intercept --> Observe["获得客观事实 (Observation)"]
    Observe --> FeedBack["将真实事实追加至消息历史 (role: tool)"]
    FeedBack --> CheckLimit{"检查是否超过最大安全步数"}
    CheckLimit -- "未超限" --> LoopStart
    CheckLimit -- "超限" --> SafetyError["触发安全熔断 (Fail-Fast)"]
    
    CheckResponse -- "无 tool_calls,返回最终文本" --> ExitLoop["退出 while 循环"]
    ExitLoop --> Finish["向用户交付最终严谨答复"]

具体执行分为以下 5 个确定性步骤:

  1. 本地程序提供工具说明书:在发起 API 请求时,本地程序附带一组工具定义(例如搜索函数 searchWeb(keyword))。
  2. 大模型输出调用意图:大模型发现自己内部知识不足以回答时,不会输出普通文本,而是输出一段结构化的工具调用指令(如 {"name": "searchWeb", "args": {"keyword": "MIT CS 2026 GRE"}})。本次大模型请求随即结束。
  3. 本地程序实际执行操作:本地程序拦截到指令,在真实网络环境中发起请求,抓取官网文本。
  4. 环境反馈回灌:本地程序把真实获取到的客观事实存入消息列表,再次发送给大模型。
  5. 判断任务结束:
    • 如果大模型认为信息依然不完整,它会继续输出下一个工具调用指令,本地程序继续执行。
    • 一旦大模型认为证据链完整,它将不再返回工具调用,而是直接返回最终答复。
    • 本地程序检测到没有新的工具调用指令(或触发显式的完成标记),立即退出 while 循环,将结果交还给用户。

代码结构直观对比

模式 A:静态管道调用(Workflow / Chatbot)

控制流由代码固定编排,中间发生偏差无法自动纠正:

async function runTraditionalWorkflow(profile: StudentProfile) {
  // 控制流写死:第一步提取结构化字段
  const parsed = await llm.generate(`提取字段: ${JSON.stringify(profile)}`);

  // 控制流写死:第二步查本地库
  const schools = await db.querySchools({ gpa: parsed.gpa });

  // 控制流写死:第三步直接生成报告
  // 如果数据库信息陈旧或没有对应数据,模型只能在这里开始开环编造
  const report = await llm.generate(`基于信息生成规划: ${JSON.stringify(schools)}`);

  return report; // 单向流动结束,没有任何真实纠偏机制
}

模式 B:状态机闭环推演(Agent 核心微内核骨架)

控制流由大模型与环境真实反馈共同驱动:

interface AgentState {
  history: Array<{ role: string; content: string }>;
  isFinished: boolean;
  stepCount: number;
}

async function runAgentLoop(userGoal: string, tools: ToolRegistry) {
  const state: AgentState = {
    history: [{ role: "user", content: userGoal }],
    isFinished: false,
    stepCount: 0,
  };

  // 代码充当安全缰绳:步数超限熔断,防止死循环
  while (!state.isFinished && state.stepCount < MAX_STEPS) {
    state.stepCount++;

    // 1. 模型根据历史事实推演下一步动作
    const decision = await llm.decideNextStep(state.history, tools.getDefinitions());

    // 2. 终止判定:模型认为已有充分事实作答,无需再调用工具
    if (decision.type === "finish") {
      state.isFinished = true;
      return decision.finalText;
    }

    // 3. 本地程序作为沙箱替模型执行真实动作(抓取、查库等)
    const observation = await tools.execute(decision.toolName, decision.toolArgs);

    // 4. 环境反馈回灌:真实世界的结果成为消除幻觉的客观依据
    state.history.push({
      role: "assistant",
      content: `调用工具: ${decision.toolName}(${JSON.stringify(decision.toolArgs)})`,
    });
    state.history.push({
      role: "tool",
      content: `环境返回真实数据: ${observation.text}`,
    });
  }

  throw new Error("推演未收敛,触发步数熔断");
}

核心机制的本质

Agent 的核心不是提示词工程,而是运行时架构(Runtime Architecture)。

在复杂业务中,消除大模型幻觉的唯一物理保证,不是换用参数量更大的模型,也不是把提示词写得天花乱坠,而是 Observation 回路:让真实环境返回的客观数据(不论是 404 报错、最新的政策变更,还是空查询结果)打断模型的自由发挥,强行覆盖掉它内部的统计学偏置。