feat(aibox): add DeepSeek reasoning mode support with tool calling on deepseek-v4-flash
- Add api.reasoning_enabled config (default false) to enable thinking mode - Uses deepseek-v4-flash native thinking capability (thinking param), supports tool calls while reasoning - Real-time reasoning content streaming via reasoning_start/reasoning/reasoning_end WS messages - Frontend shows reasoning in gray italic area, auto-folds long reasoning (>2000 chars) - Dynamic reasoning detection: shows reasoning even if model returns it without explicit config - Increase default API timeout to 120s for longer reasoning responses - Remove duplicate _add_assistant_message_with_reasoning method - Update docs: config example, message types table, v2.5 changelog
This commit is contained in:
1 parent
81ae84851d
commit
b79044d631
5 files changed
+131
-39
No files matched your search
+19
-4
@@ -215,9 +215,11 @@ const ws = new WebSocket('ws://localhost:8765');
|
||||
| 类型 | 说明 |
|
||||
|-----|------|
|
||||
| `chunk` | AI 响应的**增量片段**(流式输出,chunk_buffer 发送后即清零,为内容权威来源) |
|
||||
| `reasoning_start` | AI 开始思考信号(思考模式,创建思考区域展示) |
|
||||
| `reasoning` | AI 思考过程增量片段(流式输出,灰色/斜体样式) |
|
||||
| `reasoning_end` | AI 思考结束信号(切换到正式回答) |
|
||||
| `complete` | AI 响应**收尾信号**(chunk 流式是内容权威来源,complete 仅用于收尾;完全丢帧时可用 full_text 补建) |
|
||||
| `line` | 过程行(🔧 工具调用提示、工具输出、💬 助手前缀、思考提示等,供任务侧栏/终端显示) |
|
||||
| `reasoning` | AI 思考过程(思考模式,仅 debug_level≥3 发送) |
|
||||
| `line` | 过程行(🔧 工具调用提示、工具输出、💬 助手前缀等,供任务侧栏/终端显示) |
|
||||
| `error` | 错误信息(API 请求失败、解析失败等;服务端自动回滚本轮消息防止对话历史被污染) |
|
||||
| `command_result` | 命令执行结果 |
|
||||
| `task_status` | 任务状态更新(executing/complete/failed) |
|
||||
@@ -427,8 +429,9 @@ AI 可以通过 `update_soul` 工具动态更新 `99_SOUL.md`,通过 `update_i
|
||||
"api": {
|
||||
"deepseek_api_url": "https://api.deepseek.com/chat/completions",
|
||||
"deepseek_model": "deepseek-v4-flash",
|
||||
"reasoning_enabled": false,
|
||||
"api_key_env": "DEEPSEEK_API_KEY",
|
||||
"timeout": 30,
|
||||
"timeout": 120,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"context": {
|
||||
@@ -492,7 +495,9 @@ AI 可以通过 `update_soul` 工具动态更新 `99_SOUL.md`,通过 `update_i
|
||||
}
|
||||
```
|
||||
|
||||
> 默认模型为 `deepseek-v4-flash`(通过 `api.deepseek_model` 修改)。API Key 从环境变量 `DEEPSEEK_API_KEY` 读取(亦支持 `~/.cert/deepseek.key` 文件)。
|
||||
> 默认模型为 `deepseek-v4-flash`(通过 `api.deepseek_model` 修改)。设置 `api.reasoning_enabled: true` 可启用思考模式,此时会在请求中添加 `thinking: {type: "enabled"}` 参数,模型会先进行思考再回答,实时展示思考过程(灰色斜体区域),回答质量更高且**支持工具调用**(文件操作、命令执行、记忆搜索等工具均可在思考模式下正常使用)。
|
||||
>
|
||||
> API Key 从环境变量 `DEEPSEEK_API_KEY` 读取(亦支持 `~/.cert/deepseek.key` 文件)。
|
||||
|
||||
## 🛠️ 命令行参数
|
||||
|
||||
@@ -701,6 +706,16 @@ elif command == "/mycommand":
|
||||
|
||||
## 📄 更新日志
|
||||
|
||||
### v2.5
|
||||
- ✅ **新增 DeepSeek 思考模式支持**(Reasoning Mode):
|
||||
- 新增 `api.reasoning_enabled` 配置项(默认 `false`),启用后在请求中添加 `thinking: {type: "enabled"}` 参数
|
||||
- 使用 `deepseek-v4-flash` 模型原生思考能力,**思考模式下完整支持工具调用**(文件操作、命令执行、记忆搜索等均可正常使用)
|
||||
- 实时展示 AI 思考过程:新增 `reasoning_start`/`reasoning`/`reasoning_end` WebSocket 消息类型
|
||||
- 思考内容在前端以灰色斜体区域独立展示,超长思考自动折叠显示最后 2000 字符
|
||||
- 即使未启用思考模式,若模型返回 `reasoning_content` 也会自动实时展示
|
||||
- API 超时默认从 30s 提高到 120s,适配思考模式更长的响应时间
|
||||
- ✅ 删除重复定义的 `_add_assistant_message_with_reasoning` 方法
|
||||
|
||||
### v2.4
|
||||
- ✅ **新增专用工作目录规范**:
|
||||
- AI 主动创建的临时文件、脚本、数据文件默认写入 `~/.aibox/workspace/`,避免污染系统其他目录
|
||||
|
||||
+43
-23
@@ -1168,8 +1168,9 @@ class ConfigManager:
|
||||
"api": {
|
||||
"deepseek_api_url": "https://api.deepseek.com/chat/completions",
|
||||
"deepseek_model": "deepseek-v4-flash",
|
||||
"reasoning_enabled": false,
|
||||
"api_key_env": "DEEPSEEK_API_KEY",
|
||||
"timeout": 30,
|
||||
"timeout": 120,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"context": {
|
||||
@@ -1356,7 +1357,11 @@ class Constants:
|
||||
|
||||
@property
|
||||
def DEEPSEEK_MODEL(cls):
|
||||
return cls._get_config().get("api.deepseek_model")
|
||||
return cls._get_config().get("api.deepseek_model", "deepseek-v4-flash")
|
||||
|
||||
@property
|
||||
def REASONING_ENABLED(cls):
|
||||
return cls._get_config().get("api.reasoning_enabled", False)
|
||||
|
||||
@property
|
||||
def DEFAULT_TIMEOUT(cls):
|
||||
@@ -7169,11 +7174,13 @@ class DeepSeekChat:
|
||||
"stream": True
|
||||
}
|
||||
|
||||
# 可选:添加 thinking 模式配置(如果有)
|
||||
payload["thinking"] = {
|
||||
"type": "enabled"
|
||||
}
|
||||
# 思考模式:启用 thinking 参数
|
||||
if constants.REASONING_ENABLED:
|
||||
payload["thinking"] = {
|
||||
"type": "enabled"
|
||||
}
|
||||
|
||||
# 工具调用(v4-flash 支持思考+工具调用)
|
||||
tools = self.tool_registry.get_tools_schemas()
|
||||
if tools:
|
||||
payload["tools"] = tools
|
||||
@@ -7182,10 +7189,16 @@ class DeepSeekChat:
|
||||
current_time = datetime.now().strftime("%H:%M:%S")
|
||||
if output_callback:
|
||||
output_callback("line", f"\n{i18n.get('thinking', current_time)}\n")
|
||||
output_callback("line", i18n.get('assistant_prefix'))
|
||||
if constants.REASONING_ENABLED:
|
||||
output_callback("reasoning_start", "🤔 思考中...")
|
||||
else:
|
||||
# 普通模式先显示助手前缀
|
||||
output_callback("line", i18n.get('assistant_prefix'))
|
||||
|
||||
full_response = ""
|
||||
full_reasoning = "" # 存储思考内容
|
||||
reasoning_started = False
|
||||
reasoning_ended = False
|
||||
tool_calls_buffer = []
|
||||
current_tool_calls = {}
|
||||
|
||||
@@ -7236,10 +7249,25 @@ class DeepSeekChat:
|
||||
if 'reasoning_content' in delta and delta['reasoning_content']:
|
||||
reasoning = delta['reasoning_content']
|
||||
full_reasoning += reasoning
|
||||
# 可选:将思考内容也发送给前端(可以单独处理)
|
||||
if output_callback and self.debug_level >= 3:
|
||||
|
||||
# 发送思考开始信号(仅第一次,且未提前发送过)
|
||||
if not reasoning_started and output_callback:
|
||||
if not constants.REASONING_ENABLED:
|
||||
# 非显式思考模式但模型返回了思考内容,动态发送开始信号
|
||||
output_callback("reasoning_start", "🤔 思考中...")
|
||||
reasoning_started = True
|
||||
|
||||
# 实时发送思考内容给前端(无需debug_level限制)
|
||||
if output_callback:
|
||||
output_callback("reasoning", reasoning)
|
||||
|
||||
# 思考结束:当开始收到content且之前有reasoning时,发送结束信号
|
||||
if 'content' in delta and delta['content'] and reasoning_started and not reasoning_ended:
|
||||
reasoning_ended = True
|
||||
if output_callback:
|
||||
output_callback("reasoning_end", "")
|
||||
output_callback("line", i18n.get('assistant_prefix'))
|
||||
|
||||
# 处理正常内容
|
||||
if 'content' in delta and delta['content']:
|
||||
content = delta['content']
|
||||
@@ -7290,7 +7318,12 @@ class DeepSeekChat:
|
||||
# 处理工具调用
|
||||
if current_tool_calls:
|
||||
tool_calls_buffer = list(current_tool_calls.values())
|
||||
if output_callback:
|
||||
|
||||
# 如果之前在思考,先结束思考状态
|
||||
if reasoning_started and not reasoning_ended and output_callback:
|
||||
output_callback("reasoning_end", "")
|
||||
output_callback("line", i18n.get('calling_tools') + "\n")
|
||||
elif output_callback:
|
||||
output_callback("line", i18n.get('calling_tools') + "\n")
|
||||
|
||||
# 【关键修复1】先添加助手消息,包含 tool_calls
|
||||
@@ -7388,19 +7421,6 @@ class DeepSeekChat:
|
||||
except Exception as e:
|
||||
self.logger.error(f"消息回滚失败: {e}")
|
||||
|
||||
|
||||
def _add_assistant_message_with_reasoning(self, content: str, reasoning_content: str = None, tool_calls: List = None):
|
||||
"""添加助手消息,包含 reasoning_content"""
|
||||
msg = {"role": "assistant"}
|
||||
if content:
|
||||
msg["content"] = content
|
||||
if reasoning_content:
|
||||
msg["reasoning_content"] = reasoning_content
|
||||
if tool_calls:
|
||||
msg["tool_calls"] = tool_calls
|
||||
msg["content"] = None
|
||||
self.messages.append(msg)
|
||||
|
||||
def reset_conversation(self, reload_prompts: bool = True):
|
||||
"""
|
||||
重置对话状态 - 清除所有对话记忆,可选择是否重新加载系统提示词
|
||||
|
||||
Reference in new issue
Block a user