Chapter 01

概念:它由什么组成

起点页给了概念地图和「一句话本质」。这一章把地图上的每个节点拆成可命名的零件——data plane、三类流量、请求路径四件套、backend 多态、横切策略。先建立词汇,02 章再讲它们怎么运转。

本章你将建立的 schema

  • data plane 与 control plane 的分工,以及网关为什么必须站在请求热路径上
  • LLM / MCP / A2A 三类流量各自的方向、协议、有无状态
  • 一条请求穿过网关的四件套:bind → listener → route → backend
  • backend 的三种形态(ai / mcp / a2a)如何把「流量类型」落到配置上
  • policy 作为横切关注点,挂在请求路径的哪些点

1.1Data plane 与 control plane

数据平面处理每一条真实流量;控制平面只下发配置和策略,不碰流量。

为什么需要它

网关要做两件性质完全不同的事:一是「现在这条请求该转给谁、要不要拦」——必须快、必须在线;二是「路由规则、密钥、限流额度长什么样」——可以慢、允许偶尔不可用。把这两件事塞进一个进程,等于让配置变更的风险压在流量热路径上。拆成两个平面,各自按自己的可靠性要求演化。

底层机制(比文档深一层):控制平面把高层意图——在 Kubernetes 里是 Gateway API 的 CRD,在单机是一份配置文件——翻译成数据平面能直接执行的低层规则,再推送给每个 proxy 实例。数据平面持有这份配置的本地副本,独立处理流量。关键推论:控制平面宕机时,数据平面仍按最后一次下发的配置继续转发——代价是这段时间内你改不了路由。agentgateway 在 K8s 模式下由 kgateway 充当控制平面,把 Gateway API 资源翻译成 agentgateway(数据平面)的配置;两者是分开的进程,甚至现在是分开的代码仓库。

类比 · 带边界声明

像剧院的导演和演员:导演(控制平面)排练时定好走位,演出时离场;演员(数据平面)按最后定好的走位现场表演。类比失效处:演员会即兴,数据平面不会——它只机械执行最后一次下发的配置,一个字都不会自己改。

Control Plane 翻译配置 + 下发 下发配置(不碰流量) 请求 Data Plane 处理每一条真实流量 持有配置本地副本 上游 控制平面宕机 → 数据平面仍按最后配置转发
图 1.1两个平面按不同可靠性要求各自演化。 注意:配置是虚线从上往下推的,流量是实线横着穿过数据平面——两条线不相交,正是「配置变更不压在流量热路径上」的可视化。
想一想

你把一条新的限流规则提交给控制平面,但控制平面此刻正好挂了。已经在途的请求会怎样?新规则会生效吗?

展开答案(先停 10 秒)

在途请求不受影响:它们由数据平面用本地副本处理,控制平面是否在线与之无关。新规则不会生效:它卡在控制平面侧,没能翻译并下发到数据平面。

这正是两平面解耦的设计意图——可用性(转发)和可变性(改配置)被刻意分到了不同的可靠性域。代价就是:配置变更的生效依赖控制平面在线。

与下一个概念的关系:数据平面处理的「真实流量」具体分三类。下一节给这三类命名。

1.2三类 agent 流量:LLM / MCP / A2A

Agent 网关治理三种流量:agent→模型(LLM)、agent→工具(MCP)、agent→agent(A2A)。

为什么需要它

这三类流量过去分属三套互不相干的基础设施:LLM 调用走各家 SDK,工具调用走 MCP client,agent 间协作走 A2A client。结果是鉴权、限流、可观测性这些横切关注点要在三处各实现一遍。把三类流量收进同一个网关,这些策略才能写一次、管三类。

底层机制(比文档深一层):三者协议形态差异很大,而网关的工作正是把差异收敛掉——

  • LLM:多是 OpenAI / Anthropic 风格的「一问一答」,可 streaming;请求体里带 model 名和 prompt,响应尾部带 usage(token 计数)。无跨请求状态。
  • MCP:JSON-RPC 2.0,有状态 session(靠 MCP-Session-Id 头跨多次交互维持),传输走 Streamable HTTP 或本地 stdio;一次会话里 agent 反复 tools/list、tools/call。
  • A2A:JSON-RPC over HTTPS,靠 Agent Card(对端在 /.well-known/agent-card.json 暴露的能力清单)发现彼此,再把任务作为有生命周期的 Task 委托过去。

网关把三者统一成「listener → route → backend」一套原语,把协议差异收敛到 backend 的类型上(见 §1.4)。这就是「一个数据平面同时讲三种协议」在工程上的落点。

agent 模型 LLM:OpenAI schema · 一问一答 · 无状态 agent 工具 server MCP:JSON-RPC · 有状态 session · 双向 agent 另一个 agent A2A:Agent Card 发现 · JSON-RPC · 委托 Task
图 1.2三类流量的方向不同:LLM 单向问答、MCP 双向有状态、A2A 先发现再委托。 注意:只有 MCP 那条线是双向箭头——它的 session 状态正是经典无状态网关最难承接的部分(02 章展开)。
例 · 一次任务里三类流量都出现

一个 coding agent 接到「修复这个 bug」:先调 LLM 规划步骤 → 调 MCP 工具读取仓库文件、跑测试 → 把「写文档」子任务通过 A2A 委托给一个专门的文档 agent。三段流量,全部经过同一个 agent 网关——鉴权、限流、trace 因此能串成一条线。

与下一个概念的关系:三类流量要被统一治理,得先有一套统一的「请求怎么穿过网关」的原语。下一节就是这套原语。

1.3请求路径四件套:bind → listener → route → backend

一条请求按 bind(端口)→ listener(入口)→ route(匹配)→ backend(上游)四步被处理。

为什么需要它

三类流量协议各异,但「进来 → 匹配 → 转出去」的骨架是共用的。把骨架固定成四件套,新增一类流量时只需要新增一种 backend,而不必重写入口和匹配逻辑。这套词汇也是你读懂任何 agent 网关配置的钥匙。

底层机制(比文档深一层):这是 agentgateway 当前 schema(binds 模型)的核心抽象。route 的 match 基于 path / header;backend 的 kind 决定请求走 LLM / MCP / A2A 哪条处理逻辑。四件套是层层包含的:一个 bind 下可挂多个 listener,一个 listener 下多条 route,一条 route 指向一个或一组 backend。

agentgateway 配置骨架(简化) YAML
binds:
  - port: 3000                 # bind:绑定端口
    listeners:
      - routes:                # listener:入口
          - matches:
              - path:
                  pathPrefix: /          # route:匹配规则
            backends:
              - ai:                       # backend:kind = ai(LLM)
                  provider: anthropic
请求 bind 端口绑定 listener 入口监听 route match 规则 backend 选上游 kind 上游
图 1.3三类流量共用这一条骨架,差异全部收敛到最后一步 backend 的 kind。 注意:只有 backend 是朱红高亮的——前三步对 LLM/MCP/A2A 完全一样,「讲哪种协议」是在 backend 这一步才分叉的。
陷阱 · schema 正在迁移

agentgateway 的配置 schema 处于迁移期:旧文档里的 listeners: / llm.providers: / target: 已被新的 binds: / backends: / ai: 取代。网上抄到老配置会跑不起来——以 binds 模型为准。这本身也是这个品类「还很年轻」的信号。

与下一个概念的关系:四件套的最后一步 backend 有三种形态,正是它把「三类流量」接回了「一套骨架」。

1.4Backend 多态:ai / mcp / a2a

同一种 route 可以指向三种 backend——ai(LLM 供应商)、mcp(工具 server)、a2a(其他 agent)。

为什么需要它

§1.3 的骨架要对三类流量都成立,差异就得有个地方安放。backend 的 kind 就是这个安放点:它决定网关「怎么解析这条请求的 body、能对它用哪些策略」。这是「一个数据平面三种协议」从口号变成配置字段的地方。

底层机制(比文档深一层):不同 kind 的 backend,网关对它的「理解能力」不同——

  • ai backend:知道怎么读 OpenAI 风格 body 里的 model 字段、怎么从响应里抽 usage 做 token 计量、怎么把统一 schema 翻译成各家供应商的私有格式。
  • mcp backend:知道怎么向多个后端 MCP server 扇出 tools/list、把工具名加前缀防冲突、按前缀把 tools/call 路由回正确的 server。
  • a2a backend:知道怎么拉取对端 Agent Card、按能力路由、在 agent 之间做鉴权。

换句话说:backend kind 不只是「转给谁」,而是「以哪种协议的语义去看待这条流量」。同一段字节,在 ai backend 眼里是一次模型调用,在 mcp backend 眼里是一次工具调用——解析方式和可用策略随之不同。具体怎么实现,是 02 章的主题。

类比 · 带边界声明

像同一个收银台贴三种结算标签:扫码、刷卡、现金。顾客走的是同一条排队动线(四件套),但收银员看到标签后用不同流程结算(backend kind)。类比失效处:结算方式之间没有共享状态,而 MCP backend 要维护跨调用的 session——它比「结算方式」更重。

想一想

同样一段 HTTP POST body,为什么 ai backend 和 mcp backend 会以完全不同的方式处理它?网关是靠 body 里的什么来区分的吗?

展开答案(先停 10 秒)

不是靠「猜 body 内容」来区分,而是靠配置:这条 route 在配置里被声明指向哪种 kind 的 backend,网关就用哪种协议语义去解析。是配置决定了「以什么眼光看这段字节」,不是字节自己声明身份。

这点很关键——它意味着同一个端口/路径,改一下 backend kind,网关的整个解析与策略链就换了一套。路由依据(model/prompt/tool)虽在 body 里,但「该用哪套语义读 body」是配置先定的。

与下一个概念的关系:四件套和 backend 解决了「流量怎么进出」。但鉴权、限流、guardrails 这些不属于任何单一 backend——它们横切三类流量,需要单独的挂载点。

1.5Policy:横切关注点的挂载点

policy 是挂在请求路径某个点上的策略——鉴权、限流、guardrails、可观测性。

为什么需要它

「请求要先过鉴权、再查限流额度、可疑内容要拦」这些规则,对 LLM、MCP、A2A 三类流量都适用。若写进每个 backend,就要重复三遍且容易写歪。抽成 policy 挂在路径的固定点上,一处定义、三类复用。

底层机制(比文档深一层):policy 按挂载位置分两类——

  • frontend 侧(靠近客户端入口):CORS、客户端认证等,决定「这个调用方能不能进来」。
  • backend 侧(靠近上游):backendAuth 注入访问上游所需的凭据、RBAC / OPA 做工具级授权,决定「这条请求能不能碰这个上游 / 这个工具」。

guardrails(防 prompt 注入、PII 脱敏)是一类特殊 policy:它不在单点运行,而在请求生命周期的多个闸口上各跑一次——输入时、构造 prompt 时、工具调用时、输出时。为什么要四道闸而不是一道,是 02 章的核心机制之一。

类比 · 带边界声明

像机场的安检、海关、登机口:它们不属于任何一架飞机,是横切所有航班的检查点,旅客(请求)按动线依次通过。类比失效处:机场每道检查只过一次,而 guardrails 要在同一条请求的多个阶段反复检查——因为注入未必在入口,而是在中途从一份被检索回来的文档里钻进来。

亲手回顾

把本章五个概念按「进来 → 匹配 → 转出去 → 横切」摆一遍:请求从 data plane 进(§1.1),走 bind→listener→route→backend(§1.3),backend 决定按哪种协议看待它(§1.4,对应 §1.2 的三类流量),全程被 policy 横切检查(§1.5)。这条句子就是整章的骨架。

§本章 self-check

先合上教程,把答案写在纸上或编辑器里。写完再点开对照——直接点开等于把这一节当再读一遍。

  1. 控制平面和数据平面,哪个宕机会让「已在途的请求」立刻失败?为什么?
  2. 三类流量(LLM / MCP / A2A)里,哪一类是有状态的?它的状态靠什么维持?
  3. 请求路径四件套里,哪一步决定了「这条流量按 LLM 还是 MCP 协议来解析」?
  4. guardrails 为什么不是挂在单一一个点上的 policy,而要在多个闸口各跑一次?(设计层面回答)
答案(先做完再展开)
  1. 都不会让在途请求立刻失败——在途请求由数据平面用本地配置副本处理。控制平面宕机只让「新配置无法下发」;数据平面宕机才会断流量,但那已不是「控制平面 vs 数据平面」的取舍,而是数据平面本身要做多副本高可用。陷阱在于把「控制平面挂 = 流量断」当成必然,其实两平面解耦正是为了避免这点。
  2. MCP 是有状态的,靠 MCP-Session-Id 头跨多次 JSON-RPC 交互维持 session。LLM 和 A2A 的单次调用本身无需跨请求状态(A2A 的 Task 有生命周期,但那是应用层对象,不是传输层 session)。
  3. backend 这一步——更准确说是 backend 的 kind(ai / mcp / a2a)。前三步(bind/listener/route)对三类流量完全一样。而且区分依据是配置声明,不是网关去猜 body 内容。
  4. 因为 prompt 注入不一定从用户输入进来——它可能藏在一份被检索回来的文档、或一个工具返回的结果里,在请求中途才出现。只在入口检查一次,挡不住中途注入。所以要在输入、构造 prompt、工具调用、输出多个闸口各检查一次。
进阶挑战 · 刚好够不着

把「一个数据平面三种协议」翻译成配置会长什么样?

不查文档,凭 §1.3 的骨架和 §1.4 的 backend 多态,试着写出一份「同一个端口 3000,/llm 走 ai backend、/tools 走 mcp backend」的配置草图。你会卡在哪个字段?那个卡点往往就是这个品类还没完全标准化的地方。

提示(卡住再展开)

骨架是:一个 bind: {port: 3000} → 一个 listener → 两条 route(matches 分别匹配 /llm 和 /tools)→ 各自指向 ai: 和 mcp: backend。卡点常出现在 mcp backend 怎么声明「后端有哪几个 MCP server」——这块各家 schema 还不统一,正是 02 章 multiplexing 机制要解释的。