Skip to content

Free Claude Code 采用清晰的模块化架构:api(HTTP 路由和请求编排)→ providers(上游适配器)→ core(共享协议工具)→ config(配置)。Provider 通过工厂模式注册,新增后端只需实现 BaseProvider 接口并注册工厂函数。消息系统使用平台无关的接口,Discord 和 Telegram 是两个独立的平台实现。

Free Claude Code 架构设计:一个 Anthropic 代理的模块化拆分思路

模块总览

free-claude-code/
├── server.py              # ASGI 入口
├── api/                   # FastAPI 路由、服务层、模型路由、请求优化
├── core/                  # 共享 Anthropic 协议工具和 SSE 工具
├── providers/             # Provider 适配器、注册表、限流
├── messaging/             # Discord/Telegram 适配器、会话、语音
├── cli/                   # 包入口点和 Claude CLI 进程管理
├── config/                # 设置、Provider 目录、日志
└── tests/                 # 单元测试和契约测试

依赖方向

模块之间有明确的依赖规则:

config → api, providers, messaging(配置被所有模块依赖)
core.anthropic → api, providers, messaging(协议工具被所有模块依赖)
providers → api(Provider 适配器被 API 层调用)
api → cli, messaging(API 层编排 CLI 和消息系统)

核心原则:共享协议工具放在中立的 core/ 模块,Provider 适配器之间不互相依赖。API 和消息代码不导入 Provider 内部实现。

这条规则通过 tests/contracts/test_import_boundaries.py 强制执行——如果某个模块越界导入,契约测试会直接报错。

Provider 扩展机制

接口定义

每个 Provider 继承 BaseProvider,实现三个方法:

python
class BaseProvider(ABC):
    async def cleanup(self) -> None: ...
    async def list_model_ids(self) -> frozenset[str]: ...
    async def stream_response(self, request, ...) -> AsyncIterator[str]: ...

注册新 Provider

  1. 描述符config/provider_catalog.py):定义 Provider 的 ID、传输类型、认证方式、默认 URL
python
"ollama": ProviderDescriptor(
    provider_id="ollama",
    transport_type="anthropic_messages",
    static_credential="ollama",
    default_base_url="http://localhost:11434",
    capabilities=("chat", "streaming", "tools", "thinking", "local"),
)
  1. 工厂函数providers/registry.py):创建 Provider 实例
python
def _create_ollama(config, settings):
    from providers.ollama import OllamaProvider
    return OllamaProvider(config)
  1. 注册:把工厂函数加到 PROVIDER_FACTORIES 字典

启动时会自动校验 PROVIDER_DESCRIPTORSPROVIDER_FACTORIESSUPPORTED_PROVIDER_IDS 三者一致。

两种传输类型

传输类型使用者说明
openai_chatNVIDIA NIM需要 OpenAI Chat → Anthropic SSE 协议转换
anthropic_messagesOpenRouter、DeepSeek、LM Studio、llama.cpp、Ollama原生 Anthropic Messages 协议,直接转发

模型路由

ModelRouter 根据 Claude Code 请求中的模型名,匹配到配置的 Provider/模型:

claude-opus-4-20250514 → MODEL_OPUS → nvidia_nim/moonshotai/kimi-k2.5

路由逻辑:解析模型名中的层级关键词 → 查找对应的 MODEL_* 环境变量 → fallback 到 MODEL → 解析出 provider_idmodel_name

消息系统设计

消息系统采用平台无关的接口设计:

MessagingPlatform(接口)
├── DiscordPlatform(Discord 实现)
└── TelegramPlatform(Telegram 实现)

ClaudeMessageHandler 是平台无关的核心处理器,通过 MessagingPlatform 接口与具体平台交互。核心设计是树状消息队列

  • 新消息创建消息树的根节点
  • 回复成为被回复消息的子节点
  • 每个节点有状态:PENDINGIN_PROGRESSCOMPLETED / ERROR
  • 同一树内的消息按队列顺序处理,不同树并行处理

请求优化层

api/optimization_handlers.py 中的优化链在请求到达 Provider 之前执行:

请求进入 → try_optimizations() → 命中 → 本地直接响应
                              → 未命中 → 转发到 Provider

优化通过检测请求内容的模式(系统提示词、消息结构)来判断是否拦截。

二次开发指南

添加新 Provider

  1. config/provider_catalog.py 添加 ProviderDescriptor
  2. 创建 providers/你的provider.py,实现 BaseProvider
  3. providers/registry.py 添加工厂函数并注册
  4. tests/ 添加对应的测试

添加新消息平台

  1. 实现 MessagingPlatform 接口(参考 Discord 或 Telegram 的实现)
  2. api/runtime.py 中添加平台初始化逻辑
  3. 配置对应的环境变量

FAQ

Q: 为什么 Provider 用工厂模式而不是直接实例化? A: 工厂模式实现了延迟导入——只有实际使用的 Provider 才会被 import。避免安装某个 Provider 的依赖(如 discord.py)才能启动代理。

Q: core/ 模块里放了什么? A: Anthropic 协议工具:流式 SSE 解析、token 估算、错误消息格式化、stream contract 断言等。这些工具被 API、Provider 和消息模块共同依赖,所以放在中立位置。

Q: 契约测试怎么工作的? A: tests/contracts/test_import_boundaries.py 使用 AST 解析检查每个模块的 import 语句,确保没有违反依赖方向规则。例如,如果 messaging/ 意外导入了 api/,测试会失败。