Appearance
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
- 描述符(
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"),
)- 工厂函数(
providers/registry.py):创建 Provider 实例
python
def _create_ollama(config, settings):
from providers.ollama import OllamaProvider
return OllamaProvider(config)- 注册:把工厂函数加到
PROVIDER_FACTORIES字典
启动时会自动校验 PROVIDER_DESCRIPTORS、PROVIDER_FACTORIES 和 SUPPORTED_PROVIDER_IDS 三者一致。
两种传输类型
| 传输类型 | 使用者 | 说明 |
|---|---|---|
openai_chat | NVIDIA NIM | 需要 OpenAI Chat → Anthropic SSE 协议转换 |
anthropic_messages | OpenRouter、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_id 和 model_name。
消息系统设计
消息系统采用平台无关的接口设计:
MessagingPlatform(接口)
├── DiscordPlatform(Discord 实现)
└── TelegramPlatform(Telegram 实现)ClaudeMessageHandler 是平台无关的核心处理器,通过 MessagingPlatform 接口与具体平台交互。核心设计是树状消息队列:
- 新消息创建消息树的根节点
- 回复成为被回复消息的子节点
- 每个节点有状态:
PENDING→IN_PROGRESS→COMPLETED/ERROR - 同一树内的消息按队列顺序处理,不同树并行处理
请求优化层
api/optimization_handlers.py 中的优化链在请求到达 Provider 之前执行:
请求进入 → try_optimizations() → 命中 → 本地直接响应
→ 未命中 → 转发到 Provider优化通过检测请求内容的模式(系统提示词、消息结构)来判断是否拦截。
二次开发指南
添加新 Provider
- 在
config/provider_catalog.py添加ProviderDescriptor - 创建
providers/你的provider.py,实现BaseProvider - 在
providers/registry.py添加工厂函数并注册 - 在
tests/添加对应的测试
添加新消息平台
- 实现
MessagingPlatform接口(参考 Discord 或 Telegram 的实现) - 在
api/runtime.py中添加平台初始化逻辑 - 配置对应的环境变量
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/,测试会失败。