读书笔记 · 约 20,274 字 · 预计推送 3 部分

API 设计风格对比:REST、GraphQL、gRPC、SSE、WebSocket —— 结合 Agent 工具服务给出选型表(精读笔记) 未开始

目录

题记与说明

精读日期:2026-10-31
唯一前缀:knowledge-fexxiou8-1
精读方式:网络可用,共精读 5 个来源(WebFetch 全文抓取并提取原文引述),另有 3 组搜索级结果作为旁证(已标注精读级别)。
注:本次精读对象多为"对比指南/规范/工程博客"而非学术论文,因此"数据与证据"维度多为定性论证与规范原文,定量基准数据普遍缺失(已在局限中标注)。

0. 来源清单与精读级别

#来源链接精读级别
S1REST vs GraphQL vs gRPC — Level Up Coding (Nikki Siapno)https://blog.levelupcoding.com/p/rest-vs-graphql-vs-grpc全文精读
S2MCP 规范:Transports(2025-06-18 版)https://modelcontextprotocol.io/specification/2025-06-18/basic/transports全文精读
S3Stop 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全文精读(含评论区勘误)
S4Writing effective tools for agents — Anthropic Engineering (2025-09-11)https://www.anthropic.com/engineering/writing-tools-for-agents全文精读
S5gRPC 官方文档:Introduction + Core conceptshttps://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》等仅搜索摘要,未全文精读
S7Medium《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 提取):

优劣清单(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 的选型建议(原文):

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"
(客户端可以直接调用另一台机器上服务端应用的方法,就像调用本地对象一样。)

四种 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",各自保序、读写随意

内建能力(逐字要点):

S2. MCP 规范 Transports(Agent 工具服务的事实标准)

消息层:JSON-RPC。 规范第一句:"MCP uses JSON-RPC to encode messages. JSON-RPC messages MUST be UTF-8 encoded."

传输层:两种标准传输 + 自定义。

  1. stdio:"The client launches the MCP server as a subprocess",客户端写 stdin、服务端写 stdout;消息按行分隔、不得含内嵌换行;stdout 只许写合法 MCP 消息;"Clients SHOULD support stdio whenever possible."
  2. 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."

对我们的含义: MCP 的消息层是 RPC 风格(不是资源风格),传输层是"HTTP POST + 可选 SSE 推送"——它把 gRPC 的"方法调用"心智模型、SSE 的"服务器推送"能力、HTTP 的基础设施兼容性缝合在一起,且刻意不用 WebSocket。

S3. SSE vs WebSocket(dev.to 精读,含评论区勘误)

两者技术分野(逐字):

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):

  1. 选对要实现的工具(和不要实现的):"More tools don't always lead to better outcomes."(工具多≠效果好);把 1:1 包装原始 API 端点是常见错误
  2. 命名空间划边界:相关工具用公共前缀,如 asana_search、asana_projects_search;但前缀 vs 后缀命名对评测有 "non-trivial effects" 且因模型而异——用自家评测定方案
  3. 返回有意义的上下文:避免 uuid、256px_image_url、mime_type 这类低层技术标识;改用 name、image_url、file_type;把任意 UUID 解析成自然语言标识符,"significantly improves Claude's precision in retrieval tasks by reducing hallucinations"(显著提升检索精度、减少幻觉)
  4. token 效率:实现分页、范围选择、过滤、截断并给合理默认值;"Claude Code caps tool responses at 25,000 tokens by default";错误信息要可执行,而非裸错误码/堆栈
  5. 描述当文档写:像给新同事做 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)

维度RESTGraphQLgRPCSSEWebSocket
交互模型资源 + 动词查询 + 类型化 schema方法(过程调用)服务器单向事件流全双工消息帧
底层HTTP/1.1 为主(S6:AWS 称 gRPC 需 HTTP/2、REST 通常 1.1)HTTP POST(单端点)HTTP/2一条长开 HTTP 响应TCP 协议升级握手
数据格式JSON 为主JSONprotobuf 二进制(可换)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 选型速判(三条心法,均有原文支撑)

  1. 先问方向,再问风格。 交互是"客户端拉"还是"服务器推"?单向用 REST/RPC + SSE,双向高频才用 WebSocket/gRPC bidi。——S3:"WebSockets and SSE aren't competitors; they solve different shapes of problems."
  2. 按边界组合,不要全线统一。 ——S1:"Most production systems do not choose a single API style. They choose boundaries." 典型生产组合:边缘 REST/GraphQL + 内部 gRPC + 面向 Agent 的 MCP(JSON-RPC)+ 会话层 SSE。
  3. 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 主要主张

  1. 五种风格解决不同形状的问题,错误用法是"选一个用到底"(S1:"The trap isn't choosing the wrong one. It's choosing one and using it everywhere.")。
  2. 生产系统的答案是按边界混合:边缘 REST/GraphQL、内部 gRPC、会话推送 SSE(S1 + S3 + S6)。
  3. 对 LLM 应用,SSE 是默认选项,WebSocket 只在生成过程中需要客户端高频回推时使用(S3:"…WebSockets are massive overkill";S6:各主流 LLM API 皆用 SSE)。
  4. Agent 工具服务的通用底座是 MCP:JSON-RPC 2.0 消息 + stdio/Streamable HTTP 传输(S2),它验证了"RPC 心智 + SSE 推送 + HTTP 兼容"的混搭在 Agent 语境下是主流路线。
  5. 工具接口的设计原则独立于传输协议:少而整合、命名空间、自然语言标识符、token 效率、可执行错误(S4)。

5.3 方法

对比分析(S1 五风格逐维度表)、规范文本精读(S2、S5 官方规范级证据)、工程实战复盘(S3 含评论区勘误)、厂商一手工程经验(S4,Anthropic 自家评测结论)。本次笔记采用五来源交叉验证:同一结论(如"SSE 适合 LLM 流")至少有两处独立来源(S3 全文精读 + S6 搜索级多文)。

5.4 数据与证据

5.5 结论

选型不是单选题而是分层组合题:① 工具服务层——本地用 MCP stdio,远程/多客户端用 MCP Streamable HTTP,内部高频走裸 gRPC,对第三方开放走 REST;② 会话层——token 流/进度推送用 SSE(行业事实标准,基础设施全兼容),仅语音级双向或高频回推才上 WebSocket/gRPC 双向流;③ 工具的"内容设计"(数量、命名、响应形状)按 S4 原则做,与协议选择正交且同样影响 Agent 表现。

5.6 局限

5.7 对我的启发

  1. 给 Agent 项目选型时,默认组合直接抄 MCP 的答案:JSON-RPC 风格消息 + stdio(本地)/ Streamable HTTP + SSE(远程),不要为"新技术冲动"上 WebSocket——S2 与 S3/S6 形成闭环证据。
  2. 工具设计比传输协议更影响 Agent 效果(S4):把 1:1 包装 REST 端点改成聚合工具(如 schedule_event 代替 list_users+list_events+create_event)、给响应加 response_format 开关、UUID 换自然语言名——这些是零协议成本的收益,值得在任何现有工具上先做。
  3. 写 SSE 续传要一次做对(S3 勘误):id: 行 + 单调序列号 + 服务端缓冲重放,三者缺一不可;宣称可续传却不重放比不宣称更糟。
  4. "选择边界"可以直接落成架构图(S1):以后评审 API 设计文档时,先问三件事——这个接口的消费者是谁(浏览器/第三方/内部服务/Agent)?数据形状会不会频繁变?有没有服务器→客户端的推送需求?三问答完,风格基本自选。
  5. 取消语义要在工具层显式设计(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. 本次学到什么

  1. 把"风格"与"通道"两个正交决策拆开,选型题就从五选一变成两次二选一,错误率骤降;MCP 规范本身就是这个拆法的活标本(JSON-RPC 消息层 × stdio/HTTP+SSE 传输层)。
  2. 推送通道的默认答案是 SSE,不是 WebSocket——判断标准只有一条:生成/推送进行中,客户端要不要高频回推。
  3. Agent 工具是"确定性系统与非确定性 Agent 的契约":协议选型只解决"怎么传",工具的数量、命名、响应形状决定 Agent"用得好不好",后者往往收益更大且成本更低。
  4. 规范文档(MUST/SHOULD/MAY)是最便宜的一手证据:比博客对比文可靠一个量级,精读优先级应最高。
← 资料库今日播报 →