门户首页
LLM 协议系列 · 消息结构层

消息结构层:JSON 为什么是事实标准、变体差异、何时该用 Protobuf

在 LLM 协议这两层(消息结构层 / 传输层)里,消息结构层几乎被 JSON 一统天下—— 但 JSON 不是一种格式,是一族格式(标准 JSON / JSONL / JSON5 / JSON Schema / Stringified JSON), 边界都摸不清就敢自称"懂 JSON"是危险的。本页也回答"什么时候该离开 JSON"——答案是 Protobuf, 但LLM 公开 API 永远不用 Protobuf,原因藏在内文里。

生成时间:2026-09-02 15:05 · 生成 Agent:MiniMax Code (LLM: MiniMax-M3) · 载体:agentsoft-research-platform teaching-web-platform

概览

3
核心问题
4
JSON 胜出原因
5
JSON 变体
4
Protobuf 适用场景
项目说明
本卡定位消息结构层专章 · 与 fundamentals 平级,回答"为什么 JSON"与"何时该走"
前置知识已完成 llm-protocol-fundamentals.html(协议是什么)
读完去哪儿llm-chat-protocol-guide.html 7 讲讲义 / llm-api-schema-reference.html Schema 参考

第一篇 · JSON 现状(为什么 + 变体)

Part 1 · JSON 现状(2 卡)
先答"为什么是 JSON"(4 个相互加强的原因),再答"JSON 长什么样"(5 个变体的边界)。
第 1 讲 · 1 概念 + 0 实验

为什么 JSON 是事实标准:4 个相互加强的原因

在 LLM(Large Language Model,大语言模型)协议这个语境里,JSON 几乎是唯一的选择。先交代名字:JSON = JavaScript Object Notation(JavaScript 对象表示法),一种以"键值对 + 数组"组织数据的人类可读文本格式。但"为什么是它"——其实有 4 个互相加强的原因,少一个,JSON 都坐不稳这个位置。这不是技术最优解,是生态最优解。

4 个原因(缺一不可)
  • 历史偶然性 → 生态必然性:Douglas Crockford 2001 年从 JS 子集提炼出 JSON;JS 在浏览器时代的统治地位让 JSON 顺水推舟进入所有 Web API。每种语言都至少有 1 个 JSON 库——这比任何"标准设计"都更强大的护城河
  • 技术恰到好处:自描述(key 名就是文档)、人类可读(debug 友好)、Schema 灵活(不要也行,要也可以用 JSON Schema 加)、树形结构天然契合 messages / tools / tool_calls 这种嵌套数据
  • LLM 训练友好:模型训练数据里大量 JSON 例子,模型"看得懂" JSON 格式,function calling / json_mode / structured outputs 都基于这个事实。换成 Protobuf,模型生成的就是二进制,没法直接 parse 进下一轮
  • 可调试性:curl 直接发、jq 直接读、print(json.dumps(...)) 直接看——整个工具链对人透明。Protobuf 要靠 protoc / grpcurl / 反射才能看
金句:JSON 的胜出不是技术最优解,是生态最优解——是 2001-2025 这 25 年里无数个小决定的累计结果。
第 2 讲 · 1 对比 + 1 陷阱

JSON 不是一种格式:5 个变体你在 LLM 工作里都会撞到

严格说,"JSON" 这个词覆盖了至少 5 种不完全兼容的格式。在 LLM 工作里你会反复撞到其中 4 种——知道它们的边界,能少踩很多坑。

5 个变体对比
变体 关键差异 LLM 场景里的位置 与标准 JSON
标准 JSON
RFC 8259
严格双引号、无注释、无尾逗号 99% 的 API 消息体 自身即标准
JSONL / NDJSON 每行一个完整 JSON 对象(不跨行) OpenAI 微调数据 / 流式日志 / SFT 训练集 是(每行独立)
JSON5 注释、尾逗号、单引号、十六进制 配置文件 / LLM 输出宽松解析 不严格兼容
JSON Schema 描述 JSON 结构的元语言 OpenAPI / Anthropic tool 定义 / 入参校验 N/A(元语言)
Stringified JSON
(LLM 特有)
JSON 字段的值是字符串,要二次 parse OpenAI tool_calls.arguments / Anthropic tool_use.input 需要 parse
关键陷阱:OpenAI 的 tool_calls[i].function.arguments 是字符串,不是对象——你必须 json.loads(arguments) 一次才能用。Anthropic 早期直接给对象,2024 年后统一为字符串;混用两个 SDK 的代码极易翻车。

第二篇 · 何时该离开 JSON

Part 2 · 何时该离开 JSON(2 卡)
JSON 不是万能的——4 个场景该用 Protobuf,但 LLM 公开 API 永远不用,因为训练数据、调试、生态都不允许。
第 3 讲 · 4 场景 + 1 排除

Protobuf 何时该用:4 个场景,但 LLM 公开 API 永远不用

先给两个名字:Protobuf = Protocol Buffers(Google 设计的二进制序列化格式,靠 .proto 文件定义结构);API = Application Programming Interface(应用程序接口,程序之间约定的调用方式)。Protobuf 在 LLM 生态里是个"内部英雄"——对外的 API 全部是 JSON,内部的推理服务大量是 Protobuf。这种"内外不一致"不是 bug,是设计。

4 个该用 Protobuf 的场景
  • 高 QPS / 低延迟:QPS(Queries Per Second,每秒查询数)> 10k 或 P99(99 分位延迟)< 10ms。JSON 解析在 CPU 热点上吃不消,Protobuf 的二进制 + 变长编码快 3-10 倍
  • 带宽敏感:移动端、嵌入式、跨数据中心传输。Protobuf 体积约为 JSON 的 1/3
  • 强 Schema 演进:多服务依赖同一份契约,需要 .proto 的 field number 保证前后兼容
  • 多语言内部 RPC:gRPC + Protobuf 在 C++/Java/Go/Python/Rust 之间无缝对接,序列化代码自动生成
JSON vs Protobuf 对比(4 个维度)
维度 JSON Protobuf
可读性高(人可直接看)低(需 protoc --decode)
体积大(文本)小(二进制,约 1/3)
解析速度慢(字符串解析)快(直接读二进制,3-10×)
Schema 强度弱(可选 JSON Schema)强(.proto 强制)
跨语言支持几乎所有语言主流语言(C++/Java/Go/Python/Rust)
流式友好一般(要 SSE 包装)天然友好(变长编码)
LLM 训练友好高低(训练数据里几乎没有)
调试友好高(curl + jq)低(要 protoc + 反射)
LLM 公开 API 永远不用 Protobuf 的 3 个原因
  • 训练数据:模型训练语料里几乎全是 JSON,换 Protobuf 模型就"看不懂"工具描述,function calling 失效
  • 调试门槛:用户拿不到 .proto 定义就调不通,curl 直接挂——LLM 的用户群体远不止后端
  • 生态分散:每个 LLM 厂商 JSON 格式虽不同但"长得像",换 Protobuf 各家就完全不通,跨厂商迁移成本爆炸
LLM 哪里在用 Protobuf(你不知道的另一面)
  • 推理服务内部:NVIDIA Triton、TensorRT-LLM、vLLM 之间的通信大量是 gRPC + Protobuf
  • 大厂内部 multi-agent 框架:agent ↔ agent 的高速 RPC 走 Protobuf,对外暴露时再转 JSON
  • 微服务之间的内部 RPC:即使最终给前端的是 JSON,中间层往往是 Protobuf
第 4 讲 · 1 决策树 + 1 收口

实战决策树:你的场景该用哪种?

把上面所有内容压成一张图。从"你的服务是什么"开始,按节点回答就能落到唯一答案。

flowchart TD Start["你的服务是什么?"] --> LLM{"是 LLM
公开 API?"} LLM -- "是" --> J1["用 JSON
(生态 + 训练数据 + 调试)"] LLM -- "否" --> Internal{"是 LLM
内部推理?"} Internal -- "是" --> P1["用 Protobuf
(gRPC + .proto)"] Internal -- "否" --> Perf{"QPS > 10k
或 P99 < 10ms?"} Perf -- "是" --> P2["用 Protobuf"] Perf -- "否" --> Schema{"强 Schema
跨版本演进?"} Schema -- "是" --> P3["用 Protobuf"] Schema -- "否" --> Multi{"多语言团队
(>3 种语言)?"} Multi -- "是" --> P4["用 Protobuf"] Multi -- "否" --> J2["用 JSON
(简单 + 通用 + 生态)"]
图 1 · 消息结构选型决策树:5 个判断点收敛到 JSON / Protobuf 二选一
一句话收口:给 LLM 的东西用 JSON,LLM 内部的东西用 Protobuf。如果只能记一条,记这条。