workspace/ files existed on disk but were not included in previous incremental commit, causing git to record them as deleted. Re-adding all workspace card components, AgentWorkspace, ActivityTimeline, and WorkspaceCardRenderer to properly track them. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
3.0 KiB
3.0 KiB
CoT 整体架构与数据流
数据流
用户选择 Auto / Pro
↓
后端注入 CoT system prompt
(要求模型输出 <think>推理</think>最终回答)
↓
LLM 流式输出:
"<think>让我先分析...</think>最终回答内容..."
↓
ThinkTagParser 状态机实时解析
IN_THINK 状态 → thinking token
IN_ANSWER 状态 → answer token
↓
SSE 事件分流:
{"type": "thinking", "content": "让我先分析..."}
{"type": "token", "content": "最终回答..."}
{"type": "tool_start", "tool": "kb_search"}
{"type": "tool_end", "tool": "kb_search"}
{"type": "done"}
↓
前端 SSE 解析器接收事件
↓
ThinkingBlock 组件(Auto: 脉冲动画 / Pro: 折叠块)
ToolCallIndicator 组件(工具调用进度)
消息内容正常渲染
SSE 事件协议
// CoT 推理过程(流式分块,Auto/Pro 模式)
{"type": "thinking", "content": "让我先分析这个问题..."}
// 最终回答(流式分块,所有模式)
{"type": "token", "content": "根据分析,答案是..."}
// 工具调用开始
{"type": "tool_start", "tool": "kb_search"}
// 工具调用结束
{"type": "tool_end", "tool": "kb_search"}
// 流结束
{"type": "done"}
// 错误
{"type": "error", "content": "错误信息"}
ThinkTagParser 状态机
feed("<think>")
INITIAL ─────────────────→ IN_THINK
│
feed(text) │ emit("thinking", text)
│
feed("</think>")
↓
IN_ANSWER
│
feed(text) │ emit("token", text)
↓
(done)
边界处理:流式 token 可能在标签中间截断(如 "<thi" + "nk>"),需要 buffer 积累直到标签完整。
ReAct Agent 中的 CoT
使用 create_react_agent 时,LangGraph 多轮调用 LLM:
轮1: LLM 决定调用工具
→ tool_start 事件告知前端"我在做什么"
→ LLM 通常不输出 text content(tool_call 模式)
工具执行中...
→ tool_end 事件
轮N(最终): LLM 基于工具结果生成回答
→ <think> 标签内是完整推理
→ thinking + token 事件流出
结论:tool_start/tool_end 本身已经是"正在做什么"的可视化,最终轮的 <think> 提供深度推理展示。
原生 Reasoning Tokens(升级路径)
Azure OpenAI 从 API version 2024-12-17 起,o1/o3/o4-mini 系列支持:
- 请求参数:
reasoning_effort: "low" | "medium" | "high" - 响应字段:
message.additional_kwargs.reasoning_content
如确认 gpt-5.4 部署支持,只需在 _get_llm() 中添加:
if thinking and native_reasoning_supported:
kwargs["reasoning_effort"] = "medium" if model == "auto" else "high"
SSE 层无需任何改动,因为 reasoning_content 和 <think> 标签都走同一个 thinking 事件。