0%

Agent 几个问题思考

最近遇到了几个大模型模型算法应用的关键问题,作为记录。

Agent 设计范式

目前主流的 AI Agent(智能体)设计模式,通常不是单一的,而是基于一些核心思想和框架的组合。这些设计模式旨在赋予大语言模型自主思考、规划、行动和反思的能力,以完成更复杂的任务。

1. ReAct (Reasoning and Acting)

这是目前最流行、最基础也是最核心的一种 Agent 设计模式。它的核心思想是让大语言模型在一个“思考-行动-观察”的循环中持续工作,直到任务完成。

  • 思考(Thought):LLM 会根据当前任务和过往观察,产生一段内部思考,比如“我需要找到XX信息,我应该使用什么工具?”
  • 行动(Action):LLM 根据思考,生成一个调用外部工具的指令(即 Function Call)。
  • 观察(Observation):LLM 接收到外部工具返回的结果。

这个循环会反复进行,直到 LLM 判断任务已完成并生成最终回复。这种模式将”思考”过程显性化,使得模型的决策过程更加透明和可控。

2. Plan-and-Execute(规划与执行)

这种模式更侧重于对复杂任务的结构化分解。它将一个大任务分为两个阶段:

  • 规划阶段(Planning):LLM 首先会分析用户的请求,并生成一个详细的、分步骤的行动计划。这个计划是固定的,不会在执行过程中轻易改变。
  • 执行阶段(Execution):LLM 严格按照规划好的步骤,一步一步地调用工具和执行任务。

这种模式的优点是任务流程清晰、稳定,适合需要按部就班完成的复杂任务。但缺点是缺乏灵活性,如果计划中的某个步骤失败,Agent 可能无法自主调整。

3. Self-Correction(自我纠正/反思)

这种设计模式的核心是让 Agent 具备复盘和纠错的能力。它通常与其他模式结合使用,为 Agent 增加一个”反思”步骤。

  • 反思(Reflection):Agent 在完成一个任务或得到一个结果后,会重新评估这个结果是否正确或达到预期。
  • 纠正(Correction):如果评估结果不理想,Agent 会根据反思结果,修改其原始的思考路径或行动计划,然后再次尝试,直到达到满意的结果。

这种模式能显著提升 Agent 在复杂问题上的表现,因为它允许 Agent 从错误中学习,避免重复犯错。

这三种模式并不是相互独立的。一个强大的 Agent 通常会结合使用这些思想:例如,一个 Agent 可能先用 Plan-and-Execute 进行任务分解,然后在每个执行步骤中,使用 ReAct 循环来调用工具,并最终用 Self-Correction 机制来验证和修正结果。

大模型如何”用”工具?Agent、Function Call 与 MCP 的进化之路

在构建基于大语言模型(LLM)的应用时,一个核心挑战是让 LLM 不只停留在”聊天”,而是真正具备”行动”能力,比如联网搜索、调用 API 或执行代码。这就是 Agent 的核心思想:让 LLM 像一个智能体一样,能够根据用户的指令,自主决定是直接回答,还是调用外部工具来获取信息或完成任务。

1. Agent 的决策过程:LLM 如何知道何时调用工具?

Agent 的决策机制本质上是 Prompt Engineering 的一种高级应用。开发者会设计一个精巧的 Prompt,将可用的工具列表、它们的用途和描述一并告诉 LLM。

例如,当我们问一个 Agent:“今天北京的天气怎么样?”它的思考过程可能如下:

  1. 用户意图分析: 用户想知道北京的天气。
  2. 工具匹配: 我有一个可以查询天气的工具(get_weather(location))。
  3. 决策与执行: 我需要调用这个工具,并把“北京”作为参数。

这个思考过程并不神秘,而是通过精心设计的 Prompt 来引导 LLM 生成。LLM 会根据输入的指令和工具描述,在输出中”思考”并生成一个结构化的行动指令,然后由外部程序(Agent 框架)去实际执行。

2. Function Call (FC):将决策能力内置到模型中

Function Call (FC) 是对上述 Agent 决策机制的一种原生优化。它将“思考”和“生成调用指令”的能力直接通过模型训练内置进去。

FC 的核心是: 模型能够根据上下文,直接以预先定义好的 JSON 格式 生成对外部工具的调用,而不是像传统 Agent 那样需要外部框架去解析 LLM 生成的文本。

这是一种巨大的进步,因为它使得工具调用更加稳定、高效,并减少了外部解析的复杂性。

那么,为什么说 FC 存在“MxN”的问题?

这里有一个常见的误解:很多人以为每增加一个工具,就需要重新训练模型。这是不正确的。

FC 的”MxN”问题不在于模型本身,而在于 工具的描述格式。每个拥有 FC 能力的 LLM 平台(如 OpenAI, Google, Anthropic)都有自己独特的工具描述 Schema(函数签名)。一个搜索工具,为了能被不同的模型调用,开发者需要为它编写 M 份不同的描述文档。同样,一个 Agent 开发者如果想使用 N 个工具,并支持 M 个不同的 LLM,就需要处理 MxN 个兼容性问题。

简而言之,FC 解决了“让模型知道如何调用工具”的问题,但没有解决“工具描述格式不统一”的问题。

3. MCP:通过抽象层实现真正的解耦

Multi-tool Coordinator Protocol (MCP) 正是为了解决 FC 带来的兼容性与扩展性问题而诞生的。

MCP 的核心思想是:在模型和工具之间增加一个抽象的中间层。

这个中间层通常由一个 MCP Server 组成,其工作流程如下:

  1. 工具注册: 所有外部工具都按照一套统一的 MCP 协议 接入并注册到 MCP Server。
  2. Agent (LLM) 接入: 所有的 Agent 只需要学习并支持这套统一的 MCP 协议。它们不再需要知道每个工具的具体描述细节,只需向 MCP Server 发送一个统一的请求,来获取可用的工具列表或执行工具调用。

为什么说 MCP 实现了“M+N”?

  • M 个不同的模型(或 Agent)只需要对接 1 个统一的 MCP Server。
  • N 个不同的工具也只需要对接 1 个统一的 MCP Server。

通过这种方式,模型与工具之间不再是复杂的点对点连接,而是通过一个中心化的枢纽进行通信。这不仅解决了 FC 在不同平台间的兼容性问题,更是一种架构上的巨大优化,它让工具的管理、维护和扩展变得前所未有的简单。

总结来说:

  • Agent 是让 LLM 具备行动能力的 思想
  • Function Call 是将这种思想 内置到模型中 的一种能力。
  • MCP 是在此基础上,进一步将 模型与工具解耦 的一种 架构设计

当然,MCP 还需要在调用端封装。在典型的 MCP (Multi-tool Coordinator Protocol) 实现中,会区分 AI Host (AI 宿主)MCP Client (MCP 客户端) 这两个角色,它们通过一种清晰的协作模式来共同完成任务。

  1. AI Host (AI 宿主)

    • 角色: AI Host 是整个系统的核心,通常是运行大语言模型(LLM)或 Agent 框架的那部分。它负责接收用户的指令,并进行高级别的决策与推理。
    • 职责:
      • 接收用户输入。
      • 与 LLM 交互,进行意图分析。
      • 根据 LLM 的输出,决定是直接生成回复还是需要调用工具。
      • 注意: AI Host 不直接与具体的工具交互,它只知道 MCP 协议。
  2. MCP Client (MCP 客户端)

    • 角色: MCP Client 是一个独立的模块或库,作为 AI Host 与 MCP Server 之间的桥梁。它封装了所有与 MCP Server 通信的细节。
    • 职责:
      • 将来自 AI Host 的工具调用请求,按照 MCP 协议 进行格式化,并发送给 MCP Server。
      • 接收 MCP Server 返回的结果,并将其转换回 AI Host 可理解的格式。
      • 管理与 MCP Server 的连接和会话。
      • 注意: MCP Client 也不关心具体的工具是如何实现的,它只负责协议层面的通信。

整个 MCP 协作过程可以分解为以下几个步骤:

  1. 用户请求: 用户向 AI Host 发出指令,例如:“帮我查一下旧金山的天气。”
  2. AI Host 意图分析: AI Host 将用户指令发送给内置的 LLM。LLM 基于其 Function Call 或 ReAct 能力,判断出需要调用一个天气查询工具。它会生成一个结构化的调用请求,比如 {"tool_name": "weather_api", "parameters": {"city": "旧金山"}}
  3. AI Host 委托: AI Host 拿到 LLM 生成的调用请求后,并不会自己去执行,而是将其 委托MCP Client
  4. MCP Client 协议转换与发送: MCP Client 接收到这个请求,将其封装成符合 MCP 协议的格式(例如一个特定的 HTTP POST 请求或 gRPC 调用),然后发送给远端的 MCP Server
  5. MCP Server 工具协调与执行: MCP Server 接收到请求后,根据 tool_name 找到对应的工具,将 parameters 传递给该工具并执行。
  6. 结果返回: 工具执行完毕,结果返回给 MCP Server,MCP Server 再将结果通过 MCP 协议返回给 MCP Client。
  7. MCP Client 结果转换与回传: MCP Client 接收到 MCP Server 的响应,将其解析并转换为 AI Host 可理解的格式,然后返回给 AI Host。
  8. AI Host 回复生成: AI Host 拿到工具执行结果(例如:”旧金山今天多云,气温 15 摄氏度”),将其作为上下文的一部分再次输入给 LLM,最终由 LLM 生成完整的自然语言回复给用户。

通过这种方式,AI Host 始终保持”干净”,只关心高级别的推理和决策,而具体的工具调用和协议通信的复杂性则完全由 MCP Client 和 MCP Server 这层抽象来处理,实现了 AI 能力与工具生态的彻底解耦。

最后,通过一个图说明 FC 和 MCP 工作模式:

FC 和 MCP 工作模式

JSON 格式化输出

Function Call (FC) 模式下,要保证模型稳定输出 JSON 格式,主要依赖于 模型本身的训练和微调

如何保证模型稳定输出 JSON?

这并非单纯通过 Prompt Engineering 就能完美解决的问题。核心在于:

  1. 大规模训练: 在模型的预训练和指令微调阶段,会使用大量的包含 JSON 格式的结构化数据作为训练样本。这些样本告诉模型,当它接收到特定类型的指令(例如,要求它调用某个工具)时,应该输出一个遵循特定 JSON Schema 的结果。
  2. 特殊的解码策略: 一些模型在解码时会采用特殊的约束,比如 JSON Schema 约束解码。这意味着,模型在生成每一个 token 时,都会检查其是否符合预先定义的 JSON 格式规则。如果生成的 token 会导致 JSON 格式无效,模型会将其“回溯”并尝试生成另一个 token,直到生成完整且正确的 JSON。这种方法极大地提高了输出的稳定性和正确性。
  3. Prompt 工程辅助: 尽管核心能力来自模型本身,但好的 Prompt 仍然至关重要。例如,在 Prompt 中清晰地描述工具的函数签名,并明确要求模型“请以 JSON 格式输出调用结果”,可以进一步引导模型输出期望的格式。

比如这个 FC 输出的格式:

1
2
3
4
5
6
7
{
"name": "get_current_weather",
"arguments": {
"location": "旧金山",
"unit": "celsius"
}
}

其中的每个 key 和 value 都要非常精准的匹配到调用的工具才可以。

MCP 是否也要求模型输出固定格式?

是的,但要求的是更简单、更统一的格式。

MCP 的核心理念是 解耦。它将工具的复杂性和多样性从模型端剥离,因此模型不需要了解每个工具具体的 JSON Schema。模型唯一需要知道的,是与 MCP Client 交互的 统一协议

这个统一协议的格式通常非常简单,比如一个包含 tool_nameparameters 的 JSON 对象。模型需要做的,只是稳定输出这个简单的、所有工具都通用的 JSON 格式,然后由 MCP Client 去处理后续的协议转换和工具调用。

这正是 MCP 的优势所在:它降低了对模型的要求。模型不需要针对每一个新工具去学习其独特的调用格式,它只需要掌握一套通用的、简单的输出格式即可。这使得模型可以更专注于其核心的自然语言理解和意图识别,而将复杂的
工具协调任务交给 MCP ClientMCP Server 去完成。

下面是一个模型输出的 MCP 格式的调用:

1
2
3
4
5
6
7
{
"tool_name": "weather_api",
"parameters": {
"city": "旧金山",
"temp_unit": "celsius"
}
}

这个看起来比较类似,但实际上模型并不知道 weather_api 到底是什么,也不知道对于一个 city,应该传入的参数是什么(city?location?),对于温度单位,也类似。

FC (Function Call) 模式下,模型的难度体现在 “量” 上。模型需要记忆并理解每一个工具独特的 JSON Schema,而且要非常精确。如果你的系统有 100 个不同的工具,每个工具的参数都不一样,那模型就需要稳定地输出 100 种不同结构的 JSON。这就像让一个人记住 100 个完全不同的表格格式,并根据指令填写。

而 MCP (Multi-tool Coordinator Protocol) 模式下,模型的难度只体现在 “质” 上。它只需要学会一种 统一且简单的 JSON 格式,即 {“tool_name”: “…”, “parameters”: {…}}。无论有多少个工具,这个输出格式始终不变。这就像让一个人永远只填写一种固定格式的表格,然后把表格交给一个“总机”去处理后续的细节。

MCP Client 拿到的模型输出,也就是通用且简单的 JSON 格式(例如:{“tool_name”: “…”, “parameters”: {…}}),负责将其解析、封装、调用 Server、接收响应、解析响应,回传给 AI Host。