- Add overview of three endpoint modes - Add /v1/responses endpoint documentation (OpenAI transparent proxy) - Add /v1/messages endpoint documentation (Anthropic transparent proxy) - Add endpoint comparison table - Add usage guide for choosing appropriate endpoint - Clarify format conversion only applies to /v1/chat/completions - Add detailed examples for each endpoint - Update feature list and usage instructions
416 lines
10 KiB
Markdown
416 lines
10 KiB
Markdown
# droid2api
|
||
|
||
OpenAI 兼容 API 代理服务器,用于在不同 LLM API 格式之间进行转换。
|
||
|
||
## 功能特性
|
||
|
||
- **三种接口模式**:
|
||
- **统一格式接口**:`/v1/chat/completions` - 支持所有端点类型,自动格式转换
|
||
- **OpenAI 透明代理**:`/v1/responses` - 直接转发 OpenAI 请求,零转换
|
||
- **Anthropic 透明代理**:`/v1/messages` - 直接转发 Anthropic 请求,零转换
|
||
- **标准 OpenAI API 接口**:提供完全兼容 OpenAI 的 API 端点
|
||
- **多格式支持**:支持 Anthropic 和自定义 OpenAI 格式之间的自动转换
|
||
- **流式响应**:自动转换 SSE (Server-Sent Events) 流式响应为标准 OpenAI 格式
|
||
- **自动刷新 API Key**:集成 WorkOS 认证,自动管理和刷新访问令牌(8小时有效期,每6小时自动刷新)
|
||
- **智能 Header 管理**:自动添加和管理所有必需的 Factory 特定 headers
|
||
- **配置化路由**:通过 config.json 灵活配置模型和端点映射
|
||
- **开发模式**:详细的日志输出,便于调试
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
## 配置
|
||
|
||
### 1. 配置端点和模型
|
||
|
||
编辑 `config.json` 文件:
|
||
|
||
```json
|
||
{
|
||
"port": 3000,
|
||
"endpoint": [
|
||
{
|
||
"name": "openai",
|
||
"base_url": "https://app.factory.ai/api/llm/o/v1/responses"
|
||
},
|
||
{
|
||
"name": "anthropic",
|
||
"base_url": "https://app.factory.ai/api/llm/a/v1/messages"
|
||
}
|
||
],
|
||
"models": [
|
||
{
|
||
"name": "Claude Opus 4",
|
||
"id": "claude-opus-4-1-20250805",
|
||
"type": "anthropic"
|
||
},
|
||
{
|
||
"name": "GPT-5 Codex",
|
||
"id": "gpt-5-codex",
|
||
"type": "openai"
|
||
}
|
||
],
|
||
"dev_mode": false
|
||
}
|
||
```
|
||
|
||
### 2. 配置认证(二选一)
|
||
|
||
#### 方式一:使用环境变量(推荐用于开发/测试)
|
||
|
||
```bash
|
||
export DROID_REFRESH_KEY="your_refresh_token_here"
|
||
```
|
||
|
||
刷新后的 API key 会保存到工作目录的 `auth.json` 文件。
|
||
|
||
#### 方式二:使用配置文件(推荐用于生产环境)
|
||
|
||
确保 `~/.factory/auth.json` 文件存在并包含有效的 tokens:
|
||
|
||
```json
|
||
{
|
||
"access_token": "your_access_token_here",
|
||
"refresh_token": "your_refresh_token_here"
|
||
}
|
||
```
|
||
|
||
刷新后的 tokens 会自动更新到原文件。
|
||
|
||
## 使用方法
|
||
|
||
### 启动服务器
|
||
|
||
```bash
|
||
npm start
|
||
```
|
||
|
||
或使用快捷脚本:
|
||
|
||
```bash
|
||
./start.sh
|
||
```
|
||
|
||
服务器默认运行在 `http://localhost:3000`。
|
||
|
||
### API 端点总览
|
||
|
||
| 端点 | 方法 | 支持类型 | 格式转换 | 适用场景 |
|
||
|------|------|---------|---------|---------|
|
||
| `/v1/models` | GET | - | - | 获取模型列表 |
|
||
| `/v1/chat/completions` | POST | anthropic, openai | ✅ 自动转换 | 需要统一OpenAI格式 |
|
||
| `/v1/responses` | POST | 仅 openai | ❌ 直接转发 | 已是目标格式,追求性能 |
|
||
| `/v1/messages` | POST | 仅 anthropic | ❌ 直接转发 | 已是目标格式,追求性能 |
|
||
|
||
### API 端点详细说明
|
||
|
||
#### 1. 获取可用模型列表
|
||
|
||
```bash
|
||
GET /v1/models
|
||
```
|
||
|
||
**示例:**
|
||
```bash
|
||
curl http://localhost:3000/v1/models
|
||
```
|
||
|
||
**响应:**
|
||
```json
|
||
{
|
||
"object": "list",
|
||
"data": [
|
||
{
|
||
"id": "claude-opus-4-1-20250805",
|
||
"object": "model",
|
||
"created": 1704067200000,
|
||
"owned_by": "factory"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 2. 统一格式接口 - 对话补全(带格式转换)
|
||
|
||
```bash
|
||
POST /v1/chat/completions
|
||
```
|
||
|
||
**功能特点:**
|
||
- ✅ 支持所有端点类型(anthropic, openai)
|
||
- ✅ 自动转换请求格式到目标端点格式
|
||
- ✅ 自动转换响应为标准 OpenAI 格式
|
||
- ✅ 适合需要统一接口的场景
|
||
|
||
**请求参数:**
|
||
- `model` (必需): 模型 ID
|
||
- `messages` (必需): 标准 OpenAI 格式消息数组
|
||
- `stream` (可选): 是否使用流式响应,默认 true
|
||
- `max_tokens` (可选): 最大输出 tokens 数
|
||
- `temperature` (可选): 温度参数 0-1
|
||
- `top_p` (可选): Top-p 采样参数
|
||
|
||
**示例(Anthropic 模型,自动转换):**
|
||
```bash
|
||
curl http://localhost:3000/v1/chat/completions \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "claude-opus-4-1-20250805",
|
||
"messages": [
|
||
{"role": "user", "content": "你好,请介绍一下你自己"}
|
||
],
|
||
"stream": true,
|
||
"max_tokens": 2000
|
||
}'
|
||
```
|
||
|
||
**示例(OpenAI 模型,自动转换):**
|
||
```bash
|
||
curl http://localhost:3000/v1/chat/completions \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "gpt-5-codex",
|
||
"messages": [
|
||
{"role": "user", "content": "写一个 Python 快速排序"}
|
||
],
|
||
"stream": false
|
||
}'
|
||
```
|
||
|
||
#### 3. OpenAI 透明代理接口(不做转换)
|
||
|
||
```bash
|
||
POST /v1/responses
|
||
```
|
||
|
||
**功能特点:**
|
||
- ⚠️ **仅支持 openai 类型端点**
|
||
- ❌ 请求体不做任何转换,直接转发
|
||
- ❌ 响应体不做任何转换,直接转发
|
||
- ✅ 适合已是目标格式,追求最高性能的场景
|
||
|
||
**限制:**
|
||
使用非 openai 类型模型会返回 400 错误:
|
||
```json
|
||
{
|
||
"error": "Invalid endpoint type",
|
||
"message": "/v1/responses 接口只支持 openai 类型端点"
|
||
}
|
||
```
|
||
|
||
**示例:**
|
||
```bash
|
||
curl http://localhost:3000/v1/responses \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "gpt-5-codex",
|
||
"messages": [{"role": "user", "content": "Hello"}],
|
||
"stream": true
|
||
}'
|
||
```
|
||
|
||
#### 4. Anthropic 透明代理接口(不做转换)
|
||
|
||
```bash
|
||
POST /v1/messages
|
||
```
|
||
|
||
**功能特点:**
|
||
- ⚠️ **仅支持 anthropic 类型端点**
|
||
- ❌ 请求体不做任何转换,直接转发
|
||
- ❌ 响应体不做任何转换,直接转发
|
||
- ✅ 适合已是目标格式,追求最高性能的场景
|
||
|
||
**限制:**
|
||
使用非 anthropic 类型模型会返回 400 错误:
|
||
```json
|
||
{
|
||
"error": "Invalid endpoint type",
|
||
"message": "/v1/messages 接口只支持 anthropic 类型端点"
|
||
}
|
||
```
|
||
|
||
**示例:**
|
||
```bash
|
||
curl http://localhost:3000/v1/messages \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "claude-opus-4-1-20250805",
|
||
"messages": [{"role": "user", "content": "Hello"}],
|
||
"max_tokens": 1024,
|
||
"stream": true
|
||
}'
|
||
```
|
||
|
||
## API Key 自动刷新机制
|
||
|
||
代理服务器会自动管理 API key 的刷新:
|
||
|
||
1. **启动时刷新**:服务器启动时自动获取新的 access token
|
||
2. **定期刷新**:每次 API 请求前检查,如果距离上次刷新超过 6 小时则自动刷新
|
||
3. **令牌有效期**:access token 有效期为 8 小时
|
||
4. **自动保存**:刷新后的 tokens 自动保存到相应的配置文件
|
||
|
||
**刷新日志示例:**
|
||
```
|
||
[INFO] Refreshing API key...
|
||
[INFO] Authenticated as: user@example.com (John Doe)
|
||
[INFO] User ID: user_01K69S755R2TWYFWKPSP74TRKZ
|
||
[INFO] Organization ID: org_01K69S7KKYK6F2WYJ8CB384GW6
|
||
[INFO] API key refreshed successfully
|
||
```
|
||
|
||
## 接口模式选择指南
|
||
|
||
### 何时使用 `/v1/chat/completions`(统一格式)
|
||
|
||
✅ **推荐场景:**
|
||
- 需要统一的 OpenAI 兼容接口
|
||
- 应用代码已使用 OpenAI SDK
|
||
- 需要在不同 LLM 提供商之间切换
|
||
- 不关心轻微的性能损耗
|
||
|
||
❌ **不推荐场景:**
|
||
- 已有原生格式的请求/响应处理逻辑
|
||
- 对性能要求极高(需要避免格式转换开销)
|
||
|
||
### 何时使用 `/v1/responses`(OpenAI 透明代理)
|
||
|
||
✅ **推荐场景:**
|
||
- 请求已经是目标 OpenAI 端点格式
|
||
- 追求最高性能,避免格式转换开销
|
||
- 只使用 OpenAI 端点
|
||
|
||
❌ **不推荐场景:**
|
||
- 使用 Anthropic 端点(会返回错误)
|
||
- 需要格式转换
|
||
|
||
### 何时使用 `/v1/messages`(Anthropic 透明代理)
|
||
|
||
✅ **推荐场景:**
|
||
- 请求已经是标准 Anthropic 格式
|
||
- 追求最高性能,避免格式转换开销
|
||
- 只使用 Anthropic 端点
|
||
|
||
❌ **不推荐场景:**
|
||
- 使用 OpenAI 端点(会返回错误)
|
||
- 需要格式转换
|
||
|
||
## 格式转换说明
|
||
|
||
> 注意:仅 `/v1/chat/completions` 接口会进行格式转换,`/v1/responses` 和 `/v1/messages` 直接转发,不做任何转换。
|
||
|
||
### Anthropic 格式转换(仅 /v1/chat/completions)
|
||
|
||
**请求转换:**
|
||
- `messages` → `messages`(提取 system 消息到顶层)
|
||
- `max_tokens` → `max_tokens`(默认 4096)
|
||
- 文本内容包装为 `{type: 'text', text: '...'}`
|
||
- 工具格式转换
|
||
|
||
**响应转换:**
|
||
- 转换 SSE 事件:`message_start`, `content_block_delta`, `message_delta`, `message_stop`
|
||
- 转换为标准 OpenAI chunk 格式
|
||
- 映射停止原因:`end_turn` → `stop`, `max_tokens` → `length`
|
||
|
||
### OpenAI 格式转换(仅 /v1/chat/completions)
|
||
|
||
**请求转换:**
|
||
- `messages` → `input`
|
||
- `max_tokens` → `max_output_tokens`
|
||
- 用户消息:`text` → `input_text`
|
||
- 助手消息:`text` → `output_text`
|
||
- 提取 system 消息为 `instructions` 参数
|
||
|
||
**响应转换:**
|
||
- 转换 SSE 事件:`response.created`, `response.in_progress`, `response.done`
|
||
- 转换为标准 OpenAI chunk 格式
|
||
|
||
## Header 管理
|
||
|
||
代理服务器会自动添加所有必需的 headers:
|
||
|
||
### Anthropic 端点
|
||
- `x-model-provider: anthropic`
|
||
- `x-factory-client: cli`
|
||
- `user-agent: a$/JS 0.57.0`
|
||
- `anthropic-version: 2023-06-01`
|
||
- `anthropic-beta: interleaved-thinking-2025-05-14`
|
||
- `x-stainless-helper-method: stream`(流式请求)
|
||
- 自动生成的 UUID:`x-session-id`, `x-assistant-message-id`
|
||
|
||
### OpenAI 端点
|
||
- `x-factory-client: cli`
|
||
- `user-agent: cB/JS 5.22.0`
|
||
- 自动生成的 UUID:`x-session-id`, `x-assistant-message-id`
|
||
|
||
## 开发模式
|
||
|
||
在 `config.json` 中设置 `dev_mode: true` 可以启用详细日志:
|
||
|
||
```json
|
||
{
|
||
"dev_mode": true
|
||
}
|
||
```
|
||
|
||
**日志内容包括:**
|
||
- 完整的请求和响应 headers
|
||
- 请求体和响应体
|
||
- 格式转换过程
|
||
- SSE 事件处理详情
|
||
|
||
## 端口冲突处理
|
||
|
||
如果端口 3000 已被占用,可以:
|
||
|
||
1. **修改配置文件**:编辑 `config.json` 中的 `port` 字段
|
||
2. **或者结束占用进程**:
|
||
```bash
|
||
lsof -ti:3000 | xargs kill -9
|
||
```
|
||
|
||
## 故障排查
|
||
|
||
### 启动时报错 "Refresh token not found"
|
||
|
||
**原因**:未配置 refresh token
|
||
|
||
**解决方案**:
|
||
- 设置环境变量 `DROID_REFRESH_KEY`
|
||
- 或配置 `~/.factory/auth.json` 文件
|
||
|
||
### 请求返回 401 错误
|
||
|
||
**可能原因**:
|
||
1. refresh token 已过期或无效
|
||
2. API key 刷新失败
|
||
|
||
**解决方案**:
|
||
- 检查日志中的刷新错误信息
|
||
- 重新获取有效的 refresh token
|
||
- 确认 `~/.factory/auth.json` 中的 tokens 正确
|
||
|
||
### 响应格式错误
|
||
|
||
**原因**:模型类型配置错误
|
||
|
||
**解决方案**:
|
||
- 检查 `config.json` 中模型的 `type` 字段
|
||
- Anthropic 模型使用 `"type": "anthropic"`
|
||
- OpenAI 模型使用 `"type": "openai"`
|
||
|
||
## 技术架构
|
||
|
||
- **语言**:Node.js (ES Modules)
|
||
- **框架**:Express
|
||
- **HTTP 客户端**:node-fetch
|
||
- **认证**:WorkOS OAuth 2.0 Refresh Token Flow
|
||
|
||
## 许可证
|
||
|
||
MIT
|