Skip to content

About

Go-based LLM proxy for cost tracking and rate limiting

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

LLM Proxy

轻量的自建 LLM 透明反向代理。下游统一访问 /v1/...,代理在运行时从 SQLite 管理的上游池里选择可用上游,并处理鉴权、模型路由、Key 调度、故障切换、审计日志和中文管理面板。

运行形态为一个 Go 二进制和一个 SQLite 数据库,无需 Redis、DynamoDB 或独立前端服务。管理端使用 Vue 3 构建,构建时通过 go:embed 打入二进制;运行时不需要 Node.js。

版本号定义在根目录 VERSION 文件中,构建时通过 -ldflags 注入。

核心能力

代理与路由

  • 统一 /v1/... 代理入口,自动识别 OpenAI / Anthropic 风格请求。
  • 每个上游支持多个 API Key,可单独启停、测试、复制,支持 round-robin / fill 调度。
  • 下游 Key 可绑定指定上游,也可配置 per-key 模型路由覆盖。
  • 支持上游独立代理地址:http、https、socks5。
  • 支持无鉴权上游,适配公益站或本身不需要 API Key 的兼容服务。
  • /v1/models 可合并上游真实模型和本地声明模型,并受模型白名单过滤。
  • SSE 流式响应边读边写,不把流式结果缓冲到请求结束。

可靠性与弹性

  • 上游失败时按候选上游故障切换,连续失败可自动禁用对应上游 Key。
  • 熔断器(Circuit Breaker):per-upstream 连续失败达阈值自动熔断,可配置恢复策略。
  • 上游限速(Upstream RPM Limit):为每个上游设置 RPM 上限,超限自动跳过。
  • 速率感知路由:从上游响应头观测 rate limit 信息,自动绕过触发 429 的上游。
  • 智能 429 退避:跟踪上游连续 429 次数,动态调整退避时间。

Key 管理

  • 下游 Key 并发限制(Max Concurrent):限制单个 Key 同时请求数。
  • 下游 Key per-key RPM 限流,滑动窗口实现。

上游管理

  • 软删除与撤销:上游删除后可恢复,不立即清除数据。
  • 上游模板:内置常见服务商模板(base_url、auth_mode),快速添加上游。
  • 模型自动发现:开启后每 24 小时从上游 /v1/models 拉取模型并覆盖该上游路由模式;开启或管理端「立即发现」会马上拉一次。
  • 上游列表直接显示探活状态、连续失败与退避信息,并可快捷打开或复制上游地址、复制显式代理地址。
  • 健康历史:记录每次探活结果和延迟,支持按时间段查询。
  • 延迟统计:聚合请求日志中的上游延迟数据,支持 24h 等时间窗口。

管理面板

  • 透明/解包模式总开关:一键在“透明代理”(仅转发+替换鉴权头,记录与解包类功能全部停用)与“解包模式”(完整功能)之间切换,即时生效、切换需二次确认。
  • Web 管理上游、下游 Key、模型路由、白名单、声明模型和运行设置。
  • Dashboard SSE 实时刷新:RPM/RPS/活跃上游状态自动推送,无需手动刷新。
  • 完整请求记录可在运行时选择全部或指定下游 Key,按连续会话查看请求/响应 Header 与正文。
  • 会话内容全文搜索:按请求/响应正文关键词搜索(SQLite FTS5),命中片段高亮并可跳转到对应会话。
  • 请求重放:从会话时间线选择历史请求,预填参数重新发送。
  • 多上游对比重放:从会话时间线选一条历史请求,同时发给最多 4 个已配置且启用的上游并排比较输出、延迟与 Token 用量,强制非流式、不落库。
  • 配置导入/导出:一键备份和恢复上游、Key、白名单、设置。

可观测性

  • 异步审计日志记录下游 Key、上游、上游 Key 索引、模型、代理、IP、状态码和延迟。
  • TTFT / 输出速率指标:记录每次请求首字节时间(TTFT),结合输出 Token 数计算 tokens/s 速率,延迟统计面板按上游聚合展示。
  • 完整记录启用后保存脱敏 Header、请求/响应正文、会话来源和 Responses 响应链,并支持 NDJSON 导出。
  • Token 用量统计:从上游响应提取输入/输出 Token 数,支持 per-Key 日/月配额(超限 429)、按价格表估算成本,以及 Dashboard 24h 用量曲线。
  • 会话级 Token/成本汇总:会话列表卡片与会话时间线对话框显示该会话累计输入/输出 Token 数,并按价格表估算成本(无匹配价格显示 -)。
  • Webhook 事件通知:熔断开启/恢复、Key 自动禁用、Token 配额超限、完整记录丢弃等关键事件异步推送到管理员配置的 Webhook(通用 JSON / 飞书文本两种格式),支持管理面板一键测试。

快速开始

从源码执行完整构建需要 Go 1.25、Node.js 24 和 pnpm。首次检出或锁文件变更后先恢复前端依赖:

make frontend-install
make build

ENCRYPTION_KEY=01234567890123456789012345678901 \
ADMIN_TOKEN=my-secret-token \
./bin/llm-proxy

开发模式:

ENCRYPTION_KEY=01234567890123456789012345678901 \
ADMIN_TOKEN=my-secret-token \
make dev

启动后访问:

  • 管理面板:http://localhost:9002/admin/
  • 旧版管理面板(临时回退):http://localhost:9002/admin/legacy/
  • 存活检查:http://localhost:9002/healthz
  • 就绪检查:http://localhost:9002/readyz

/healthz 只表示进程存活;/readyz 会在没有健康上游时返回 503。

最小使用流程

1. 添加上游

curl -X POST http://localhost:9002/admin/api/upstreams \
  -H "Authorization: Bearer my-secret-token" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "openai-main",
    "base_url": "https://api.openai.com",
    "api_keys": ["sk-upstream-1", "sk-upstream-2"],
    "priority": 100,
    "key_scheduling_mode": "round-robin"
  }'

2. 创建下游 Key

curl -X POST http://localhost:9002/admin/api/keys \
  -H "Authorization: Bearer my-secret-token" \
  -H "Content-Type: application/json" \
  -d '{"name":"user-1","rpm_limit":60}'

3. 发起请求

OpenAI 风格:

curl http://localhost:9002/v1/chat/completions \
  -H "Authorization: Bearer sk-downstream..." \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"你好"}]}'

Anthropic 风格:

curl http://localhost:9002/v1/messages \
  -H "x-api-key: sk-downstream..." \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-sonnet-4-20250514","max_tokens":128,"messages":[{"role":"user","content":"你好"}]}'

常用配置

必要环境变量:

变量 说明
ENCRYPTION_KEY 32 字节原始字符串,或 64 位十六进制字符串,用于加密保存 Key
ADMIN_TOKEN 管理面板和管理 API 的 Bearer token

常用可选环境变量:

变量 说明
ENVIRONMENT 加载 configs/{ENVIRONMENT}.yml 覆盖 configs/base.yml,默认 dev
PORT 覆盖监听端口
BIND_ADDR 监听地址,默认 127.0.0.1
LOG_LEVEL debug、info、warn、error
LOG_FORMAT text 或 json
GEOIP_DB_PATH GeoLite2 City mmdb 路径,默认 data/GeoLite2-City.mmdb

基础配置在 configs/base.yml,环境覆盖在 configs/dev.yml、configs/staging.yml、configs/production.yml。

文档

完整请求记录依赖 YAML 中的 audit.enabled: true,通过管理面板“系统设置”在运行时启停和选择下游 Key,无需重启。关闭 audit.enabled 时不会保存正文详情,但解包模式仍会写入轻量请求元数据、Token usage 与 TTFT,保证 Token 配额可跨重启恢复。记录正文可能包含提示词、工具结果、上传内容或业务秘密,只应在可信管理网络中启用;Header 和查询参数中的常见凭据(包括 Auth / X-Auth)会替换为 [REDACTED],正文不会做内容级脱敏。单侧正文最多保存 32 MiB,超过后明确标记截断;尚未落库的正文总量受 64 MiB 内存预算约束,压力下会提前截断并标记。完整记录队列满时最多回压等待 1 秒,仍无法入队则释放正文预算、累加丢弃计数,避免请求 goroutine 无界堆积;WebSocket 只保存握手信息,不保存帧内容。

开发

管理端源码位于 internal/admin/web/,生产构建输出到 internal/admin/static/dist/。生产资源使用 /admin/assets/dist/ 前缀。static/dist/ 由 Vite 生成,不提交到 Git;编译前必须先构建前端。

后端和前端开发服务器分别运行:

# 终端 1:Go 服务,监听 9002
ENCRYPTION_KEY=01234567890123456789012345678901 \
ADMIN_TOKEN=my-secret-token \
make dev

# 终端 2:Vite 开发服务器,代理管理 API 到 9002
make frontend-install
make frontend-dev

访问 http://localhost:5173/admin/next/ 调试 Vue 管理端。常用检查命令:

make frontend-check  # ESLint、类型检查、Vitest 和生产构建
make test            # 前端检查和 Go 单元测试
make fmt
make vet

make build 会先重新构建管理端,再生成 bin/llm-proxy。直接执行 go build 前需要本地已有 static/dist/:

make frontend-install
make frontend-build
go build -o bin/llm-proxy ./cmd/llm-proxy

常用源码入口:

  • cmd/llm-proxy/main.go:启动、配置加载、中间件链和路由注册。
  • internal/admin:管理 API、Vue 管理端源码、已构建资源和临时保留的旧版页面。
  • internal/admin/web:Vue 3、TypeScript、Vite、Pinia、Tailwind CSS 和组件测试。
  • internal/admin/static/dist:本地生成的管理端生产构建产物,不提交到 Git。
  • internal/store:SQLite schema、迁移和数据访问。
  • internal/proxy:动态上游选择、认证头重写、故障切换和 transport 缓存。
  • internal/middleware:鉴权、绑定、限流、审计、统计、模型过滤和流式刷新。

版本与发布

版本号集中管理在根目录 VERSION 文件中(内容为 x.x.x 格式)。

本地构建时 Makefile 先构建管理端,再读取 VERSION 并通过 -ldflags 注入版本信息:

make frontend-install  # 首次检出或 pnpm-lock.yaml 变更后执行
make build    # 输出 ./bin/llm-proxy (v2.12.0)

自动发布:当 VERSION 文件变更推送到 main 分支时,GitHub Actions 使用 Node.js 24 恢复依赖,执行前端检查和生产构建,再交叉编译 Go 二进制。随后工作流自动执行:

  1. 运行测试
  2. 交叉编译 5 个平台二进制(linux/darwin amd64+arm64, windows amd64)
  3. 压缩并生成 checksums.txt
  4. 创建 Git tag vX.X.X
  5. 创建 GitHub Release 并上传构建产物

发布新版本只需修改 VERSION 文件并推送:

echo "2.12.0" > VERSION
git add VERSION
git commit -m "chore(version): bump to 2.12.0"
git push origin main

工作流配置位于 .github/workflows/release.yml,具有幂等性——已存在的 tag 不会重复发布。

安全边界

  • 上游 Key 和可复制下游 Key 使用 ENCRYPTION_KEY 做 AES-256-GCM 加密。
  • 下游鉴权使用 Key 哈希,不用明文 Key 查询。
  • 管理 API 会返回上游明文 Key,必须只暴露在可信网络或反向代理鉴权之后。
  • 完整请求记录包含请求与响应正文,数据库、备份和 NDJSON 导出文件必须按敏感数据保护。
  • 上游 base_url 会解析 DNS 并拒绝内网、loopback、link-local IP。
  • 代理转发前会移除下游伪造身份相关请求头,并对上游错误响应做脱敏。
  • DLP 敏感信息告警:后台扫描已记录正文中的密钥/凭据模式(AWS/OpenAI/GitHub/Slack/Google API Key、私钥、JWT 等,支持自定义覆盖),命中仅保留脱敏样本,管理面板显示红色徽章并支持 Webhook 通知。

About

Go-based LLM proxy for cost tracking and rate limiting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages