Files
zend-token/docs/compatibility-layers.md
T
2026-08-23 02:12:08 +08:00

130 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 官方兼容层的做法(现成参考实现)
各家自己都做了"接受他家格式"的兼容层。它们踩过的坑和做出的取舍,正好是中转站的设计参考——尤其是**"忽略 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` 退化)→ 报错或强提示