轻量的自建 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。
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"
}'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}'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 vetmake 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 二进制。随后工作流自动执行:
- 运行测试
- 交叉编译 5 个平台二进制(linux/darwin amd64+arm64, windows amd64)
- 压缩并生成
checksums.txt - 创建 Git tag
vX.X.X - 创建 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 通知。