【Nanobot】README04_LEVEL2 提供商系统设计

【Nanobot】README04_LEVEL2 提供商系统设计

源码地址:https://github.com/HKUDS/nanobot

### 文章目录

  • [【Nanobot】README04_LEVEL2 提供商系统设计](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [@[toc]](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🎯 现实类比:万能电源适配器](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🧬 0 到 1 推演:如何从零设计 Provider 系统](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 1:直接调用 OpenAI API](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 2:抽象 Provider 基类](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 3:统一响应格式(LLMResponse)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 4:自动 Provider 选择(ProviderFactory)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 5:Provider 注册表(Registry)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [阶段 6:消息格式转换](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🏗️ 核心类/函数列表](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [1. LLMProvider(抽象基类)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [2. AnthropicProvider(Claude API 实现)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [3. ProviderFactory(Provider 工厂)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [4. ProviderRegistry(Provider 注册表)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🔗 调用链追踪](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [完整 LLM 调用链路](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [📊 数据流图](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🎨 设计模式分析](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [1. 策略模式(Strategy Pattern)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [2. 工厂模式(Factory Pattern)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [3. 适配器模式(Adapter Pattern)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [4. 注册表模式(Registry Pattern)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🔍 代码标注分析](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [AnthropicProvider.chat() 完整实现(带标注)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [_convert_messages() 格式转换(带标注)](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [🎯 Provider 速查表](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)
  • [📚 扩展阅读](#文章目录 【Nanobot】README04_LEVEL2 提供商系统设计 @[toc] 🎯 现实类比:万能电源适配器 🧬 0 到 1 推演:如何从零设计 Provider 系统 阶段 1:直接调用 OpenAI API 阶段 2:抽象 Provider 基类 阶段 3:统一响应格式(LLMResponse) 阶段 4:自动 Provider 选择(ProviderFactory) 阶段 5:Provider 注册表(Registry) 阶段 6:消息格式转换 🏗️ 核心类/函数列表 1. LLMProvider(抽象基类) 2. AnthropicProvider(Claude API 实现) 3. ProviderFactory(Provider 工厂) 4. ProviderRegistry(Provider 注册表) 🔗 调用链追踪 完整 LLM 调用链路 📊 数据流图 🎨 设计模式分析 1. 策略模式(Strategy Pattern) 2. 工厂模式(Factory Pattern) 3. 适配器模式(Adapter Pattern) 4. 注册表模式(Registry Pattern) 🔍 代码标注分析 AnthropicProvider.chat() 完整实现(带标注) _convert_messages() 格式转换(带标注) 🎯 Provider 速查表 📚 扩展阅读)

🎯 现实类比:万能电源适配器

想象国际旅行时的万能电源适配器

  • LLMProvider = 接口标准:定义了输入/输出的规范

    • 输入:消息列表 + 工具定义 + 生成参数
    • 输出:LLMResponse(文本内容、工具调用、Token 使用量)
  • 具体 Provider = 不同国家的插头转换器

    • AnthropicProvider = 美国插头转换器(Claude API)
    • AzureOpenAIProvider = 欧盟插头转换器(Azure OpenAI)
    • OpenAICompatProvider = 通用插头转换器(兼容 OpenAI 格式的 API)
  • ProviderFactory = 插头识别器

    • 根据模型名称自动识别使用哪个 Provider
    • 例如:claude-opus-4-6AnthropicProvider

核心设计思想

  1. 接口统一 :所有 Provider 实现相同的 chat() 方法
  2. 格式转换:将统一的 OpenAI 格式消息转换为各 Provider 原生格式
  3. 自动重试:内置智能重试机制,处理速率限制和瞬态错误

🧬 0 到 1 推演:如何从零设计 Provider 系统

阶段 1:直接调用 OpenAI API

python 复制代码
# 伪代码:最初的最简单设计
import openai

async def chat(messages: list, model: str = "gpt-4"):
    response = await openai.ChatCompletion.acreate(
        model=model,
        messages=messages,
    )
    return response.choices[0].message.content

问题

  • 只支持 OpenAI
  • 无法切换到 Claude、Gemini 等其他 LLM
  • 难以处理不同 API 的差异

阶段 2:抽象 Provider 基类

python 复制代码
class LLMProvider(ABC):
    @abstractmethod
    async def chat(
        self, messages: list, model: str, temperature: float
    ) -> str:
        """调用 LLM 并返回文本。"""
        pass

class AnthropicProvider(LLMProvider):
    async def chat(self, messages, model, temperature):
        # 将 OpenAI 格式消息转换为 Anthropic 格式
        # 调用 Anthropic API
        # 返回结果
        ...

class OpenAIProvider(LLMProvider):
    async def chat(self, messages, model, temperature):
        # 直接调用 OpenAI API
        ...

对应代码base.py:92anthropic_provider.py:737

python 复制代码
class LLMProvider(ABC):
    """[核心业务] LLM 提供商基类。"""

    @abstractmethod
    async def chat(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
        ...
    ) -> LLMResponse:
        """[核心] 执行聊天请求。"""
        ...

问题:LLM 返回格式不同,需要标准化。


阶段 3:统一响应格式(LLMResponse)

python 复制代码
@dataclass
class LLMResponse:
    """[核心业务] 标准化的 LLM 响应。"""
    content: str | None              # 文本内容
    tool_calls: list[ToolCallRequest]  # 工具调用列表
    finish_reason: str               # 结束原因(stop/tool_calls/length/error)
    usage: dict[str, int]            # Token 使用量

对应代码base.py:48-78

python 复制代码
@dataclass
class LLMResponse:
    """
    [核心业务] 来自 LLM 提供者的响应数据类。

    统一不同 Provider 的响应格式:
    - Anthropic 返回 {"stop_reason": "tool_use"}
    - OpenAI 返回 {"finish_reason": "tool_calls"}
    → 统一为 finish_reason="tool_calls"
    """
    content: str | None
    tool_calls: list[ToolCallRequest]
    finish_reason: str = "stop"
    usage: dict[str, int] = field(default_factory=dict)

    @property
    def has_tool_calls(self) -> bool:
        """[工具代码] 检查是否包含工具调用。"""
        return len(self.tool_calls) > 0

阶段 4:自动 Provider 选择(ProviderFactory)

python 复制代码
def make_provider(config: Config) -> LLMProvider:
    """
    [核心] 根据模型名称自动选择 Provider。

    示例:
    - "claude-opus-4-6" → AnthropicProvider
    - "gpt-4" → OpenAIProvider
    - "bedrock/claude" → BedrockProvider
    """
    model = config.model
    provider_name = config.get_provider_name(model)

    if provider_name == "anthropic":
        return AnthropicProvider(api_key=config.api_key)
    elif provider_name == "azure_openai":
        return AzureOpenAIProvider(...)
    elif provider_name == "openai_compat":
        return OpenAICompatProvider(...)
    else:
        raise ValueError(f"Unknown provider: {provider_name}")

对应代码factory.py:29-100


阶段 5:Provider 注册表(Registry)

python 复制代码
@dataclass(frozen=True)
class ProviderSpec:
    """
    [核心] Provider 元数据。

    示例:
    ProviderSpec(
        name="anthropic",
        keywords=("claude",),
        env_key="ANTHROPIC_API_KEY",
        backend="anthropic",
        default_api_base="https://api.anthropic.com",
    )
    """
    name: str
    keywords: tuple[str, ...]
    env_key: str
    backend: str
    default_api_base: str = ""

PROVIDERS = [
    ProviderSpec(
        name="anthropic",
        keywords=("claude",),
        env_key="ANTHROPIC_API_KEY",
        backend="anthropic",
    ),
    ProviderSpec(
        name="openrouter",
        keywords=("openrouter", "mistral", "deepseek"),
        env_key="OPENROUTER_API_KEY",
        backend="openai_compat",
        is_gateway=True,
    ),
    ...
]

对应代码registry.py:21-82


阶段 6:消息格式转换

问题:不同 Provider 的消息格式不同。

OpenAI 格式

json 复制代码
{
  "role": "user",
  "content": "你好"
}

Anthropic 格式

json 复制代码
{
  "role": "user",
  "content": [{"type": "text", "text": "你好"}]
}

解决方案:在 Provider 内部转换消息格式。

对应代码anthropic_provider.py:168-229

python 复制代码
def _convert_messages(
    self, messages: list[dict[str, Any]]
) -> tuple[str, list[dict]]:
    """
    [核心] 将 OpenAI 格式消息转换为 Anthropic 格式。

    处理:
    1. 系统提示词分离
    2. 工具结果消息转换
    3. 用户消息内容转换(文本/图片)
    4. 助手消息(文本/工具调用)
    """
    raw = []
    system = ""

    for msg in messages:
        role = msg["role"]
        content = msg.get("content")

        if role == "system":
            system = content
        elif role == "user":
            raw.append({
                "role": "user",
                "content": self._convert_user_content(content),
            })
        elif role == "assistant":
            raw.append({
                "role": "assistant",
                "content": self._assistant_blocks(msg),
            })
        ...

    return system, self._merge_consecutive(raw)

🏗️ 核心类/函数列表

1. LLMProvider(抽象基类)

职责

  • 定义 Provider 接口
  • 提供通用功能(重试逻辑、错误处理)
  • 定义响应数据结构

关键方法base.py:92-680):

python 复制代码
class LLMProvider(ABC):
    """
    [核心业务] LLM 提供商基类。

    统一不同 LLM API 的差异:
    1. 消息格式(OpenAI vs Anthropic vs Gemini)
    2. 工具调用格式
    3. 流式传输接口
    4. 错误处理和重试
    """

    # 是否支持增量进度通知
    supports_progress_deltas = False

    @abstractmethod
    async def chat(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
        reasoning_effort: str | None = None,
        tool_choice: str | dict[str, Any] | None = None,
    ) -> LLMResponse:
        """
        [核心] 执行聊天请求(非流式)。

        返回标准化的 LLMResponse。
        """
        ...

    async def chat_stream(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
        on_content_delta: Callable[[str], Awaitable[None]] | None = None,
    ) -> LLMResponse:
        """
        [核心] 执行聊天请求(流式)。

        on_content_delta: 接收增量文本的回调函数
        """
        ...

    async def _run_with_retry(
        self, func: Callable, retry_mode: str = "standard"
    ) -> LLMResponse:
        """
        [工具代码] 带智能重试的执行器。

        特性:
        1. 识别瞬态错误(429, 500, 503, timeout)
        2. 指数退避重试(1s, 2s, 4s)
        3. 持久重试模式(用于配额限制)
        4. 心跳机制(长时间等待时定期通知进度)
        """
        ...

2. AnthropicProvider(Claude API 实现)

职责

  • 实现 chat()chat_stream() 方法
  • OpenAI 格式 ↔ Anthropic 格式转换
  • 提示词缓存(cache_control)
  • 扩展思维模式(thinking blocks)

关键方法anthropic_provider.py:29-880):

python 复制代码
class AnthropicProvider(LLMProvider):
    """
    [Adapter - 可替换组件] Anthropic Claude API 实现。

    特性:
    1. 原生 SDK 集成(anthropic-python)
    2. 自动流式降级(max_tokens 超限时透明切换)
    3. 提示词缓存(breakpoints)
    4. 扩展思维模式支持
    """

    def __init__(
        self,
        api_key: str | None = None,
        api_base: str | None = None,
        default_model: str = "claude-sonnet-4-20250514",
        extra_headers: dict[str, str] | None = None,
    ):
        from anthropic import AsyncAnthropic

        # [核心] 初始化 Anthropic 客户端
        self._client = AsyncAnthropic(
            api_key=api_key,
            base_url=api_base,
            default_headers=extra_headers,
            max_retries=0,  # 重试由 LLMProvider 统一处理
        )

    async def chat(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
        reasoning_effort: str | None = None,
        tool_choice: str | dict[str, Any] | None = None,
    ) -> LLMResponse:
        """
        [核心业务] 执行非流式聊天请求。

        流程:
        1. 构建请求参数(_build_kwargs)
        2. 调用 Anthropic API
        3. 解析响应(_parse_response)
        4. 错误处理(必要时透明切换到流式)
        """
        kwargs = self._build_kwargs(
            messages, tools, model, max_tokens, temperature,
            reasoning_effort, tool_choice,
        )

        try:
            response = await self._client.messages.create(**kwargs)
            return self._parse_response(response)
        except Exception as e:
            if self._is_streaming_required_error(e):
                # [核心] 透明切换到流式(避免 max_tokens 超限)
                return await self.chat_stream(
                    messages=messages,
                    tools=tools,
                    model=model,
                    max_tokens=max_tokens,
                    ...
                )
            return self._handle_error(e)

    def _convert_messages(
        self, messages: list[dict]
    ) -> tuple[str, list[dict]]:
        """
        [核心] OpenAI 格式 → Anthropic 格式。

        转换规则:
        1. 提取系统提示词
        2. 工具结果消息 → tool_result 块
        3. 用户消息 → content 块(支持图片)
        4. 助手消息 → text/tool_use 块
        """
        ...

    def _parse_response(self, response) -> LLMResponse:
        """
        [核心] Anthropic 格式 → LLMResponse。

        解析:
        1. 文本内容(content 块)
        2. 工具调用(tool_use 块)
        3. Token 使用量(usage)
        4. 停止原因(stop_reason → finish_reason)
        """
        ...

3. ProviderFactory(Provider 工厂)

职责

  • 根据配置创建 Provider 实例
  • 自动检测 Provider 类型
  • 验证 API 密钥

关键方法factory.py:29-100):

python 复制代码
def make_provider(config: Config) -> LLMProvider:
    """
    [核心] 根据配置创建 Provider。

    流程:
    1. 解析模型名称 → Provider 名称
    2. 查找 Provider 注册表
    3. 确定后端类型(anthropic/openai_compat/azure_openai/...)
    4. 验证配置(API 密钥、base URL)
    5. 实例化具体 Provider
    """
    model = config.agents.defaults.model
    provider_name = config.get_provider_name(model)
    p = config.get_provider(model)
    spec = find_by_name(provider_name)
    backend = spec.backend if spec else "openai_compat"

    # [工具代码] 配置验证
    if backend == "azure_openai":
        if not p or not p.api_key or not p.api_base:
            raise ValueError("Azure OpenAI requires api_key and api_base.")
    elif backend == "openai_compat" and not model.startswith("bedrock/"):
        needs_key = not (p and p.api_key)
        exempt = spec and (spec.is_oauth or spec.is_local or spec.is_direct)
        if needs_key and not exempt:
            raise ValueError(f"No API key configured for '{provider_name}'.")

    # [核心] 实例化 Provider
    if backend == "anthropic":
        from nanobot.providers.anthropic_provider import AnthropicProvider
        provider = AnthropicProvider(
            api_key=p.api_key if p else None,
            api_base=config.get_api_base(model),
            default_model=model,
            extra_headers=p.extra_headers if p else None,
        )
    elif backend == "openai_codex":
        from nanobot.providers.openai_codex_provider import OpenAICodexProvider
        provider = OpenAICodexProvider(default_model=model)
    ...

    return provider

4. ProviderRegistry(Provider 注册表)

职责

  • 维护所有 Provider 的元数据
  • 提供查找功能(按名称/模型/关键词)
  • 管理环境变量映射

关键数据结构registry.py:21-500):

python 复制代码
@dataclass(frozen=True)
class ProviderSpec:
    """
    [核心] Provider 元数据。

    字段说明:
    - name: 配置文件中的字段名(如 "anthropic")
    - keywords: 模型名称关键词(用于自动检测)
    - env_key: API 密钥的环境变量名
    - backend: 实现类型(anthropic/openai_compat/...)
    - default_api_base: 默认 API 端点
    - is_gateway: 是否为网关(路由任意模型)
    - is_local: 是否为本地部署
    - is_oauth: 是否使用 OAuth(无 API 密钥)
    """
    name: str
    keywords: tuple[str, ...]
    env_key: str
    backend: str = "openai_compat"
    default_api_base: str = ""
    is_gateway: bool = False
    is_local: bool = False
    is_oauth: bool = False
    ...

# Provider 注册表
PROVIDERS = [
    ProviderSpec(
        name="anthropic",
        keywords=("claude",),
        env_key="ANTHROPIC_API_KEY",
        backend="anthropic",
        default_api_base="https://api.anthropic.com",
        supports_prompt_caching=True,
    ),
    ProviderSpec(
        name="openrouter",
        keywords=("openrouter", "mistral", "deepseek", "qwen"),
        env_key="OPENROUTER_API_KEY",
        backend="openai_compat",
        is_gateway=True,
        default_api_base="https://openrouter.ai/api/v1",
    ),
    ProviderSpec(
        name="ollama",
        keywords=("ollama",),
        env_key="OLLAMA_API_KEY",
        backend="openai_compat",
        is_local=True,
        default_api_base="http://localhost:11434/v1",
    ),
    ...
]

🔗 调用链追踪

完整 LLM 调用链路

复制代码
AgentRunner 需要调用 LLM
    ↓
AgentRunner.run(spec) [runner.py:237]
    ↓
LLMProvider.chat(messages, tools, model) [anthropic_provider.py:737]
    ↓
构建请求参数
    ├→ _convert_messages(messages) [格式转换]
    │   ├→ 提取系统提示词
    │   ├→ 转换工具结果消息
    │   ├→ 转换用户消息(文本/图片)
    │   └→ 转换助手消息(文本/工具调用)
    └→ _build_kwargs(tools, temperature, ...)
    ↓
调用 Anthropic API
    ├→ 非流式:_client.messages.create(**kwargs)
    └→ 流式:_client.messages.stream(**kwargs)
    ↓
解析响应
    ├→ _parse_response(response)
    │   ├→ 提取文本内容
    │   ├→ 提取工具调用(tool_use 块)
    │   ├→ 提取 Token 使用量
    │   └→ 转换 finish_reason
    └→ 返回 LLMResponse
    ↓
AgentRunner 处理 LLMResponse
    ├→ 如果有 tool_calls → 执行工具
    └→ 如果是纯文本 → 结束循环

📊 数据流图

LLMProvider Anthropic API AnthropicProvider AgentRunner LLMProvider Anthropic API AnthropicProvider AgentRunner 1. 消息格式转换 2. 构建请求参数 3. 调用 API 4. 解析响应 5. 处理响应 alt [response.t- ool_calls] [response.c- ontent] chat(messages, tools, model) _convert_messages(messages) OpenAI 格式 → Anthropic 格式 _build_kwargs(tools, temp, ...) client.messages.create(**kwargs) Response _parse_response(response) Anthropic 格式 → LLMResponse LLMResponse 执行工具 返回结果


🎨 设计模式分析

1. 策略模式(Strategy Pattern)

体现LLMProvider 定义接口,具体 Provider 实现不同策略。

好处

  • 运行时切换 LLM 后端
  • 统一的调用接口
  • 易于添加新 Provider

代码位置base.py:92


2. 工厂模式(Factory Pattern)

体现make_provider() 根据配置创建具体 Provider。

好处

  • 集中管理 Provider 创建逻辑
  • 隐藏具体实例化细节
  • 支持自动检测

代码位置factory.py:29


3. 适配器模式(Adapter Pattern)

体现AnthropicProvider 将 Anthropic API 适配到统一接口。

适配内容

  • 消息格式(OpenAI ↔ Anthropic)
  • 工具调用格式
  • 响应格式

代码位置anthropic_provider.py:168-229, 310-340


4. 注册表模式(Registry Pattern)

体现PROVIDERS 列表维护所有 Provider 元数据。

好处

  • 单一事实来源
  • 自动配置匹配
  • 环境变量管理

代码位置registry.py:21-500


🔍 代码标注分析

AnthropicProvider.chat() 完整实现(带标注)

python 复制代码
async def chat(
    self,
    messages: list[dict[str, Any]],
    tools: list[dict[str, Any]] | None = None,
    model: str | None = None,
    max_tokens: int = 4096,
    temperature: float = 0.7,
    reasoning_effort: str | None = None,
    tool_choice: str | dict[str, Any] | None = None,
) -> LLMResponse:
    """
    [核心业务] 执行非流式聊天请求。

    关键特性:
    1. 透明流式降级(max_tokens 超限时自动切换)
    2. 提示词缓存(cache_control)
    3. 扩展思维模式支持
    """

    # [核心] 构建请求参数
    kwargs = self._build_kwargs(
        messages, tools, model, max_tokens, temperature,
        reasoning_effort, tool_choice,
    )

    try:
        # [核心业务] 调用 Anthropic API
        response = await self._client.messages.create(**kwargs)

        # [核心] 解析响应
        return self._parse_response(response)

    except Exception as e:
        # [核心] 透明流式降级
        # 当 max_tokens 过大时,Anthropic API 要求使用流式
        # 此处自动切换,无需调用方感知
        if self._is_streaming_required_error(e):
            return await self.chat_stream(
                messages=messages,
                tools=tools,
                model=model,
                max_tokens=max_tokens,
                temperature=temperature,
                reasoning_effort=reasoning_effort,
                tool_choice=tool_choice,
            )

        # [工具代码] 错误处理
        return self._handle_error(e)

_convert_messages() 格式转换(带标注)

python 复制代码
def _convert_messages(
    self, messages: list[dict[str, Any]]
) -> tuple[str, list[dict]]:
    """
    [核心] OpenAI 格式 → Anthropic 格式。

    转换对照表:
    | OpenAI 格式 | Anthropic 格式 |
    |-------------|----------------|
    | {"role": "system", "content": "..."} | system = "..." (独立参数) |
    | {"role": "user", "content": "文本"} | {"role": "user", "content": [{"type": "text", "text": "文本"}]} |
    | {"role": "tool", "content": "...", "tool_call_id": "..."} | {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "...", "content": "..."}]} |
    | {"role": "assistant", "tool_calls": [...]} | {"role": "assistant", "content": [{"type": "tool_use", "name": "...", "input": {...}}]} |
    """
    raw = []
    system = ""

    for msg in messages:
        role = msg["role"]
        content = msg.get("content")

        # [核心] 处理系统提示词(Anthropic 要求独立参数)
        if role == "system":
            system = content
            continue

        # [核心] 处理工具结果消息
        if role == "tool":
            block = self._tool_result_block(msg)
            # 合并到上一条用户消息(Anthropic 要求)
            if raw and raw[-1]["role"] == "user":
                prev_c = raw[-1]["content"]
                if isinstance(prev_c, list):
                    prev_c.append(block)
                else:
                    raw[-1]["content"] = [
                        {"type": "text", "text": prev_c or ""},
                        block,
                    ]
            else:
                raw.append({"role": "user", "content": [block]})
            continue

        # [核心] 处理用户消息(支持文本和图片)
        if role == "user":
            raw.append({
                "role": "user",
                "content": self._convert_user_content(content),
            })
            continue

        # [核心] 处理助手消息(文本 + 工具调用)
        if role == "assistant":
            raw.append({
                "role": "assistant",
                "content": self._assistant_blocks(msg),
            })
            continue

    # [核心] 合并连续的同角色消息(Anthropic 推荐)
    return system, self._merge_consecutive(raw)

🎯 Provider 速查表

Provider 后端类型 配置键 环境变量 特殊特性
Anthropic anthropic anthropic ANTHROPIC_API_KEY 提示词缓存、思维模式
OpenAI Codex openai_codex openai_codex GITHUB_TOKEN OAuth 认证
Azure OpenAI azure_openai azure_openai AZURE_API_KEY 需要 api_base
GitHub Copilot github_copilot github_copilot GITHUB_TOKEN OAuth 认证
OpenRouter openai_compat openrouter OPENROUTER_API_KEY 网关
Ollama openai_compat ollama OLLAMA_API_KEY 本地部署
vLLM openai_compat vllm VLLM_API_KEY 本地部署
Bedrock bedrock bedrock AWS_* AWS 集成

📚 扩展阅读

下一篇 : README05_LEVEL2_渠道系统设计

相关文件

  • nanobot/providers/base.py - LLMProvider 基类和 LLMResponse 定义
  • nanobot/providers/factory.py - Provider 工厂
  • nanobot/providers/registry.py - Provider 注册表
  • nanobot/providers/anthropic_provider.py - Anthropic Provider 实现
  • nanobot/providers/openai_compat_provider.py - OpenAI 兼容 Provider 实现

如何添加新 Provider

  1. registry.pyPROVIDERS 中添加 ProviderSpec
  2. config/schema.pyProvidersConfig 中添加配置字段
  3. 如果是新后端类型,在 factory.py 中添加实例化逻辑
相关推荐
厚国兄1 小时前
Agent 工程化系列 · 第 13 篇_Agent安全与可靠性如何保障
人工智能·安全·llm·prompt·agent
坐吃山猪1 小时前
【Nanobot】README09_LEVEL4 添加新聊天渠道
开发语言·网络·python·源码·nanobot
Mr.朱鹏1 小时前
9-检索增强生成RAG详解
python·gpt·langchain·大模型·llm·rag
shehuiyuelaiyuehao1 小时前
算法27,二维前缀和
开发语言·python·算法
码界筑梦坊2 小时前
125-基于Flask的客户购物偏好数据可视化分析系统
python·信息可视化·flask·毕业设计
测试秃头怪2 小时前
接口测试与常用接口测试工具详解
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·接口测试
坐吃山猪2 小时前
【Nanobot】README03_LEVEL2_工具系统架构
python·源码·agent·nanobot
河阿里2 小时前
Python容器:特性、区别和使用场景
开发语言·python
AC赳赳老秦2 小时前
OpenClaw与思维导图工具联动:自动生成工作规划脑图、拆解任务节点,适配职场管理
java·大数据·服务器·数据库·python·php·openclaw