游乐游手机版
首页/AI教程/文章详情

LLM多协议抽象管道实现与优化指南

时间:2026-07-15 22:31
理解 Protocol:API 的“语义契约” 这个包最核心的洞见其实很简单:把“这个 API 长什么样”和“请求发到哪儿、怎么认证”这两件事彻底分开。前者是由 Protocol 负责的“语义契约”,它只关心三件事: 如何把通用的 LLMRequest,转换成每个服务商(Provider)自己的原生

理解 Protocol:API 的“语义契约”

这个包最核心的洞见其实很简单:把“这个 API 长什么样”和“请求发到哪儿、怎么认证”这两件事彻底分开。前者是由 Protocol 负责的“语义契约”,它只关心三件事:

  1. 如何把通用的 LLMRequest,转换成每个服务商(Provider)自己的原生请求体。
  2. 这个请求体必须满足什么数据格式(Schema)。
  3. 如何把服务商返回的流式响应,解码回我们通用的 LLMEvent

四类型参数,定义一条完整管道

Protocol 接口用了四个泛型参数,它们精确地映射了数据流经管道时的四个阶段:

类型参数 管道阶段 干什么的? 生命周期
Body 请求体 构建好的 Provider 原生请求体。Route.make 会用 body.schema 校验后,编码成 JSON 发出去。 每次请求都构建一个
Frame 传输帧 流式响应的一个最小单元。比如 SSE 协议里的一段 data: 字符串,或是 AWS Event Stream 里的一个二进制帧。 每个分帧都是一个
Event 原生事件 从一个 Frame 里,经过 stream.event 这个 Schema 解码后,得到的 Provider 原生事件。 每帧解析出一个
State 解析状态 贯穿 stream.step 的累加器,它的任务是把一系列 Provider 原生事件,翻译成我们想要的 LLMEvent 序列。 每次响应一个

请求侧:ProtocolBody

ProtocolBody 只有两个字段,但职责清晰:

  • schema: 这是 Body 类型的 JSON 编解码器(Codec)。它既是 TypeScript 的类型推断来源,也是运行时的校验器。compile 阶段会用它来确保构建出来的请求体是合法的。
  • from: 这是一个函数,负责把通用的 LLMRequest “降级”为 Provider 的原生请求体。这里就是封存每个 Provider 奇技淫巧的地方,所有 Provider 的怪异之处都被锁在这个函数里,不会污染到上层通用的 LLMRequest

响应侧:ProtocolStream

ProtocolStream 是一个流式状态机,它由五个字段构成,对应五个处理阶段:

  • event: 一个 Schema 编解码器,负责从传输帧解码出原生事件。类型上就是 Frame → Event
  • initial: 每次响应开始时被调用一次,传入解析后的请求,返回一个初始的 State
  • step: 这是核心翻译器。它输入 (当前State, 一个Event),输出 [下一个State, 要发射的LLMEvent数组]这是唯一一个把 Provider 的流式语义(比如 OpenAI 的 delta,Anthropic 的 content_block_delta)翻译成我们统一事件(text-delta, tool-input-delta)的地方
  • terminal: 可选的,用于标记那些不会自然结束的传输(比如 WebSocket),告诉状态机哪个事件表示“结束了”。
  • onHalt: 可选的,当分帧流结束时(比如 OpenAI 发完所有数据块),用最终状态冲刷出剩余的事件。

完整流水线:从请求到用户事件

把上面这些串联起来,一个完整的请求-响应流程就是这样:

  1. 编译阶段LLMRequest 经过 applyCachePolicyresolveRequestOptions 处理后,交给 route.body.from 构建出原始的 Body
  2. 校验阶段:用 body.schemaBody 进行校验,确保其符合契约。
  3. 预备阶段route.prepareTransport 将校验后的 Body 和请求信息,打包成 Transport 层所需的数据(比如 HTTP 请求对象)。
  4. 执行阶段Transport 开始发送请求,接收响应流,并通过 Framing 将字节流切成一个个 Frame
  5. 解码阶段:每个 Frame 经过 stream.event Schema 解码,变成 Event
  6. 翻译阶段:每个 Event 进入 stream.step 状态机,结合当前的 State,产出最终的 LLMEvent 流。

每一步的类型转换都有对应的 Schema.Codec 把关,既是编译期的类型来源,也是运行时的校验闸门。

Route.make():四轴正交组合的艺术

Route.make 是协议层的核心构造器。它把四个完全正交的部署维度组合成一个可执行的 Route一个 Protocol + 一个 Endpoint + 一个 Auth + 一个 Framing。这种分离带来的最大好处是:DeepSeek、TogetherAI 这类兼容 OpenAI 的厂商,只需要复用 OpenAIChat.protocol,零代码即可接入

Route 的完整结构

一个 Route 持有四个轴的绑定结果,加上两个运行时方法(prepareTransport + streamPrepared)和一个可变性方法(with)。

四轴正交模型

这四个轴的职责边界非常清晰:

  • Protocol:定义“我说的是什么 API?”(例如:OpenAI Chat / Anthropic Messages)
  • Endpoint:定义“请求发到哪个 URL?”(例如:baseURL + path
  • Auth:定义“怎么认证?”(例如:bearer / header / none
  • Framing:定义“响应字节流怎么切成帧?”(例如:sse / AWS Event Stream)

两个重载:常用与高级

Route.make 提供了两个重载:

  • MakeInput(常用):你只需要提供 framing,它自动帮你构造默认的 HTTP Transport。适用于绝大多数 HTTP+SSE 的 Provider。
  • MakeTransportInput(高级):你需要提供完整的 Transport。这适用于 WebSocket 或自定义传输协议。

DeepSeek/TogetherAI 如何复用 OpenAIChat.protocol?

这一步是检验设计是否优秀的试金石。来看看它有多简单:

  1. 第一步,定义 OpenAIChat.protocol:它定义了 Chat Completions 的完整语义契约,包括 body.schemabody.from 和流式状态机。
  2. 第二步,创建 OpenAICompatibleChat.route:它直接复用 OpenAIChat.protocol零改动。只修改了 route.id 以防冲突,并指定了 EndpointFraming
  3. 第三步,为每个 Provider 创建专属 Route:通过一个 define(profile) 工厂函数,为每个 Provider 覆盖 Endpoint(baseURL)和 Auth(bearer token)。
// 代码示例:DeepSeek 和 TogetherAI 的接入
export const deepseek = define(profiles.deepseek) // baseURL = "https://api.deepseek.com/v1"
export const togetherai = define(profiles.togetherai) // baseURL = "https://api.together.xyz/v1"

注意,configure 内部是通过 route.with({ ... }) 来生成一个新 Route 的,这是一个不可变拷贝,所以原始的 route 不会被影响,每个 Provider 都拿到自己专属的 Route 实例。

衡量一下复用效果:DeepSeek、TogetherAI、Cerebras、Groq 等七个 Provider,共享同一份约500行的 OpenAIChat.protocol。每个 Provider 只需要3行 define(profile) 代码。如果没有四轴正交,每个 Provider 都得复制这500行代码。这正是这套设计的威力所在。

compile():编译边界,而非执行边界

compileLLMClient 的内部核心函数,它是公共 LLMRequest 与 Provider 原生世界之间的一个编译边界。它的任务是编译,而不是执行。

compile 的四步流水线

  1. resolveRequestOptions:合并三层默认值(Route 级 -> Model 级 -> 请求级),得到完整的请求对象。
  2. applyCachePolicy:根据缓存策略,在正确的位置注入缓存提示(hint)。
  3. body.from + Schema 校验:调用 Protocol 的 from 函数构建 Provider 原生请求体,然后用 body.schema 对其进行校验。这一步是关键的编译期闸门,如果 from 函数有 bug,会在这里就失败,而不是等到请求发出去后收到 Provider 的400错误。
  4. prepareTransport:把校验好的 body 和请求对象交给 Transport,准备 Transport 所需的私有数据(比如 HTTP 请求对象)。

编译边界的设计含义

compile 是“编译”而非“执行”,它有三个关键设计约束:

  • 编译不执行compile 只是产出数据,不发送网络请求。这让 LLMClient.prepare() 可以安全地暴露给调试工具,让用户预览“即将发什么”而不实际发送。
  • Schema 是编译期闸门body.from 产出 body 后,立即用 Schema 校验。这意味着 Protocol 实现者的逻辑 bug(比如遗漏必填字段)会在编译阶段就被捕获,错误类型是“Provider 输出无效”,而不是等到运行时再报错。
  • 缓存策略先于 body 构建applyCachePolicybody.from 之前执行,这样降级函数拿到的请求已经带上了缓存提示,可以自然地将其翻译为线格式标记。这是一个“在正确位置注入,让后续自然处理”的设计模式。

总结:一个类型化的 LLM 网关设计范式

OpenCode 的 LLM 网关设计展示了一个完整的、强调类型安全的范式。它比像 Vercel AI SDK 这样的方案更重、更显式,但换来的好处是实实在在的:新 Provider 的接入成本极低(只需改 Endpoint 和 Auth),错误处理可以基于类型做决策,缓存策略可以统一管理。

核心的设计哲学可以概括为:

  1. Protocol 是“API 语义”的唯一来源:一个 Protocol 定义了 API 的全部语义知识。部署(URL、Auth、Transport)是与之正交的、可替换的维度。这使得 Protocol 成为一种可复用的语义资产。
  2. compile 是“类型安全”的编译边界:在 body 和 Transport 之间插入 Schema 校验,把 bug 捕获在编译期。compile 不执行的设计,让请求预览成为免费的副产品。
  3. 缓存策略是“协议无关”的策略层auto 策略在编译边界注入语义提示,Protocol 的 lowering 函数自然翻译为线格式标记。两层分离让缓存策略可以统一演进,而不需要改动每个 Protocol。
  4. 错误是“类型化决策”的输入:10 种 Reason 加上 retryable getter,让上层可以用类型开关做不同策略。Executor 的预输出重试是这一层的默认消费者。
  5. 正交组合优于继承:DeepSeek 不继承 OpenAIChat,而是 OpenAIChat.protocol + DeepSeek.endpoint + bearer.auth。这避免了继承层次的爆炸,用 M+N 个正交维度覆盖所有组合。
来源:https://juejin.cn/post/7662054174280990783
上一篇月薪3万测试开发都在用5个AI插件每天多出5小时 下一篇AI编程概念与Harness工程实践入门
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Vibe Coding出海首月获取100用户赚美金的方法
AI教程 · 2026-07-15

Vibe Coding出海首月获取100用户赚美金的方法

VibeCoding出海获客的关键在于精准找到付费用户,而非写代码。通过竞品情报监听、定向搜索潜在客户、多维画像筛选、个性化开发信触达以及持续跟进动态,跑通五关链路,提升获客效率与转化率。

程序员Agent协作方式实践指南
AI教程 · 2026-07-15

程序员Agent协作方式实践指南

基于TRAE与DeepSeek,以工具、记忆、Skill三系统构建Agent协作体系。工具系统执行确定性任务,记忆系统实现分层记忆与增量构建,Skill系统处理复杂推理。通过实践验证,该方案提升了可观测性与交互性。

大模型微调全自动工厂:基座模型成为AI专家
AI教程 · 2026-07-15

大模型微调全自动工厂:基座模型成为AI专家

LlamaFactory开源高效微调框架,提供WebUI和命令行,集成LoRA、QLoRA、FlashAttention等,支持超100种模型,低显存下完成微调、偏好训练及模型导出,大幅降低大模型定制门槛。

Hermes上下文压缩架构:长任务Agent不失忆的关键设计
AI教程 · 2026-07-15

Hermes上下文压缩架构:长任务Agent不失忆的关键设计

Hermes上下文压缩架构通过可替换引擎、双层压缩及预检、响应后、错误恢复三触发器管理当前窗口。先剪枝降噪后生成结构化handoff摘要,阈值计算预留输出空间,避免长窗口过早压缩。该机制保障长任务Agent的上下文完整性,不替代长期记忆。

年首批被AI取代的测试员已送外卖
AI教程 · 2026-07-15

年首批被AI取代的测试员已送外卖

去年冬天,前同事老周发了一条朋友圈,定位在望京的一处外卖站点。配文只有一句话:“以前跑测试用例,现在跑单,都是跑。” 我问他近况。他说被裁三个月了,面试了十几家公司,手工测试岗位要么早就招满了,要么上来就问“你会不会调 prompt 做自动化测试”。 他苦笑,写了八年测试用例,如今连面试机会都拿不到