一套 Go SDK,打通 OpenAI / Claude / Gemini / Responses 协议互转:OpenTrans 设计与性能实战

你有没有遇到过这种场景:
上游是 OpenAI Chat Completions,请求到了网关以后,要转成 Claude Messages;
或者某条链路要兼容 OpenAI Responses,另一条链路要接 Gemini;
再或者你想做一个统一的大模型 API 网关、代理层、中间件,但每家协议都不一样,字段结构完全不统一。

这时候最麻烦的不是“发请求”,而是“协议互转”。

项目地址

go get github.com/xy200303/OpenTrans

导入:

import opentrans "github.com/xy200303/OpenTrans"

最近我做了一个 Go 项目:OpenTrans
它的目标很明确:

  • 把 OpenAI Chat
  • OpenAI Responses
  • Anthropic Claude
  • Google Gemini

这几种主流 LLM 协议的请求体、响应体、流式事件统一到一套中间结构,再按目标协议重新输出。

这个项目不是代理服务,不是完整网关,而是一个专门做协议互转的 Go SDK
如果你在做:

  • LLM API 网关
  • 多模型路由
  • 协议兼容层
  • 聚合代理
  • 统一日志 / 缓存 / 审计
  • Gin 中间件适配

那它会非常顺手。


一、为什么要做这个库?

现在的大模型生态有一个很现实的问题:

模型能力越来越接近,但协议层越来越碎。

比如:

1. OpenAI Chat 与 Responses 不是一回事

虽然都属于 OpenAI 体系,但:

  • Chat Completions 用的是 messages
  • Responses 用的是 input
  • tool call / tool result 的结构也不一样

2. Claude 协议和 OpenAI 差异很大

Claude 的请求一般是:

  • system
  • messages
  • content 里是 text / image / tool_use / tool_result

而 OpenAI 常见是:

  • messages
  • content 支持字符串或数组
  • 工具调用是 tool_calls
  • 工具结果靠 tool 消息承载

3. Gemini 更不一样

Gemini 的输入结构通常是:

  • contents
  • parts
  • inline_data
  • file_data
  • functionCall
  • functionResponse

如果你想做一个统一接入层,最笨的方法当然也能做:

  1. 每种协议都写一套转换逻辑
  2. A 转 B 写一份
  3. A 转 C 写一份
  4. B 转 C 再写一份
  5. 再加上响应和流式事件……

最后代码会指数级膨胀。

所以更合理的方式是:

所有协议先转成统一中间结构,再从中间结构转出去。

这就是 OpenTrans 的核心思路。


二、OpenTrans 是什么?

OpenTrans 是一个用 Go 编写的多协议 LLM 互转 SDK,当前支持:

  • OpenAI Chat
  • OpenAI Responses
  • Claude
  • Gemini

并且支持三类核心对象:

  • 请求体 Request
  • 响应体 Response
  • 流式事件 StreamEvent

项目地址导入方式:

import opentrans "github.com/xy200303/OpenTrans"

它既可以处理:

  • []byte 原始 JSON body 互转

也可以直接处理:

  • 各 provider 的结构体模型互转

也就是说,你既能把它当成:

  • API 网关里的协议转换器

也能把它当成:

  • 应用内部的模型适配层

三、核心设计:不是用 OpenAI 当中间层,而是独立 canonical 结构

很多人做协议兼容时,喜欢直接“统一成 OpenAI 格式”。

这个做法初期简单,但很快就会遇到问题:

  • Claude 的 tool_result 怎么表示?
  • Gemini 的 file_data 怎么表示?
  • 多模态内容怎么统一?
  • provider 特有字段怎么保留?

所以 OpenTrans 最终没有选择“OpenAI 作为中间结构”,而是定义了一套独立的标准化中间结构

例如请求结构核心就是:

type Request struct {
    Model       string
    Messages    []Message
    Temperature *float64
    TopP        *float64
    MaxTokens   *int
    Stream      bool
    Tools       []Tool
    Metadata    map[string]any
    Extra       map[string]any
}

消息里的内容统一为 ContentPart

type ContentPart struct {
    Type      string
    Text      string
    ImageURL  string
    MIMEType  string
    Data      string
    CallID    string
    Name      string
    Arguments json.RawMessage
    Result    json.RawMessage
}

当前这套中间结构已经覆盖了常见能力:

  • text
  • image_url
  • image_base64
  • tool_call
  • tool_result

这意味着不同协议之间的公共能力,都可以先收敛到同一种表达方式。


四、这个库现在支持到什么程度?

目前能力矩阵可以概括成下面这张表:

图例

  • 已支持
  • 🟡 部分支持
  • 未完整支持
能力 OpenAI Chat OpenAI Responses Claude Gemini
请求文本输入
请求图片 URL 输入
请求 Base64 图片输入
请求工具定义
请求工具调用消息
请求工具结果消息
非流式文本响应
非流式图片/视频输出
流式文本增量
流式开始/结束/usage 事件
provider 特有高级字段透传 🟡 🟡 🟡 🟡

这个覆盖面对于以下场景已经足够好用了:

  • 文本聊天
  • 多轮对话
  • 图片输入
  • 工具调用
  • 工具结果回传
  • 基础 SSE 流式转发

五、最实用的几个能力


1. 原始 body 直接互转

最常见的场景,就是你已经拿到了 HTTP body,想直接转协议。

例如把 OpenAI 请求转成 Claude:

src := []byte(`{
  "model": "gpt-4.1-mini",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Write a haiku about Go"}
  ],
  "temperature": 0.4
}`)

out, err := opentrans.ConvertRequestBody(
    src,
    opentrans.ProtocolOpenAI,
    opentrans.ProtocolClaude,
)
if err != nil {
    panic(err)
}

fmt.Println(string(out))

这个接口非常适合:

  • 网关
  • 中间件
  • HTTP 代理层
  • 兼容 API 层

2. 先标准化,再二次处理

如果你不只是想“转协议”,还想中间做点逻辑,比如:

  • 审计
  • 路由
  • 模型名替换
  • 消息裁剪
  • 加 metadata
  • 缓存 key 生成

那就可以先标准化:

req, err := opentrans.NormalizeRequest(opentrans.ProtocolGemini, body)
if err != nil {
    panic(err)
}

req.Model = "gpt-4.1-mini"

out, err := opentrans.MarshalRequest(req, opentrans.ProtocolOpenAI)
if err != nil {
    panic(err)
}

这比“每种协议写一套业务逻辑”要优雅太多。


3. 支持工具调用链路互转

这是很多协议互转库最容易做残的地方。

OpenTrans 现在已经把这条链路打通了:

OpenAI Chat
  • assistant.tool_calls
  • tool 消息
OpenAI Responses
  • function_call
  • function_call_output
Claude
  • tool_use
  • tool_result
Gemini
  • functionCall
  • functionResponse

而且中间结构里引入了 CallID,所以工具调用和结果能对应起来,不是简单“只保留名字”。


4. 支持图片 URL / Base64 输入

现在请求侧图片输入已经比较完整:

  • OpenAI image_url
  • Claude URL / base64 图片 source
  • Gemini file_data / inline_data

尤其是这次做完之后:

  • OpenAI -> Claude 的图片 URL 输入已经支持
  • OpenAI -> Gemini 的图片 URL 输入已经支持
  • Gemini file_data -> image_url
  • Claude image source(type=url) -> image_url

这点对做多模态网关非常重要。


5. 直接接入 Gin 中间件

如果你正在做 Gin 网关,这个点会特别香。

项目内置了 pkg/opentrans/ginx

  • ginx.ConvertRequestBody
  • ginx.ConvertResponseBody
  • ginx.ConvertStreamEventBody

示例:

router.POST(
    "/v1/chat/completions",
    ginx.ConvertRequestBody(opentrans.ProtocolOpenAI, opentrans.ProtocolClaude),
    func(c *gin.Context) {
        c.Status(200)
    },
)

流式场景也支持 SSE data: 帧转换。

这意味着你可以很快搭一个:

  • OpenAI 兼容入口
  • Claude / Gemini 后端
  • 自动协议转换

而不用自己手搓每个字段。


六、为了性能,我做了哪些优化?

协议互转这件事,很容易一不小心就写成:

  • json.Unmarshal
  • 转成 map
  • 再组 map
  • json.Marshal

功能是能跑,但性能会非常差。

OpenTrans 在这方面做了不少约束和优化:

1. 优先结构体转换,而不是 JSON 往返桥接

如果已经拿到了结构体,直接走结构体适配,不需要先转 []byte 再解析回来。

2. 用独立 canonical 结构,而不是 provider 套 provider

避免 OpenAI -> Claude 先转 OpenAI struct,再桥 Claude struct,再中间反复绕。

3. 运行时热路径切到高性能 JSON

内部已经用 jsoniter 处理核心 JSON 热路径,而不是一直用标准库默认实现。

4. body 输出默认走 compact JSON

避免无意义 pretty-print 带来的额外开销。

5. Gin SSE 路径做了减分配优化

例如:

  • 去掉多余切片复制
  • 避免 string(...) 来回转换
  • bytes.Buffer 原地消费
  • 用 typed struct 代替热路径里的 map[string]any

七、性能到底怎么样?

这个项目我专门做了 benchmark 目录,拆成:

  • request_benchmark_test.go
  • response_benchmark_test.go
  • stream_benchmark_test.go
  • ginx_benchmark_test.go
  • comparison_benchmark_test.go

1. OpenTrans 自身整链路性能

比较接近真实网关场景的整链路转换,大致是这种量级:

Benchmark ns/op B/op allocs/op
BenchmarkConvertRequestBodyOpenAIToClaude 1807 1113 21
BenchmarkConvertResponseBodyClaudeToOpenAI 1978 1322 22
BenchmarkConvertStreamEventBodyClaudeToOpenAI 720.1 606 9
BenchmarkConvertStreamEventBodyOpenAIToClaude 917.8 638 11

这意味着:

请求体 / 响应体 / 流式事件的协议转换已经稳定在微秒级。

对于 API 网关或代理层,这个开销是完全可接受的。


2. 与常见函数实现方式对比

这里我没有拿“完整代理服务”来硬比,因为那样口径不公平。
而是选了三种纯函数实现方式做同口径对比:

  • OpenTrans
  • encoding/json + typed struct bridge
  • encoding/json + map[string]any bridge
纯文本 OpenAI -> Claude
实现 ns/op B/op allocs/op
OpenTrans 4048 1715 32
StdJSON struct bridge 6919 1409 27
Map bridge 10183 3659 76
多模态 OpenAI -> Claude

样本包含:

  • system 文本
  • user 文本
  • image_url 图片 URL 输入
实现 ns/op B/op allocs/op
OpenTrans 8832 3694 74
StdJSON struct bridge 11233 2009 41
Map bridge 15839 5925 111

3. 怎么看这组数字?

我觉得可以总结成四句话:

  • 对纯文本协议互转,OpenTrans 已经明显快于常见手写桥接实现
  • 对多模态请求,OpenTrans 目前也快于这两种常见基线
  • map[string]any 风格的动态桥接,在速度和分配上都最差
  • OpenTrans 虽然不是所有场景分配最少,但换来的是更统一、更可扩展、更完整的协议兼容能力

这也是我做这个项目时很看重的一点:

不是为了极端 micro benchmark 而牺牲协议表达能力,
而是在“功能完整”和“运行足够快”之间做平衡。


八、这个项目适合谁用?

我觉得特别适合下面几类开发者:

1. 做 LLM API 网关的人

你要统一入口协议,比如:

  • 前端全走 OpenAI
  • 后端可能接 Claude / Gemini / Responses

那 OpenTrans 可以直接放在入口转换层。

2. 做多模型路由的人

你希望业务逻辑只看统一结构,而不是关心每家 provider 的字段差异。

3. 做兼容代理的人

比如做 OpenAI-compatible API,但实际后端不是 OpenAI。

4. 做日志 / 缓存 / 审计的人

统一中间结构特别适合:

  • 提取关键信息
  • 生成缓存 key
  • 做输入输出审计
  • 做 tool call 追踪

5. 想把 LLM 能力嵌入自己业务系统的人

你不想为了支持多个模型供应商,把整个业务代码写成一锅协议适配 if-else。


九、当前还有限制吗?

当然有,而且我觉得明确写出来比“假装全能”更重要。

目前还存在这些边界:

  • 非流式图片 / 视频输出还没完全统一打通
  • provider 特有高级字段目前还是部分透传
  • 某些复杂多模态输出还需要继续补
  • 完整官方 SDK 级别的所有边角字段还没有完全覆盖

不过从工程角度看,当前版本已经足够覆盖绝大多数:

  • 文本聊天
  • 多轮消息
  • 图片输入
  • 工具调用
  • 工具结果
  • 流式文本

这已经能支撑不少真实项目。


十、我最满意的地方

如果让我总结这个项目最有价值的几个点,我会选这几个:

1. 不是“代理应用”,而是“协议互转 SDK”

这个定位很关键。
你可以把它嵌到任何架构里,而不是必须整套接管你的服务。

2. 不用 OpenAI 充当中间层

而是抽象出独立 canonical 结构,扩展性更好。

3. 请求、响应、流式三条线都打通了

很多项目只做请求,响应和 stream 很容易烂尾。

4. 工具调用链路处理得比较完整

尤其是 CallID 这条线打通后,已经不只是“能转”,而是“能正确表达”。

5. 性能不是嘴上说说,是真的做了 benchmark

这一点我自己也很看重。
能跑、能测、能对比,才能持续优化。


十一、最后

如果你也在做:

  • OpenAI / Claude / Gemini 多协议兼容
  • LLM API 网关
  • 模型代理
  • 协议适配层
  • 工具调用桥接

那 OpenTrans 这个思路应该能给你一些启发:

协议碎片化不可避免,但中间结构可以统一。

把协议互转从“散落在各处的临时代码”,收敛成一个独立 SDK,本身就是一种工程收益。

如果后面继续迭代,我下一步会重点看:

  • 非流式图片/视频输出统一
  • 更多 response / stream 的协议对齐
  • 更进一步的多模态性能优化
  • 更多 provider 特有字段透传

项目地址

go get github.com/xy200303/OpenTrans

导入:

import opentrans "github.com/xy200303/OpenTrans"

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐