- 新增 ConversionEngine 核心引擎,支持 OpenAI 和 Anthropic 协议转换 - 添加 stream decoder/encoder 实现 - 更新 provider client 支持新引擎 - 补充单元测试和集成测试 - 更新 specs 文档
104 lines
3.9 KiB
Markdown
104 lines
3.9 KiB
Markdown
# Unified Proxy Handler
|
||
|
||
## ADDED Requirements
|
||
|
||
### Requirement: 实现统一代理 Handler
|
||
|
||
系统 SHALL 实现统一的 ProxyHandler,替代现有的 OpenAIHandler 和 AnthropicHandler。
|
||
|
||
ProxyHandler SHALL 依赖 ConversionEngine、ProviderClient、RoutingService、StatsService。
|
||
|
||
#### Scenario: 从 URL 提取客户端协议
|
||
|
||
- **WHEN** 收到 `/{protocol}/v1/{path}` 格式的请求
|
||
- **THEN** SHALL 从 URL 第一段提取 protocol 作为 clientProtocol
|
||
- **THEN** SHALL 剥离前缀得到 nativePath
|
||
|
||
#### Scenario: 协议前缀必须是已注册协议
|
||
|
||
- **WHEN** 收到的 URL 前缀不是已注册的协议名称
|
||
- **THEN** SHALL 返回 404 错误
|
||
|
||
#### Scenario: 接口类型识别
|
||
|
||
- **WHEN** 提取 nativePath 后
|
||
- **THEN** SHALL 通过 ConversionEngine.convertHttpRequest 内部调用 clientAdapter.detectInterfaceType(nativePath) 识别接口类型
|
||
- **THEN** 未知路径 SHALL 使用透传模式
|
||
|
||
### Requirement: 非流式请求处理流程
|
||
|
||
ProxyHandler SHALL 按以下流程处理非流式请求。
|
||
|
||
#### Scenario: 完整转换流程
|
||
|
||
- **WHEN** 收到非流式请求
|
||
- **THEN** SHALL 解析请求体为 JSON
|
||
- **THEN** SHALL 调用 RoutingService.Route(modelName) 获取路由结果
|
||
- **THEN** SHALL 从路由结果的 Provider.Protocol 获取 providerProtocol
|
||
- **THEN** SHALL 构建 TargetProvider(base_url, api_key, model_name, adapter_config)
|
||
- **THEN** SHALL 调用 engine.convertHttpRequest(body, clientProtocol, providerProtocol, provider)
|
||
- **THEN** SHALL 调用 providerClient.Send(ctx, requestSpec)
|
||
- **THEN** SHALL 调用 engine.convertHttpResponse(response, clientProtocol, providerProtocol, interfaceType)
|
||
- **THEN** SHALL 将转换后的响应返回给客户端
|
||
|
||
#### Scenario: 路由失败处理
|
||
|
||
- **WHEN** RoutingService.Route 返回错误
|
||
- **THEN** SHALL 使用 clientProtocol 对应的 Adapter.encodeError 编码错误响应
|
||
- **THEN** SHALL 返回适当的 HTTP 状态码
|
||
|
||
#### Scenario: 上游请求失败处理
|
||
|
||
- **WHEN** ProviderClient.Send 返回错误
|
||
- **THEN** SHALL 使用 clientProtocol 对应的 Adapter.encodeError 编码错误响应
|
||
- **THEN** SHALL 包装原始错误信息
|
||
|
||
### Requirement: 流式请求处理流程
|
||
|
||
ProxyHandler SHALL 按以下流程处理流式请求。
|
||
|
||
#### Scenario: 流式转换流程
|
||
|
||
- **WHEN** 请求中 stream=true 或接口类型为 CHAT 且请求体含 stream:true
|
||
- **THEN** SHALL 执行与非流式相同的前置处理(路由、构建 TargetProvider)
|
||
- **THEN** SHALL 调用 engine.convertHttpRequest 获取 HTTPRequestSpec
|
||
- **THEN** SHALL 调用 providerClient.SendStream(ctx, requestSpec) 获取流
|
||
- **THEN** SHALL 调用 engine.createStreamConverter(clientProtocol, providerProtocol, provider)
|
||
- **THEN** SHALL 设置响应 Header `Content-Type: text/event-stream`
|
||
- **THEN** SHALL 对每个流 chunk 调用 converter.processChunk 并写入响应
|
||
- **THEN** SHALL 在流结束时调用 converter.flush() 刷新缓冲
|
||
|
||
#### Scenario: 同协议透传流式
|
||
|
||
- **WHEN** clientProtocol == providerProtocol
|
||
- **THEN** SHALL 直接将上游 SSE 字节流写入响应
|
||
- **THEN** SHALL NOT 做任何解析或转换
|
||
|
||
#### Scenario: 流式错误处理
|
||
|
||
- **WHEN** 流过程中发生错误
|
||
- **THEN** SHALL 记录错误日志
|
||
- **THEN** SHALL 关闭响应流
|
||
|
||
### Requirement: 统计记录
|
||
|
||
ProxyHandler SHALL 记录请求统计。
|
||
|
||
#### Scenario: 异步记录统计
|
||
|
||
- **WHEN** 请求处理完成(成功或失败)
|
||
- **THEN** SHALL 异步调用 StatsService.Record
|
||
- **THEN** SHALL NOT 阻塞响应返回
|
||
|
||
### Requirement: GET 请求透传
|
||
|
||
ProxyHandler SHALL 支持 GET 请求的扩展层接口代理。
|
||
|
||
#### Scenario: Models 接口<E68EA5><E58FA3>理
|
||
|
||
- **WHEN** 收到 GET /{protocol}/v1/models 请求
|
||
- **THEN** SHALL 执行路由和协议识别
|
||
- **THEN** SHALL 调用 engine.convertHttpRequest(GET 请求 body 为空)
|
||
- **THEN** SHALL 调用 providerClient.Send 发送请求
|
||
- **THEN** SHALL 调用 engine.convertHttpResponse 转换响应格式
|
||
- **THEN** SHALL 返回转换后的响应 |