回答之前,先互相审一遍
几个模型一起把问题想透。
一个模型起草,另一个挑它的毛病,草稿因此变得更扎实。每个答案都不止一个头脑过手,客户端看到的永远只是最终稿。
多花一次调用。第二个模型可以看到你的工具,但调不动它们。
所有模型共用一个端点。重试、回退、编排都由它完成,客户端代码一行不用改。
Hydrogen 替你保管各家供应商的 API 密钥,每个请求由它决定交给哪家供应商的哪个模型处理。客户端只报一个模型服务的名字,从不指定真实模型。OpenAI 和 Anthropic 两种协议格式都支持,并在两者之间转换。
客户端从不指定真实模型,只指定一个模型服务;这个名字实际意味着什么,由 Hydrogen 按请求在你自己维护的清单里决定。
model = "sonnet-any"客户端只能看到模型服务sonnet4.6claude-sonnet-4-6| 概念 | 是什么 | 示例 |
|---|---|---|
| 供应商 | 一个上游端点及其 API 密钥。 | openai-official、anthropic-official |
| 模型 | 你为一个模型起的内部名称。 | sonnet4.6 |
| 映射 | 由哪家供应商服务这个模型,用什么上游 ID。 | sonnet4.6 → anthropic-official,上游 ID claude-sonnet-4-6 |
| 模型服务 | 客户端请求的名称,以及背后的规则。 | sonnet-any |
模型服务的每个步骤都绑定一个明确的(模型, 供应商)对,各有自己的重试次数、重试间隔,以及哪些故障重试、哪些故障跳下一步。供应商回退和模型回退,都只是再加一步。所有步骤都走完仍未成功,真正的上游错误会转换成客户端使用的协议格式,返回给客户端。
| 模型服务 | 行为 |
|---|---|
sonnet-any | 先试 sonnet4.6 @ anthropic → 失败则回退到 gpt5.4 @ openai |
sonnet-persist | 试 sonnet4.6 @ anthropic,每隔 1 秒重试,最多 5 次 |
essay 微代理 | draft → critique → revise,评审通过时直接返回草稿 |
换来的是:换供应商、加回退、限制思考预算,或者插入一整条代理流水线,都只是仪表盘上改一改。客户端代码照旧请求 sonnet-any。
全部装在一个容器里,内置 SQLite。供应商密钥落盘即加密,客户端密钥只存哈希,整个实例可以导出成一个用口令封存的文件。
OpenAI Chat Completions、OpenAI Responses 和 Anthropic Messages:流式与非流式、工具调用、图片、思考块,都完整转换过去,不会半路丢掉。
chat、ocr、image、video、tts、stt、embedding、rerank。非对话类型走 OpenAI 风格的直通转发,同样会跑你的步骤链。
只往前走的阶段流水线,支持条件分支和路由。每个阶段都运行一个已保存的模型服务,自动继承它的重试与回退规则。可以嵌套,环路会被校验拒绝。
Temperature、top-p/top-k、max tokens、停止序列、思考等级、system 覆写,外加任意额外的 body 参数,全部钉在步骤上,与客户端无关。
上游流先缓冲,中途截断按可重试失败处理,然后重放完整响应,或者干脆返回一个干净的 502,总之不会给一半。
视觉预检先把图片转成文字,给后面的阶段用;转写按图片哈希缓存,在 LRU 字节预算内复用。
把密钥限定在指定服务上,设请求数和 Token 上限,设过期时间;持有人可以在公开的密钥查询页随时查看自己的状态。
每个请求都有日志:每次尝试、载荷、延迟、Token 用量,代理的各阶段嵌套在客户端请求之下;另有实时的活动请求面板和仪表盘统计。
整个实例导出成一个用口令封存的文件,能恢复到任何另一台 Hydrogen 上。恢复是单个事务:要么全部成功,要么什么都没动。
供应商密钥用 AES-256-GCM 加密,密码用 argon2id 散列,客户端密钥用 SHA-256,供应商 Base URL 有 SSRF 防护,启动时还会自检主密钥。
admin 和 manager:manager 什么都能管,唯独签发 API 密钥和系统设置不行。仪表盘有中文和英文。
仪表盘和 API 共用一个端口,SQLite 内置在镜像里。数据库和主密钥都在 /data 里;把这一目录持久化,其余随时可以扔掉重来。
可组合的流水线:路由、评估、图片 OCR、嵌套代理,都搭在你的模型服务上。
模型服务把一个请求路由到一次上游调用;微代理跑的是多次模型调用(多个阶段),对客户端却仍然只是一个模型名。在外界看来,微代理就是一个模型服务,客户端不需要任何改造:把现有应用从 sonnet-any 改指 essay,它拿到的就是一条 起草 → 评审 → 修订 的流水线。
阶段从上往下依次运行。每个阶段跑完,按顺序检查它的转移条件,第一条命中的生效;都没有命中,就落到下一个阶段。跑出最后一个阶段,代理结束,返回停下的那个阶段的输出。
链条运行之前,请求里的每张图片都会先交给一个多模态/OCR 模型,替换成它的转写文本,这样纯文本的阶段模型也能处理请求。转写按图片哈希缓存。
APPROVED 跳到结束,返回 draft评审说出 APPROVED,代理就停在阶段 2,返回的是草稿,也就是阶段 1 的文本,APPROVED 这个词不会出现;否则落到 revise,它是最后一个阶段,输出就是响应。两种走法,客户端看到的都是一次普通的回答;日志里每个阶段各记一次调用,嵌套在那一条客户端请求之下。
几个模型一起把问题想透。
一个模型起草,另一个挑它的毛病,草稿因此变得更扎实。每个答案都不止一个头脑过手,客户端看到的永远只是最终稿。
多花一次调用。第二个模型可以看到你的工具,但调不动它们。
便宜的模型决定何时用贵的。
阶段 1 用你最便宜的模型跑,只做一件事:给请求定难度。它的判断决定走哪条路:难的活儿交给强模型,其余的直接放行给便宜的。
打分只花一次便宜调用。改用正则分流,一个 router 阶段一分钱都不花。
任何 OpenAI SDK 指向 /v1,任何 Anthropic SDK 指向根路径,把 model 设为模型服务的名字。客户端的格式和供应商的格式互不相关。
http://localhost:8080/v1http://localhost:8080curl http://localhost:8080/v1/chat/completions \ -H "Authorization: Bearer sk-hproxy-..." \ -H "content-type: application/json" \ -d '{"model":"sonnet-any","messages":[{"role":"user","content":"hello"}]}'
curl http://localhost:8080/v1/messages \ -H "x-api-key: sk-hproxy-..." \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"sonnet-any","max_tokens":256,"messages":[{"role":"user","content":"hello"}]}'
| 方法 | 路径 | 类别 | 说明 |
|---|---|---|---|
| POST | /v1/chat/completions | chat | OpenAI Chat Completions,流式 + 非流式 |
| POST | /v1/responses | chat | OpenAI Responses API |
| POST | /v1/messages | chat | Anthropic Messages |
| GET | /v1/models | — | 你的模型服务(发送 anthropic-version 时返回 Anthropic 形态) |
| POST | /v1/embeddings | embedding | 兼容 OpenAI 的供应商 |
| POST | /v1/rerank | rerank | |
| POST | /v1/images/generations | image | |
| POST | /v1/videos | video | 返回自带路由后缀的任务 ID |
| GET | /v1/videos/:id · /v1/videos/:id/content | video | 轮询与下载,无状态路由 |
| POST | /v1/audio/speech | tts | 二进制音频直接流过 |
| POST | /v1/audio/transcriptions | stt | multipart,改写 model 后转发 |
/v1/models 返回的是模型服务,所以任何带模型选择器的工具都会显示你的服务名。这正是设计意图:在客户端眼里,sonnet-any 就是模型。认证用 Authorization: Bearer … 或 x-api-key: …。
三条路径,按投入从小到大。无论走哪条,先记住一条规则。
/data 必须持久化。里面是 SQLite 数据库,还有 hydrogen-secrets.json:解密供应商 API 密钥的主密钥就在这个文件里。丢了它,Hydrogen 宁可拒绝启动,也不会带着读不出的密钥硬跑。
Hydrogen 已上架为雨云云应用。在商店里搜索 Hydrogen,保留模板自带的 /data 卷,主密钥和会话密钥留空,让 Hydrogen 自己生成并持久化。
docker run -d --name hydrogen \
-p 8080:8080 \
-v hydrogen-data:/data \
ghcr.io/arrosam/hydrogen-llm-proxy:v1.7.3
接着 docker logs hydrogen,初始管理员凭据就打印在启动横幅里;然后放开 8080 端口。deploy/vps/ 里有现成的 compose 栈,附带 Caddy TLS 配置。
git clone https://github.com/Arrosam/Hydrogen-LLM-proxy.git cd Hydrogen-LLM-proxy cp .env.example .env docker compose up -d --build
仓库根目录的 compose 从工作树构建,不走拉取。不用 Docker 的话:npm install、npm run build,设好 DATA_DIR 再启动服务器。