1
0

refactor: 实现 ConversionEngine 协议转换引擎,替代旧 protocol 包

引入 Canonical Model 和 ProtocolAdapter 架构,支持 OpenAI/Anthropic 协议间
无缝转换,统一 ProxyHandler 替代分散的 OpenAI/Anthropic Handler,简化
ProviderClient 为协议无关的 HTTP 发送器,Provider 新增 protocol 字段。
This commit is contained in:
2026-04-20 00:36:27 +08:00
parent 26810d9410
commit 1dac347d3b
65 changed files with 9690 additions and 2139 deletions

View File

@@ -180,14 +180,14 @@ type ProviderClient interface {
- 路由时需要知道 providerProtocol 以选择正确的 Adapter
- 默认值 `'openai'` 确保现有数据兼容
### D7: 删除旧 `internal/protocol/` 包,在 `internal/conversion/` 中重建
### D7: 删除旧 `internal/protocol/` 包,在 `internal/conversion/` 中全新实现
**选择**:直接删除 `internal/protocol/openai/``internal/protocol/anthropic/`,在 `internal/conversion/`从零构建新架构
**选择**:直接删除 `internal/protocol/openai/``internal/protocol/anthropic/`,在 `internal/conversion/`对照设计文档全新编写所有代码
**理由**
- 旧代码的设计模式OpenAI 类型为枢纽)与新架构根本不同
- 旧代码的设计模式OpenAI 类型为枢纽)与新架构根本不同,无法复用
- 保留旧代码容易导致混用两种模式,引入隐蔽 bug
- 旧代码中的类型定义可以迁移copy-paste但组织方式需重建
- 旧代码中的类型定义不迁移,直接根据设计文档重新定义,确保与新架构一致
### D8: 目标包结构
@@ -206,7 +206,7 @@ internal/conversion/
engine.go # ConversionEngine 门面 + HTTPRequestSpec/HTTPResponseSpec
openai/
types.go # OpenAI 线路格式类型(从旧 protocol/openai/types.go 迁移并补全
types.go # OpenAI 线路格式类型(对照 conversion_openai.md 全新定义
adapter.go # ProtocolAdapter 实现detectInterfaceType/buildUrl/buildHeaders/supportsInterface/encodeError
decoder.go # decodeRequest/decodeResponse/扩展层 decode 方法
encoder.go # encodeRequest/encodeResponse/扩展层 encode 方法
@@ -214,7 +214,7 @@ internal/conversion/
stream_encoder.go # OpenAIStreamEncoder缓冲策略
anthropic/
types.go # Anthropic 线路格式类型(从旧 protocol/anthropic/types.go 迁移并补全
types.go # Anthropic 线路格式类型(对照 conversion_anthropic.md 全新定义
adapter.go # ProtocolAdapter 实现detectInterfaceType/buildUrl/buildHeaders/supportsInterface/encodeError
decoder.go # decodeRequest/decodeResponse/扩展层 decode 方法
encoder.go # encodeRequest/encodeResponse/扩展层 encode 方法
@@ -260,14 +260,14 @@ internal/conversion/
### 步骤
1. **创建 `internal/conversion/` 包**:实现 Layer 1-3Canonical Model、接口定义、Engine不改动现有代码
2. **实现 OpenAI Adapter 和 Anthropic Adapter**Layer 4-5在 conversion 包内自包含
2. **全新实现 OpenAI Adapter 和 Anthropic Adapter**Layer 4-5对照设计文档在 conversion 包内全新编写,不沿用旧 protocol 包代码
3. **编写全面测试**:覆盖编解码、流式转换、错误处理、同协议透传
4. **改造 `domain.Provider`**:新增 `Protocol` 字段
5. **创建数据库迁移**`ALTER TABLE providers ADD COLUMN protocol TEXT DEFAULT 'openai'`
6. **改造 `ProviderClient`**:简化为接受 `HTTPRequestSpec` 的 HTTP 发送器
7. **创建 `ProxyHandler`**:统一代理入口,集成 ConversionEngine
8. **更新 `cmd/server/main.go`**:注册 Adapter、创建 Engine、配置新路由
9. **删除旧 `internal/protocol/` 包**:确认新架构完全替代后删除
9. **删除旧 `internal/protocol/` 包**直接删除,不迁移代码,确认新架构完全替代
10. **更新 README.md**项目结构、API 接口、路由说明
### 兼容策略
@@ -279,7 +279,7 @@ internal/conversion/
### 回滚策略
- Git 分支隔离:在新分支开发,合并前充分测试
-`internal/protocol/` 包在确认新架构稳定后再删除
-`internal/protocol/` 包在删除前确认新架构所有测试通过,删除后不可恢复旧代码(从 git 历史仍可找回)
- 数据库迁移向下兼容(仅 ADD COLUMN
## Open Questions

View File

@@ -7,14 +7,14 @@
- **引入 Canonical Model**:定义协议无关的 `CanonicalRequest``CanonicalResponse``CanonicalStreamEvent` 等规范模型,作为所有协议间转换的统一枢纽
- **引入 ConversionEngine**:无状态的转换引擎门面,协调 Adapter 注册、接口识别、透传判断、请求/响应转换、流式转换
- **引入 ProtocolAdapter 接口**统一适配器契约每种协议实现完整的编解码Chat 请求/响应、流式、扩展层接口、错误编码)
- **实现 OpenAI Adapter**:对照 `docs/conversion_openai.md` 实现 OpenAI 协议的完整 Adapter含状态机流式解码器/编码器)
- **实现 Anthropic Adapter**:对照 `docs/conversion_anthropic.md` 实现 Anthropic 协议的完整 Adapter含命名事件流式解码器/编码器)
- **实现 OpenAI Adapter**:对照 `docs/conversion_openai.md` 全新实现 OpenAI 协议的完整 Adapter含状态机流式解码器/编码器),不沿用旧 `internal/protocol/openai/` 代码
- **实现 Anthropic Adapter**:对照 `docs/conversion_anthropic.md` 全新实现 Anthropic 协议的完整 Adapter含命名事件流式解码器/编码器),不沿用旧 `internal/protocol/anthropic/` 代码
- **统一代理 Handler**:合并 `OpenAIHandler``AnthropicHandler` 为统一的 `ProxyHandler`,支持 `/{protocol}/v1/...` URL 前缀路由
- **同协议透传**client == provider 时跳过 Canonical 转换,仅重建 Header 后原样转发
- **接口分层**核心层Chat走 Canonical 深度转换扩展层Models/Embeddings/Rerank走轻量映射未知接口走透传
- **ProviderClient 简化**:移除 OpenAI Adapter 硬编码,变为协议无关的 HTTP 发送器
- **Provider 新增 Protocol 字段****BREAKING** — Provider 模型新增 `protocol` 字段标识上游协议类型
- **删除旧 protocol 包**:移除 `internal/protocol/openai/``internal/protocol/anthropic/`全部逻辑迁入 `internal/conversion/`
- **删除旧 protocol 包**:移除 `internal/protocol/openai/``internal/protocol/anthropic/` `internal/conversion/` 中全新实现
- **URL 路由变更****BREAKING** — 代理端点从 `/v1/chat/completions` + `/v1/messages` 变更为 `/{protocol}/v1/...`,不保留旧路由
## Capabilities
@@ -37,7 +37,7 @@
## Impact
- **代码结构**:新增 `internal/conversion/` 包(约 20+ 文件),删除 `internal/protocol/` 包,改造 `internal/handler/``internal/provider/`
- **代码结构**:新增 `internal/conversion/` 包(约 20+ 文件,全新编写),删除 `internal/protocol/`(不迁移,直接删除后重写),改造 `internal/handler/``internal/provider/`
- **API 兼容性****BREAKING** — 代理端点 URL 变更(`/v1/chat/completions``/openai/v1/chat/completions``/v1/messages``/anthropic/v1/messages`),不保留旧路由
- **数据库**Provider 表新增 `protocol` 列,需数据库迁移
- **依赖**:无新增外部依赖,复用现有 Go 标准库和已引入的包

View File

@@ -2,7 +2,7 @@
### Requirement: 实现 Anthropic ProtocolAdapter
系统 SHALL 实现 Anthropic 协议的完整 ProtocolAdapter对照 `docs/conversion_anthropic.md`
系统 SHALL 全新实现 Anthropic 协议的完整 ProtocolAdapter对照 `docs/conversion_anthropic.md`不沿用旧 `internal/protocol/anthropic/` 代码。
- `protocolName()` SHALL 返回 `"anthropic"`
- `supportsPassthrough()` SHALL 返回 true

View File

@@ -2,7 +2,7 @@
### Requirement: 实现 OpenAI ProtocolAdapter
系统 SHALL 实现 OpenAI 协议的完整 ProtocolAdapter对照 `docs/conversion_openai.md`
系统 SHALL 全新实现 OpenAI 协议的完整 ProtocolAdapter对照 `docs/conversion_openai.md`不沿用旧 `internal/protocol/openai/` 代码。
- `protocolName()` SHALL 返回 `"openai"`
- `supportsPassthrough()` SHALL 返回 true

View File

@@ -1,49 +1,49 @@
## 1. 基础类型层 — Canonical Model 和核心类型定义
- [ ] 1.1 创建 `internal/conversion/errors.go`:定义 ConversionError 结构体Code, Message, ClientProtocol, ProviderProtocol, InterfaceType, Details, Cause和 ErrorCode 枚举INVALID_INPUT, MISSING_REQUIRED_FIELD, INCOMPATIBLE_FEATURE, FIELD_MAPPING_FAILURE, TOOL_CALL_PARSE_ERROR, JSON_PARSE_ERROR, STREAM_STATE_ERROR, UTF8_DECODE_ERROR, PROTOCOL_CONSTRAINT_VIOLATION, ENCODING_FAILURE, INTERFACE_NOT_SUPPORTED实现 error 接口
- [ ] 1.2 创建 `internal/conversion/interface.go`:定义 InterfaceType 枚举CHAT, MODELS, MODEL_INFO, EMBEDDINGS, RERANK
- [ ] 1.3 创建 `internal/conversion/provider.go`:定义 TargetProvider 结构体BaseURL, APIKey, ModelName, AdapterConfig map[string]any编写测试
- [ ] 1.4 创建 `internal/conversion/canonical/types.go`:定义 CanonicalRequestmodel, system, messages, tools, tool_choice, parameters, thinking, stream, user_id, output_format, parallel_tool_use、CanonicalMessagerole 枚举: system/user/assistant/tool, content []ContentBlock、ContentBlock使用 type 字段的 discriminated uniontext/tool_use/tool_result/thinkingToolInput 使用 json.RawMessage、CanonicalToolname, description, input_schema、ToolChoice 联合体auto/none/any/tool+name、RequestParametersmax_tokens, temperature, top_p, top_k, frequency_penalty, presence_penalty, stop_sequences、ThinkingConfigtype: enabled/disabled/adaptive, budget_tokens, effort、OutputFormatjson_object/json_schema+schema/text、CanonicalResponseid, model, content, stop_reason 枚举, usage、CanonicalUsageinput_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens、SystemBlocktext编写构造和序列化测试
- [ ] 1.5 创建 `internal/conversion/canonical/stream.go`:定义 CanonicalStreamEvent 联合体message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, error, ping及各事件的具体结构MessageStartEvent 含 message{id,model,usage}、ContentBlockStartEvent 含 index 和 content_block、ContentBlockDeltaEvent 含 index 和 delta、ContentBlockStopEvent 含 index、MessageDeltaEvent 含 delta{stop_reason} 和 usage、MessageStopEvent、ErrorEvent、PingEventdelta 联合体text_delta, input_json_delta, thinking_deltacontent_block 联合体text, tool_use, thinking编写测试
- [ ] 1.6 创建 `internal/conversion/canonical/extended.go`:定义扩展层 Canonical ModelsCanonicalModelList, CanonicalModel, CanonicalModelInfo, CanonicalEmbeddingRequest, CanonicalEmbeddingResponse, CanonicalRerankRequest, CanonicalRerankResponse编写测试
- [x] 1.1 创建 `internal/conversion/errors.go`:定义 ConversionError 结构体Code, Message, ClientProtocol, ProviderProtocol, InterfaceType, Details, Cause和 ErrorCode 枚举INVALID_INPUT, MISSING_REQUIRED_FIELD, INCOMPATIBLE_FEATURE, FIELD_MAPPING_FAILURE, TOOL_CALL_PARSE_ERROR, JSON_PARSE_ERROR, STREAM_STATE_ERROR, UTF8_DECODE_ERROR, PROTOCOL_CONSTRAINT_VIOLATION, ENCODING_FAILURE, INTERFACE_NOT_SUPPORTED实现 error 接口
- [x] 1.2 创建 `internal/conversion/interface.go`:定义 InterfaceType 枚举CHAT, MODELS, MODEL_INFO, EMBEDDINGS, RERANK
- [x] 1.3 创建 `internal/conversion/provider.go`:定义 TargetProvider 结构体BaseURL, APIKey, ModelName, AdapterConfig map[string]any编写测试
- [x] 1.4 创建 `internal/conversion/canonical/types.go`:定义 CanonicalRequestmodel, system, messages, tools, tool_choice, parameters, thinking, stream, user_id, output_format, parallel_tool_use、CanonicalMessagerole 枚举: system/user/assistant/tool, content []ContentBlock、ContentBlock使用 type 字段的 discriminated uniontext/tool_use/tool_result/thinkingToolInput 使用 json.RawMessage、CanonicalToolname, description, input_schema、ToolChoice 联合体auto/none/any/tool+name、RequestParametersmax_tokens, temperature, top_p, top_k, frequency_penalty, presence_penalty, stop_sequences、ThinkingConfigtype: enabled/disabled/adaptive, budget_tokens, effort、OutputFormatjson_object/json_schema+schema/text、CanonicalResponseid, model, content, stop_reason 枚举, usage、CanonicalUsageinput_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, reasoning_tokens、SystemBlocktext编写构造和序列化测试
- [x] 1.5 创建 `internal/conversion/canonical/stream.go`:定义 CanonicalStreamEvent 联合体message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, error, ping及各事件的具体结构MessageStartEvent 含 message{id,model,usage}、ContentBlockStartEvent 含 index 和 content_block、ContentBlockDeltaEvent 含 index 和 delta、ContentBlockStopEvent 含 index、MessageDeltaEvent 含 delta{stop_reason} 和 usage、MessageStopEvent、ErrorEvent、PingEventdelta 联合体text_delta, input_json_delta, thinking_deltacontent_block 联合体text, tool_use, thinking编写测试
- [x] 1.6 创建 `internal/conversion/canonical/extended.go`:定义扩展层 Canonical ModelsCanonicalModelList, CanonicalModel, CanonicalModelInfo, CanonicalEmbeddingRequest, CanonicalEmbeddingResponse, CanonicalRerankRequest, CanonicalRerankResponse编写测试
## 2. 接口定义层 — Adapter、Stream、Middleware 接口
- [ ] 2.1 创建 `internal/conversion/adapter.go`:定义 ProtocolAdapter 接口protocolName, protocolVersion, supportsPassthrough, detectInterfaceType, buildUrl, buildHeaders, supportsInterface, decodeRequest, encodeRequest, decodeResponse, encodeResponse, createStreamDecoder, createStreamEncoder, encodeError, 扩展层编解码方法decodeModelsResponse/encodeModelsResponse/decodeModelInfoResponse/encodeModelInfoResponse/decodeEmbeddingRequest/encodeEmbeddingRequest/decodeEmbeddingResponse/encodeEmbeddingResponse/decodeRerankRequest/encodeRerankRequest/decodeRerankResponse/encodeRerankResponse定义 AdapterRegistry 接口register, get, listProtocols和 memoryRegistry 实现sync.RWMutex 保护的 map编写 Registry 注册/查询/重复注册测试
- [ ] 2.2 创建 `internal/conversion/stream.go`:定义 StreamDecoder 接口processChunk(rawChunk []byte) []CanonicalStreamEvent, flush() []CanonicalStreamEvent、StreamEncoder 接口encodeEvent(event CanonicalStreamEvent) [][]byte, flush() [][]byte、StreamConverter 接口processChunk(rawChunk []byte) [][]byte, flush() [][]byte、PassthroughStreamConverter 实现直接传递原始字节、CanonicalStreamConverter 实现(组合 StreamDecoder + MiddlewareChain + StreamEncoderprocessChunk 内部调用 decoder → middleware → encoder 管道);编写 PassthroughStreamConverter 测试
- [ ] 2.3 创建 `internal/conversion/middleware.go`:定义 ConversionMiddleware 接口intercept(canonical, clientProtocol, providerProtocol, context) (CanonicalRequest, error) 和可选的 interceptStreamEvent(event, clientProtocol, providerProtocol, context) (CanonicalStreamEvent, error)、ConversionContext 结构体conversionId, interfaceType, timestamp, metadata、MiddlewareChain 结构体(按注册顺序链式执行,任一返回错误则中断后续);编写链式执行和中断测试
- [x] 2.1 创建 `internal/conversion/adapter.go`:定义 ProtocolAdapter 接口protocolName, protocolVersion, supportsPassthrough, detectInterfaceType, buildUrl, buildHeaders, supportsInterface, decodeRequest, encodeRequest, decodeResponse, encodeResponse, createStreamDecoder, createStreamEncoder, encodeError, 扩展层编解码方法decodeModelsResponse/encodeModelsResponse/decodeModelInfoResponse/encodeModelInfoResponse/decodeEmbeddingRequest/encodeEmbeddingRequest/decodeEmbeddingResponse/encodeEmbeddingResponse/decodeRerankRequest/encodeRerankRequest/decodeRerankResponse/encodeRerankResponse定义 AdapterRegistry 接口register, get, listProtocols和 memoryRegistry 实现sync.RWMutex 保护的 map编写 Registry 注册/查询/重复注册测试
- [x] 2.2 创建 `internal/conversion/stream.go`:定义 StreamDecoder 接口processChunk(rawChunk []byte) []CanonicalStreamEvent, flush() []CanonicalStreamEvent、StreamEncoder 接口encodeEvent(event CanonicalStreamEvent) [][]byte, flush() [][]byte、StreamConverter 接口processChunk(rawChunk []byte) [][]byte, flush() [][]byte、PassthroughStreamConverter 实现直接传递原始字节、CanonicalStreamConverter 实现(组合 StreamDecoder + MiddlewareChain + StreamEncoderprocessChunk 内部调用 decoder → middleware → encoder 管道);编写 PassthroughStreamConverter 测试
- [x] 2.3 创建 `internal/conversion/middleware.go`:定义 ConversionMiddleware 接口intercept(canonical, clientProtocol, providerProtocol, context) (CanonicalRequest, error) 和可选的 interceptStreamEvent(event, clientProtocol, providerProtocol, context) (CanonicalStreamEvent, error)、ConversionContext 结构体conversionId, interfaceType, timestamp, metadata、MiddlewareChain 结构体(按注册顺序链式执行,任一返回错误则中断后续);编写链式执行和中断测试
## 3. 引擎层 — ConversionEngine 门面
- [ ] 3.1 创建 `internal/conversion/engine.go`:定义 HTTPRequestSpecURL, Method string, Headers map[string]string, Body []byte、HTTPResponseSpecStatusCode int, Headers map[string]string, Body []byte、ConversionEngine structregistry, middlewareChain实现 registerAdapter、use、isPassthrough、convertHttpRequest接口识别 → 透传判断 → clientAdapter.decode → middleware → providerAdapter.encode → providerAdapter.buildUrl + buildHeaders、convertHttpResponse透传判断 → providerAdapter.decodeResponse → clientAdapter.encodeResponse、createStreamConverter透传 → PassthroughStreamConverter否则 → CanonicalStreamConverter、内部 convertBody 分发CHAT 走深度转换,扩展层走轻量映射,默认透传);编写集成测试:使用 mock adapter 测试跨协议转换、同协议透传、未知接口透传
- [x] 3.1 创建 `internal/conversion/engine.go`:定义 HTTPRequestSpecURL, Method string, Headers map[string]string, Body []byte、HTTPResponseSpecStatusCode int, Headers map[string]string, Body []byte、ConversionEngine structregistry, middlewareChain实现 registerAdapter、use、isPassthrough、convertHttpRequest接口识别 → 透传判断 → clientAdapter.decode → middleware → providerAdapter.encode → providerAdapter.buildUrl + buildHeaders、convertHttpResponse透传判断 → providerAdapter.decodeResponse → clientAdapter.encodeResponse、createStreamConverter透传 → PassthroughStreamConverter否则 → CanonicalStreamConverter、内部 convertBody 分发CHAT 走深度转换,扩展层走轻量映射,默认透传);编写集成测试:使用 mock adapter 测试跨协议转换、同协议透传、未知接口透传
## 4. OpenAI Adapter 实现
- [ ] 4.1 创建 `internal/conversion/openai/types.go``internal/protocol/openai/types.go` 迁移 OpenAI 线路格式类型,补全缺失字段developer role, custom tools, reasoning_effort, reasoning_content, max_completion_tokens, parallel_tool_calls, response_format 的 json_schema 类型, stream_options, 废弃的 functions/function_call编写序列化测试
- [ ] 4.2 创建 `internal/conversion/openai/decoder.go`:实现 decodeRequest对照 conversion_openai.md §4.1decodeSystemPrompt 提取 system+developer 消息、decodeMessage 含 tool_calls/refusal/reasoning_content 解码、tool 消息 tool_call_id→tool_use_id、decodeTools 含 function+custom 类型、decodeToolChoice 含 required→any/allowed_tools 降级、decodeParameters 含 max_completion_tokens 优先、decodeOutputFormat、decodeThinking 含 reasoning_effort→ThinkingConfig、废弃字段 functions→tools 兼容、decodeResponse§5.2content/refusal/reasoning_content/tool_calls 解码、finish_reason 映射表、usage 映射含 cached_tokens/reasoning_tokens、扩展层 decodedecodeModelsResponse、decodeEmbeddingRequest/Response、decodeRerankRequest/Response编写完整测试覆盖每类消息和字段映射
- [ ] 4.3 创建 `internal/conversion/openai/encoder.go`:实现 encodeRequest对照 conversion_openai.md §4.2provider.model_name 覆盖、system 注入到 messages[0]、encodeMessage 含 tool_calls 编码到 message 顶层、角色交替合并、encodeTools 含 function 包装、encodeToolChoice 含 any→required、encodeParameters 含 max_completion_tokens、encodeOutputFormat、encodeThinking 含 disabled→"none"、encodeResponse§5.3text→content、tool_use→tool_calls、thinking→reasoning_content、finish_reason 反向映射、usage 编码含 prompt_tokens_details、扩展层 encodeencodeModelsResponse、encodeEmbeddingRequest/Response、encodeRerankRequest/Response编写完整测试
- [ ] 4.4 创建 `internal/conversion/openai/adapter.go`:实现 OpenAI ProtocolAdapterprotocolName→"openai"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/chat/completions→CHAT、/v1/models→MODELS 等、buildHeaders 含 Authorization+Content-Type+OpenAI-Organization、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO/EMBEDDINGS/RERANK 返回 true、encodeError 含 ErrorCode→OpenAI 错误类型映射),组合 decoder 和 encoder 方法;编写测试覆盖所有路径模式和边界情况
- [ ] 4.5 创建 `internal/conversion/openai/stream_decoder.go`:实现 OpenAIStreamDecoder对照 conversion_openai.md §6.2-§6.3processChunk 解析 SSE data 行,维护状态机 messageStarted/openBlocks/toolCallIdMap/toolCallNameMap/toolCallArguments/textBlockStarted/thinkingBlockStarted/utf8Remainder/accumulatedUsage首个 chunk→MessageStartEventdelta.content→text block 生命周期delta.tool_calls→tool_use block 生命周期含索引映射和参数累积delta.reasoning_content→thinking block非标准delta.refusal→text blockfinish_reason→关闭所有 open blocks + MessageDeltaEvent + MessageStopEventusage chunk→MessageDeltaEvent[DONE]→flush 关闭);编写测试覆盖每种 delta 类型和边界情况(空 chunk、多 tool_calls、UTF-8 截断)
- [ ] 4.6 创建 `internal/conversion/openai/stream_encoder.go`:实现 OpenAIStreamEncoder对照 conversion_openai.md §6.4encodeEventContentBlockStart 缓冲策略等待首次 ContentBlockDelta 合并输出tool_use id/name 在首次 delta 时合并编码text_delta 直接输出 data: {choices:[{delta:{content}}]}input_json_delta 含 tool_calls 数组编码thinking_delta 含 reasoning_content 字段MessageStartEvent→{choices:[{delta:{role:"assistant"}}]}MessageDeltaEvent→{choices:[{delta:{},finish_reason}]}MessageStopEvent→[DONE]PingEvent/ErrorEvent 丢弃flush 输出缓冲区);编写测试
- [x] 4.1 创建 `internal/conversion/openai/types.go`对照 `docs/conversion_openai.md` 全新定义 OpenAI 线路格式类型(不沿用`internal/protocol/openai/types.go`),包含完整字段developer role, custom tools, reasoning_effort, reasoning_content, max_completion_tokens, parallel_tool_calls, response_format 的 json_schema 类型, stream_options, 废弃的 functions/function_call编写序列化测试
- [x] 4.2 创建 `internal/conversion/openai/decoder.go`:实现 decodeRequest对照 conversion_openai.md §4.1decodeSystemPrompt 提取 system+developer 消息、decodeMessage 含 tool_calls/refusal/reasoning_content 解码、tool 消息 tool_call_id→tool_use_id、decodeTools 含 function+custom 类型、decodeToolChoice 含 required→any/allowed_tools 降级、decodeParameters 含 max_completion_tokens 优先、decodeOutputFormat、decodeThinking 含 reasoning_effort→ThinkingConfig、废弃字段 functions→tools 兼容、decodeResponse§5.2content/refusal/reasoning_content/tool_calls 解码、finish_reason 映射表、usage 映射含 cached_tokens/reasoning_tokens、扩展层 decodedecodeModelsResponse、decodeEmbeddingRequest/Response、decodeRerankRequest/Response编写完整测试覆盖每类消息和字段映射
- [x] 4.3 创建 `internal/conversion/openai/encoder.go`:实现 encodeRequest对照 conversion_openai.md §4.2provider.model_name 覆盖、system 注入到 messages[0]、encodeMessage 含 tool_calls 编码到 message 顶层、角色交替合并、encodeTools 含 function 包装、encodeToolChoice 含 any→required、encodeParameters 含 max_completion_tokens、encodeOutputFormat、encodeThinking 含 disabled→"none"、encodeResponse§5.3text→content、tool_use→tool_calls、thinking→reasoning_content、finish_reason 反向映射、usage 编码含 prompt_tokens_details、扩展层 encodeencodeModelsResponse、encodeEmbeddingRequest/Response、encodeRerankRequest/Response编写完整测试
- [x] 4.4 创建 `internal/conversion/openai/adapter.go`:实现 OpenAI ProtocolAdapterprotocolName→"openai"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/chat/completions→CHAT、/v1/models→MODELS 等、buildHeaders 含 Authorization+Content-Type+OpenAI-Organization、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO/EMBEDDINGS/RERANK 返回 true、encodeError 含 ErrorCode→OpenAI 错误类型映射),组合 decoder 和 encoder 方法;编写测试覆盖所有路径模式和边界情况
- [x] 4.5 创建 `internal/conversion/openai/stream_decoder.go`:实现 OpenAIStreamDecoder对照 conversion_openai.md §6.2-§6.3processChunk 解析 SSE data 行,维护状态机 messageStarted/openBlocks/toolCallIdMap/toolCallNameMap/toolCallArguments/textBlockStarted/thinkingBlockStarted/utf8Remainder/accumulatedUsage首个 chunk→MessageStartEventdelta.content→text block 生命周期delta.tool_calls→tool_use block 生命周期含索引映射和参数累积delta.reasoning_content→thinking block非标准delta.refusal→text blockfinish_reason→关闭所有 open blocks + MessageDeltaEvent + MessageStopEventusage chunk→MessageDeltaEvent[DONE]→flush 关闭);编写测试覆盖每种 delta 类型和边界情况(空 chunk、多 tool_calls、UTF-8 截断)
- [x] 4.6 创建 `internal/conversion/openai/stream_encoder.go`:实现 OpenAIStreamEncoder对照 conversion_openai.md §6.4encodeEventContentBlockStart 缓冲策略等待首次 ContentBlockDelta 合并输出tool_use id/name 在首次 delta 时合并编码text_delta 直接输出 data: {choices:[{delta:{content}}]}input_json_delta 含 tool_calls 数组编码thinking_delta 含 reasoning_content 字段MessageStartEvent→{choices:[{delta:{role:"assistant"}}]}MessageDeltaEvent→{choices:[{delta:{},finish_reason}]}MessageStopEvent→[DONE]PingEvent/ErrorEvent 丢弃flush 输出缓冲区);编写测试
## 5. Anthropic Adapter 实现(与 Layer 4 并行)
- [ ] 5.1 创建 `internal/conversion/anthropic/types.go``internal/protocol/anthropic/types.go` 迁移 Anthropic 线路格式类型,补全缺失字段thinking.type 含 adaptive、output_config.format/effort、disable_parallel_tool_use、metadata.user_id、redacted_thinking、pause_turn/refusal stop_reason、stop_details、container、cache_control编写序列化测试
- [ ] 5.2 创建 `internal/conversion/anthropic/decoder.go`:实现 decodeRequest对照 conversion_anthropic.md §4.1decodeSystem 从顶层 system 提取、decodeMessage 含 tool_result 从 user 消息拆分为独立 tool 角色消息、参数直接映射含 top_k、decodeThinking 含 enabled/disabled/adaptive 三种类型、decodeOutputFormat 仅支持 json_schema、公共字段提取含 metadata.user_id/disable_parallel_tool_use 反转/output_config.effort、协议特有字段 redacted_thinking 丢弃/cache_control 忽略、decodeResponse§5.2text/tool_use/thinking 块解码、redacted_thinking 丢弃、stop_reason 映射含 pause_turn/refusal、usage 映射含 cache_read_input_tokens/cache_creation_input_tokens、扩展层 decodedecodeModelsResponse 含 RFC3339→Unix 时间戳转换、decodeModelInfoResponse编写完整测试覆盖角色拆分、thinking 三种类型、时间戳转换
- [ ] 5.3 创建 `internal/conversion/anthropic/encoder.go`:实现 encodeRequest对照 conversion_anthropic.md §4.2provider.model_name 覆盖、system 注入为顶层字段、encodeMessages 含 tool→user 合并(优先合并到相邻 user 消息)、首消息 user 保证(自动注入空 user、角色交替合并、encodeThinkingConfig 含 enabled/disabled/adaptive、encodeOutputFormat 含 json_object→空 schema 降级/text 丢弃、公共字段编码含 metadata.user_id/disable_parallel_tool_use 反转/output_config、参数编码含 max_tokens 必填/top_k 直接映射、encodeResponse§5.3text/tool_use/thinking 块直接编码、stop_reason 映射含 content_filter→end_turn 降级、usage 编码含 cache_read_input_tokens/cache_creation_input_tokens、扩展层 encodeencodeModelsResponse 含 Unix→RFC3339 转换和 has_more/first_id/last_id 字段、encodeModelInfoResponse编写完整测试覆盖角色合并、首消息注入、降级处理
- [ ] 5.4 创建 `internal/conversion/anthropic/adapter.go`:实现 Anthropic ProtocolAdapterprotocolName→"anthropic"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/messages→CHAT、/v1/models→MODELS 等、buildHeaders 含 x-api-key + anthropic-version + anthropic-beta + Content-Type、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO 返回 true 对 EMBEDDINGS/RERANK 返回 false、encodeError 返回 {type:"error",error:{type,message}});编写测试覆盖所有路径模式和边界情况
- [ ] 5.5 创建 `internal/conversion/anthropic/stream_decoder.go`:实现 AnthropicStreamDecoder对照 conversion_anthropic.md §6.2-§6.3:解析命名 SSE 事件 event: message_start/data: {...}1:1 映射到 CanonicalStreamEvent维护状态 messageStarted/redactedBlocks/utf8Remainder/accumulatedUsageredacted_thinking 检测后加入 redactedBlocks 并丢弃后续 delta/stopcitations_delta/signature_delta 直接丢弃server_tool_use 等服务端工具块丢弃UTF-8 跨 chunk 安全处理);编写测试覆盖所有事件类型和 redacted_thinking 丢弃
- [ ] 5.6 创建 `internal/conversion/anthropic/stream_encoder.go`:实现 AnthropicStreamEncoder对照 conversion_anthropic.md §6.4:直接映射无缓冲,每个 CanonicalStreamEvent 直接编码为对应的 Anthropic 命名 SSE 事件,格式 event: `<type>`\ndata: `<json>`\n\ndelta 编码 text_delta/input_json_delta/thinking_delta 直接映射);编写测试
- [x] 5.1 创建 `internal/conversion/anthropic/types.go`对照 `docs/conversion_anthropic.md` 全新定义 Anthropic 线路格式类型(不沿用`internal/protocol/anthropic/types.go`),包含完整字段thinking.type 含 adaptive、output_config.format/effort、disable_parallel_tool_use、metadata.user_id、redacted_thinking、pause_turn/refusal stop_reason、stop_details、container、cache_control编写序列化测试
- [x] 5.2 创建 `internal/conversion/anthropic/decoder.go`:实现 decodeRequest对照 conversion_anthropic.md §4.1decodeSystem 从顶层 system 提取、decodeMessage 含 tool_result 从 user 消息拆分为独立 tool 角色消息、参数直接映射含 top_k、decodeThinking 含 enabled/disabled/adaptive 三种类型、decodeOutputFormat 仅支持 json_schema、公共字段提取含 metadata.user_id/disable_parallel_tool_use 反转/output_config.effort、协议特有字段 redacted_thinking 丢弃/cache_control 忽略、decodeResponse§5.2text/tool_use/thinking 块解码、redacted_thinking 丢弃、stop_reason 映射含 pause_turn/refusal、usage 映射含 cache_read_input_tokens/cache_creation_input_tokens、扩展层 decodedecodeModelsResponse 含 RFC3339→Unix 时间戳转换、decodeModelInfoResponse编写完整测试覆盖角色拆分、thinking 三种类型、时间戳转换
- [x] 5.3 创建 `internal/conversion/anthropic/encoder.go`:实现 encodeRequest对照 conversion_anthropic.md §4.2provider.model_name 覆盖、system 注入为顶层字段、encodeMessages 含 tool→user 合并(优先合并到相邻 user 消息)、首消息 user 保证(自动注入空 user、角色交替合并、encodeThinkingConfig 含 enabled/disabled/adaptive、encodeOutputFormat 含 json_object→空 schema 降级/text 丢弃、公共字段编码含 metadata.user_id/disable_parallel_tool_use 反转/output_config、参数编码含 max_tokens 必填/top_k 直接映射、encodeResponse§5.3text/tool_use/thinking 块直接编码、stop_reason 映射含 content_filter→end_turn 降级、usage 编码含 cache_read_input_tokens/cache_creation_input_tokens、扩展层 encodeencodeModelsResponse 含 Unix→RFC3339 转换和 has_more/first_id/last_id 字段、encodeModelInfoResponse编写完整测试覆盖角色合并、首消息注入、降级处理
- [x] 5.4 创建 `internal/conversion/anthropic/adapter.go`:实现 Anthropic ProtocolAdapterprotocolName→"anthropic"、supportsPassthrough→true、detectInterfaceType 根据正则匹配识别 /v1/messages→CHAT、/v1/models→MODELS 等、buildHeaders 含 x-api-key + anthropic-version + anthropic-beta + Content-Type、buildUrl 按接口类型映射、supportsInterface 对 CHAT/MODELS/MODEL_INFO 返回 true 对 EMBEDDINGS/RERANK 返回 false、encodeError 返回 {type:"error",error:{type,message}});编写测试覆盖所有路径模式和边界情况
- [x] 5.5 创建 `internal/conversion/anthropic/stream_decoder.go`:实现 AnthropicStreamDecoder对照 conversion_anthropic.md §6.2-§6.3:解析命名 SSE 事件 event: message_start/data: {...}1:1 映射到 CanonicalStreamEvent维护状态 messageStarted/redactedBlocks/utf8Remainder/accumulatedUsageredacted_thinking 检测后加入 redactedBlocks 并丢弃后续 delta/stopcitations_delta/signature_delta 直接丢弃server_tool_use 等服务端工具块丢弃UTF-8 跨 chunk 安全处理);编写测试覆盖所有事件类型和 redacted_thinking 丢弃
- [x] 5.6 创建 `internal/conversion/anthropic/stream_encoder.go`:实现 AnthropicStreamEncoder对照 conversion_anthropic.md §6.4:直接映射无缓冲,每个 CanonicalStreamEvent 直接编码为对应的 Anthropic 命名 SSE 事件,格式 event: `<type>`\ndata: `<json>`\n\ndelta 编码 text_delta/input_json_delta/thinking_delta 直接映射);编写测试
## 6. 基础设施改造 — Provider、Handler、Domain
- [ ] 6.1 修改 `internal/domain/provider.go`Provider 结构体新增 Protocol string 字段;修改 `internal/config/models.go`GORM Provider 模型同步新增 Protocol 字段gorm:"column:protocol;default:'openai'");修改 `internal/repository/` 中 toDomainProvider 和 toConfigProvider 转换函数同步 Protocol 字段;修改 `internal/handler/provider_handler.go`CreateProvider 和 UpdateProvider 的请求结构体新增 Protocol 字段(可选,默认 "openai"),创建/更新 Provider 时赋值 Protocol 字段List/Get 响应中包含 Protocol 字段;更新 `internal/service/service_test.go` 中所有创建测试 Provider 的地方补充 Protocol 字段;更新 `internal/handler/handler_test.go` 中 Provider CRUD 测试的请求体补充 Protocol 字段;创建数据库迁移文件 `backend/migrations/YYYYMMDDHHMMSS_add_provider_protocol.sql`ALTER TABLE providers ADD COLUMN protocol TEXT DEFAULT 'openai'
- [ ] 6.2 重写 `internal/provider/client.go`:定义 HTTPRequestSpec 和 HTTPResponseSpec或引用 conversion 包的定义),简化 ProviderClient 接口为 Send(ctx, HTTPRequestSpec) → (*HTTPResponseSpec, error) 和 SendStream(ctx, HTTPRequestSpec) → (<-chan StreamEvent, error),移除所有 openai.Adapter 硬编码依赖Send 方法直接使用 http.NewRequest + spec.URL/Headers/BodySendStream 保留现有 readStream goroutine 逻辑但输入改为 HTTPRequestSpec重写 `provider/client_test.go`:删除所有基于 openai.ChatCompletionRequest 的旧测试用例,基于 HTTPRequestSpec 重写成功/失败/流式测试用例,使用 httptest.Server 验证请求构建和响应解析
- [ ] 6.3 创建 `internal/handler/proxy_handler.go`:实现 ProxyHandler struct依赖 ConversionEngine、ProviderClient、RoutingService、StatsService实现 HandleProxy(w, r) 方法:从 URL 提取 clientProtocol仅支持 `/{protocol}/v1/...` 前缀路由,不支持旧路由)、解析请求体 JSON、调用 RoutingService.Route(modelName) 获取路由结果(含 Provider.Protocol 作为 providerProtocol、构建 TargetProvider、调用 engine.convertHttpRequest、调用 providerClient.Send/SendStream、调用 engine.convertHttpResponse、设置响应 Content-Type 和状态码、流式处理设置 text/event-stream 并用 StreamConverter 逐块转换写入、错误处理使用 clientAdapter.encodeError、异步调用 StatsService.Record编写测试使用 httptest + mock engine/client/service
- [ ] 6.4 修改 `cmd/server/main.go`:创建 AdapterRegistry 并注册 OpenAI 和 Anthropic Adapter、创建 ConversionEngine注入 registry、创建 ProxyHandler注入 engine + providerClient + routingService + statsService、配置 Gin 路由:新增 `/{protocol}/v1/{path:*}` → ProxyHandler.HandleProxy删除旧路由 `/v1/chat/completions``/v1/messages`,移除旧的 OpenAIHandler 和 AnthropicHandler 的路由注册,除旧 Adapter 创建代码
- [x] 6.1 修改 `internal/domain/provider.go`Provider 结构体新增 Protocol string 字段;修改 `internal/config/models.go`GORM Provider 模型同步新增 Protocol 字段gorm:"column:protocol;default:'openai'");修改 `internal/repository/` 中 toDomainProvider 和 toConfigProvider 转换函数同步 Protocol 字段;修改 `internal/handler/provider_handler.go`CreateProvider 和 UpdateProvider 的请求结构体新增 Protocol 字段(可选,默认 "openai"),创建/更新 Provider 时赋值 Protocol 字段List/Get 响应中包含 Protocol 字段;更新 `internal/service/service_test.go` 中所有创建测试 Provider 的地方补充 Protocol 字段;更新 `internal/handler/handler_test.go` 中 Provider CRUD 测试的请求体补充 Protocol 字段;创建数据库迁移文件 `backend/migrations/YYYYMMDDHHMMSS_add_provider_protocol.sql`ALTER TABLE providers ADD COLUMN protocol TEXT DEFAULT 'openai'
- [x] 6.2 重写 `internal/provider/client.go`:定义 HTTPRequestSpec 和 HTTPResponseSpec或引用 conversion 包的定义),简化 ProviderClient 接口为 Send(ctx, HTTPRequestSpec) → (*HTTPResponseSpec, error) 和 SendStream(ctx, HTTPRequestSpec) → (<-chan StreamEvent, error),移除所有旧协议硬编码依赖Send 方法直接使用 http.NewRequest + spec.URL/Headers/BodySendStream 保留现有 readStream goroutine 逻辑但输入改为 HTTPRequestSpec重写 `provider/client_test.go`:删除所有基于旧协议类型的测试用例,基于 HTTPRequestSpec 重写成功/失败/流式测试用例,使用 httptest.Server 验证请求构建和响应解析
- [x] 6.3 创建 `internal/handler/proxy_handler.go`:实现 ProxyHandler struct依赖 ConversionEngine、ProviderClient、RoutingService、StatsService实现 HandleProxy(w, r) 方法:从 URL 提取 clientProtocol仅支持 `/{protocol}/v1/...` 前缀路由,不支持旧路由)、解析请求体 JSON、调用 RoutingService.Route(modelName) 获取路由结果(含 Provider.Protocol 作为 providerProtocol、构建 TargetProvider、调用 engine.convertHttpRequest、调用 providerClient.Send/SendStream、调用 engine.convertHttpResponse、设置响应 Content-Type 和状态码、流式处理设置 text/event-stream 并用 StreamConverter 逐块转换写入、错误处理使用 clientAdapter.encodeError、异步调用 StatsService.Record编写测试使用 httptest + mock engine/client/service
- [x] 6.4 修改 `cmd/server/main.go`:创建 AdapterRegistry 并注册 OpenAI 和 Anthropic Adapter、创建 ConversionEngine注入 registry、创建 ProxyHandler注入 engine + providerClient + routingService + statsService、配置 Gin 路由:新增 `/{protocol}/v1/{path:*}` → ProxyHandler.HandleProxy删除旧路由 `/v1/chat/completions``/v1/messages`,移除旧的 OpenAIHandler 和 AnthropicHandler 的路由注册,除旧 Adapter 创建代码
## 7. 清理和文档
- [ ] 7.1 删除旧代码:删除 `internal/protocol/openai/` 目录types.go, adapter.go, adapter_test.go、删除 `internal/protocol/anthropic/` 目录types.go, converter.go, converter_test.go, stream_converter.go, stream_converter_test.go、删除 `internal/handler/openai_handler.go``internal/handler/anthropic_handler.go`、删除 `internal/handler/handler_test.go` 中旧 OpenAI/Anthropic handler 测试用例和旧 `mockProviderClient`(基于 openai.ChatCompletionRequest 的签名)、重写 `handler_test.go` 为 ProxyHandler 测试(基于新 ProviderClient 接口和 ConversionEngine mock、删除 `internal/protocol/` 空目录、确认所有编译通过且无残留 import
- [ ] 7.2 更新 `README.md`:更新项目结构说明(新增 internal/conversion/、删除 internal/protocol/)、更新 API 接口说明(代理接口变更:`/{protocol}/v1/...`,移除旧路由 `/v1/chat/completions``/v1/messages`、更新配置说明Provider 新增 protocol 字段)
- [ ] 7.3 端到端测试:在 `backend/tests/integration/` 中新增 `conversion_test.go`,使用 httptest mock 上游服务器验证完整请求流OpenAI→OpenAI 同协议透传、Anthropic→Anthropic 同协议透传、OpenAI→Anthropic 跨协议非流式、Anthropic→OpenAI 跨协议非流式、4 种方向的流式转换(含 tool_calls 和 thinking、Models 接口跨协议转换、错误响应格式验证(各协议格式)、旧路由 `/v1/chat/completions``/v1/messages` 返回 404复用 `tests/helpers.go` 中的测试数据库和 Provider/Model 创建辅助函数
- [x] 7.1 删除旧代码:删除 `internal/protocol/openai/` 目录types.go, adapter.go, adapter_test.go、删除 `internal/protocol/anthropic/` 目录types.go, converter.go, converter_test.go, stream_converter.go, stream_converter_test.go、删除 `internal/handler/openai_handler.go``internal/handler/anthropic_handler.go`、删除 `internal/handler/handler_test.go` 中旧 OpenAI/Anthropic handler 测试用例和旧 `mockProviderClient`(基于旧协议类型的签名)、重写 `handler_test.go` 为 ProxyHandler 测试(基于新 ProviderClient 接口和 ConversionEngine mock、删除 `internal/protocol/` 空目录、确认所有编译通过且无残留 import
- [x] 7.2 更新 `README.md`:更新项目结构说明(新增 internal/conversion/、删除 internal/protocol/)、更新 API 接口说明(代理接口变更:`/{protocol}/v1/...`,移除旧路由 `/v1/chat/completions``/v1/messages`、更新配置说明Provider 新增 protocol 字段)
- [x] 7.3 端到端测试:在 `backend/tests/integration/` 中新增 `conversion_test.go`,使用 httptest mock 上游服务器验证完整请求流OpenAI→OpenAI 同协议透传、Anthropic→Anthropic 同协议透传、OpenAI→Anthropic 跨协议非流式、Anthropic→OpenAI 跨协议非流式、4 种方向的流式转换(含 tool_calls 和 thinking、Models 接口跨协议转换、错误响应格式验证(各协议格式)、旧路由 `/v1/chat/completions``/v1/messages` 返回 404复用 `tests/helpers.go` 中的测试数据库和 Provider/Model 创建辅助函数