130 lines
5.7 KiB
Markdown
130 lines
5.7 KiB
Markdown
# 官方兼容层的做法(现成参考实现)
|
||
|
||
各家自己都做了"接受他家格式"的兼容层。它们踩过的坑和做出的取舍,正好是中转站的设计参考——尤其是**"忽略 vs 报错"的边界划在哪里**。
|
||
|
||
> 来源:
|
||
> - https://platform.claude.com/docs/en/api/openai-sdk
|
||
> - https://api-docs.deepseek.com/guides/anthropic_api
|
||
> - https://api-docs.deepseek.com/guides/responses_api
|
||
>
|
||
> 采集于 2026-08-12。
|
||
|
||
---
|
||
|
||
## 1. Anthropic 的 OpenAI SDK 兼容层
|
||
|
||
Base URL:`https://api.anthropic.com/v1/`,用 Anthropic API key,模型名填 Claude 模型名。
|
||
|
||
官方定位明确写着:**主要用于测试和能力对比,不建议作为长期生产方案**。
|
||
|
||
### 核心行为差异
|
||
|
||
1. **`strict` 被忽略** —— 工具调用 JSON 不保证符合 schema。要严格保证得用原生 Structured Outputs。
|
||
2. **音频输入被忽略并从输入中剥离**(不报错)。
|
||
3. **Prompt caching 不支持**(原生 SDK 支持)。
|
||
4. **system/developer 消息被提升并拼接**:所有 system/developer 消息用**单个 `\n`** 连接成一条,放在对话最前面。
|
||
5. **大部分不支持的字段静默忽略,不报错。**
|
||
|
||
### 参数支持表
|
||
|
||
| 支持 | 部分支持 | 忽略 |
|
||
| --- | --- | --- |
|
||
| `model`、`max_tokens`、`max_completion_tokens`、`stream`、`stream_options`、`top_p`、`parallel_tool_calls` | `stop`(仅非空白停止序列)<br>`temperature`(0~1,**>1 截断为 1**)<br>`n`(**必须恰为 1**) | `logprobs`、`top_logprobs`、`metadata`、`response_format`、`prediction`、`presence_penalty`、`frequency_penalty`、`seed`、`service_tier`、`audio`、`logit_bias`、`store`、`user`、`modalities`、`reasoning_effort` |
|
||
|
||
消息字段层面:
|
||
|
||
| 位置 | 忽略的字段 |
|
||
| --- | --- |
|
||
| 所有 role | `name` |
|
||
| user + `image_url` | `detail` |
|
||
| user | `input_audio`、`file` 类型 content |
|
||
| assistant | `refusal` content、`audio`、`refusal` |
|
||
| tools | `function.strict` |
|
||
|
||
### 响应字段
|
||
|
||
| 恒定行为 | 字段 |
|
||
| --- | --- |
|
||
| 长度恒为 1 | `choices[]` |
|
||
| 恒为空 | `usage.completion_tokens_details`、`usage.prompt_tokens_details`、`choices[].message.refusal`、`choices[].message.audio`、`logprobs`、`service_tier`、`system_fingerprint` |
|
||
|
||
### Header
|
||
|
||
支持 `x-ratelimit-*` 全套、`retry-after`、`request-id`、`authorization`。
|
||
`openai-version` 恒为 `2020-10-01`,`openai-processing-ms` 恒为空。
|
||
|
||
### 错误
|
||
|
||
错误**格式**与 OpenAI 一致,但**错误消息内容不等价**。官方明确说明:只用于日志和调试,**不要基于错误消息文本做逻辑判断**。
|
||
|
||
### thinking 的传法
|
||
|
||
通过 `extra_body` 透传:
|
||
|
||
```python
|
||
response = client.chat.completions.create(
|
||
model="claude-sonnet-4-6",
|
||
messages=[{"role": "user", "content": "Who are you?"}],
|
||
extra_body={"thinking": {"type": "enabled", "budget_tokens": 2000}},
|
||
)
|
||
```
|
||
|
||
但 **OpenAI SDK 不会返回 Claude 的详细思考过程**——要拿到思考内容必须用原生 API。
|
||
|
||
---
|
||
|
||
## 2. DeepSeek 的 Anthropic 兼容层
|
||
|
||
Base URL:`https://api.deepseek.com/anthropic`(配置 `ANTHROPIC_BASE_URL`)。
|
||
|
||
### 模型名映射(静默兜底)
|
||
|
||
| 传入 | 实际使用 |
|
||
| --- | --- |
|
||
| `claude-opus*` | `deepseek-v4-pro` |
|
||
| `claude-haiku*` / `claude-sonnet*` | `deepseek-v4-flash` |
|
||
| 其他任意值 | `deepseek-v4-flash` |
|
||
|
||
**未知模型名不报错**。这是个值得商榷的设计——用户拼错模型名会得到一个成功但非预期的响应。
|
||
|
||
### 支持 / 忽略
|
||
|
||
| 支持 | 忽略或不支持 |
|
||
| --- | --- |
|
||
| `model`、`max_tokens`、`system`、`stream`、`stop_sequences`、`tools` | `anthropic-beta` / `anthropic-version` header |
|
||
| `temperature`(**0.0~2.0**,比官方 Anthropic 的 0~1 宽) | image / document content 类型 |
|
||
| `thinking`(但 **`budget_tokens` 被忽略**) | `top_k` |
|
||
| `metadata.user_id`(用于限流隔离) | 其他 metadata 字段 |
|
||
|
||
### 思考参数命名不一致
|
||
|
||
DeepSeek 的 Anthropic 入口用 **`reasoning.effort`**,而官方 Anthropic API 用 `thinking` + `output_config.effort`。
|
||
换句话说:**同一段客户端代码不能同时对接官方 Anthropic 和 DeepSeek 的 Anthropic 入口**。
|
||
|
||
---
|
||
|
||
## 3. DeepSeek 的 Responses API 兼容层
|
||
|
||
Base URL:`https://api.deepseek.com`,目前**只支持 `deepseek-v4-flash`**。
|
||
|
||
- **"未支持的参数一律静默忽略,不报错"** —— 官方明文的设计原则,理由是不破坏既有实现。
|
||
- `store` 恒返回 `false`。
|
||
- `previous_response_id`、`conversation` 不支持(无状态架构)。
|
||
- 上下文缓存自动进行,无手动参数。
|
||
- **image / file 输入被替换成占位文本**。这是"静默忽略"里最危险的一种:请求成功、响应看起来正常,但模型根本没看到图片。
|
||
|
||
---
|
||
|
||
## 4. 对本项目的设计启示
|
||
|
||
1. **"静默忽略"是行业默认做法**,但它把调试成本转嫁给用户。建议:
|
||
- 默认静默忽略(保持生态兼容);
|
||
- 同时通过响应 header(如 `x-gateway-dropped-params`)或可选的严格模式(`?strict=1`)暴露被丢弃的参数。
|
||
- **对会改变语义的丢弃(图片、音频、工具 strict)必须有更强的信号**,不能和 `seed` 这种无害丢弃一视同仁。
|
||
2. **模型名兜底要谨慎**。DeepSeek 的"未知名字 → flash"会掩盖拼写错误。建议白名单 + 显式别名表,未匹配则 404。
|
||
3. **错误消息不要求等价,但格式必须等价**。Anthropic 兼容层的态度是对的:格式对齐,消息内容不承诺。
|
||
4. **能力降级要分级**:
|
||
- 无害(`seed`、`logit_bias`、`metadata`)→ 静默丢
|
||
- 影响质量(`temperature` clamp、`top_k` 丢弃)→ 记录日志
|
||
- 改变语义(图片被丢、`strict` 失效、`n>1` 退化)→ 报错或强提示
|