news 2026/8/25 14:55:25

Agent Content Protocol: 一种基于 RFC 2046 的内容封装规范

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent Content Protocol: 一种基于 RFC 2046 的内容封装规范

Agent Content Protocol: 一种基于 RFC 2046 的内容封装规范

2026-08-22

Agent Content Protocol: 一种基于 RFC 2046 的内容封装规范

版本:0.5.0-draft


1. 协议定位与核心宣言

1.1 定位

ACP 定义了一种可互操作的 Agent 消息内容信封。它规定了如何将一个 JSON 控制文档与零个或多个 MIME 内容部分组合在同一报文中。

ACP 不定义 Agent 语义(tool calling、意图识别)、执行语义(重试、超时、流式传输)或传输语义(HTTP 方法、路由、认证)。这些全部属于上层协议或应用层约定。ACP 仅解决一个问题:如何让结构化控制数据与原生内容数据在标准 MIME 框架下安全、高效地共存。

1.2 核心设计宣言

控制数据保持 JSON 结构化;内容数据保持其原生 MIME 表示;两者通过 Content-Disposition 的name参数连接。

传统方案将二进制嵌入 JSON(base64 / data URI),导致编码膨胀、解析负担、类型丢失、调试困难。ACP 让内容以原始字节存在于独立的 MIME part 中,JSON 仅持有引用指针。这是"零转换"设计的本质。

1.3 为什么不使用 base64

base64 不应成为默认封装方式。当内容本身已有成熟的 MIME 表示时,重复编码带来约 33% 体积膨胀、JSON parser 处理巨大字符串的压力、类型信息丢失、大文件无法流式处理、调试工具不可读等问题。MIME part 天然解决所有这些问题。

备注:ACP 并不禁止 base64。在 JSON 表示(application/json)中,上层协议完全可以将内容以 base64 字符串内嵌在 JSON 字段内——这依然是合法的 ACP 消息。ACP 仅提供一种更优的 multipart 替代方案,而非排斥 base64 的使用场景。

1.4 为什么选择 multipart/form-data

RFC 2046 定义了多种 multipart 子类型。ACP 选择multipart/form-data而非multipart/mixedmultipart/related,理由如下:

  • 生态兼容性:主流 Web 框架(Express/FastAPI/Spring/Gin)、HTTP 客户端(axios/fetch/curl/requests)、网关(Nginx/Envoy/Kong)、浏览器原生 FormData API 对multipart/form-data的支持是一等公民,开箱即用。multipart/mixed在多数场景需开发者自行实现解析器。
  • 语义适配form-data的语义是"一组命名键值对,值为文件或文本",与 ACP "JSON 控制文档 + 若干命名内容载荷"的模型高度吻合。每个内容部分可通过name参数标识,便于中间件按名称提取。
  • 引用机制兼容multipart/form-dataContent-Disposition: form-data; name=...参数天然提供命名空间,可直接作为 ACP 的引用锚点。

2. 核心不变量

以下三条是整个协议的公理,所有后续规则均由此推导:

  1. 单一控制文档:每条 ACP 消息恰好包含一个application/json控制文档。
  2. 内容引用绑定:每个参与消息语义的内容部分必须拥有唯一的name参数,且被控制文档显式引用。
  3. 传输无关性:ACP 是内容封装规范,不绑定任何特定传输协议。HTTP、SMTP、消息队列、WebSocket 均可承载。

3. 消息表示形式

ACP 消息有两种序列化表示,语义完全等价:

表示形式Content-Type结构适用场景
JSON 表示application/json单个 JSON 文档无内容载荷时的简化形式;或内容以 base64 内嵌于 JSON 字段时
Multipart 表示multipart/form-dataJSON 控制文档 + 0…N 内容部分通用形式,含或不含载荷

关键说明:

  • JSON 表示与"仅含 JSON 的 multipart 表示"在语义上完全等价。
  • 接收方必须同等处理两种形式。
  • 发送方可根据接收方能力或自身偏好任选其一。
  • 这不是三个模型,而是同一模型的两种序列化选择。
  • base64 内嵌:在 JSON 表示中,上层协议可将二进制内容以 base64 编码后内嵌在任意 JSON 字段中。ACP 协议层对此无限制,也不提供特殊语义——base64 字符串就是普通 JSON 字符串值。当需要引用外部 MIME part 时,才使用$ref机制。

4. Multipart 表示的严格解析规则

4.1 第一个 Part 必须是 JSON

  • 第一个 part 的 media type 必须是application/json
  • 比较规则:提取 Content-Type 的 media type 部分(忽略参数)。即application/json; charset=utf-8视为合法。
  • 第一个 part 的Content-Dispositionname参数建议为_acp_control,但不强制。
  • 第一个 part 不需要被$ref引用(它是控制文档本身)。
  • 若第一个 part 不是application/json,接收方必须拒绝该消息。

4.2 后续 Part 为内容载荷

  • Part 2…N 是内容载荷,可使用任何合法的 MIME media type。
  • ACP 不根据内容是文本还是二进制赋予不同语义。text/plaintext/csvapplication/xmlimage/pngapplication/pdf等均作为平等的内容载荷对待。
  • 内容类型完全由 MIME 自身负责,ACP 不做二次分类。
  • 每个内容部分必须携带Content-Disposition: form-data; name="...",其name参数作为该 part 的全局唯一标识符,供 JSON 中的$ref引用。

4.3 字符集与编码声明

  • JSON 控制文档默认使用 UTF-8 编码。若显式声明charset参数,以声明值为准。
  • 内容载荷的字符集处理完全遵循 RFC 2046 和 RFC 6657 的既有规则。
  • text/*类型的内容载荷若无charset参数,接收方应按 RFC 6657 默认规则处理(通常为 US-ASCII 或 UTF-8,取决于具体 media type 注册)。
  • ACP 不做任何额外的字符集推断或自动检测。编码责任完全归属于 MIME 层。

4.4name参数规则

ACP 使用Content-Disposition: form-data; name="..."中的name参数作为内容部分的标识符和引用锚点。

ACP 施加以下约束:

  1. 存在性:每个被 JSON 引用的内容部分必须携带Content-Disposition: form-data; name="..."
  2. 唯一性:在同一消息信封内,name参数必须唯一。出现重复name时,接收方必须拒绝该消息。
  3. 作用域name的作用域严格限定在当前消息信封内。不允许跨消息引用。
  4. 匹配:JSON 中的$ref值必须与某个内容部分的name参数精确匹配(区分大小写)。
  5. 自引用禁止name不得指向 JSON 控制文档本身(即不应与控制文档的name值冲突)。
  6. 嵌套禁止name不得指向另一个 multipart 容器。ACP 不支持递归嵌套引用。
  7. 字符限制name参数值应仅使用 ASCII 字母、数字、连字符、下划线和句点,避免特殊字符和空格,以确保跨平台兼容性。
name生成推荐策略

在分布式 Agent 系统中,多个 Agent 可能并行构造消息并合并,name冲突风险真实存在。推荐以下生成模式:

首选:UUIDv7

0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b

优势:时间有序、全局唯一概率极高、仅含连字符和字母数字、无需协调。

备选:{agent-id}-{timestamp-ms}-{random}

planner-alpha-1724338200000-x9k2m

优势:人类可读、便于日志关联。注意 agent-id 和 random 部分必须仅含 ASCII 字母、数字、连字符、下划线。

4.5 内容引用机制

内容引用是从 JSON 控制文档到恰好一个 MIME 内容部分的逻辑指针,通过{ "$ref": "<name>" }对象建立绑定。

显式引用对象

ACP 采用严格校验 + 显式声明策略:只有包裹在{ "$ref": "..." }对象中的值才会被解析为引用。纯字符串(如"image-001")永远被视为普通文本,不产生引用语义。

{"payload":{"instruction":"分析这张图片","image":{"$ref":"image-001"}}}

机制:解析器在遍历 JSON 时,遇到键值为{ "$ref": "<name>" }的对象,即视为对该name对应的内容部分的引用。该对象所在位置的业务语义由上层协议定义。

优势

  • 零歧义:字符串值与引用值严格区分,不存在"猜测"字符串是否为引用的场景。
  • 零冲突:普通文本中即使出现类似引用的字符串,也不会被误解析。
  • 无需转义:引用是结构化的,不是字符串前缀或特殊格式。
  • 认知成本低:与 JSON Schema / OpenAPI 的$ref惯例一致,开发者无需学习新的引用语法。

代价:JSON 结构稍显冗长,但换来的是不可比拟的正确性和互操作性。

业务引用字段

协议不规定 JSON 中承载业务引用的具体字段名。上层可使用imageattachmentinputresultpayload等任意命名。只要字段值为{ "$ref": "<name>" }对象,即构成有效引用。

引用解析规则
  1. 深度遍历:解析器必须对 JSON 控制文档进行深度遍历,发现所有{ "$ref": "..." }对象。
  2. 值校验$ref的值必须是合法的name字符串(符合 §4.4 的字符限制)。
  3. 存在性校验:每个被引用的name必须在当前消息的某个内容部分的Content-Disposition中存在。引用不存在的name为致命错误。
  4. 重复引用:JSON 中多个位置可引用同一name,这是允许的。
  5. 非对象值:任何非{ "$ref": "..." }形式的值(包括纯字符串name、数组、其他对象)均不产生引用语义。

4.6 未引用内容的处理

未被 JSON 控制文档中任何{ "$ref": "..." }对象引用的内容部分不得影响消息语义。接收方可将其暴露用于诊断,但不得将其解释为应用载荷的一部分。


5. 错误处理模型

ACP 在协议层保持严格验证,同时为上层提供降级指导。

5.1 致命错误(必须拒绝整条消息)

错误类型说明
Part 1 非 application/json控制文档缺失或格式错误
重复name参数引用歧义,无法确定绑定目标
$ref引用不存在的name消息不完整,语义无法成立
$ref值语法非法引用格式非法(含非法字符等)
name指向 JSON part违反自引用禁止规则
name指向嵌套 multipart违反嵌套禁止规则
MIME header 注入 / boundary 非法安全风险
超出实现方声明的尺寸/数量限制资源保护

5.2 可恢复警告(记录并继续)

情况处理方式
未引用的内容部分不影响语义,可丢弃或记日志
text/* 内容缺少 charset 参数按 RFC 6657 默认规则处理

5.3 上层降级指导

ACP 本身不提供"部分成功"语义。但在容错场景中,上层协议可定义降级策略:

  • 收到 ACP 致命错误时,上层可选择:提取 JSON 控制文档(若可解析)并忽略内容载荷,转为纯文本模式继续处理。
  • 此降级行为完全由上层定义,不属于 ACP 协议范畴。
  • 降级后的消息不再是合法的 ACP 消息,应在上层日志中标注。

6. 安全模型与约束

6.1 引用安全

场景规定行为
重复name参数拒绝消息
$ref引用不存在的name拒绝消息
$ref值语法非法拒绝消息
name指向 JSON part拒绝消息
name指向嵌套 multipart拒绝消息
跨消息name引用拒绝消息
JSON 多处$ref引用同一name允许
未引用的内容部分不影响语义,可诊断暴露
纯字符串形式的name视为普通文本,不产生引用

6.2 尺寸与数量限制

ACP 本身不设硬性上限,但强烈建议实现方设定以下防护阈值:

参数推荐默认值理由
最大内容部分数量64防止 DoS / 解析爆炸
单 part 最大大小100 MB防止内存耗尽
消息总大小500 MB与网关/代理限制对齐
boundary 最大长度70 字符RFC 2046 上限
JSON 控制文档最大大小1 MB控制信令不应过大

实现方应在文档中声明自身限制。超出限制的消息应被拒绝并返回明确错误。

6.3 Header 注入防护

  • 所有 MIME header 值必须进行合法性校验。
  • boundary 参数不得包含换行符、空字节或控制字符。
  • name参数值应符合 ASCII 安全字符集。
  • 不符合语法的 header 应导致消息被拒绝。

7. 报文示例

7.1 JSON 表示(无内容载荷)

POST /messages HTTP/1.1 Host: gateway.example.com Content-Type: application/json { "id": "msg_001", "from": "planner-alpha", "to": "reasoner-beta", "payload": { "text": "请总结以下要点", "items": ["要点1", "要点2"] } }

7.2 JSON 表示(含 base64 内嵌内容)

POST /messages HTTP/1.1 Host: gateway.example.com Content-Type: application/json { "id": "msg_001b", "from": "planner-alpha", "to": "vision-worker-01", "payload": { "instruction": "识别图片中的所有文字", "image": { "mime_type": "image/png", "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" } } }

注:此形式是合法的 ACP JSON 表示。base64 内嵌由上层协议定义字段结构,ACP 协议层不做特殊处理。当需要避免 base64 膨胀时,应使用 multipart 表示。

7.3 Multipart 表示(含内容载荷)

POST /messages HTTP/1.1 Host: gateway.example.com Content-Type: multipart/form-data; boundary=ACP-B2 --ACP-B2 Content-Type: application/json Content-Disposition: form-data; name="_acp_control" { "id": "msg_002", "from": "planner-alpha", "to": "vision-worker-01", "payload": { "instruction": "识别图片中的所有文字", "image": { "$ref": "input_image" } }, "refs": [ {"name": "input_image", "content_ref": { "$ref": "input_image" }}, {"name": "reference_doc", "content_ref": { "$ref": "reference_doc" }} ] } --ACP-B2 Content-Type: image/png Content-Disposition: form-data; name="input_image" <二进制 PNG 数据> --ACP-B2 Content-Type: application/pdf Content-Disposition: form-data; name="reference_doc" <二进制 PDF 数据> --ACP-B2--

7.4 请求/响应中的引用示例

以下示例展示上层协议如何在业务数据中使用$ref

请求(Tool Calling)

{"requests":[{"id":"1","action":"read","arguments":{"filename":"a.txt","line":10}},{"id":"2","action":"read","arguments":{"filename":"b.txt","line":10},"after":["1"]}]}

响应(结果引用)

{"responses":[{"id":"1","operate":"read","status":"ok","result":{"$ref":"a.txt"}},{"id":"2","operate":"read","status":"ok","result":{"$ref":"b.txt"}}]}

7.5 Multipart 表示(仅 JSON,无载荷)

POST /messages HTTP/1.1 Host: gateway.example.com Content-Type: multipart/form-data; boundary=ACP-B3 --ACP-B3 Content-Type: application/json Content-Disposition: form-data; name="_acp_control" { "id": "msg_003", "from": "planner-alpha", "to": "reasoner-beta", "payload": {"text": "hello"} } --ACP-B3--

此形式与 §7.1 的 JSON 表示语义完全等价。


8. 与现有 Agent 生态的适配指南

主流 Agent API(OpenAI、Anthropic、Google 等)目前普遍使用 base64 内嵌方式。ACP 提供双向适配路径。

8.1 ACP → 厂商 API(出站适配)

当需要将 ACP 消息发送给仅支持 base64 的 API 时:

  1. 解析 ACP multipart 消息,提取 JSON 控制文档和所有内容部分。
  2. 对 JSON 进行深度遍历,定位所有{ "$ref": "<name>" }对象。
  3. 对每个被引用的内容部分:读取原始字节,执行 base64 编码,获取 Content-Type。
  4. 将编码后的数据注入厂商 API 要求的字段结构中(如 OpenAI 的image_url.url: "data:{mime};base64,{data}"),并替换原$ref对象为厂商要求的内联格式。
  5. 发送转换后的请求。

8.2 厂商 API → ACP(入站适配)

当接收到厂商 API 返回的 base64 内容时:

  1. 从响应中提取 base64 数据和对应的 MIME type。
  2. 解码 base64 得到原始字节。
  3. 生成唯一的name(推荐使用 UUIDv7)。
  4. 构造 ACP multipart 消息:JSON 控制文档 + 解码后的内容部分。
  5. 在 JSON 中需要引用内容的位置,插入{ "$ref": "<name>" }对象。

8.3 注意事项

  • 适配层是有损转换:ACP 的零传输开销优势在 base64 回退时丧失。
  • 大文件场景下,适配层应考虑流式 base64 编解码,避免全量加载。
  • 适配层应记录转换日志,便于排查问题。
  • 长期目标是推动厂商原生支持 multipart/form-data,适配层作为过渡方案。

9. 与上层协议的关系

ACP 是封装层,不是语义层。上层协议在 JSON 控制文档中自由定义 tool calling 格式、动作类型、错误码、重试策略、流式分片、会话关联、能力协商、认证令牌等。ACP 仅保证:无论 JSON 内部结构如何变化,其与内容载荷的组合、引用、传输机制始终稳定且互操作。

上层协议在使用$ref时应注意:

  • $ref是 ACP 的保留键,在 JSON 控制文档的任何位置出现{ "$ref": "..." }对象,均会被 ACP 层解析为内容引用。
  • 上层协议不应将$ref用于非引用语义,以避免与 ACP 解析器冲突。

附录 A:设计决策记录

决策理由
使用 multipart/form-data 而非 mixed一等公民级别的生态支持,name 参数天然适配命名载荷
不使用自定义 MIME 类型最大化基础设施兼容性
不内置 intent/action 语义保持封装层纯粹性
使用Content-Dispositionname作为引用锚点直接利用 form-data 已有机制,无需额外的 Content-ID header,简化解析链路
name值使用 ASCII 安全字符集确保跨平台、跨框架兼容性,避免编码歧义
采用{ "$ref": "..." }显式引用对象零歧义、零冲突、与 JSON Schema / OpenAPI 惯例一致,开发者认知成本低
区分致命错误与可恢复警告协议层严格,上层可灵活降级
不做字符集推断编码责任归属 MIME 层,避免歧义
允许 JSON 表示中 base64 内嵌ACP 不排斥 base64,仅提供更优的 multipart 替代方案
提供厂商 API 适配指南降低采用门槛,承认 base64 现状

附录 B:术语表

术语定义
控制文档消息中恰好一个 application/json part,承载上层语义
内容部分消息中除控制文档外的 MIME part,承载原生内容数据
内容引用JSON 控制文档中通过{ "$ref": "<name>" }对象指向某个内容部分name的逻辑指针
消息信封一条完整的 ACP 消息,无论是 JSON 表示还是 multipart 表示
零转换内容数据以原始 MIME 表示进入消息,无需 base64 等二次编码
致命错误导致整条消息被拒绝的协议违规
可恢复警告不影响消息语义、可记录并继续处理的非致命情况
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 14:51:44

SkillGo,支持多用户与独立沙箱执行的 Skill 平台

一、为什么要做 SkillGo&#xff1f; 聚焦于解决&#xff1a; 创造一个私有化部署的社区&#xff0c;Skill 获得以后&#xff0c;在社区中怎样管理、怎样运行、怎样隔离&#xff0c;以及怎样将skill配置成可以接入业务系统的api。 这是 SkillGo 出现的原因。 GitHub&#xff1…

作者头像 李华
网站建设 2026/8/25 14:49:11

Python3.10自然语言处理项目:HuggingFace+镜像部署教程

.10自然语言处理项目&#xff1a;镜像部署教程想要迅速搭建一个归属于自身的 AI 开发环境, 然而又不愿被繁杂的依赖以及版本冲突弄得顾此失彼、疲惫不堪? 今日, 就在这里讲述一下怎样运用最为简单的方式, 在.10 环境里面, 借由一个预先配置好的镜像, 顺利实行部署生态, 进而开…

作者头像 李华
网站建设 2026/8/25 14:44:48

skill、agent、mcp、workflow 到底怎么分

摘要&#xff1a;skill、agent、mcp、workflow——AI 编程文章里这四个词出镜率最高&#xff0c;却最容易被混为一谈。本文用你每天写的代码作参照&#xff0c;讲清它们各是哪一层、实际长什么样、怎么按自己的真实工作流搭起来&#xff0c;以及单条提示词到底怎么写才不白写。…

作者头像 李华
网站建设 2026/8/25 14:42:13

自动驾驶图像分割开源数据集指南(2026)

2026 年 8 月  开源数据笔记 做分割几乎都从 Cityscapes 下起&#xff0c;下完才发现&#xff1a;BDD 名字带 100K&#xff0c;有分割标签的只有 10K&#xff1b;*_color.png 不能当监督&#xff1b;SYNTHIA 的 13/16 类 mIoU 和 Cityscapes 19 类不能写在同一格。下面按任务…

作者头像 李华
网站建设 2026/8/25 14:41:15

构建高效 CI 缓存策略:加速你的 GitLab CI 流水线

系列导读 你现在看到的是《GitLab CI/CD 从入门到治理:企业级平台搭建与运维实战》的第 6/10 篇,当前这篇会重点解决:通过合理的缓存策略,显著提升 CI 效率,节省企业计算资源。 上一篇回顾:第 5 篇《GitLab CI 高级技巧:条件判断、矩阵构建与动态流水线》主要聚焦 提升…

作者头像 李华