一个轻量级反向代理,让 Cursor(及其他 OpenAI 兼容客户端)能够对接任意 LLM 后端——Anthropic、Gemini、OpenAI Responses API 或标准 OpenAI Chat——自动完成 API 格式转换,内置管理后台、请求日志和逐模型配置。
- 多格式请求转换 —— 接收 Anthropic Messages、Gemini Contents、OpenAI Responses、OpenAI Chat Completions 四种格式,统一转换为 OpenAI Chat 格式后转发至上游。
- 逐模型配置 —— 为每个模型名称单独定义输入格式和 body 修改规则。
<think>标签处理 —— 自动将reasoning_content字段转换为<think>...</think>标签(流式和非流式响应均支持),让 Cursor 正确显示思维链内容。- 流式支持 —— 完整的 SSE 透传,使用状态机在 chunk 边界正确处理
<think>标签的开闭。 - Body 修改 —— 支持对转发请求体进行 set(设置/覆盖字段)和 delete(删除字段,值为 null)操作,例如注入
reasoning_effort、删除temperature等。 - 请求日志 —— 每个请求/响应对均记录到按配置分表、按日期分库的 SQLite 数据库中,包含原始和转换后的 body、headers 及耗时数据。
- 管理后台 —— Vue 3 + Tailwind CSS 单页应用,用于管理配置、模型映射、查看日志和监控使用统计。
- Token 认证 —— 管理 API 通过可配置的
ADMIN_TOKEN保护;代理端点保持开放。 - 单文件部署 —— 前端在构建时嵌入 Go 二进制文件,无需额外 Web 服务器。
- Docker 就绪 —— 包含多阶段 Dockerfile 和 docker-compose;CI 在每次推送到
main时自动发布到 GHCR。
Cursor IDE
|
| POST /{config_id}/v1/chat/completions
v
+----------------------------------------------------------+
| NewCursorProxy |
| |
| 1. 路由匹配 config_id |
| 查找 Config(upstream_url)和 ModelMapping |
| |
| 2. 匹配模型名 --> 确定 input_format |
| |
| 3. 入站转换(Inbound Transform) |
| anthropic/messages \ |
| openai/responses }--> 统一 LLM 请求 |
| gemini/contents / |
| openai/chat_completions (直接透传) |
| |
| 4. 出站转换(Outbound Transform) |
| 统一 LLM 请求 --> OpenAI Chat 格式 body |
| |
| 5. 应用 body_modifications |
| set: 设置/覆盖字段 delete: 值为 null 删除字段 |
| |
| 6. 转发至上游 |
| Headers 透传(去除 hop-by-hop 头) |
| 可选: UPSTREAM_AUTHORIZATION 覆盖 |
| |
| 7. 响应处理 |
| 流式: SSE 状态机将 |
| reasoning_content --> <think> 标签 |
| 非流式: JSON 重写 reasoning_content |
| |
| 8. 记录到 SQLite(按配置分表,按日期分库) |
| |
+----------------------------------------------------------+
|
v
上游 LLM 服务(OpenAI、Azure、本地部署等)
一条命令启动:
docker run -d \
--name newcursorproxy \
-p 8080:8080 \
-e ADMIN_TOKEN=your-secret \
-v proxy-data:/app/data \
ghcr.io/nickjerome/newcursorproxy:latest仓库中已包含 docker-compose.yml:
services:
proxy:
image: ghcr.io/nickjerome/newcursorproxy:latest
ports:
- "8080:8080"
environment:
- PORT=8080
- DATA_DIR=/app/data
- ADMIN_TOKEN=${ADMIN_TOKEN:-changeme}
volumes:
- proxy-data:/app/data
restart: unless-stopped
volumes:
proxy-data:启动:
ADMIN_TOKEN=your-secret docker compose up -d管理后台:http://localhost:8080
代理端点:http://localhost:8080/{config_id}/v1/chat/completions
| 工具 | 版本 |
|---|---|
| Go | 1.25+ |
| Node | 22+ |
| pnpm | latest |
-
克隆仓库
git clone https://github.com/NickJerome/NewCursorProxy.git cd NewCursorProxy -
安装前端依赖并构建
cd frontend pnpm install pnpm build cd ..
-
构建 Go 二进制
开发模式(前端由
pnpm dev单独启动):go build -o proxy ./cmd/proxy/
生产模式(前端嵌入二进制):
cp -r frontend/dist cmd/proxy/frontend/dist go build -tags embed_frontend -ldflags="-s -w" -o proxy ./cmd/proxy/ -
运行
ADMIN_TOKEN=your-secret ./proxy
| 变量 | 默认值 | 说明 |
|---|---|---|
PORT |
8080 |
服务监听端口 |
DATA_DIR |
data |
SQLite 数据目录(配置库 + 日志库),自动创建 |
ADMIN_TOKEN |
(无) | /api/* 管理端点的 Bearer Token;未设置时管理 API 不做认证 |
UPSTREAM_INSECURE_SKIP_VERIFY |
(无) | 设为 1 或 true 跳过上游 TLS 证书验证(用于自签名证书) |
UPSTREAM_AUTHORIZATION |
(无) | 设置后覆盖所有上游请求的 Authorization 头 |
浏览器访问 http://localhost:8080。
输入 ADMIN_TOKEN 即可登录。Token 以 Bearer 方式通过 Authorization 头发送。
一个 配置 代表一个上游 LLM 服务端点:
| 字段 | 说明 |
|---|---|
id |
URL 安全的短标识符(如 openai、azure-gpt4、local),用于代理 URL 路径 |
name |
显示名称 |
upstream_url |
上游服务地址。代理会自动拼接 /v1/chat/completions(如果路径中尚未包含) |
示例:配置 ID 为 mycloud,服务器地址为 proxy.example.com,则 Cursor 请求地址为:
http://proxy.example.com/mycloud/v1/chat/completions
每个配置可包含多个 模型映射。请求到达时,代理根据请求体中的 model 字段匹配对应的模型配置。
| 字段 | 说明 |
|---|---|
model_name |
要匹配的模型名(如 claude-3.5-sonnet、gpt-4o) |
input_format |
入站请求的 API 格式(见下表) |
body_modifications |
对转发请求体的修改规则(见下方说明) |
header_modifications |
对转发请求头的修改规则(与请求体规则相同,见下方说明) |
在 Cursor 设置中,将 API 基础 URL 设为:
http://your-server:8080/{config_id}/v1/chat/completions
将 {config_id} 替换为你创建的配置 ID。
input_format 告诉代理入站请求体使用的格式,代理会将其转换为 OpenAI Chat Completions 格式后转发上游。
| 格式 | 说明 |
|---|---|
openai/chat_completions |
标准 OpenAI Chat Completions API,无需转换(直接透传) |
openai/responses |
OpenAI Responses API 格式,转换为 Chat Completions |
anthropic/messages |
Anthropic Messages API 格式(messages、system、max_tokens 等) |
gemini/contents |
Google Gemini API 格式(contents、generationConfig 等) |
如果请求中的模型名没有对应的模型映射,请求体将原样转发,不做转换。
body_modifications 是一个 JSON 对象,在格式转换 之后 应用到转发的请求体上:
- 设置字段(set):
{"reasoning_effort": "high", "temperature": 0.7}—— 添加或覆盖这些字段 - 删除字段(delete):
{"stream_options": null}—— 将值设为null表示从请求体中删除该字段
适用场景:注入 Cursor 不会发送的提供商专属参数,或移除上游不支持的字段。
header_modifications 是一个 JSON 对象,在复制完入站请求头 之后 应用到转发的请求头上,规则与请求体修改一致:
- 设置/覆盖(set):
{"X-Custom-Header": "value", "Authorization": "Bearer xxx"}—— 添加或覆盖这些请求头 - 删除(delete):
{"X-Unwanted": null}—— 将值设为null表示删除该请求头
适用场景:为上游设置固定或按模型区分的请求头(如 API 版本、自定义认证等)。
许多推理模型在 reasoning_content 字段中返回思维链内容(与主 content 分开)。Cursor 期望这些内容以 <think>...</think> 标签包裹在 content 字段中。
NewCursorProxy 自动处理此转换:
- 流式响应:状态机跟踪
<think>标签是否已打开。当reasoning_contentchunk 到达时,自动注入<think>\n前缀;当普通content恢复或流结束时,注入\n</think>\n闭合标签。reasoning_content字段从每个 chunk 中移除。 - 非流式响应:如果响应 JSON 中包含
reasoning_content,将其作为<think>\n...\n</think>\n前置到content字段,并移除reasoning_content字段。
无需任何配置,此处理始终生效。
所有管理端点位于 /api/ 下,需要 Authorization: Bearer <ADMIN_TOKEN> 头(ADMIN_TOKEN 未设置时无需认证)。
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/auth/check |
验证 token 是否有效,返回 {"status":"ok"} |
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/configs |
列出所有配置 |
POST |
/api/configs |
创建配置 |
GET |
/api/configs/{id} |
获取单个配置 |
PUT |
/api/configs/{id} |
更新配置 |
DELETE |
/api/configs/{id} |
删除配置及其所有模型映射 |
创建/更新请求体:
{
"id": "my-provider",
"name": "My LLM Provider",
"upstream_url": "https://api.example.com"
}| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/configs/{id}/models |
列出模型映射 |
POST |
/api/configs/{id}/models |
创建模型映射 |
PUT |
/api/configs/{id}/models/{model_id} |
更新模型映射 |
DELETE |
/api/configs/{id}/models/{model_id} |
删除模型映射 |
创建/更新请求体:
{
"model_name": "claude-3.5-sonnet",
"input_format": "anthropic/messages",
"body_modifications": {
"reasoning_effort": "high",
"stream_options": null
}
}| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/configs/{id}/logs |
查询配置的请求日志 |
查询参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
date |
今天 | 按日期筛选(YYYY-MM-DD) |
page |
1 |
页码 |
limit |
20 |
每页条数 |
响应:
{
"data": [ ... ],
"total": 42,
"page": 1,
"limit": 20
}| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/configs/{id}/overview |
获取配置下所有模型的聚合统计(token 用量、请求数、平均 TTFT、平均 TPS) |
NewCursorProxy/
|-- cmd/proxy/
| |-- main.go # 入口
| |-- embed_prod.go # 生产构建:嵌入 frontend/dist
| `-- embed_dev.go # 开发构建:前端 FS 为 nil
|-- internal/
| |-- config/
| | |-- model.go # Config、ModelMapping 数据模型
| | `-- store.go # SQLite 配置存储(CRUD)
| |-- logging/
| | |-- model.go # LogEntry 数据模型
| | `-- store.go # SQLite 日志存储(按日期分库)
| |-- proxy/
| | |-- handler.go # 代理主处理器 + 格式转换
| | |-- forwarder.go # 上游转发 + body_modifications 应用
| | `-- think.go # <think> 标签处理(流式 + 非流式)
| `-- web/
| |-- router.go # HTTP 路由、SPA 服务、CORS
| |-- auth.go # ADMIN_TOKEN 认证中间件
| |-- config_handler.go # 配置和模型映射 API
| |-- logs_handler.go # 日志查询 API
| `-- overview_handler.go # 使用统计 API
|-- llm/ # 协议转换库(来自 axonhub)
| |-- model.go # 统一 LLM 请求/响应类型
| |-- transformer/
| | |-- interfaces.go # Inbound/Outbound 转换器接口
| | |-- anthropic/ # Anthropic Messages <-> 统一格式
| | |-- openai/ # OpenAI Chat <-> 统一格式
| | | `-- responses/ # OpenAI Responses API <-> 统一格式
| | `-- gemini/ # Gemini Contents <-> 统一格式
| `-- httpclient/ # HTTP 客户端工具
|-- frontend/ # Vue 3 + Tailwind CSS 管理后台
|-- Dockerfile # 多阶段构建(Node + Go + Alpine)
|-- docker-compose.yml
`-- .github/workflows/docker.yml # CI:构建并推送镜像到 GHCR
MIT License