常见协议
一次 Agent 任务的运行离不开对 LLM 等多个环节的 API交互,由此产生了非常多的 Agent 相关的协议,它们沿着 Agent 能力扩张逐步形成。
模型最初只接收一段文本,随后开始理解多轮消息和工具调用;工具越来越多后,需要统一的能力接入协议;任务变长、参与者增多后,又出现状态化模型接口、Agent 间协议和客户端协议。
1. 协议演进时间线
1.1 从文本生成到 Agent 系统
| 阶段 | 代表协议 | 主要变化 | 通信双方 |
|---|---|---|---|
| 早期文本生成 | Completions API | 输入 prompt,返回续写文本 | 应用与 LLM |
| 2023 年起 | OpenAI Chat Completions | 用角色消息表达对话,逐步加入 Function Calling | Agent 框架与 LLM |
| 2023—2024 年 | Anthropic Messages | 用 Messages 和 Content Blocks 表达文本、图片与工具调用 | Agent 框架与 LLM |
| 2024 年末 | MCP(Model Context Protocol) | 统一工具、资源和提示的发现与调用 | Agent Host 与能力服务 |
| 2025 年 | OpenAI Responses | 用类型化 Items 统一消息、推理、工具和多轮状态 | Agent 框架与 OpenAI 平台 |
| 2025 年 | A2A(Agent2Agent Protocol) | 用 Agent Card、Task 和 Artifact 支持跨 Agent 协作 | Agent 与 Agent |
| 2025 年后 | Agent Client Protocol 等 | 将 Agent 任务、事件和权限交互接入 IDE 与客户端 | 客户端与 Agent 框架 |
这条时间线包含三种不同层次:
- LLM 请求与响应协议:Chat Completions、Responses、Anthropic Messages,决定 Context 如何送入模型以及模型动作如何返回。
- 能力接入协议:MCP,决定 Host 如何发现并调用外部工具、资源和提示。
- Agent 通信协议:A2A、Agent Client Protocol 等,决定任务如何跨 Agent 或客户端流转。
同一项任务可以使用多种协议。协议名称相似时,先判断通信双方,再判断传递的是消息、工具调用还是任务。
2. OpenAI Chat Completions:以消息为中心
2.1 从 prompt 到 messages 消息
早期 Completions API 的核心输入是一段 prompt。应用要把系统规则、用户问题和历史对话拼成字符串,模型无法从协议结构中准确区分这些内容的来源。
Chat Completions 将输入改为 messages 数组。每条消息带有角色,这使得 Agent 框架可以分别表达系统规则、用户输入、模型历史和工具结果。因此,这种结构很快就成为了兼容 OpenAI 接口的模型服务所采用的基础形态。
该协议中常见角色包括:
| 角色 | 内容来源 | 作用 |
|---|---|---|
developer / system | 应用开发者 | 定义行为、约束、任务规则和输出要求 |
user | 用户 | 提交目标、问题和补充信息 |
assistant | 模型 | 保存历史回答或工具调用请求 |
tool | Agent 框架执行工具后产生 | 把真实观察结果回填给模型 |
模型 API 不会自动知道本地文件、工具执行结果或未提交的历史。Agent 框架必须在请求中提供当前决策需要的 Context。
2.2 请求与响应结构
Chat Completions 使用 POST /v1/chat/completions,通过 Bearer API Key 认证。一个最小请求由模型和消息列表组成:
{
"model": "model-id",
"messages": [
{
"role": "developer",
"content": "你是产品研究助手,结论必须注明依据。"
},
{
"role": "user",
"content": "整理三款同类产品的核心差异。"
}
]
}响应以 choices 表示候选结果,每个 choice 包含模型消息和结束原因:
{
"id": "chatcmpl_123",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "我需要先获取三款产品的最新资料。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 128,
"completion_tokens": 24,
"total_tokens": 152
}
}其中,Agent 框架主要关注 choices[0].message、finish_reason 和 usage 这些字段,用于核心流程的设计。finish_reason 可以表示自然结束、长度限制、工具调用或内容策略等情况,具体枚举取决于模型和接口版本。
2.3 Function Calling 的完整闭环
工具定义位于请求顶层 tools,它不属于 messages。每个函数包含名称、说明和 JSON Schema 参数:
{
"model": "model-id",
"messages": [
{"role": "user", "content": "搜索产品 A 的定价方案。"}
],
"tools": [
{
"type": "function",
"function": {
"name": "search_web",
"description": "搜索公开网页并返回标题、URL 和摘要。",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"],
"additionalProperties": false
},
"strict": true
}
}
]
}当模型需要工具时,会在 assistant 消息中返回 tool_calls 来发起工具调用。其中 arguments 通常是 JSON 字符串,Agent 框架需要解析和校验:
{
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_search_01",
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"产品 A 官方定价\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}模型只提出候选动作。Agent 框架校验权限与参数、执行工具后,使用 role: tool 和 tool_call_id 回填结果:
{
"model": "model-id",
"messages": [
{"role": "user", "content": "搜索产品 A 的定价方案。"},
{
"role": "assistant",
"tool_calls": [
{
"id": "call_search_01",
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\":\"产品 A 官方定价\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_search_01",
"content": "{\"title\":\"Pricing\",\"url\":\"https://example.com/pricing\"}"
}
]
}第二次模型调用才能基于工具结果形成回答。若模型仍可继续调用工具,请求还要携带与上一轮一致的 tools 定义。并行工具调用会产生多个 call ID,每个结果都要与原调用准确关联。
这里要区分“模型提出动作”和“工具真正执行”两个环节。自定义函数工具通常由 Agent 框架接住并分发:
例如,模型返回 read_file(path="docs/plan.md") 时,模型本身没有读取用户磁盘;Agent 框架会在允许的工作区内调用本地函数,再把文件内容作为 tool 消息回传。query_order(order_id="A-1024") 则可能由框架调用企业订单 HTTP API;search_notes(keyword="向量数据库") 可以继续转发给 MCP Client,由 notes MCP Server 执行。
平台托管工具的路径不同。以 OpenAI Responses 的 web_search 为例,Agent 框架只需在请求中声明工具,搜索、网页抓取和部分工具循环由远端模型平台完成,客户端收到的是 web_search_call、引用及最终文本,应用无需实现一个本地 search_web()。
2.4 多轮状态与流式响应
Chat Completions 的多轮状态通常由 Agent 应用自身维护。Agent 框架保存历史消息,并在下一轮请求中重放仍然需要的部分。历史过长时可以做摘要、裁剪或检索,但工具调用消息与对应结果必须成对保留,否则模型会看到不完整的动作轨迹。
启用 stream: true 后,接口通过 SSE 返回增量 chunk。文本通常位于 choices[].delta.content,工具参数也可能分片到达。客户端需要累计 delta,直到接收到结束信号,再解析完整参数或提交最终文本。
这种协议适合已有消息式架构、兼容接口和简单生成场景。复杂 Agent 仍然需要应用自己维护工具循环、历史状态与流事件类型。
3. Anthropic Messages:以 Content Blocks 表达内容
3.1 顶层结构
Anthropic Messages API 同样使用多轮消息,但系统指令、消息内容和工具事件的组织方式不同:
system位于请求顶层,不作为messages中的system角色。messages主要使用user和assistant角色。content可以是字符串,也可以是由文本、图片、工具调用和工具结果组成的 Content Blocks。max_tokens是请求中的显式输出上限。- 工具参数 schema 使用
input_schema。
Messages API 使用 POST /v1/messages。请求通常携带 x-api-key、anthropic-version 和 content-type,其中版本请求头决定采用的协议版本。
{
"model": "model-id",
"max_tokens": 1024,
"system": "你是产品研究助手,结论必须注明依据。",
"messages": [
{
"role": "user",
"content": "搜索产品 A 的定价方案。"
}
],
"tools": [
{
"name": "search_web",
"description": "搜索公开网页并返回标题、URL 和摘要。",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
]
}3.2 tool_use 与 tool_result
模型调用工具时,响应的 content 中出现 tool_use block:
{
"id": "msg_123",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "我先查询官方定价页面。"
},
{
"type": "tool_use",
"id": "toolu_search_01",
"name": "search_web",
"input": {
"query": "产品 A 官方定价"
}
}
],
"stop_reason": "tool_use",
"usage": {
"input_tokens": 180,
"output_tokens": 48
}
}Agent 框架执行后,把 tool_result block 放在下一条 user 消息中,并通过 tool_use_id 关联原调用:
{
"model": "model-id",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "搜索产品 A 的定价方案。"},
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_search_01",
"name": "search_web",
"input": {"query": "产品 A 官方定价"}
}
]
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_search_01",
"content": "{\"title\":\"Pricing\",\"url\":\"https://example.com/pricing\"}"
}
]
}
]
}Content Blocks 让一条消息可以同时携带解释文本和工具动作。Agent 框架处理响应时应遍历所有 blocks,不能假设 content 只有一段文本。
3.3 状态、停止原因与流式事件
Messages API 的对话历史由调用方提供。Agent 框架需要保存 user/assistant 轮次、tool_use 与 tool_result,再构造下一次请求。
stop_reason 表示本轮停止原因,例如自然结束、达到 token 上限、需要工具或遇到停止序列。流式模式使用类型化 SSE 事件,包括消息开始、内容块开始、内容增量、内容块结束和消息结束。客户端应按照事件类型组装文本、工具输入或其他 block。
3.4 Chat Completions 与 Anthropic Messages
| 语义 | OpenAI Chat Completions | Anthropic Messages |
|---|---|---|
| 系统规则 | developer / system 消息 | 顶层 system |
| 历史消息 | messages | messages |
| 主要角色 | developer/system、user、assistant、tool | user、assistant |
| 内容结构 | message content 与 tool_calls | content 中的类型化 blocks |
| 工具 schema | tools[].function.parameters | tools[].input_schema |
| 工具调用 | assistant.tool_calls[] | tool_use block |
| 工具结果 | role: tool + tool_call_id | user 消息中的 tool_result + tool_use_id |
| 结束原因 | finish_reason | stop_reason |
| 流式处理 | choices[].delta | 类型化 message/content block 事件 |
两种协议表达的核心语义接近:规则、历史、工具定义、模型动作、工具观察和结束状态。适配层可以把它们转换成 Agent 框架内部统一的 message、tool_call、tool_result 和 usage 事件。
4. MCP:工具生态开始标准化
4.1 MCP 标准化
Function Calling 规定模型如何表达工具调用,却没有规定工具服务如何安装、连接、发现能力和传输结果。每个 Agent 框架仍需为文件系统、数据库和业务平台编写专用适配器。
2024 年末出现的 Model Context Protocol(MCP) 将 Agent Host 与外部能力服务之间的通信标准化。一个 MCP Server 可以被多个兼容 Host 复用,工具提供方无需分别适配每种模型协议。
4.2 Host、Client 与 Server
| 角色 | 所处位置 | 职责 |
|---|---|---|
| Host | IDE、桌面助手或 Agent 应用 | 管理模型、用户会话、权限、Context 和多个 MCP 连接 |
| Client | Host 内部 | 与一个 Server 建立连接并交换协议消息 |
| Server | 本地进程或远程服务 | 声明能力,访问真实数据源或业务系统 |
模型通常不直接连接 MCP Server。Host 通过 Client 发现能力,把当前可用的 MCP Tool 映射成模型能够理解的工具定义。模型生成调用后,Agent 框架再将参数发送给 MCP Server。
4.3 数据层、生命周期与 JSON-RPC
MCP 包含数据层和传输层。数据层基于 JSON-RPC 2.0,定义初始化、能力协商、请求、响应和通知。传输层负责在本地进程或网络服务之间承载这些消息。
连接建立后通常经历以下过程:
- Client 发送
initialize,声明协议版本、客户端信息和能力。 - Server 返回协商后的版本、服务端信息和能力。
- Client 发送
initialized通知,初始化完成。 - Client 根据能力调用
tools/list、resources/list或prompts/list。 - Host 选择适合当前任务的能力提供给模型。
- 模型产生动作后,Client 使用
tools/call或资源方法与 Server 交互。
带 id 的 JSON-RPC 请求需要对应响应;通知不带 id。Host 应校验响应 ID、协议版本和 Server 声明的能力,不能假设所有 Server 都支持同一组方法。
4.4 Tools、Resources 与 Prompts
| 能力 | 表达内容 | 常见方法 | 示例 |
|---|---|---|---|
| Tool | 可执行且可能失败的动作 | tools/list、tools/call | 搜索笔记、查询数据库、创建工单 |
| Resource | 通过 URI 定位的上下文 | resources/list、resources/read | 文件、文档、配置、数据库记录 |
| Prompt | 可复用的消息模板 | prompts/list、prompts/get | 代码审查模板、报告整理模板 |
Tool 通过名称、描述和 inputSchema 声明参数。Resource 适合浏览和读取内容。Prompt 适合向用户或 Host 提供领域任务入口。Server 还可以通过通知报告能力或资源变化。
MCP Tool 与模型工具之间需要适配。MCP Server 返回的是 MCP 自己的工具描述,模型 API 接收的则是 OpenAI tools[].function 或 Anthropic tools[].input_schema;Agent 框架负责转换两种 schema,并把模型返回的 tool call 重新映射为 MCP tools/call。下图只保留这条核心数据链路:
4.5 MCP 的传输层:stdio 与 Streamable HTTP
MCP 数据层定义了初始化、能力发现和工具调用等 JSON-RPC 消息,传输层负责把这些消息送到 Server。当前规范主要提供两种传输方式:本地进程使用 stdio,远程服务使用 Streamable HTTP。两者承载的是同一套 MCP 消息,差异在于连接位置、进程生命周期和网络治理方式。
| 传输 | 连接形态 | 适用场景 | 主要风险 |
|---|---|---|---|
stdio | Host 启动本地 Server,通过 stdin/stdout 通信 | 文件系统、Git、本地 CLI | 进程权限、工作目录、stdout 被日志污染 |
| Streamable HTTP | Client 连接远程 HTTP 服务 | 企业 API、共享知识库、云端工具 | 身份认证、租户隔离、限流、网络中断 |
stdio Server 应把协议消息写入 stdout,把普通日志写入 stderr。远程 Server 要在服务端执行身份认证和授权,Host 隐藏某个工具只能减少模型看到的能力,无法替代服务端权限检查。
早期远程传输使用 HTTP + SSE。新实现应使用当前规范中的 Streamable HTTP,并在初始化阶段确认协议版本。
当 MCP Server 很多时,把全部工具 schema 放进每轮请求会消耗 Context,也会降低工具选择准确率。Agent 框架可以先暴露能力索引,再根据任务按需加载完整工具定义;Skill 负责按需加载任务知识、模板或脚本,MCP 负责能力连接与发现,两者分工不同。
4.6 实现一个最小 MCP Server
4.6.1 能力设计
下面的内存笔记 Server 同时暴露 Tool、Resource 和 Prompt:
| 能力 | 名称 | 作用 |
|---|---|---|
| Tool | search_notes | 按关键词搜索笔记 |
| Resource | note://{note_id} | 读取指定笔记 |
| Prompt | summarize_note | 生成笔记整理任务模板 |
4.6.2 FastMCP 示例
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("notes")
notes = {
"vector-db": "向量数据库保存 embedding,并支持相似度检索。",
"rag": "RAG 先检索资料,再把相关片段交给模型生成回答。",
}
@mcp.tool()
def search_notes(keyword: str) -> list[dict]:
"""按关键词搜索可访问的笔记。"""
return [
{"id": note_id, "preview": text[:80]}
for note_id, text in notes.items()
if keyword in text
]
@mcp.resource("note://{note_id}")
def read_note(note_id: str) -> str:
"""读取一篇笔记。"""
return notes.get(note_id, "")
@mcp.prompt()
def summarize_note(note_id: str) -> str:
"""生成笔记整理任务。"""
return f"读取 note://{note_id},整理核心概念、适用场景和限制。"
if __name__ == "__main__":
mcp.run(transport="stdio")Host 初始化连接并发现 search_notes 后,可以发送:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_notes",
"arguments": {
"keyword": "向量数据库"
}
}
}Server 返回搜索结果后,Agent 框架将结果转换成模型协议对应的工具结果。模型若要阅读全文,Agent 框架再调用 resources/read 获取 note://vector-db。
真实服务还需要补充认证授权、输入限制、分页、超时、错误类型、版本管理和审计日志。协议统一接口,工具的正确性仍由 Server 实现和 Agent 框架的执行策略共同保证。
5. OpenAI Responses:从 Messages 走向 Items
5.1 为什么出现 Responses API
Chat Completions 以 message 为核心,工具调用、推理、文本和多轮状态需要应用组织。随着 Agent 开始使用网页搜索、文件搜索、代码执行、计算机操作和远程 MCP,单一 message 对象越来越难表达不同类型的动作。
2025 年推出的 Responses API 使用类型化 Items 作为基本单元。message、reasoning、function_call 和 function_call_output 都是独立 Item。接口还可以使用平台托管工具,并通过 previous_response_id 或 Conversations 管理多轮关系。
OpenAI 当前仍支持 Chat Completions,同时建议新项目优先使用 Responses API。
5.2 请求与输出结构
Responses 使用 POST /v1/responses。请求通过 instructions 和 input 组织内容,简单输入可以是一段字符串,复杂输入可以是 Item 数组:
{
"model": "model-id",
"instructions": "你是产品研究助手,结论必须注明依据。",
"input": "整理三款同类产品的核心差异。"
}响应顶层包含状态、用量和 output。output 是类型化 Item 数组,不能假设其中每一项都是文本消息:
{
"id": "resp_123",
"object": "response",
"status": "completed",
"output": [
{
"type": "message",
"id": "msg_123",
"role": "assistant",
"status": "completed",
"content": [
{
"type": "output_text",
"text": "以下是三款产品的核心差异。",
"annotations": []
}
]
}
],
"usage": {
"input_tokens": 96,
"output_tokens": 32,
"total_tokens": 128
}
}SDK 常提供 response.output_text 聚合文本。需要处理工具、推理或多模态内容时,应遍历 output 并根据 type 分派。
5.3 Function Calling 的 Item 闭环
Responses 中函数定义采用扁平结构:
{
"model": "model-id",
"input": "搜索产品 A 的定价方案。",
"tools": [
{
"type": "function",
"name": "search_web",
"description": "搜索公开网页并返回标题、URL 和摘要。",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"],
"additionalProperties": false
},
"strict": true
}
]
}模型动作以 function_call Item 返回:
{
"type": "function_call",
"id": "fc_123",
"call_id": "call_search_01",
"name": "search_web",
"arguments": "{\"query\":\"产品 A 官方定价\"}",
"status": "completed"
}Agent 框架执行函数后,提交 function_call_output Item,并使用相同 call_id 建立关联:
{
"model": "model-id",
"previous_response_id": "resp_123",
"input": [
{
"type": "function_call_output",
"call_id": "call_search_01",
"output": "{\"title\":\"Pricing\",\"url\":\"https://example.com/pricing\"}"
}
]
}使用 previous_response_id 可以引用上一轮 Response。若应用选择手动管理状态,则需要把相关 Items 按原顺序放入后续 input。调用链中的 reasoning、function call 和 function output 都可能影响下一步,不能只保留最终文本。
5.4 内置工具、状态与流事件
Responses API 可以在请求中声明平台托管的网页搜索、文件搜索、代码执行、计算机操作、图像生成和远程 MCP 等工具。部分工具循环可以在一次 API 请求内部完成;自定义函数仍需要应用接收调用、执行并回填结果。
多轮状态有三种常见方式:
- 使用
previous_response_id串联相邻 Response。 - 使用 Conversations 保存长期会话中的 Items。
- 设置
store: false并由应用完整管理输入历史,适合有特定数据保留要求的场景。
引用前一条 Response 会简化状态传递,但历史输入仍会计入模型输入。instructions 只描述当前请求应使用的高层规则,构建多轮调用时要明确哪些指令需要再次提供。
流式模式返回类型化 SSE 事件,例如 response.created、response.output_text.delta、函数参数增量、response.completed 和 error。客户端可以按事件类型更新文本、工具状态和任务状态。
5.5 三种 LLM 协议的核心区别
| 维度 | Chat Completions | Anthropic Messages | OpenAI Responses |
|---|---|---|---|
| 基本单位 | Message | Message + Content Block | Item |
| 规则入口 | developer/system 消息 | 顶层 system | instructions 或输入消息 |
| 输入历史 | messages | messages | input Items、previous_response_id 或 Conversation |
| 文本输出 | choices[].message.content | content[type=text] | output[type=message],SDK 可用 output_text |
| 自定义函数 | tool_calls | tool_use | function_call Item |
| 函数结果 | tool 消息 | tool_result block | function_call_output Item |
| 平台内置工具 | 能力较少,循环多由应用管理 | 取决于平台能力 | 原生支持多类托管工具与远程 MCP |
| 状态管理 | 应用重放消息 | 应用重放消息 | 支持应用重放,也支持 Response/Conversation 串联 |
| 流式形态 | choices[].delta | content block 类型事件 | response 类型事件 |
| 适用场景 | 兼容接口、消息式应用、现有系统 | Claude 应用与 block 式内容处理 | 新建 OpenAI Agent、内置工具和复杂事件流 |
迁移时不能只替换 URL。应用还要调整输入结构、输出遍历、函数 schema、函数结果关联、状态策略、Structured Outputs 字段和流式事件处理。
6. A2A(Agent2Agent Protocol):Agent 开始跨系统协作
6.1 工具调用与任务委派的差异
工具调用通常是一次边界清晰的动作:Agent 框架提交参数,等待结果或错误。Agent 任务可能包含多轮推理、内部工具调用、补充输入、进度事件和多个产物。
2025 年推出的 A2A(Agent2Agent Protocol) 面向跨 Agent、跨框架和跨组织协作。调用方关注对方能做什么、任务进展到哪里、需要补充什么以及交付了哪些 Artifact,无需了解下游 Agent 的内部执行轨迹。
6.2 核心对象
| 对象 | 作用 |
|---|---|
| Agent Card | 描述 Agent 的身份、地址、能力、输入输出模式和认证要求 |
| Task | 表达可持续运行、查询状态和恢复的工作 |
| Message | 用户、调用方和 Agent 之间交换的内容 |
| Part | Message 或 Artifact 中的文本、文件或结构化数据单元 |
| Artifact | Agent 生成的报告、代码补丁、数据文件等交付物 |
Agent Card 解决能力发现。调用方选择 Agent 后创建 Task,使用任务 ID 关联后续消息、状态和产物。
6.3 任务生命周期
长任务需要表达已提交、处理中、需要输入、完成、失败和取消等状态。具体状态名称以采用的规范版本为准。
下游 Agent 缺少资料时,可以进入 input-required 一类状态,由调用方补充信息后继续。任务完成后返回 Artifact;失败时返回错误与可恢复信息。流式事件或状态订阅让调用方持续获得进展。
6.4 MCP 与 A2A
| 维度 | MCP | A2A |
|---|---|---|
| 交互对象 | Tool、Resource、Prompt | Agent、Task、Message、Artifact |
| 粒度 | 一次能力调用或资源读取 | 可能持续多轮的任务 |
| 发现内容 | Server 提供的具体能力 | Agent 的专业能力和交互方式 |
| 状态 | 以请求响应和通知为主 | 强调任务生命周期和产物 |
Supervisor 可以通过 A2A 委派代码审查任务,审查 Agent 再通过 MCP 读取仓库、查询工单和运行测试。
7. Agent Client Protocol:Agent 进入 IDE 与桌面端
7.1 客户端需要哪些事件
IDE、终端和桌面应用需要展示完整任务过程,包括:
- 创建、恢复和取消会话。
- 接收流式文本、计划与执行进度。
- 展示工具开始、工具完成和终端输出。
- 请求用户确认文件写入、命令或外部操作。
- 展示文件 diff、诊断结果和最终产物。
Agent Client Protocol 将这些交互组织为客户端与 Agent 框架之间的标准消息。客户端负责展示和收集用户输入,Agent 框架负责模型调用、工具调度、状态管理和执行控制。规范源码和实现可参阅 Agent Client Protocol GitHub 仓库。
7.2 与模型流式协议的区别
模型 API 的流事件描述一次模型调用,例如文本 token 或函数参数增量;客户端协议描述完整 Agent 任务,其中可能包含多次模型调用、多个工具和用户确认。
Agent 框架通常会把底层模型事件转换成更稳定的任务事件。产品可以扩展 trace_id、耗时、风险等级和结果摘要,但应明确区分标准字段与应用字段。
7.3 ACP 的名称歧义
ACP 可能指 Agent Client Protocol,也可能指 Agent Communication Protocol。前者连接客户端与 Agent 框架,后者通常描述 Agent 间消息和任务交换。不同项目使用相同缩写不代表协议兼容,接入时应核对全称、规范版本、维护组织和 SDK。
8. 如何选择协议
8.1 先看通信双方
| 需求 | 选择方向 | 关键判断 |
|---|---|---|
| 调用 OpenAI 模型并兼容现有消息系统 | Chat Completions | 是否依赖 messages、choices 和现有兼容网关 |
| 新建 OpenAI Agent 或使用内置工具 | Responses | 是否需要 Items、托管工具、状态串联和类型化事件 |
| 调用 Claude | Anthropic Messages | 是否正确处理 system、Content Blocks 和 tool_use/tool_result |
| 接入工具与数据源 | MCP | 是否需要跨 Host 复用、能力发现和统一连接 |
| 跨 Agent 委派任务 | A2A | 是否需要能力发现、长任务状态和 Artifact |
| 连接 IDE 或桌面客户端 | Agent Client Protocol 或产品协议 | 是否需要会话、事件、权限与文件变更 |
| 同一进程内模块调用 | Agent 框架内部接口 | 是否存在真正的跨进程或互操作需求 |
8.2 Agent 框架的统一事件模型
支持多种协议时,Agent 框架不宜让业务逻辑直接依赖供应商字段。可以先转换为内部事件:
user_message
assistant_message
tool_call(id, name, arguments)
tool_result(id, content, is_error)
state_update
artifact
usage
final协议适配器负责外部 JSON 与内部事件之间的转换。这样可以替换模型供应商、把 MCP Tool 映射到多个模型接口,并用统一 trace 串起客户端、模型、工具和下游 Agent。
8.3 安全与可靠性
- 身份传递:区分用户、Agent 框架、工具服务和下游 Agent,记录每次调用代表谁执行。
- 最小权限:模型只看到当前任务需要的能力,Server 对每次读取和写入独立授权。
- 参数校验:模型产生的 JSON 仍是不可信输入,Agent 框架要校验 schema、路径、范围和副作用。
- 工具描述污染:第三方工具名称、描述和返回内容都可能包含诱导指令,接入和升级时需要审查。
- 上下文隔离:跨 Server 或跨 Agent 只传递完成任务所需的信息,执行脱敏与租户隔离。
- 状态完整性:工具调用与结果必须通过 call ID 配对,任务事件要有顺序和可恢复状态。
- 审计链路:使用 trace ID 串联客户端事件、模型请求、MCP 调用和 A2A Task。