--- feature: "thinking" scope: "Agent 思考功能(基于 GuidelineMiddleware 的前置辅助推理),在主回答前生成一次 内容" updated_at: "2026-06-01" status: active --- # Thinking(思考功能) ## 当前状态 思考功能通过自定义的 **`GuidelineMiddleware`** 实现:在主 agent 执行前,先用业务指引 prompt 调一次模型做"思考", 把结果包成 `...` 标签并打上 `message_tag: "THINK"` 元数据,供前端识别/折叠展示。 > 重要:这是"主请求前的一次辅助请求",**不是** Qwen 模型内置的 reasoning/extended-thinking 模式,因此与具体模型无关,任何 LLM 都能用。对标 OpenAI o1 / Claude thinking,但实现更轻。 ## 配置开关 | 层级 | 字段 | 默认 | 位置 | |------|------|------|------| | Agent 配置 | `enable_thinking: bool` | `False` | `agent/agent_config.py:26` | | API 请求 | `enable_thinking: bool` | `False` | `utils/api_models.py:54` | 开启路径:V1 走请求体 `enable_thinking`,V2 走 bot 配置 `enable_thinking`。 中间件注册在 `agent/deep_assistant.py:294`:`if config.enable_thinking: middleware.append(GuidelineMiddleware(...))`。 ## 核心文件 - `agent/guideline_middleware.py` — 思考主逻辑。`get_guideline_prompt`(行 53+)组装指引 prompt;`before_agent`/`abefore_agent` 调模型生成思考,包 `` 标签并标 `THINK`(行 120-124 / 146-149)。 - `agent/deep_assistant.py:294-295` — 按 `enable_thinking` 注册中间件。 ## 数据流 1. `before_agent` 加载指引(system prompt 中的 Guidelines 块)。 2. 从 system prompt 提取 guidelines / tool_description / scenarios / terms_list。 3. 组装 `guideline_prompt` = 业务规则 + 聊天历史 + **记忆上下文** + 工具描述 + 场景 + 术语分析。 4. 调模型一次:`SystemMessage(guideline_prompt)` + 用户最后一条消息 → 得到思考内容。 5. 内容包成 `...`,`additional_kwargs["message_tag"] = "THINK"`。 6. 追加一条空 `HumanMessage`(兼容"最后必须是 user 消息"的模型)。 7. 主 agent 继续执行,产出正式回答。 ## 与记忆功能的耦合 `guideline_middleware.py:63` 读取 `config._mem0_context`(由 [[../memory/MEMORY|memory]] 的 `before_agent` 写入)。 即:思考阶段会把已召回的长期记忆纳入指引 prompt,从而基于记忆做更好的分析。 **顺序依赖**:memory 中间件需在 thinking 之前执行,`_mem0_context` 才有值。 ## Gotchas(开发必读) - **思考是非流式的**:思考内容在 `before_agent` 一次性完整生成,只有正式回答才流式输出。前端靠 `` 标签 + `message_tag:"THINK"` 折叠展示。 - **额外一次模型调用**:每次开启都多打一次 LLM 请求,增加延迟和成本,按场景权衡。 - **不是模型原生 reasoning**:别误以为依赖 `enable_thinking` 透传给 Qwen,它是中间件层的自定义实现。 - **空 HumanMessage 收尾**:思考消息后会补一条空 user 消息,改消息列表处理逻辑时勿误删。 - **依赖记忆上下文顺序**:若调整中间件注册顺序,确认 memory 仍在 thinking 之前。 ## 索引 - 设计决策:`decisions/` - 变更历史:`changelog/`