fix: 完善转换代理行为
This commit is contained in:
@@ -325,3 +325,137 @@ TargetProvider 的 ModelName 字段 SHALL 存储上游供应商的模型名称
|
||||
|
||||
- **WHEN** 协议适配器编码请求时
|
||||
- **THEN** SHALL 使用 `TargetProvider.ModelName` 作为发给上游的 `model` 字段值(值为路由结果中的 model_name)
|
||||
|
||||
### Requirement: 同协议请求 URL 使用 Adapter 映射
|
||||
|
||||
ConversionEngine SHALL 在同协议透传和 Smart Passthrough 场景下使用 providerAdapter.BuildUrl 构建上游 URL 路径。
|
||||
|
||||
#### Scenario: 同协议 Chat URL 映射
|
||||
|
||||
- **WHEN** clientProtocol == providerProtocol 且 interfaceType 为 CHAT
|
||||
- **THEN** ConversionEngine SHALL 调用 providerAdapter.BuildUrl(nativePath, interfaceType)
|
||||
- **THEN** 上游 URL SHALL 为 provider.BaseURL 与 BuildUrl 返回路径的组合
|
||||
- **THEN** ConversionEngine SHALL NOT 直接将 provider.BaseURL 与 nativePath 拼接为上游 URL
|
||||
|
||||
#### Scenario: 未知接口 URL 映射
|
||||
|
||||
- **WHEN** interfaceType 为 PASSTHROUGH
|
||||
- **THEN** providerAdapter.BuildUrl SHALL 返回适合目标协议的路径或原 nativePath
|
||||
- **THEN** ConversionEngine SHALL 使用该路径构建上游 URL
|
||||
|
||||
### Requirement: 上游 URL 构建使用目标协议 Adapter
|
||||
|
||||
ConversionEngine SHALL 始终使用目标供应商协议的 adapter 构建上游 URL 路径,避免客户端协议 nativePath 中的版本段泄露到目标协议上游 URL。
|
||||
|
||||
#### Scenario: OpenAI 客户端到 OpenAI 供应商
|
||||
|
||||
- **WHEN** clientProtocol 为 `openai`,providerProtocol 为 `openai`,nativePath 为 `/v1/chat/completions`
|
||||
- **THEN** ConversionEngine SHALL 调用 OpenAI adapter 的 `BuildUrl(nativePath, InterfaceTypeChat)`
|
||||
- **THEN** 上游 path SHALL 为 `/chat/completions`
|
||||
- **THEN** 当 provider.base_url 为 `https://api.openai.com/v1` 时,最终上游 URL SHALL 为 `https://api.openai.com/v1/chat/completions`
|
||||
|
||||
#### Scenario: OpenAI 客户端到 Anthropic 供应商
|
||||
|
||||
- **WHEN** clientProtocol 为 `openai`,providerProtocol 为 `anthropic`,nativePath 为 `/v1/chat/completions`
|
||||
- **THEN** ConversionEngine SHALL 使用 OpenAI adapter 识别接口类型为 `InterfaceTypeChat`
|
||||
- **THEN** ConversionEngine SHALL 调用 Anthropic adapter 的 `BuildUrl(nativePath, InterfaceTypeChat)`
|
||||
- **THEN** 上游 path SHALL 为 `/v1/messages`
|
||||
- **THEN** OpenAI nativePath 中的 `/v1/chat/completions` SHALL NOT 被直接拼接到 Anthropic 上游 URL
|
||||
|
||||
#### Scenario: Anthropic 客户端到 OpenAI 供应商
|
||||
|
||||
- **WHEN** clientProtocol 为 `anthropic`,providerProtocol 为 `openai`,nativePath 为 `/v1/messages`
|
||||
- **THEN** ConversionEngine SHALL 使用 Anthropic adapter 识别接口类型为 `InterfaceTypeChat`
|
||||
- **THEN** ConversionEngine SHALL 调用 OpenAI adapter 的 `BuildUrl(nativePath, InterfaceTypeChat)`
|
||||
- **THEN** 上游 path SHALL 为 `/chat/completions`
|
||||
- **THEN** 当 provider.base_url 为 `https://api.openai.com/v1` 时,最终上游 URL SHALL 为 `https://api.openai.com/v1/chat/completions`
|
||||
|
||||
### Requirement: SSE Frame 级 Smart Passthrough
|
||||
|
||||
系统 SHALL 支持同协议流式 Smart Passthrough 对 SSE frame 中的 model 字段进行最小化改写。
|
||||
|
||||
#### Scenario: 改写 SSE data JSON
|
||||
|
||||
- **WHEN** 同协议流式响应需要将上游模型名改写为统一模型 ID
|
||||
- **THEN** 系统 SHALL 按 SSE frame 解析上游字节流
|
||||
- **THEN** 对包含 JSON payload 的 `data` 行 SHALL 调用 adapter.RewriteResponseModelName 改写 model 字段
|
||||
- **THEN** SHALL 重建合法 SSE frame 输出
|
||||
|
||||
#### Scenario: 保留 DONE 事件
|
||||
|
||||
- **WHEN** SSE frame 的 data payload 为 `[DONE]`
|
||||
- **THEN** 系统 SHALL 原样输出 `[DONE]`
|
||||
- **THEN** SHALL NOT 尝试按 JSON 解析
|
||||
|
||||
#### Scenario: 改写失败宽容降级
|
||||
|
||||
- **WHEN** SSE frame 解析或 model 改写失败
|
||||
- **THEN** 系统 SHALL 记录 warn 日志
|
||||
- **THEN** SHALL 输出原始 SSE frame
|
||||
- **THEN** SHALL 继续处理后续 frame
|
||||
|
||||
### Requirement: Adapter 模型提取边界
|
||||
|
||||
ProtocolAdapter SHALL 只对明确适配的接口提供 model 提取和 model 改写能力。
|
||||
|
||||
#### Scenario: 已适配接口提取 model
|
||||
|
||||
- **WHEN** ifaceType 为 adapter 明确支持提取 model 的接口
|
||||
- **THEN** ExtractModelName SHALL 按该协议和接口的请求格式提取 model 字段
|
||||
|
||||
#### Scenario: 未适配接口不提取 model
|
||||
|
||||
- **WHEN** ifaceType 为 PASSTHROUGH 或 adapter 未明确支持提取 model 的接口
|
||||
- **THEN** ExtractModelName SHALL 返回错误或空结果
|
||||
- **THEN** 调用方 SHALL 按无 model 请求处理
|
||||
|
||||
### Requirement: 跨协议多模态暂不支持
|
||||
|
||||
ConversionEngine SHALL 在跨协议完整转换中对当前暂不支持的多模态内容返回明确错误。
|
||||
|
||||
#### Scenario: 跨协议请求包含多模态内容块
|
||||
|
||||
- **WHEN** clientProtocol != providerProtocol 且 CanonicalRequest 中包含 image、audio、video 或 file 内容块
|
||||
- **THEN** ConversionEngine SHALL 中断转换
|
||||
- **THEN** SHALL 返回网关层 `UNSUPPORTED_MULTIMODAL` 错误
|
||||
- **THEN** SHALL NOT 静默丢弃多模态内容
|
||||
|
||||
#### Scenario: 同协议多模态请求
|
||||
|
||||
- **WHEN** clientProtocol == providerProtocol 且请求通过 Smart Passthrough 或 raw passthrough 处理
|
||||
- **THEN** 系统 SHALL 保留原始请求体中未改写字段
|
||||
- **THEN** SHALL NOT 因多模态字段存在而执行跨协议多模态校验
|
||||
|
||||
### Requirement: 上游非 2xx 响应不进入转换
|
||||
|
||||
ConversionEngine SHALL 只转换调用方传入的成功响应,ProxyHandler SHALL 在调用转换前过滤上游非 2xx 响应。
|
||||
|
||||
#### Scenario: 非 2xx 响应绕过响应转换
|
||||
|
||||
- **WHEN** 上游响应状态码不是 2xx
|
||||
- **THEN** ProxyHandler SHALL NOT 调用 ConversionEngine.ConvertHttpResponse
|
||||
- **THEN** ProxyHandler SHALL 直接透传该响应
|
||||
|
||||
#### Scenario: 流式非 2xx 响应绕过流式转换
|
||||
|
||||
- **WHEN** 流式请求收到上游非 2xx 响应
|
||||
- **THEN** ProxyHandler SHALL NOT 调用 ConversionEngine.CreateStreamConverter
|
||||
- **THEN** ProxyHandler SHALL 直接透传该响应
|
||||
|
||||
### Requirement: 协议路径来源
|
||||
|
||||
ProtocolAdapter SHALL 以对应协议的本地 API reference 文档作为 URL 识别和 URL 映射的事实来源。
|
||||
|
||||
#### Scenario: OpenAI 路径来源
|
||||
|
||||
- **WHEN** 实现或测试 OpenAI adapter 的 DetectInterfaceType 或 BuildUrl
|
||||
- **THEN** SHALL 参考 `docs/api_reference/openai` 中的接口路径
|
||||
- **THEN** SHALL 忽略 `docs/api_reference/openai/responses` 目录
|
||||
- **THEN** SHALL NOT 因其他协议包含 `/v1` 而给 OpenAI nativePath 添加 `/v1`
|
||||
|
||||
#### Scenario: Anthropic 路径来源
|
||||
|
||||
- **WHEN** 实现或测试 Anthropic adapter 的 DetectInterfaceType 或 BuildUrl
|
||||
- **THEN** SHALL 参考 `docs/api_reference/anthropic` 中的接口路径
|
||||
- **THEN** SHALL 保留文档中接口路径自带的 `/v1` 前缀
|
||||
- **THEN** SHALL NOT 因 OpenAI nativePath 不含 `/v1` 而移除 Anthropic nativePath 中的 `/v1`
|
||||
|
||||
Reference in New Issue
Block a user