大语言模型 Agent 原理与工程实践

这两年,大模型从对话、内容生成和辅助编程,快速走向工具调用和多步骤任务执行。对程序员来说,一个直观感受是:刚弄清 Prompt,又遇到 RAG、Tool Calling、MCP、Skill、Memory 和 Agent;概念越来越多,彼此的边界却越来越容易混在一起。

这些名词并不是同一层能力的不同叫法:有的组织输入,有的补充知识,有的连接外部系统,还有的负责任务编排和状态管理。本文从一次 LLM 调用出发,把它们串联起来,说明各自解决什么问题、如何协作,以及 Prompt、Workflow 和 Agent 分别适合什么场景。

一、从一次模型调用到 Agent

1.1 LLM 的能力与边界

大语言模型的一次调用,可以抽象为:

output = LLM(context)

模型接收当前 Context,根据训练得到的参数计算 Token 概率分布并逐步生成输出。随着模型规模、训练数据和训练方法演进,模型在指令遵循、复杂推理和代码生成等任务上的表现持续提升,但一次调用的基本形态并没有改变。

这意味着模型天然存在几个边界:

今天常见的大模型应用能力,几乎都可以看作对这些边界的补充:

模型提供智能,但一次模型调用本身还不是一个完整的应用。

1.2 Tools 与 Loop:Agent 如何从“想”到“做”

Agent 不是一种更聪明的模型,而是围绕模型构建的执行系统。不同框架对 Agent 的定义并不完全一致,本文采用下面的工程抽象(参见 Anthropic:Building effective agents):

最小 Agent = LLM + Tools + Loop

工程化 Agent = 最小 Agent
             + Context / State / Memory
             + Guardrails

Evaluation 是独立的质量验证层,也可以作为反馈机制接入 Agent Loop。Guardrails 用于检查输入、输出和工具调用;在具体框架中,它属于可选的运行时能力(参见 OpenAI Agents SDK:Guardrails)。

1.2.1 Tool 是如何工作的

模型可以生成“读取文件”“查询数据库”这样的文字,却不会真的执行这些操作。Tool 为模型提供了与外部系统交互的入口。

应用会把工具名称、用途和输入 Schema 等能力描述随请求提供给模型,让模型知道“可以做什么”以及“应该怎样调用”。当模型决定使用工具时,它返回的是结构化调用意图,而不是工具执行结果。

模型生成 tool_call
  → Tool Runtime 校验工具名、参数和权限
  → Tool Runtime 执行真实操作
  → tool_result 写回消息队列
  → 模型根据新结果继续判断

Tool Calling 只负责生成调用请求,并不执行工具。真实操作由应用、SDK Tool Runtime 或模型服务商托管的工具环境执行,执行结果随后重新返回模型。文件读写、命令执行、网络请求和数据库访问都发生在模型之外(参见 OpenAI:Function callingAnthropic:Tool use)。

MCP 为 Prompts、Resources 和 Tools 提供标准化的发现与调用协议,减少不同 AI 应用重复集成的成本。但统一协议本身不会替代具体系统中的鉴权、用户授权、参数校验、危险操作防护和审计(参见 MCP 2025-06-18 版官方规范)。

模型负责提出操作意图,执行环境必须对真实操作负责。

1.2.2 一次完整的 Agent 交互

将模型调用和工具执行放在一起,一次完整的 Agent 交互会经历以下过程:

用户提出目标
  → Harness 组织 Prompt、历史消息、工具描述和当前状态
  → LLM 根据 Context 生成响应
  → 是否返回工具调用?
      → 是:生成结构化 tool_call
          → Tool Runtime 校验并执行工具
          → tool_result 写回消息队列
          → 再次调用 LLM
      → 否:返回最终结果,结束循环

模型始终只负责根据 Context 做出判断,并生成文本或结构化的工具调用意图。对于客户端工具,应用需要把工具结果写回消息队列;对于服务端工具,这一步可能由 SDK 或服务商自动完成。无论由谁编排,模型都必须在后续调用中获得工具结果,才能感知环境变化。

1.2.3 Agent Loop

把上述过程写成代码,一个最小 Agent Loop 可以表示为:

messages = [user_request]

for step in range(max_steps):
    response = llm(messages, tools)
    messages.append(response.message)

    if response.has_tool_calls():
        results = execute_tools(response.tool_calls)
        messages.extend(results)
        continue

    return response.text

raise MaxStepsExceeded()

每次 LLM 调用仍然相互独立。所谓“Agent 正在持续工作”,来自外部系统不断重复“模型决策—工具执行—结果反馈”,并将新的环境状态交给下一次模型调用。

观察状态 → 做出决策 → 执行动作 → 获得反馈 → 更新状态

如果没有最大步数、停止条件和结果验证,Loop 不会带来自治,只会带来重复操作和失控的资源消耗。

二、组成大模型应用的基础能力

2.1 Prompt:表达目标,而不是替代程序

Prompt 是开发者和用户向模型表达任务的方式。它不仅是聊天框中的一句话,也可能包含长期规则、任务背景、示例和输出约束。

一次模型请求中常见的指令与约束包括:

Structured Output 可以用于约束面向用户的响应,也可以配合 Function Calling 约束工具参数;两者用途不同(参见 OpenAI:Structured Outputs)。

好的 Prompt 能提高模型理解目标的概率,却不能把概率系统变成确定性程序。把“必须鉴权”“金额不能为负数”这类规则写入 Prompt,并不等于系统已经实现了鉴权和参数校验。

真正影响安全与正确性的规则,仍然需要由代码、权限系统、Schema 校验和测试兜底。

Prompt 用来引导模型,程序用来守住边界。

2.2 Context:模型这一轮真正看到的内容

Prompt 和 Context 经常被混为一谈。Prompt 是我们主动表达的指令,而 Context 是一次请求中模型能够看到的全部信息。

Context 可能包括:

很多看起来像“模型拥有的新能力”,本质上是应用在调用模型之前,把更合适的信息组织进了 Context。模型不知道本地仓库的内容,但应用可以先读取文件,再把内容交给模型;模型不会永久记住用户偏好,但应用可以在下一次请求前重新检索并注入这些偏好。

要进一步理解 Agent 的连续性,还需要区分四种数据:

概念回答的问题
Context模型这一轮能看到什么
State任务实际上进行到哪里
Memory哪些信息值得未来任务复用
Transcript过去发生过什么

Context Window 是有限资源。对话、工具结果和文件内容持续增长后,会带来成本上升、注意力分散,最终还可能超过模型能够处理的范围。

大模型应用设计的核心之一,是决定什么信息应该在什么时候进入 Context。

2.3 RAG 与 Memory:补充知识和历史信息

当模型参数中的知识不足,或任务需要使用历史信息时,可以通过 RAG 和 Memory 向当前 Context 补充内容。两者解决的问题并不相同。

能力主要解决的问题典型内容
RAG当前问题需要哪些外部知识文档、代码、数据库记录、动态资料
Memory过去哪些信息值得在未来继续使用用户偏好、项目约束、历史决策

RAG 的关键不是“拥有知识库”,而是根据当前问题找到合适内容,并把它放回 Context。Memory 的关键也不是永久保存所有对话,而是提取值得复用的信息,在后续任务中按需检索。

RAG 的原始定义结合参数化生成模型与可检索的非参数知识源(参见 Lewis 等:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks)。

历史交互
  → 提取稳定信息
  → 分类和持久化
  → 根据新任务检索
  → 重新注入 Context

Memory 并没有让模型获得人类意义上的永久记忆。真正持久化的是外部存储,模型仍然只能看到本轮被重新注入的内容。

随着 Memory 增长,系统还需要处理重复、冲突、过期和检索噪声。记住得越多不一定越好,能否在正确时机找到正确信息才是关键。

RAG 和 Memory 都是在模型参数之外补充信息。如果仅靠 Prompt、RAG 和应用编排仍无法稳定达到目标行为,可以进一步评估 Fine-tuning;它属于模型适配层,本文不展开。

2.4 Skill:把经验封装成可复用能力

有了 Tool,模型知道自己“能做什么”;但面对一类复杂任务,它仍然需要知道“应该怎样做”。Skill 解决的是方法复用问题。

一个 Skill 通常可以包含:

例如,“运行测试”是一个 Tool;“发现构建失败后,读取日志、按文件归类错误、逐步修复并重新验证”则更接近一个 Skill。

Skill 并不是一种新的模型能力,也不是所有平台都遵循的统一标准。它更像一份可以被 Agent 按需加载的操作手册:把团队经验从临时 Prompt 中抽离出来,形成可维护、可复用、可演进的能力包。

为了节省 Context,Skill 通常适合渐进式加载:启动时只提供名称和简短描述,确定与当前任务相关后,再读取完整说明。

这种由元数据、指令以及可选脚本和资源组成,并按需逐步加载的组织方式,可参考 Anthropic:Agent Skills

Tool 告诉模型“能做什么”,Skill 告诉模型“这类任务应该怎样做”。

2.5 Workflow 与 Agent:谁来决定下一步

当任务不止一个步骤时,可以选择 Workflow,也可以构建 Agent。两者最核心的区别,是下一步由程序预先确定,还是由模型根据当前状态动态决定。Anthropic 将 Workflow 定义为由预设代码路径编排 LLM 与工具,而 Agent 由模型动态决定过程和工具使用(参见 Anthropic:Building effective agents)。

方式控制方式适合场景
单次调用应用发起一次请求总结、分类、内容生成
Workflow程序预先定义步骤和分支流程稳定、结果需要可预测
Agent模型根据执行结果决定下一步路径不确定、需要动态探索

例如,一份代码提交必须依次执行格式检查、单元测试和构建,这更适合 Workflow。排查一个未知线上问题时,需要根据日志决定读取哪些文件、运行什么命令,则更适合 Agent。

Agent 并不天然优于 Workflow。它用灵活性换取了更高的不确定性、成本和治理难度。能够由固定流程可靠解决的问题,没有必要为了“智能化”强行改造成 Agent。

三、让 Agent 完成长任务

3.1 Plan、State 与后台任务

短任务可以主要依靠 Context。对于长任务,目标、进度和中间产物更适合外置;Plan 不宜只保留为模型生成的一段文字,而可以成为模型和运行时共同维护的任务状态。

一个任务可以保存:

id
subject / description
status
owner
blockedBy
artifacts

模型负责拆分任务、判断进度和提出更新,运行时负责持久化状态、检查依赖并调度执行。

典型状态可以表示为:

pending → in_progress → completed / failed

复杂任务还可以形成依赖图。只有前置任务完成后,后续任务才能开始。安装依赖、编译和测试等耗时操作则可以转为后台执行,完成后再把事件反馈给 Agent Loop。

状态持久化的价值在于:即使发生上下文压缩、模型切换或会话恢复,系统仍然可以从真实进度继续工作,而不是要求模型从历史消息中猜测。

如果一条信息会影响任务正确性,它就不应该只存在于消息历史中。

3.2 上下文压缩:按可恢复性管理信息

随着 Agent 不断读取文件和执行工具,Context 会持续膨胀。上下文压缩不应简单理解为“把旧消息总结一下”,而应该先判断信息能否恢复:

可以重新获取       → 保存引用,需要时重新读取
可以结构化表达     → 外置为任务状态
未来任务需要复用   → 写入 Memory
只能从对话中理解   → 最后再进行有损摘要

可以采用逐层处理的策略:

  1. 裁剪重复、低价值的历史内容;
  2. 将大段工具结果落盘,只保留预览和引用;
  3. 用结构化状态替代散落在对话中的进度描述;
  4. 保存完整 Transcript,再对较早历史生成摘要;
  5. 只有在接近或触及上下文限制时,才使用高损失的紧急压缩。

压缩的首要原则不是“尽量短”,而是“尽量可恢复”。目标、约束、关键证据和下一步计划一旦丢失,Agent 即使继续运行,也可能已经偏离原任务。

3.3 错误恢复与停止条件

真实系统需要面对模型输出截断、上下文超限、限流、服务过载和工具失败。不同错误的恢复方式不同,但都应该回到同一套主循环,避免产生难以追踪的旁路状态。

失败类型常见处理方式
输出被截断提高输出预算或续写,并限制重试次数
上下文超限压缩历史、外置大结果、保留关键状态后重试
限流或过载指数退避、随机抖动、模型降级或切换
工具失败校验错误类型,决定重试、换参数或停止
重复调用检测相同动作,达到阈值后熔断

所有重试都应该有上限,所有 Loop 都应该有停止条件。无法恢复时明确失败,比在错误状态下继续消耗资源更可靠。

Agent 的可靠性并不来自“从不失败”,而来自失败能够被识别、恢复,并且不会无限循环。

四、从单 Agent 到复杂系统

4.1 Multi-Agent:多开模型不等于协作

当任务规模继续扩大,可以把工作分配给多个 Agent。但多 Agent 首先增加的是协调成本,其次才是并行收益。

为便于讨论,本文按协作范围将多 Agent 系统分为以下三类。这是一种工程分类,不是行业统一标准。

模式适用场景关键机制
SubAgent一次性探索、独立复核通常使用独立或隔离的 Context,只把精炼结果返回主 Agent
Task Team有依赖的多步交付共享任务图,通过领取、完成和依赖关系协调
Agent Team跨角色、长周期协作消息协议、独立生命周期和隔离工作区

多 Agent 要有效,需要满足几个前提:

一种常见实现是协调者—工作者模式。以 Anthropic Managed Agents 为例,协调者负责任务委派,各 Agent 使用隔离的上下文线程,同时共享 Sandbox 和文件系统;其他平台的隔离边界可能不同(参见 Anthropic:Multiagent orchestration)。

自然语言中的“我正在处理”不能代替任务所有权,“我已经完成”也不能代替验收状态。在需要可靠编排时,关机、审批等关键动作可以采用带请求标识的请求—响应协议,而不是只依赖口头约定。

并行不等于协作,共享 Context 也不等于共享 State。

4.2 Evaluation:判断任务是否真的完成

模型可以生成合理的解释,也可以声称已经完成任务,但声明本身不是证据。相比追问模型“为什么这么做”,更可靠的方式是检查系统能够提供的可观察事实:

生产系统通常需要保留模型生成、工具调用、Guardrails 和 Handoff 等完整 Trace,作为调试和评估依据(参见 OpenAI Agents SDK:Tracing)。

多轮 Review、独立评估器和多 Agent 对抗能够提高质量,也会增加 Token、时间和通信成本。只有当结果可以被稳定、重复地评价时,持续 Loop 才有可能形成真正的自动改进。

评估 Agent 时,不能只关注最终答案,还需要同时考虑:

没有客观评估,Loop 只是重复;没有稳定反馈,自我改进也可能只是自我强化。

4.3 持续沉淀:从会话中提取 Memory 与 Skill

Agent 在日常任务中会产生大量交互记录、工具结果和中间决策。将这些内容转化为可复用能力,可以形成一个持续沉淀过程:

记录任务过程
  → 提取稳定知识、用户偏好和操作方法
  → 分别写入知识库、Memory 或 Skill
  → 去重、合并冲突并清理过期内容
  → 在后续任务中按需检索和加载

这个过程可以理解为 Agent 的经验沉淀:它不改变模型参数,而是持续改进模型之外的知识、记忆和操作规范。

真正需要警惕的是错误经验被反复固化。只有经过验证、稳定且可判定的方法,才适合沉淀为 Skill;容易变化的事实,则更适合保存在可检索的数据源中。

五、回到工程决策

5.1 如何选择这些能力

面对一个具体需求,可以使用下面的判断路径:

只需要理解或生成内容
→ Prompt

需要私有知识或动态资料
→ RAG

需要操作文件、代码或外部系统
→ Tools

同类任务存在稳定、可复用的方法
→ Skill

步骤固定,可以提前编排
→ Workflow

下一步必须根据执行结果动态决定
→ Agent

任务可以独立拆分并独立验收
→ 考虑 Multi-Agent

需要跨任务保留稳定信息
→ Memory

这些能力不是互斥选项。一个完整 Agent 可以同时使用 Prompt、RAG、Memory、Tool 和 Skill,内部也可能包含确定性的 Workflow。

真正重要的不是使用了多少新概念,而是每一层是否解决了真实问题:

结语

一次 LLM 调用只负责基于 Context 生成结果。Prompt 表达目标,RAG 和 Memory 补充信息,Tool 连接外部操作,Skill 复用方法,Workflow 固化流程,Agent 根据反馈动态推进任务,Evaluation 验证结果。

这些概念最终落在五个工程问题上:模型看到什么、外部能力如何执行、状态保存在哪里、下一步由程序还是模型决定,以及结果如何验证。

参考资料