题记与说明
精读日期:2026-10-31
唯一前缀:knowledge-fexxiou8-1
精读方式:网络可用,共精读 5 个来源(WebFetch 全文抓取并提取原文引述),另有 3 组搜索级结果作为旁证(已标注精读级别)。
注:本次精读对象多为"对比指南/规范/工程博客"而非学术论文,因此"数据与证据"维度多为定性论证与规范原文,定量基准数据普遍缺失(已在局限中标注)。
0. 来源清单与精读级别
| # | 来源 | 链接 | 精读级别 |
|---|---|---|---|
| S1 | REST vs GraphQL vs gRPC — Level Up Coding (Nikki Siapno) | https://blog.levelupcoding.com/p/rest-vs-graphql-vs-grpc | 全文精读 |
| S2 | MCP 规范:Transports(2025-06-18 版) | https://modelcontextprotocol.io/specification/2025-06-18/basic/transports | 全文精读 |
| S3 | Stop Defaulting to WebSockets: Why SSE are Usually Better — dev.to (mindinu) | https://dev.to/mindinu/stop-defaulting-to-websockets-why-server-sent-events-sse-are-usually-better-3k2g | 全文精读(含评论区勘误) |
| S4 | Writing effective tools for agents — Anthropic Engineering (2025-09-11) | https://www.anthropic.com/engineering/writing-tools-for-agents | 全文精读 |
| S5 | gRPC 官方文档:Introduction + Core concepts | https://grpc.io/docs/what-is-grpc/introduction/ 、https://grpc.io/docs/what-is-grpc/core-concepts/ | 两页全文精读 |
| S6 | 搜索级旁证:各 LLM 提供商用 SSE 做 token 流;AWS "gRPC requires HTTP/2, REST typically uses HTTP/1.1";SmartDev "REST fits public/partner-facing APIs" | dev.to/pockit_tools《The Complete Guide to Streaming LLM Responses》、dev.to/martin_palopoli《End-to-End SSE Through Nginx》、dev.to/usman_khan_io《Memory Leaks and Socket Starvation in High-Throughput LLM Streaming》等 | 仅搜索摘要,未全文精读 |
| S7 | Medium《Streaming LLM Responses in Go: SSE vs WebSockets》 | https://medium.com/@erwindev/streaming-llm-responses-in-go-server-sent-events-vs-websockets-5175c300a05e | 抓取失败(连接超时),仅从搜索摘要获取结论,未精读 |
1. 一句话画像:五种风格到底在比什么
| 风格 | 本质交互模型 | 一句话 |
|---|---|---|
| REST | 围绕资源组织通信 | URL 定址资源,HTTP 动词操作它,缓存与生态是最大红利 |
| GraphQL | 围绕查询组织通信 | 客户端声明数据形状,服务端"只解析被请求的字段" |
| gRPC | 围绕方法组织通信 | 强类型过程调用,proto 契约 + HTTP/2 + 二进制消息 |
| SSE | 服务器单向推送事件流 | 一条长开的 HTTP 响应,持续 text/event-stream 文本事件 |
| WebSocket | 全双工消息通道 | 协议升级握手后,两端可同时互发帧,有状态长连接 |
关键提醒(S1):REST/GraphQL/gRPC 与 SSE/WebSocket 不是同一层的比较——前者是API 组织风格(怎么建模交互),后者是传输/推送通道(数据怎么流动)。一个 LLM 聊天服务完全可以"REST 风格的 POST + SSE 响应流"组合。MCP(S2)恰好示范了这一点:消息层用 JSON-RPC(类 gRPC 的 RPC 风格),传输层用 stdio 或"HTTP POST + 可选 SSE"。
2. 逐来源精读
S1. REST vs GraphQL vs gRPC(Level Up Coding)
核心论点:三者解决的是不同的通信问题,错误的不是选错,而是选了一个到处用。
三种风格各自"组织通信"的方式(S1 原文,经 WebFetch 提取):
- REST — "Organizes communication around resources"(围绕资源组织通信)
- GraphQL — "Organizes communication around queries",客户端指定精确的数据形状,"the server resolves only those fields"(服务端只解析被请求的字段),并对着一份类型化 schema 校验,schema 是共享契约
- gRPC — "Organizes communication around methods",服务暴露 "strongly typed procedures that other services call directly over HTTP/2 using compact binary messages"(强类型过程,经 HTTP/2 以紧凑二进制消息直接调用),网络调用感觉像本地函数调用
优劣清单(S1):
| 风格 | 优势 | 劣势 |
|---|---|---|
| REST | 浏览器可达(标准 HTTP);GET 可被 CDN/代理缓存;简单;公开 API 友好(易检视/调试) | 组合性差:一屏要多个资源时需多次往返;端点肥大导致 over-fetching |
| GraphQL | 字段级灵活选择(避免 over/under-fetching);强 schema 自动生成类型;组合性好(一屏一查询);前端独立演进 | 服务端成本:resolver 可能触发大量数据库调用;必须控制 "query depth, batching, and caching"(查询深度、批处理与缓存);单端点使授权变复杂 |
| gRPC | 强契约(.proto);二进制载荷高效;HTTP/2 多路复用与持久连接;单向/双向流;内建 deadline、重试、健康检查 | 浏览器兼容:需 gRPC-Web 加边缘代理;对公开 API 有摩擦 |
S1 的选型建议(原文):
- REST:"when stability, simplicity, and web infrastructure matter more than fine-grained data control"(当稳定性、简单性和 Web 基础设施比细粒度数据控制更重要时)
- GraphQL:"when client data needs vary frequently"(当客户端数据需求频繁变化时)
- gRPC:"for internal service communication"(用于内部服务间通信)
S1 的点睛引述(逐字):
"An API style is really a tradeoff between flexibility, simplicity, efficiency, and control."
(API 风格本质上是灵活性、简单性、效率与控制力之间的权衡。)
"The trap isn't choosing the wrong one. It's choosing one and using it everywhere."
(陷阱不在于选错了哪个,而在于选了一个然后到处都用它。)
"Most production systems do not choose a single API style. They choose boundaries."
(大多数生产系统并不选择单一 API 风格,而是选择边界。)
S1 的结论架构:混合分层。 边缘(浏览器/移动端/第三方)用 REST 或 GraphQL;内部用 gRPC(protobuf + deadline-aware calls)。示例:目录服务走 REST 过 CDN 缓存,移动端走 GraphQL 聚合层,内部服务走 gRPC。三者是互补的层次,不是竞争的哲学。
注意(S1 局限): 该文完全定性,无任何基准数字;宣称二进制载荷"比 JSON 更小更快"但未给测量。
S5. gRPC 官方文档(Introduction + Core concepts)
定义(逐字):
"In gRPC, a client application can directly call a method on a server application on a different machine as if it were a local object"
(客户端可以直接调用另一台机器上服务端应用的方法,就像调用本地对象一样。)
- 默认用 Protocol Buffers 同时作为 IDL 与消息交换格式;"gRPC can use protocol buffers as both its Interface Definition Language (IDL) and as its underlying message interchange format"
- 客户端持有一个 stub("a local object known as stub"),实现与服务端相同的方法;protoc + gRPC 插件生成客户端/服务端桩代码与序列化代码
- 跨语言互操作:"you can easily create a gRPC server in Java with clients in Go, Python, or Ruby"
四种 RPC 方法类型(逐字,来自 Core concepts 页):
| 类型 | 原文描述 |
|---|---|
| Unary | "the client sends a single request to the server and gets a single response back, just like a normal function call."(一问一答,像普通函数调用) |
| Server streaming | 客户端一请求,"gets a stream to read a sequence of messages back";"gRPC guarantees message ordering within an individual RPC call."(单 RPC 内保证消息顺序) |
| Client streaming | 客户端 "writes a sequence of messages and sends them to the server, again using a provided stream." |
| Bidirectional streaming | "both sides send a sequence of messages using a read-write stream",两条流 "operate independently",各自保序、读写随意 |
内建能力(逐字要点):
- Deadline:客户端可指定 "how long they are willing to wait for an RPC to complete",超时得 DEADLINE_EXCEEDED;服务端可查询剩余时间
- Cancellation:"Either the client or the server can cancel an RPC at any time",且 "Changes made before a cancellation are not rolled back"(取消不回滚——写工具逻辑时要自己保证幂等/补偿)
- Metadata:"information about a particular RPC call (such as authentication details)" 的键值对;键不得以
grpc-开头(保留);二进制值键以-bin结尾 - 终止语义:"both the client and server make independent and local determinations of the success of the call, and their conclusions may not match"(双方各自判定成功与否,结论可能不一致——分布式调用必须幂等)
S2. MCP 规范 Transports(Agent 工具服务的事实标准)
消息层:JSON-RPC。 规范第一句:"MCP uses JSON-RPC to encode messages. JSON-RPC messages MUST be UTF-8 encoded."
传输层:两种标准传输 + 自定义。
- stdio:"The client launches the MCP server as a subprocess",客户端写 stdin、服务端写 stdout;消息按行分隔、不得含内嵌换行;stdout 只许写合法 MCP 消息;"Clients SHOULD support stdio whenever possible."
- Streamable HTTP(2025-03-26 起取代旧的 HTTP+SSE 传输):服务端"operates as an independent process that can handle multiple client connections"。规范原文要点:
"Server can optionally make use of Server-Sent Events (SSE) to stream multiple server messages. This permits basic MCP servers, as well as more feature-rich servers supporting streaming and server-to-client notifications and requests."
- 单端点:"The server MUST provide a single HTTP endpoint path … that supports both POST and GET methods"(如
https://example.com/mcp) - 上行:每条 JSON-RPC 消息各发一个 HTTP POST;Accept 头必须同时列
application/json与text/event-stream - 下行两种形态:服务端对 POST 可回
application/json(单对象)或text/event-stream(SSE 流),客户端必须都支持 - 服务器主动消息:客户端可对端点发 GET 开 SSE 流,接收与当前请求无关的服务器发起请求/通知;无则回 405
- 多连接约束:"it MUST NOT broadcast the same message across multiple streams"(同一消息只发一条流)
- 断线与重投:SSE 事件可带
id;断线不算取消("Disconnection SHOULD NOT be interpreted as the client cancelling its request"),取消要显式发CancelledNotification;重连用Last-Event-ID头从游标续传,且服务端"MUST NOT replay messages … on a different stream" - 会话:
Mcp-Session-Id头(初始化时下发);"SHOULD be globally unique and cryptographically secure";终止发 DELETE;收到 404 则重新初始化 - 版本头:HTTP 上所有后续请求必须带
MCP-Protocol-Version: 2025-06-18 - 安全警告(逐字):"Servers MUST validate the
Originheader on all incoming connections to prevent DNS rebinding attacks";本地应只绑 127.0.0.1;"Without these protections, attackers could use DNS rebinding to interact with local MCP servers from remote websites." - 自定义传输:"The protocol is transport-agnostic and can be implemented over any communication channel that supports bidirectional message exchange"——但必须保持 JSON-RPC 消息格式与生命周期要求
对我们的含义: MCP 的消息层是 RPC 风格(不是资源风格),传输层是"HTTP POST + 可选 SSE 推送"——它把 gRPC 的"方法调用"心智模型、SSE 的"服务器推送"能力、HTTP 的基础设施兼容性缝合在一起,且刻意不用 WebSocket。
S3. SSE vs WebSocket(dev.to 精读,含评论区勘误)
两者技术分野(逐字):
- WebSocket:"Both the client and the server can shout at each other simultaneously."(全双工:客户端与服务端可同时互喊)
- SSE:"The server keeps a standard HTTP connection open and pushes text-based events down to the client."(服务端保持一条标准 HTTP 连接,向下推送文本事件)
WebSocket 的四类基础设施成本(S3):
| 成本 | 原文要点 |
|---|---|
| 有状态扩展 | 水平扩展需要 "connection-aware routing (sticky sessions)"(粘性会话) |
| 代理/防火墙 | "Aggressive corporate proxies and firewalls frequently drop WebSocket protocol upgrades, leaving connections in failure modes that are notoriously hard to debug."(企业代理常丢协议升级,故障模式极难调试) |
| 内存 | 每连接因 "bidirectional frame buffers and tracking protocol state" 而 "consumes significantly more server memory" |
| 重连 | "No Native Reconnect"——断线检测/退避/重试全要自己写;SSE 的 EventSource "automatically attempts to reconnect on its own" 并带 Last-Event-ID 续传 |
SSE 的扩展心智:"is just a long-lived HTTP request, it scales like any other HTTP endpoint"——它就是一条长 HTTP 请求,按普通 HTTP 端点的方式扩展。
S3 的判断阈值: 只有当客户端需要在流进行中高频回推(文中阈值:"10+ times per second")时才需要 WebSocket——典型是聊天室、多人游戏、协作文档(如 Google Docs)。
S3 点睛引述(逐字):
"for about 90% of modern web applications—including AI chat streaming, live dashboards, and notification feeds—WebSockets are massive overkill."
(对约 90% 的现代 Web 应用——包括 AI 聊天流、实时面板、通知流——WebSocket 都是大材小用。)
"WebSockets and SSE aren't competitors; they solve different shapes of problems."
(WebSocket 与 SSE 不是竞品,它们解决不同形状的问题。)
"don't immediately reach for the heaviest tool in the box"
(别一上来就伸手拿工具箱里最重的那个。)
评论区勘误(重要工程细节,S3 独有): 该文示例代码没发 id: 行,浏览器就不会带 Last-Event-ID——自动重连仍会触发,但续传不会。更深一层:即使补了 id:,服务端还必须真读这个头并从缓冲区重放;用 Date.now() 当事件 id 会让续传难以实现(应使用单调序列号);没有重放逻辑却宣称可续传,"the header became honest and the stream became duplicating"(头变诚实了,流却开始重复)——比不宣称续传更糟。
S4. Anthropic《Writing effective tools for agents》(工具服务的设计学)
定位(逐字):
"Tools are a new kind of software which reflects a contract between deterministic systems and non-deterministic agents."
(工具是一种新型软件:它体现的是确定性系统与非确定性 Agent 之间的契约。)
其核心主张:不该"按写给人类开发者的函数和 API 的方式"写工具与 MCP server,而要为 Agent 设计(原文:"instead of writing tools and MCP servers the way we'd write functions and APIs for other developers… we need to design them for agents",该引述经提取工具轻微压缩,语义完整)。
五条原则(S4):
- 选对要实现的工具(和不要实现的):"More tools don't always lead to better outcomes."(工具多≠效果好);把 1:1 包装原始 API 端点是常见错误
- 命名空间划边界:相关工具用公共前缀,如
asana_search、asana_projects_search;但前缀 vs 后缀命名对评测有 "non-trivial effects" 且因模型而异——用自家评测定方案 - 返回有意义的上下文:避免
uuid、256px_image_url、mime_type这类低层技术标识;改用name、image_url、file_type;把任意 UUID 解析成自然语言标识符,"significantly improves Claude's precision in retrieval tasks by reducing hallucinations"(显著提升检索精度、减少幻觉) - token 效率:实现分页、范围选择、过滤、截断并给合理默认值;"Claude Code caps tool responses at 25,000 tokens by default";错误信息要可执行,而非裸错误码/堆栈
- 描述当文档写:像给新同事做 onboarding 一样写工具描述;参数名要无歧义——"instead of a parameter named user, try a parameter named user_id";"Even small refinements to tool descriptions can yield dramatic improvements."
响应格式:没有万能答案(逐字): "there is no one-size-fits-all solution"——XML/JSON/Markdown 都可能影响评测表现,LLM 对接近训练数据分布的格式表现更好,应基于自己的评测选;推荐暴露 response_format 枚举(concise/detailed)让 Agent 自选详细度,Slack 示例中简洁模式约省 2/3 token。
工具整合(与 Agent 工具服务选型直接相关,逐字):
"Instead of implementing a list_users, list_events, and create_event tools, consider implementing a schedule_event tool"
(与其实现 list_users、list_events、create_event 三个工具,不如实现一个 schedule_event 工具。)
以及:"Too many tools or overlapping tools can also distract agents from pursuing efficient strategies."(工具太多或互相重叠会让 Agent 分心,不去走高效路径。)
3. 五风格横向对比表(综合 S1–S6)
| 维度 | REST | GraphQL | gRPC | SSE | WebSocket |
|---|---|---|---|---|---|
| 交互模型 | 资源 + 动词 | 查询 + 类型化 schema | 方法(过程调用) | 服务器单向事件流 | 全双工消息帧 |
| 底层 | HTTP/1.1 为主(S6:AWS 称 gRPC 需 HTTP/2、REST 通常 1.1) | HTTP POST(单端点) | HTTP/2 | 一条长开 HTTP 响应 | TCP 协议升级握手 |
| 数据格式 | JSON 为主 | JSON | protobuf 二进制(可换) | text/event-stream 文本 | 帧(文本/二进制,自定协议) |
| 契约 | OpenAPI(可选、弱约束) | schema(强、自校验) | .proto(最强,生成桩代码) | 无(只有事件流约定) | 无(协议自定) |
| 流式能力 | 无原生流(轮询/分块凑合) | Subscription(实现复杂) | 四种:unary/server/client/bidi | 单向(服务端→客户端) | 双向 |
| 缓存 | HTTP 原生(CDN/代理/GET) | 难(单端点 POST) | 难(需自建) | 无业务缓存语义 | 无 |
| 浏览器支持 | 原生 | 原生 | 需 gRPC-Web + 边缘代理(S1) | 原生 EventSource | 原生 WebSocket API |
| 自动重连 | — | — | 内建重试/deadline(S1) | 内建 + Last-Event-ID 续传(S3) | 需完全自建(S3:"No Native Reconnect") |
| 水平扩展 | 无状态,易 | 无状态,易 | 需 LB 支持 HTTP/2 | 无状态,"像普通 HTTP 端点一样扩展"(S3) | 有状态,需粘性会话(S3) |
| 代理/防火墙友好度 | 高 | 高 | 中(HTTP/2 一般可行) | 高(就是 HTTP) | 低(升级常被企业代理丢弃,S3) |
| 典型场景 | 公开 API、CDN 分发 | 聚合多资源的前端/移动端 | 内部微服务、低延迟高吞吐 | token 流、通知、面板推送 | 语音双向、协作、多人游戏 |
表中 SSE 与 WebSocket 两列的知识基础来自 S3 全文精读;REST/GraphQL/gRPC 列来自 S1、S5;标注 S6 的条目仅有搜索摘要级证据。
4. Agent 工具服务选型表(本次精读的核心交付)
先明确两层决策:(a) 工具服务用什么协议风格暴露;(b) Agent 会话本身的流式通道用什么。 两层可以混搭,而且通常应该混搭。
4.1 工具服务层( Agent 调工具 )
| Agent 场景 | 推荐 | 理由(对应证据) | 证据 |
|---|---|---|---|
| 本机 CLI Agent 调本地工具进程(如文件、Git、本地脚本) | MCP over stdio | 规范首选:"Clients SHOULD support stdio whenever possible";子进程模型零网络开销 | S2 |
远程/共享工具服务,要被多客户端复用、需要工具发现(tools/list)与标准化调用(tools/call) | MCP over Streamable HTTP | 单端点 + JSON-RPC 2.0 + 可选 SSE 服务器推送 + 会话/续传/版本协商全部内置 | S2 |
| Agent 高频调用自家内部微服务(每次工具调用都过网络、低延迟敏感、多语言栈) | gRPC | 强类型 proto 契约、二进制高效载荷、deadline/重试/健康检查内建;"for internal service communication" | S1、S5 |
| Agent 需要在一次工具调用内持续收流(长查询、日志 tail、批量进度) | gRPC server streaming 或 MCP SSE 流 | gRPC 单 RPC 内保证消息顺序;MCP 的 POST 可升级为 SSE 流且支持 Last-Event-ID 续传 | S5、S2 |
| 面向第三方开发者的公开能力(让别人的 Agent/应用接入你的服务) | REST | "stability, simplicity, and web infrastructure matter more than fine-grained data control";生态/调试/缓存红利 | S1、S6(SmartDev:REST fits public/partner-facing APIs) |
| 工具响应喂给 LLM 上下文(任何上述协议) | 遵循 S4 原则改造接口 | 少而整合的工具、namespace、自然语言标识符、分页/截断、可执行错误——这些与传输协议无关 | S4 |
4.2 Agent 会话层(用户 ↔ Agent 的交互通道)
| 场景 | 推荐 | 理由 | 证据 |
|---|---|---|---|
| 普通聊天:prompt 进、token 流出 | SSE | 单向推送正合模型;行业事实标准(OpenAI/Anthropic 等均用 SSE,S6);取消生成 = 中止 HTTP 请求(S6 搜索摘要) | S3、S6 |
| 实时语音 Agent(需要 barge-in 打断、流中途双向互动) | WebSocket(或内部 gRPC 双向流) | 只有客户端需要在生成过程中持续回推时才上 WS;S3 阈值:每秒 10 次以上回推 | S3、S6 |
| 长任务进度/服务器主动通知(工具后台跑,Agent 服务器要推事件) | SSE 或 MCP Streamable HTTP 的 GET-SSE 流 | 服务器→客户端单向;MCP 规范把这条通道标准化了(含续传) | S2、S3 |
| 多人协作式 Agent 看板/共享状态编辑 | WebSocket | 高频双向、有状态会话是 WS 的主场 | S3 |
| 前端聚合多数据源渲染复杂界面 | 边缘放 GraphQL(与流通道无关) | 一屏一查询,避免 over-fetching;但 S1 提醒 resolver 成本与授权复杂度 | S1 |
4.3 选型速判(三条心法,均有原文支撑)
- 先问方向,再问风格。 交互是"客户端拉"还是"服务器推"?单向用 REST/RPC + SSE,双向高频才用 WebSocket/gRPC bidi。——S3:"WebSockets and SSE aren't competitors; they solve different shapes of problems."
- 按边界组合,不要全线统一。 ——S1:"Most production systems do not choose a single API style. They choose boundaries." 典型生产组合:边缘 REST/GraphQL + 内部 gRPC + 面向 Agent 的 MCP(JSON-RPC)+ 会话层 SSE。
- Agent 工具不等于人类 API 的缩水版。 ——S4:"Tools are a new kind of software which reflects a contract between deterministic systems and non-deterministic agents." 工具数量、命名、响应形状都按 Agent 的评测来定,而不是照搬 REST 资源建模。
4.4 一个值得注意的信号:为什么 MCP 不用 WebSocket
MCP 旧版(2024-11-05)传输是 HTTP+SSE,新版(2025-03-26 起)改为 Streamable HTTP,仍以"HTTP POST + 可选 SSE"为核心(S2)。结合 S3/S6 可还原其设计逻辑:Agent 与工具服务的消息模式是客户端发起请求 + 服务端偶尔主动推送,这恰好落在 SSE 的能力甜区;WebSocket 的全双工、有状态连接在此是纯负担(粘性会话、代理不友好、无原生重连)。而双向性需求由"多个短 POST + 独立 GET-SSE 流"的组合满足,还顺带获得了 HTTP 基础设施(鉴权、负载均衡、续传头)的全部兼容性。
5. 七维提取(主题整体)
5.1 核心问题
为一个系统(尤其是带 Agent 的系统)选择 API 风格时,如何在灵活性、简单性、效率、控制力之间做权衡(S1),并把"交互建模风格(REST/GraphQL/gRPC)"与"推送通道(SSE/WebSocket)"两个正交决策分开,再落到 Agent 工具服务的具体工程选择上。
5.2 主要主张
- 五种风格解决不同形状的问题,错误用法是"选一个用到底"(S1:"The trap isn't choosing the wrong one. It's choosing one and using it everywhere.")。
- 生产系统的答案是按边界混合:边缘 REST/GraphQL、内部 gRPC、会话推送 SSE(S1 + S3 + S6)。
- 对 LLM 应用,SSE 是默认选项,WebSocket 只在生成过程中需要客户端高频回推时使用(S3:"…WebSockets are massive overkill";S6:各主流 LLM API 皆用 SSE)。
- Agent 工具服务的通用底座是 MCP:JSON-RPC 2.0 消息 + stdio/Streamable HTTP 传输(S2),它验证了"RPC 心智 + SSE 推送 + HTTP 兼容"的混搭在 Agent 语境下是主流路线。
- 工具接口的设计原则独立于传输协议:少而整合、命名空间、自然语言标识符、token 效率、可执行错误(S4)。
5.3 方法
对比分析(S1 五风格逐维度表)、规范文本精读(S2、S5 官方规范级证据)、工程实战复盘(S3 含评论区勘误)、厂商一手工程经验(S4,Anthropic 自家评测结论)。本次笔记采用五来源交叉验证:同一结论(如"SSE 适合 LLM 流")至少有两处独立来源(S3 全文精读 + S6 搜索级多文)。
5.4 数据与证据
- 规范级(最强):S2 MCP 规范原文对 Streamable HTTP 的 MUST/SHOULD 级要求(单端点、Accept 双类型、Origin 校验、Last-Event-ID 续传、Mcp-Session-Id);S5 gRPC 四种流式与 deadline/cancellation 语义的官方定义。
- 定性论证(中):S1 三风格优劣清单与边界论;S3 的 WS 四类基础设施成本与"90% 应用过度"论断;S4 的 token 效率数据点(Claude Code 工具响应默认上限 25,000 token;Slack 简洁模式约省 2/3 token)。
- 搜索级(弱,未精读):S6 中"主流 LLM 提供商均采用 SSE"、AWS"REST 通常 HTTP/1.1 / gRPC 需 HTTP/2"、Nginx SSE 缓冲与无界缓冲区内存泄漏等生产坑。
- 缺口:全部来源均无跨风格端到端延迟/吞吐基准;gRPC "二进制比 JSON 更快更小"仅是常识级宣称(S1 自认无数字);GraphQL resolver N+1 问题只有定性描述无量化。
5.5 结论
选型不是单选题而是分层组合题:① 工具服务层——本地用 MCP stdio,远程/多客户端用 MCP Streamable HTTP,内部高频走裸 gRPC,对第三方开放走 REST;② 会话层——token 流/进度推送用 SSE(行业事实标准,基础设施全兼容),仅语音级双向或高频回推才上 WebSocket/gRPC 双向流;③ 工具的"内容设计"(数量、命名、响应形状)按 S4 原则做,与协议选择正交且同样影响 Agent 表现。
5.6 局限
- 证据局限:无定量基准(S1 明示定性;S2/S5 是规范不涉及性能);S6/S7 仅有搜索摘要级证据,其中 S7(Medium SSE vs WebSocket in Go)抓取超时未能精读,其结论只经搜索摘要转述。
- 来源局限:S3 是个人博客(dev.to),其"90%""10+ 次/秒"为经验值而非测量;评论区勘误说明此类文章的代码示例可能有坑,不能照抄。
- 时效局限:MCP 传输规范以 2025-06-18 版为准,旧 HTTP+SSE 传输已弃用但仍在兼容期;S4 的评测结论(前缀命名、response_format)明确说"因模型而异",换了模型需重测。
- 范围局限:未覆盖 GraphQL Subscription 的工程细节、gRPC-Web 的具体代理配置、SSE 在 HTTP/1.1 下每域 6 连接限制(S3 精读提取明确说"未讨论");未对比 HTTP/3/QUIC 对 WS/SSE 的影响(超出全部来源范围)。
- 推断声明:4.4 节"MCP 为何不用 WebSocket"是从 S2 + S3/S6 还原的设计逻辑推断,规范原文未给动机说明——这是我的推断,不是规范声明。
5.7 对我的启发
- 给 Agent 项目选型时,默认组合直接抄 MCP 的答案:JSON-RPC 风格消息 + stdio(本地)/ Streamable HTTP + SSE(远程),不要为"新技术冲动"上 WebSocket——S2 与 S3/S6 形成闭环证据。
- 工具设计比传输协议更影响 Agent 效果(S4):把 1:1 包装 REST 端点改成聚合工具(如
schedule_event代替list_users+list_events+create_event)、给响应加response_format开关、UUID 换自然语言名——这些是零协议成本的收益,值得在任何现有工具上先做。 - 写 SSE 续传要一次做对(S3 勘误):
id:行 + 单调序列号 + 服务端缓冲重放,三者缺一不可;宣称可续传却不重放比不宣称更糟。 - "选择边界"可以直接落成架构图(S1):以后评审 API 设计文档时,先问三件事——这个接口的消费者是谁(浏览器/第三方/内部服务/Agent)?数据形状会不会频繁变?有没有服务器→客户端的推送需求?三问答完,风格基本自选。
- 取消语义要在工具层显式设计(S5):gRPC "取消不回滚"、"双方各自判定成败"提醒我:Agent 工具调用必须是幂等的,长任务要有取消通知(MCP 的
CancelledNotification)与补偿路径。
6. 重要原文引述汇总(速查)
| # | 引述(逐字) | 来源 |
|---|---|---|
| 1 | "An API style is really a tradeoff between flexibility, simplicity, efficiency, and control." | S1 |
| 2 | "The trap isn't choosing the wrong one. It's choosing one and using it everywhere." | S1 |
| 3 | "Most production systems do not choose a single API style. They choose boundaries." | S1 |
| 4 | "In gRPC, a client application can directly call a method on a server application on a different machine as if it were a local object" | S5 |
| 5 | "both sides send a sequence of messages using a read-write stream"(gRPC 双向流) | S5 |
| 6 | "MCP uses JSON-RPC to encode messages. JSON-RPC messages MUST be UTF-8 encoded." | S2 |
| 7 | "Server can optionally make use of Server-Sent Events (SSE) to stream multiple server messages." | S2 |
| 8 | "Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks" | S2 |
| 9 | "for about 90% of modern web applications—including AI chat streaming, live dashboards, and notification feeds—WebSockets are massive overkill." | S3 |
| 10 | "WebSockets and SSE aren't competitors; they solve different shapes of problems." | S3 |
| 11 | "Aggressive corporate proxies and firewalls frequently drop WebSocket protocol upgrades, leaving connections in failure modes that are notoriously hard to debug." | S3 |
| 12 | "Tools are a new kind of software which reflects a contract between deterministic systems and non-deterministic agents." | S4 |
| 13 | "More tools don't always lead to better outcomes." | S4 |
| 14 | "Instead of implementing a list_users, list_events, and create_event tools, consider implementing a schedule_event tool" | S4 |
| 15 | "Too many tools or overlapping tools can also distract agents from pursuing efficient strategies." | S4 |
| 16 | "there is no one-size-fits-all solution"(工具响应格式) | S4 |
7. 本次学到什么
- 把"风格"与"通道"两个正交决策拆开,选型题就从五选一变成两次二选一,错误率骤降;MCP 规范本身就是这个拆法的活标本(JSON-RPC 消息层 × stdio/HTTP+SSE 传输层)。
- 推送通道的默认答案是 SSE,不是 WebSocket——判断标准只有一条:生成/推送进行中,客户端要不要高频回推。
- Agent 工具是"确定性系统与非确定性 Agent 的契约":协议选型只解决"怎么传",工具的数量、命名、响应形状决定 Agent"用得好不好",后者往往收益更大且成本更低。
- 规范文档(MUST/SHOULD/MAY)是最便宜的一手证据:比博客对比文可靠一个量级,精读优先级应最高。