Files
ModelRouter/README.md
root f7f76e097d feat: ModelRouter — unified OpenAI-compatible multi-source LLM gateway
- Lua adapters per upstream (transform_request/response/stream_chunk, build_headers signing hooks)
- AUTO priority routing with per-model kind (chat/image), explicit source/model routing
- Per-source concurrency caps with queueing, exponential backoff, AUTO failover
- OpenAI-compatible API: chat completions, SSE streaming, image generations, models
- Gateway key auth, web UI for adapter/source management, runtime persistence
- e2e test running the real binary against mocked upstreams
2026-08-05 15:25:47 +08:00

5.4 KiB
Raw Blame History

llmsproxy

统一 OpenAI 兼容网关:把多个上游 LLM 源DeepSeek、OpenAI、Anthropic、Gemini、 Groq、Mistral、Ollama、KimiCode…通过 Lua 适配器 做协议转换,对内网暴露 一个标准 OpenAI Chat Completions 接口(/v1/chat/completions + /v1/models 支持单次结算与 SSE 流式。

HomeAgent 的多源 LLM 适配层 internal/agent/api/provider.go + internal/lua/adapters/*)抽离而来并独立演进。

特性

  • 多源:一个进程内配置任意多个上游源,按请求的 model 自动路由。
  • 统一输出:所有源对外都是 OpenAI 格式(含 reasoning_contenttool_callsusage)。
  • Lua 适配协议:每个源挂一个 .lua 适配器,完成 transform_request / transform_response / transform_stream_chunk 双向转换,协议差异全在 Lua 层。
  • 签名 / 请求头钩子:适配器可定义 build_headers(meta),在 Go 发 HTTP 前 动态注入/签名请求头——用于云端 API 校验调用方 app如 KimiCode 只放行特定 agent。提供 hmac_sha256_hex / sha256_hex / base64_encode 等签名辅助。
  • 鉴权:网关自身用 gateway_keys 校验客户端 Bearer key与上游各自的 key 相互独立。
  • 流式SSE chat.completion.chunk,含角色首包与 [DONE] 收尾。

快速开始

cp config.example.yaml config.yaml   # 编辑你的源与 key
GOMODCACHE=... GOPROXY=off go build -o llmsproxy ./cmd/llmsproxy
./llmsproxy -config config.yaml
# 无 key -> 401
curl http://127.0.0.1:8080/v1/models

# 单次
curl -H "Authorization: Bearer sk-gw-local-0001" \
     -d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}' \
     http://127.0.0.1:8080/v1/chat/completions

# 流式
curl -N -H "Authorization: Bearer sk-gw-local-0001" \
     -d '{"model":"deepseek-v4-flash","stream":true,"messages":[{"role":"user","content":"hi"}]}' \
     http://127.0.0.1:8080/v1/chat/completions

任何 OpenAI SDK 把 base_url 指到网关地址、api_keygateway_keys 之一即可。

配置

config.example.yaml。核心字段:

listen: 127.0.0.1:8080        # 网关监听地址(建议绑内网/回环)
gateway_keys: [sk-gw-0001]    # 客户端访问网关的 key留空=不鉴权
default_source: deepseek      # model 无法路由时回落的源
adapter_dir: adapters         # Lua 适配目录,首启自动写入内置适配器

sources:
  - name: deepseek
    base_url: https://api.deepseek.com
    api_key: sk-...
    model: deepseek-v4-flash
    adapter: deepseek
    # 静态请求头(比适配器默认优先)
    headers: { X-Tenant: prod }
    # 传给 Lua build_headers 的透传元数据
    meta: { app_id: x, app_secret: y }
    temperature: 0.7
    max_tokens: 4096
    timeout: 120s              # 请求超时,默认 120s

模型路由

/v1/chat/completionsmodel 解析顺序:

  1. source/modelsource:model 前缀 → 指定源;
  2. 精确匹配某个源的 model
  3. 回落到 default_source

任何 OpenAI 客户端,只要 model 设为某个源的 name/任意名,即可锁定走该源。

Lua 适配器协议

每个适配器是一个返回 table 的 Lua 脚本(internal/lua/adapters/<name>.lua 加载时可被 adapter_dir 下的同名脚本覆盖。

return {
  name = "mysrc",
  version = "1.0.0",
  endpoint = "/chat/completions",        -- 上游路径(可被 source.endpoint 覆盖)
  headers = { ["X-Static"] = "v" },      -- 静态默认请求头build_headers 缺省时使用)

  -- 请求转换:把 OpenAI 格式 req 转成上游原生格式,返回字符串
  transform_request = function(raw_json) ... end,

  -- 响应转换:把上游原生响应转成统一格式字符串
  --   { content, reasoning_content, finish_reason, token_usage{...}, tool_calls[{...}] }
  transform_response = function(raw_json) ... end,

  -- 流式分块转换:把上游 SSE data 转成 { content, done, ... },返回 "" 则跳过
  transform_stream_chunk = function(raw_chunk) ... end,

  -- [可选] 动态请求头/签名钩子
  -- meta = { url, method, body, api_key, timestamp, source={ name, meta={...} } }
  build_headers = function(meta) return { ["X-App-Sign"] = sign } end,
}

内置信号辅助:hmac_sha256_hex(key, data)sha256_hex(data)base64_encode(s)tohex(s)json.encode/decodelog(level, msg)

内置适配器

openai deepseek anthropic gemini github groq mistral ollama kimicode

kimicode 是展示 build_headers 的样例:云端校验调用方 app需要按 meta.app_secret 对时间戳+URL+请求体哈希做 HMAC 签名并附 X-App-Sign 等头。 配好 sources[].meta.{app_id, app_secret, app_agent} 即可。

目录

cmd/llmsproxy            # 入口
internal/config          # YAML 配置加载/校验
internal/lua             # Lua VM + AdapterCache + 内置适配器 (embed)
internal/provider        # Provider(HTTP) + Registry(路由)
internal/gateway         # OpenAI 兼容 HTTP 服务 + 鉴权 + SDK/流式
internal/types           # 统一格式 & OpenAI wire 类型

测试

go test ./...

覆盖:配置校验、适配器加载/变换、签名钩子、Gateway 鉴权、SDK 结算、SSE 流式、模型路由。