4.4 KiB
4.4 KiB
边界情况
本文档从
9-llm-provider-unified-interface.md拆分而来,包含 §9 边界情况。相关文件:
- 9b-ir-type-system.md — IR 类型定义(ContentBlock、ThinkingConfig、MessageRequest/Response 等)
- 9c-llm-provider-trait.md — StreamEvent 类型定义(ThinkingDelta 等)
- 9d-provider-implementations.md — Anthropic 流式状态机(与 Thinking signature 强相关)
- 9e-llm-cycle-and-upstream.md — LlmCycle 的 tool 循环与 compact 逻辑
9. 边界情况
9.1 工具定义的传递路径变化
| 阶段 | 路径 |
|---|---|
| 当前 | ToolRegistry.definitions() → Vec<ToolDefinition> → build_request() 包装为 Vec<OpenaiTool> → ChatRequest.tools |
| 方案 C | ToolRegistry.definitions() → Vec<ToolDefinition> → build_request() 直接放入 → MessageRequest.tools → Provider 内部包装为原生格式 |
工具定义的抽象层次从 LlmCycle 下移到 Provider 内部,更合理。
9.2 Thinking 的端到端流程
Agent 启用 thinking:
config.thinking = Some(ThinkingConfig { budget_tokens: 16000 })
LlmCycle.build_request():
→ MessageRequest { thinking: config.thinking, ... }
OpenaiProvider:
→ capabilities().features.thinking == false
→ 忽略 thinking 字段(或转为 extra.reasoning_tokens)
AnthropicProvider:
→ capabilities().features.thinking == true
→ 将 thinking 写入 Anthropic 请求参数
→ 流式响应中返回 StreamEvent::ThinkingDelta
→ 最终消息的 content 中包含 ContentBlock::Thinking
🔄 待深入推演:Thinking signature 的端到端传递 当前设计中,Anthropic 的 thinking block signature 在
ContentBlock::Thinking.signature中存储, 但从流式事件到最终 ContentBlock 的传递路径没有闭环:
content_block_start(针对 thinking block)下发的是{ type: "thinking" }没有 signaturecontent_block_delta下发thinkingdelta + signature(在 delta 中,不是独立的字段)StreamEvent::ThinkingDelta { text }当前只有 text,缺少 signature 字段- 最终需要将 signature 附着到
ContentBlock::Thinking { text, signature: Some(...) }上需要推演:
StreamEvent::ThinkingDelta是否需要增加signature: Option<String>字段?- 或者改为每个 block 结束时发一个独立的
ContentBlockSealed { index, block: ContentBlock }事件?- 非流式响应中,Anthropic 的 thinking block 是完整的(含 text 和 signature 在同一 block 中), 映射没有问题。但流式响应中,signature 的附着时机需要在 AnthropicProvider 的状态机中准确定义。
PartialMessageResponse(§4.3 待推演)需要能按 index 追踪 thinking block 的 text 累积和 signature 暂存。此问题与 9d-provider-implementations.md §5.2 的"Anthropic 流式状态机设计"直接相关, 建议在推演状态机时一并解决。 优先级:高(Phase 4 AnthropicProvider 实现的前提条件)
9.3 Multiple ContentBlock 的处理
消息的 content 为 Vec<ContentBlock>,可包含多种类型的混合:
Message::Assistant {
content: vec![
ContentBlock::Text { text: "让我思考一下..." },
ContentBlock::Thinking { text: "先用加法工具...", signature: None },
ContentBlock::Text { text: "答案是 3" },
ContentBlock::ToolUse { id: "call_1", name: "add", input: json!({"a":1,"b":2}) },
],
}
LlmCycle 处理 tool 循环时只关心 ToolUse block,其他 block 按原样传递给消息历史。
9.4 多 Choice 场景
OpenAI 的 n > 1 参数在 IR 中通过 extra 传递:
// 请求
request.set_extra("n", json!(3));
// 响应
response.extra["all_choices"] = json!([...choices 2..n]);
MessageResponse 只承载 choices[0](主消息),其他 choices 放 extra。
9.5 OpenAI Response API 的内置工具
通过 extra + 可选能力 trait 支持:
// 配置内置工具
request.set_extra("built_in_tools", json!(["web_search", "file_search"]));
// Response API 返回的搜索结果
// → ContentBlock::Extension { kind: "web_search_result", data: {...} }
如果未来内置工具成为跨 Provider 通用特性,将 BuiltInToolsCapable 升级为核心 trait。