llm-proxy
本地 LLM 代理服务,单端口同时提供管理 UI 和 AI API,支持多协议路由、协议互转、流式 SSE 转换、token 统计、协议抓包调试。
功能特性
- 多协议支持:单端口提供 Anthropic、OpenAI、OpenAI Responses 三种协议
- 协议互转:三个协议间双向转换(流式 + 非流式)
- 外挂识图:为不支持图片的模型自动接入识图模型,把图片转成文字描述再转发;自带持久化 LRU 缓存
- macOS 桌面应用:原生菜单栏 App,内嵌代理服务,拖拽安装、零依赖
- 管理界面:Alpine.js 单页应用,包含仪表盘、Provider 管理、适配器配置、识图设置、抓包调试
- 虚拟适配器:自定义端点 + 模型重映射(
/{adapter-name}/v1/...) - SSE 流式:4 个双向流转换器,每行带时间戳
- 协议抓包:环形缓冲记录原始请求/响应,支持左右对比 + 差异分析
- 热加载:配置原子替换,进行中请求不受影响
- Token 统计:按 Provider 统计 token 使用量
截图
macOS 菜单栏 — 服务控制、适配器切换、语言设置 | 适配器列表和模型映射

管理仪表盘 — Provider 状态、Token 用量、代理密钥管理

Provider 管理 — 添加/编辑/删除 AI 服务商,拉取模型列表,声明输入模态

适配器配置 — 虚拟端点 + 模型重映射
安装
macOS(推荐):
从 Releases 下载 LLMProxy.dmg,拖入 /Applications。如果 macOS 阻止运行,执行:
xattr -cr /Applications/LLMProxy.app再次打开即可。内含完整代理服务和管理界面。
macOS(Homebrew):
brew tap maplezzk/tap && brew install --cask llm-proxy仅 CLI:
npm install -g @maplezzk/llm-proxy快速开始
# 启动
llm-proxy start
# 打开管理界面 → http://127.0.0.1:9000/admin/首次启动会自动创建配置目录。打开管理界面在浏览器里完成所有配置,无需手写 YAML。
管理界面支持:
- Provider 管理:增删改 AI 服务商、拉取远程模型列表、声明输入模态(文本/图片)
- 适配器配置:创建带模型重映射和协议转换的虚拟端点
- 识图设置:为不支持图片的模型启用外挂识图、查看缓存命中率
- 代理密钥:设置 API 认证密钥
- 连通性测试:直接发送测试请求验证配置
- 协议抓包:实时查看请求/响应原文
配置
~/.llm-proxy/config.yaml:
log_level: debug # debug | info | warn | error
port: 9000 # 可选:默认 9000
max_body_size: 10485760 # 可选:请求体大小上限(字节,默认 10MB)
proxy_key: sk-xxx # 可选:设置后 /v1/* 需认证
providers:
- name: deepseek
type: openai # anthropic | openai | openai-responses
api_key: ${DEEPSEEK_API_KEY}
api_base: https://api.deepseek.com
models:
- id: deepseek-chat
- name: anthropic
type: anthropic
api_key: ${ANTHROPIC_API_KEY}
models:
# 多模态模型 — 显式声明支持图片
- id: claude-sonnet-4
input: [text, image]
thinking:
budget_tokens: 10000
# 非多模态模型 — 图片请求会自动走外挂识图
- id: deepseek-reasoner
# 不写 input → 默认 [text];图片请求触发外挂识图
# MiniMax 思考模式透传(非标准 thinking.type)
- id: MiniMax-M2
thinking:
type: enabled
adapters:
- name: my-tool
type: anthropic
models:
- sourceModelId: claude-sonnet-4
provider: anthropic
targetModelId: claude-sonnet-4-20250514
# 外挂识图 — 为不支持图片的模型自动识图
vision:
provider: anthropic # 必填:识图 Provider
model: claude-sonnet-4 # 必填:多模态模型 ID
prompt: | # 可选:自定义提示词(默认见下)
请详细描述这张图片的内容,包括其中的文字、物体、场景、颜色等关键信息。API Key 通过环境变量注入(${VAR}),配置文件不保存明文密钥。
外挂识图
当路由目标模型 未声明 input: image 时,llm-proxy 可以自动把图片内容转成文字描述,再交给模型处理:
- 入站请求包含图片块(Anthropic
image、OpenAI Chatimage_url、OpenAI Responsesinput_image) - llm-proxy 提取每张图片,通过代理自身路由调用配置的识图 Provider/Model(递归路由)
- 把图片块替换为
<image_description>...</image_description>文本块 - 非多模态模型收到文本,就能"看懂"图片内容
识图缓存(~/.llm-proxy/vision-cache.json):
- 键:base64 图片用
md5:<hash>,URL 图片用url:<原 URL> - LRU 淘汰上限 1000 条(可通过
vision_cache.max_entries调整) - 内存变更后 5s 防抖刷盘;进程退出前同步刷盘
- 统计信息:
hits / misses / hit-rate,通过/admin/vision-cache/stats查看
缓存文件位置:~/.llm-proxy/vision-cache.json
CLI 命令
llm-proxy start # 启动代理
llm-proxy stop # 停止代理
llm-proxy restart # 重启
llm-proxy reload # 热加载配置(零中断)
llm-proxy status # 查看状态管理 API
| 端点 | 方法 | 说明 |
|---|---|---|
/admin/config |
GET | 查看配置(Key 脱敏) |
/admin/config/reload |
POST | 热加载配置 |
/admin/health |
GET | 健康检查 |
/admin/status/providers |
GET | Provider 状态统计 |
/admin/logs |
GET | 请求日志 |
/admin/logs/stats |
GET | 日志统计 |
/admin/token-stats |
GET | Token 统计 |
/admin/log-level |
GET / PUT | 查看 / 修改日志级别 |
/admin/locale |
GET / PUT | 查看 / 修改界面语言(zh / en) |
/admin/port |
GET / PUT | 查看 / 修改监听端口(需重启生效) |
/admin/proxy-key |
GET / PUT | 查看 / 修改代理认证密钥 |
/admin/vision |
GET / PUT | 查看 / 修改外挂识图配置 |
/admin/vision-cache/stats |
GET | 识图缓存命中率 / 容量 |
/admin/vision-cache/clear |
POST | 清空识图缓存 |
/admin/adapters |
GET / POST / PUT / DELETE | 适配器 CRUD |
/admin/providers |
POST / PUT / DELETE | Provider CRUD |
/admin/providers/:name/pull-models |
POST | 拉取远程模型列表 |
/admin/test-model |
POST | 向 Provider/Model 发送测试请求 |
/admin/test-adapter |
POST | 通过适配器发送测试请求 |
/admin/debug/captures/* |
GET / POST | 协议抓包环形缓冲 + SSE 推送 |
协议转换矩阵
| 源 | 目标 | 非流式 | 流式 (SSE) |
|---|---|---|---|
| Anthropic | OpenAI | ||
| OpenAI | Anthropic | ||
| Anthropic | OpenAI Responses | ||
| OpenAI Responses | Anthropic |
架构
Client → POST /v1/{messages|chat/completions|responses}
→ server.ts(正则路由匹配)
→ pipeline.ts(统一请求流水线)
→ parseAndAuth()(body、JSON、认证、提取 model)
→ vision.ts(图片 → 文字(外挂识图),含 LRU 缓存)
→ router.ts(modelName → Provider)
→ translation.ts(协议转换、thinking 注入)
→ provider.ts(fetch 上游)
→ stream-converter.ts(SSE 转换)
→ capture.ts(环形缓冲 + SSE 推送)
→ token-tracker(按 Provider 统计 token 用量)
→ 响应
- 运行时:Node.js >= 20, TypeScript ESM
- 前端:Alpine.js 单页应用
- 构建:
tsc+esbuild - 测试:Node.js 原生测试运行器 + tsx(280 个测试)
开发
详见 DEVELOPMENT.md。
npm run dev # 开发模式启动代理
npm test # 运行 280 个测试
npm run build:app # 构建 macOS .app + .dmgFAQ
Homebrew 安装显示旧版本? 强制刷新 tap:
brew upgrade --cask llm-proxy如果失败,先卸载再重新安装:
brew uninstall --cask llm-proxy
brew untap maplezzk/tap && brew tap maplezzk/tap && brew install --cask llm-proxymacOS 阻止应用运行? 清除隔离标记:
xattr -cr /Applications/LLMProxy.app怎么清空识图缓存? 任选其一:
rm ~/.llm-proxy/vision-cache.json或调用 POST /admin/vision-cache/clear(也可以在管理界面 → 识图设置 → 「清空缓存」按钮)。
识图缓存在哪里? ~/.llm-proxy/vision-cache.json,重启后保留,5s 防抖刷盘。
怎么给模型开启图片输入? 在管理界面 → Providers → 编辑模型 → 勾选 输入模态 → 图片,或在 config.yaml 中加 input: [text, image]。未声明 image 的模型在配置了 vision: 后会自动走外挂识图。