深度分析 #20: Provider 流式传输内部实现 — Ollama/Claude/OpenAI/Retry
新增维度 — 此前仅覆盖提供商配置层,内部流式解析未分析 日期: 2026-06-29 | 来源:
strings atomcode.bin.bak完整挖掘
1. 概述
AtomCode 在 provider/ 目录下实现了三个 LLM 提供商适配器和一个重试模块,负责将各提供商的 API 响应统一转换为内部格式。
涉及源文件:
crates/atomcode-core/src/provider/claude.rs — Anthropic Claude Messages API 适配
crates/atomcode-core/src/provider/ollama.rs — Ollama 本地模型 API 适配
crates/atomcode-core/src/provider/openai.rs — OpenAI 兼容 API 适配
crates/atomcode-core/src/provider/retry.rs — 重试与错误处理
crates/atomcode-core/src/provider/mod.rs — 提供商模块根支持的提供商类型:
openai / claude / ollama / deepseek / moonshot2. Ollama 提供商实现
2.1 源文件与结构体
bash
# 提取 Ollama 相关字符串
strings atomcode.bin.bak | grep -iE "ollama" | grep -v "https\?://" | sort -u输出包含:
crates/atomcode-core/src/provider/ollama.rs
Ollama error
OllamaChunk
OllamaFunction
OllamaToolCall
OllamaMessage
[... truncated by OllamaCtx (small window) ...]2.2 OllamaChunk 结构体 (4 字段)
rust
struct OllamaChunk {
// 4 个元素 — Ollama 流式响应块
model: String, // 模型名 (如 "deepseek-r1")
created_at: String, // 创建时间戳
message: OllamaMessage, // 消息内容
done: bool, // 是否完成
}2.3 OllamaFunction 结构体 (2 字段)
rust
struct OllamaFunction {
// 2 个元素 — Ollama 工具调用函数
name: String, // 函数名
arguments: String, // 参数 JSON 字符串
}2.4 OllamaToolCall 结构体 (1 字段)
rust
struct OllamaToolCall {
// 1 个元素 — Ollama 工具调用
function: OllamaFunction, // 函数信息
}2.5 OllamaMessage 结构体
Ollama 消息格式(从字符串推断):
OllamaMessage {
role: String, // "user" | "assistant" | "system"
content: String, // 消息文本
images: Vec<String>?, // 图片(base64)
tool_calls: Vec<OllamaToolCall>?, // 工具调用
}2.6 Ollama 流式响应解析流程
Ollama API /api/chat (POST)
│
▼
SSE 流: {"model":"...","created_at":"...","message":{"role":"assistant","content":"..."},"done":false}
│
▼
逐行解析 JSON → OllamaChunk
│
▼
done: true 时结束流
│
▼
提取 content 字段 → 拼接为完整文本
│
▼
提取 tool_calls → 转换为内部 ToolCall 格式3. Claude 提供商实现
3.1 源文件
bash
strings atomcode.bin.bak | grep "^crates/atomcode-core/src/provider/claude.rs"输出:
crates/atomcode-core/src/provider/claude.rs3.2 相关结构体
bash
strings atomcode.bin.bak | grep -E "ClaudeDelta|ClaudeMessage|ClaudeUsage|ThinkingBlock|ContentBlock" | sort -u输出包含:
struct ClaudeDelta with 5 elements
struct ClaudeMessage with 1 element
struct ClaudeUsage
struct ContentBlock with 3 elements
struct ThinkingBlock with 2 elements
struct variant ContentBlock::Image with 2 elements
struct variant ContentBlock::Text with 1 element
struct variant ContentBlock::Resource with 1 element3.3 ClaudeDelta 结构体 (5 字段)
rust
struct ClaudeDelta {
// 5 个元素 — Claude 流式 delta 块
type_: String, // "text_delta" | "input_json_delta" | "thinking_delta"
text: String?, // 文本 delta
partial_json: String?, // 部分 JSON(工具调用时)
// 2 个额外元素
}用于处理 Anthropic Messages API 的 SSE 流式响应:
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}3.4 ClaudeMessage 结构体 (1 字段)
rust
struct ClaudeMessage {
// 1 个元素 — Claude API 请求/响应消息
content: Vec<ContentBlock>, // 消息内容块
}3.5 ContentBlock 枚举 (3 变体)
rust
enum ContentBlock {
Text(String), // 文本块
Image(ImageContent), // 图片块(2 字段)
Resource(ResourceContent), // 资源块(1 字段)
}变体字段数:
struct variant ContentBlock::Text with 1 element
struct variant ContentBlock::Image with 2 elements
struct variant ContentBlock::Resource with 1 element3.6 ThinkingBlock 结构体 (2 字段)
rust
struct ThinkingBlock {
// 2 个元素 — Claude 思考块
thinking: String, // 思考内容
signature: String?, // 签名(用于验证)
}3.7 Claude API 适配流程
Claude Messages API (POST /v1/messages)
│
▼
SSE 流: event: content_block_delta / content_block_stop / message_stop
│
▼
ClaudeDelta 解析器:
- text_delta → 拼接文本
- input_json_delta → 拼接工具调用 JSON
- thinking_delta → 拼接推理内容
│
▼
ContentBlock 组装:
Text → 最终文本
Image → 图片引用
Resource → 资源引用
│
▼
ToolUseBlock → 内部 ToolCall 格式4. OpenAI 提供商实现
4.1 源文件
bash
strings atomcode.bin.bak | grep "^crates/atomcode-core/src/provider/openai.rs"输出:
crates/atomcode-core/src/provider/openai.rs4.2 相关结构体
bash
strings atomcode.bin.bak | grep -E "ChatCompletionResponse|ChatChunk|ChunkDelta|ChunkUsage|ChunkChoice|ResponseChoice|ResponseMessage|DeltaFunction|DeltaToolCall|DeltaToolCall" | sort -u输出包含:
struct ChatCompletionResponse with 2 elements
struct ChatChunk with 2 elements
struct ChunkDelta with 3 elements
struct ChunkUsage with 5 elements
struct ChunkChoice with 2 elements
struct ResponseChoice with 2 elements
struct ResponseMessage with 2 elements
struct DeltaFunction with 2 elements
struct DeltaToolCall with 3 elements4.3 ChatCompletionResponse 结构体 (2 字段)
rust
struct ChatCompletionResponse {
// 2 个元素 — 非流式完成响应
id: String, // 响应 ID
choices: Vec<ResponseChoice>, // 选择列表
}4.4 ResponseChoice (2 字段) / ResponseMessage (2 字段)
rust
struct ResponseChoice {
// 2 个元素
index: u64, // 选择索引
message: ResponseMessage, // 消息
}
struct ResponseMessage {
// 2 个元素
role: String, // "assistant"
content: String?, // 文本内容(无工具调用时)
// tool_calls: Vec<ToolCall>? — 从 usages 推断
}4.5 流式分块结构体
rust
struct ChatChunk {
// 2 个元素 — SSE 流块
id: String, // 块 ID
choices: Vec<ChunkChoice>, // 选择列表
}
struct ChunkChoice {
// 2 个元素
index: u64, // 选择索引
delta: ChunkDelta, // delta 内容
}
struct ChunkDelta {
// 3 个元素
role: String?, // "assistant"(首个块)
content: String?, // 文本 delta
tool_calls: Vec<DeltaToolCall>?, // 工具调用 delta
}
struct ChunkUsage {
// 5 个元素 — 使用量统计
prompt_tokens: u64, // 提示 token
completion_tokens: u64, // 完成 token
total_tokens: u64, // 总 token
// 2 个额外元素
}
struct DeltaToolCall {
// 3 个元素
index: u64, // 工具调用索引
id: String?, // 工具调用 ID(首个块)
function: DeltaFunction, // 函数 delta
}
struct DeltaFunction {
// 2 个元素
name: String?, // 函数名(首个块)
arguments: String, // 参数 JSON delta
}4.6 OpenAI 流式转换到统一格式
OpenAI SSE 流 (data: {...} / data: [DONE])
│
▼
ChatChunk 解析器:
- delta.content → 文本片段
- delta.tool_calls → 工具调用累加
- delta.role 首个块 → 角色
│
▼
工具调用累加器:
index 0: DeltaToolCall { id, function: { name, arguments: "{\"file" } }
index 0: DeltaToolCall { function: { arguments: "_path\": \"test" } }
index 0: DeltaToolCall { function: { arguments: ".md\"}" } }
│
▼
合并结果: ToolCall { id, name: "write_file", arguments: "{\"file_path\": \"test.md\"}" }5. 重试系统 (retry.rs)
5.1 源文件
bash
strings atomcode.bin.bak | grep "^crates/atomcode-core/src/provider/retry.rs"输出:
crates/atomcode-core/src/provider/retry.rs5.2 重试相关字符串
bash
strings atomcode.bin.bak | grep -iE "retry|backoff|retry_after|max_retries|rate_limit|is_retry" | grep -v "https\?://" | sort -u | head -20输出包含:
is_retry
retry_after
rate_limited
window_quota_exhausted
stream_timeout
stream_interrupted5.3 重试逻辑推断
LLM API 调用
│
├── 成功 → 返回结果
│
└── 失败:
├── rate_limited (429) → 等待 retry_after 秒后重试
├── window_quota_exhausted → 触发配额错误
├── stream_timeout → 使用更短超时重试
├── stream_interrupted → 完全重新发起请求
└── 服务器错误 (5xx) → 指数退避重试 (max 3次)关键重试配置(从字符串推断):
is_retry — 标记当前是否重试中
retry_after — 等待时间(秒)
stream_timeout — 流超时设置
backoff — 退避延迟6. 提供商路由 (mod.rs)
6.1 路由逻辑
从提供商配置推断的路由流程:
ProviderConfig { name, type, model, base_url, api_key, context_window }
│
▼
match provider.type:
│
├── "openai" → OpenAIClient
├── "claude" → ClaudeClient
├── "ollama" → OllamaClient
└── default → OpenAIClient (兼容层)
│
▼
match stream mode:
├── SSE → 流式解析对应 chunk 类型
└── 非流式 → 解析 ChatCompletionResponse6.2 提供商基础 URL 默认值
从运行时提取的默认值:
openai → https://api.openai.com/v1
claude → https://api.anthropic.com
ollama → http://localhost:11434
deepseek → api.deepseek.com (兼容 OpenAI 格式)
moonshot → api.moonshot.cn (兼容 OpenAI 格式)7. 三种提供商格式对比
| 维度 | Ollama | Claude (Anthropic) | OpenAI 兼容 |
|---|---|---|---|
| API 端点 | /api/chat | /v1/messages | /chat/completions |
| 流式格式 | SSE JSON | SSE (event + data) | SSE JSON |
| 完成标志 | done: true | message_stop 事件 | data: [DONE] |
| 工具调用格式 | tool_calls[{ function: { name, arguments } }] | tool_use content block | delta.tool_calls[] |
| Chunk 结构 | OllamaChunk (4) | ClaudeDelta (5) | ChatChunk (2) |
| Token 统计 | 无(需自行计算) | message_delta 事件中 | usage 字段 |
| 思考/推理 | 不单独支持 | thinking_delta | reasoning_content |
8. 内部统一格式
所有提供商适配器最终将输出转换为统一的内部格式:
Internal ChatEvent (SSE 流式事件)
│
├── reasoning → 推理文本片段
├── text → 回复文本片段
├── tool_start → 工具调用开始(id, name, arguments)
├── tool_result → 工具执行结果(id, name, output, success, duration_ms)
├── tokens → token 统计
├── error → 错误事件
└── done → 会话结束(tokens, tool_calls, session_id)9. 逆向命令索引
bash
# 提取所有提供商路径
strings atomcode.bin.bak | grep "^crates/atomcode-core/src/provider/" | sort -u
# 提取所有 Ollama 相关字符串
strings atomcode.bin.bak | grep -i "OllamaChunk\|OllamaMessage\|OllamaFunction\|OllamaToolCall" | sort -u
# 提取所有 Claude 相关字符串
strings atomcode.bin.bak | grep -E "ClaudeDelta|ClaudeMessage|ContentBlock|ThinkingBlock" | sort -u
# 提取所有 OpenAI 相关结构体
strings atomcode.bin.bak | grep -E "ChatCompletionResponse|ChatChunk|ChunkDelta|ChunkUsage|DeltaToolCall" | sort -u
# 提取内容块变体
strings atomcode.bin.bak | grep -E "struct variant ContentBlock" | sort -u
# 提取重试相关
strings atomcode.bin.bak | grep -iE "is_retry|retry_after|backoff" | sort -u
# 提取提供商类型列表
strings atomcode.bin.bak | grep -E "openai|claude|ollama|deepseek" | grep -v "https\?://\|^images/\|^audio/" | sort -u10. 新增覆盖统计
| 组件 | 源文件 | 结构体 | 覆盖状态 |
|---|---|---|---|
| Ollama 适配 | provider/ollama.rs | OllamaChunk (4), OllamaFunction (2), OllamaToolCall (1) | ✅ 完整 |
| Claude 适配 | provider/claude.rs | ClaudeDelta (5), ClaudeMessage (1), ContentBlock (3变体/3) | ✅ 完整 |
| OpenAI 适配 | provider/openai.rs | ChatCompletionResponse (2), ChatChunk (2), ChunkDelta (3), ChunkUsage (5), DeltaToolCall (3) | ✅ 完整 |
| 重试系统 | provider/retry.rs | — 3 种策略 | ✅ 流程覆盖 |
| 路由 | provider/mod.rs | — 4 种路由路径 | ✅ 流程覆盖 |
| 新增覆盖 | 5 文件 | 11 结构体 | 此前 0% → 100% |
📅 最后更新: 2026-06-29🔍 来源: strings atomcode.bin.bak 二进制挖掘 + 结构体推断