# 边界情况 > 本文档从 `9-llm-provider-unified-interface.md` 拆分而来,包含 §9 边界情况。 > > **相关文件:** > - [9b-ir-type-system.md](9b-ir-type-system.md) — IR 类型定义(ContentBlock、ThinkingConfig、MessageRequest/Response 等) > - [9c-llm-provider-trait.md](9c-llm-provider-trait.md) — StreamEvent 类型定义(ThinkingDelta 等) > - [9d-provider-implementations.md](9d-provider-implementations.md) — Anthropic 流式状态机(与 Thinking signature 强相关) > - [9e-llm-cycle-and-upstream.md](9e-llm-cycle-and-upstream.md) — LlmCycle 的 tool 循环与 compact 逻辑 ## 9. 边界情况 ### 9.1 工具定义的传递路径变化 | 阶段 | 路径 | |------|------| | **当前** | `ToolRegistry.definitions()` → `Vec` → `build_request()` 包装为 `Vec` → `ChatRequest.tools` | | **方案 C** | `ToolRegistry.definitions()` → `Vec` → `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 的传递路径没有闭环: > 1. `content_block_start`(针对 thinking block)下发的是 `{ type: "thinking" }` 没有 signature > 2. `content_block_delta` 下发 `thinking` delta + **signature**(在 delta 中,不是独立的字段) > 3. `StreamEvent::ThinkingDelta { text }` 当前只有 text,缺少 signature 字段 > 4. 最终需要将 signature 附着到 `ContentBlock::Thinking { text, signature: Some(...) }` 上 > > **需要推演:** > 1. `StreamEvent::ThinkingDelta` 是否需要增加 `signature: Option` 字段? > 2. 或者改为每个 block 结束时发一个独立的 `ContentBlockSealed { index, block: ContentBlock }` 事件? > 3. 非流式响应中,Anthropic 的 thinking block 是完整的(含 text 和 signature 在同一 block 中), > 映射没有问题。但流式响应中,signature 的附着时机需要在 AnthropicProvider 的状态机中准确定义。 > 4. `PartialMessageResponse`(§4.3 待推演)需要能按 index 追踪 thinking block 的 text 累积和 signature 暂存。 > > 此问题与 [9d-provider-implementations.md](9d-provider-implementations.md) §5.2 的"Anthropic 流式状态机设计"直接相关, > 建议在推演状态机时一并解决。 > 优先级:高(Phase 4 AnthropicProvider 实现的前提条件) ### 9.3 Multiple ContentBlock 的处理 消息的 `content` 为 `Vec`,可包含多种类型的混合: ```rust 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` 传递: ```rust // 请求 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 支持: ```rust // 配置内置工具 request.set_extra("built_in_tools", json!(["web_search", "file_search"])); // Response API 返回的搜索结果 // → ContentBlock::Extension { kind: "web_search_result", data: {...} } ``` 如果未来内置工具成为跨 Provider 通用特性,将 `BuiltInToolsCapable` 升级为核心 trait。