feat: add deep think feature (#311)

* feat: implement backend logic

* feat: implement api/config endpoint

* rename the symbol

* feat: re-implement configuration at client-side

* feat: add client-side of deep thinking

* fix backend bug

* feat: add reasoning block

* docs: update readme

* fix: translate into English

* fix: change icon to lightbulb

* feat: ignore more bad cases

* feat: adjust thinking layout, and implement auto scrolling

* docs: add comments

---------

Co-authored-by: Henry Li <henry1943@163.com>
This commit is contained in:
DanielWalnut
2025-06-14 13:12:43 +08:00
committed by GitHub
parent a7315b46df
commit 19fa1e97c3
40 changed files with 2292 additions and 1102 deletions

View File

@@ -0,0 +1,130 @@
# 深度思考块功能实现总结
## 🎯 实现的功能
### 核心特性
1. **智能展示逻辑**: 深度思考过程初始展开,计划内容开始时自动折叠
2. **分阶段显示**: 思考阶段只显示思考块,思考结束后才显示计划卡片
3. **动态主题**: 思考阶段使用蓝色主题,完成后切换为默认主题
4. **流式支持**: 实时展示推理内容的流式传输
5. **优雅交互**: 平滑的动画效果和状态切换
### 交互流程
```
用户发送问题 (启用深度思考)
开始接收 reasoning_content
思考块自动展开 + primary 主题 + 加载动画
推理内容流式更新
开始接收 content (计划内容)
思考块自动折叠 + 主题切换
计划卡片优雅出现 (动画效果)
计划内容保持流式更新 (标题→思路→步骤)
完成 (用户可手动展开思考块)
```
## 🔧 技术实现
### 数据结构扩展
- `Message` 接口添加 `reasoningContent``reasoningContentChunks` 字段
- `MessageChunkEvent` 接口添加 `reasoning_content` 字段
- 消息合并逻辑支持推理内容的流式处理
### 组件架构
- `ThoughtBlock`: 可折叠的思考块组件
- `PlanCard`: 更新后的计划卡片,集成思考块
- 智能状态管理和条件渲染
### 状态管理
```typescript
// 关键状态逻辑
const hasMainContent = message.content && message.content.trim() !== "";
const isThinking = reasoningContent && !hasMainContent;
const shouldShowPlan = hasMainContent; // 有内容就显示,保持流式效果
```
### 自动折叠逻辑
```typescript
React.useEffect(() => {
if (hasMainContent && !hasAutoCollapsed) {
setIsOpen(false);
setHasAutoCollapsed(true);
}
}, [hasMainContent, hasAutoCollapsed]);
```
## 🎨 视觉设计
### 统一设计语言
- **字体系统**: 使用 `font-semibold` 与 CardTitle 保持一致
- **圆角规范**: 采用 `rounded-xl` 与其他卡片组件统一
- **间距标准**: 使用 `px-6 py-4` 内边距,`mb-6` 外边距
- **图标尺寸**: 18px 大脑图标,与文字比例协调
### 思考阶段样式
- Primary 主题色边框和背景
- Primary 色图标和文字
- 标准边框样式
- 加载动画
### 完成阶段样式
- 默认 border 和 card 背景
- muted-foreground 图标
- 80% 透明度文字
- 静态图标
### 动画效果
- 展开/折叠动画
- 主题切换过渡
- 颜色变化动画
## 📁 文件更改
### 核心文件
1. `web/src/core/messages/types.ts` - 消息类型扩展
2. `web/src/core/api/types.ts` - API 事件类型扩展
3. `web/src/core/messages/merge-message.ts` - 消息合并逻辑
4. `web/src/core/store/store.ts` - 状态管理更新
5. `web/src/app/chat/components/message-list-view.tsx` - 主要组件实现
### 测试和文档
1. `web/public/mock/reasoning-example.txt` - 测试数据
2. `web/docs/thought-block-feature.md` - 功能文档
3. `web/docs/testing-thought-block.md` - 测试指南
4. `web/docs/interaction-flow-test.md` - 交互流程测试
## 🧪 测试方法
### 快速测试
```
访问: http://localhost:3000?mock=reasoning-example
发送任意消息,观察交互流程
```
### 完整测试
1. 启用深度思考模式
2. 配置 reasoning 模型
3. 发送复杂问题
4. 验证完整交互流程
## 🔄 兼容性
- ✅ 向后兼容:无推理内容时正常显示
- ✅ 渐进增强:功能仅在有推理内容时激活
- ✅ 优雅降级:推理内容为空时不显示思考块
## 🚀 使用建议
1. **启用深度思考**: 点击"Deep Thinking"按钮
2. **观察流程**: 注意思考块的自动展开和折叠
3. **手动控制**: 可随时点击思考块标题栏控制展开/折叠
4. **查看推理**: 展开思考块查看完整的推理过程
这个实现完全满足了用户的需求,提供了直观、流畅的深度思考过程展示体验。

View File

@@ -0,0 +1,112 @@
# 思考块交互流程测试
## 测试场景
### 场景 1: 完整的深度思考流程
**步骤**:
1. 启用深度思考模式
2. 发送问题:"什么是 vibe coding"
3. 观察交互流程
**预期行为**:
#### 阶段 1: 深度思考开始
- ✅ 思考块立即出现并展开
- ✅ 使用蓝色主题(边框、背景、图标、文字)
- ✅ 显示加载动画
- ✅ 不显示计划卡片
- ✅ 推理内容实时流式更新
#### 阶段 2: 思考过程中
- ✅ 思考块保持展开状态
- ✅ 蓝色主题持续显示
- ✅ 推理内容持续增加
- ✅ 加载动画持续显示
- ✅ 计划卡片仍然不显示
#### 阶段 3: 开始接收计划内容
- ✅ 思考块自动折叠
- ✅ 主题从 primary 切换为默认
- ✅ 加载动画消失
- ✅ 计划卡片以优雅动画出现opacity: 0→1, y: 20→0
- ✅ 计划内容保持流式更新效果
#### 阶段 4: 计划流式输出
- ✅ 标题逐步显示
- ✅ 思路内容流式更新
- ✅ 步骤列表逐项显示
- ✅ 每个步骤的标题和描述分别流式渲染
#### 阶段 5: 计划完成
- ✅ 思考块保持折叠状态
- ✅ 计划卡片完全显示
- ✅ 用户可手动展开思考块查看推理过程
### 场景 2: 手动交互测试
**步骤**:
1. 在思考完成后,手动点击思考块
2. 验证展开/折叠功能
**预期行为**:
- ✅ 点击可正常展开/折叠
- ✅ 动画效果流畅
- ✅ 内容完整显示
- ✅ 不影响计划卡片显示
### 场景 3: 边界情况测试
#### 3.1 只有推理内容,没有计划内容
**预期**: 思考块保持展开,不显示计划卡片
#### 3.2 没有推理内容,只有计划内容
**预期**: 不显示思考块,直接显示计划卡片
#### 3.3 推理内容为空
**预期**: 不显示思考块,直接显示计划卡片
## 验证要点
### 视觉效果
- [ ] Primary 主题色在思考阶段正确显示
- [ ] 主题切换动画流畅
- [ ] 字体权重与 CardTitle 保持一致 (`font-semibold`)
- [ ] 圆角设计与其他卡片统一 (`rounded-xl`)
- [ ] 图标尺寸和颜色正确变化 (18px, primary/muted-foreground)
- [ ] 内边距与设计系统一致 (`px-6 py-4`)
- [ ] 整体视觉层次与页面协调
### 交互逻辑
- [ ] 自动展开/折叠时机正确
- [ ] 手动展开/折叠功能正常
- [ ] 计划卡片显示时机正确
- [ ] 加载动画显示时机正确
### 内容渲染
- [ ] 推理内容正确流式更新
- [ ] Markdown 格式正确渲染
- [ ] 中文内容正确显示
- [ ] 内容不丢失或重复
### 性能表现
- [ ] 动画流畅,无卡顿
- [ ] 内存使用正常
- [ ] 组件重新渲染次数合理
## 故障排除
### 思考块不自动折叠
1. 检查 `hasMainContent` 逻辑
2. 验证 `useEffect` 依赖项
3. 确认 `hasAutoCollapsed` 状态管理
### 计划卡片显示时机错误
1. 检查 `shouldShowPlan` 计算逻辑
2. 验证 `isThinking` 状态判断
3. 确认消息内容解析正确
### 主题切换异常
1. 检查 `isStreaming` 状态
2. 验证 CSS 类名应用
3. 确认条件渲染逻辑

View File

@@ -0,0 +1,125 @@
# 流式输出优化改进
## 🎯 改进目标
确保在深度思考结束后plan block 保持流式输出效果,提供更流畅丝滑的用户体验。
## 🔧 技术改进
### 状态逻辑优化
**之前的逻辑**:
```typescript
const isThinking = reasoningContent && (!hasMainContent || message.isStreaming);
const shouldShowPlan = hasMainContent && !isThinking;
```
**优化后的逻辑**:
```typescript
const isThinking = reasoningContent && !hasMainContent;
const shouldShowPlan = hasMainContent; // 简化逻辑,有内容就显示
```
### 关键改进点
1. **简化显示逻辑**: 只要有主要内容就显示 plan不再依赖思考状态
2. **保持流式状态**: plan 组件的 `animated` 属性直接使用 `message.isStreaming`
3. **优雅入场动画**: 添加 motion.div 包装,提供平滑的出现效果
## 🎨 用户体验提升
### 流式输出效果
#### 思考阶段
- ✅ 推理内容实时流式更新
- ✅ 思考块保持展开状态
- ✅ Primary 主题色高亮显示
#### 计划阶段
- ✅ 计划卡片优雅出现300ms 动画)
- ✅ 标题内容流式渲染
- ✅ 思路内容流式更新
- ✅ 步骤列表逐项显示
- ✅ 每个步骤的标题和描述分别流式渲染
### 动画效果
#### 计划卡片入场动画
```typescript
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: "easeOut" }}
>
```
#### 流式文本动画
- 所有 Markdown 组件都使用 `animated={message.isStreaming}`
- 确保文本逐字符或逐词显示效果
## 📊 性能优化
### 渲染优化
- **减少重新渲染**: 简化状态逻辑,减少不必要的组件重新挂载
- **保持组件实例**: plan 组件一旦出现就保持存在,避免重新创建
- **流式状态传递**: 直接使用消息的流式状态,避免额外的状态计算
### 内存优化
- **组件复用**: 避免频繁的组件销毁和重建
- **状态管理**: 简化状态依赖,减少内存占用
## 🧪 测试验证
### 流式效果验证
1. **思考阶段**: 推理内容应该逐步显示
2. **过渡阶段**: 计划卡片应该平滑出现
3. **计划阶段**: 所有计划内容应该保持流式效果
### 动画效果验证
1. **入场动画**: 计划卡片应该从下方滑入并淡入
2. **文本动画**: 所有文本内容应该有打字机效果
3. **状态切换**: 思考块折叠应该平滑自然
### 性能验证
1. **渲染次数**: 检查组件重新渲染频率
2. **内存使用**: 监控内存占用情况
3. **动画流畅度**: 确保 60fps 的动画效果
## 📝 使用示例
### 完整交互流程
```
1. 用户发送问题 (启用深度思考)
2. 思考块展开,推理内容流式显示
3. 开始接收计划内容
4. 思考块自动折叠
5. 计划卡片优雅出现 (动画效果)
6. 计划内容流式渲染:
- 标题逐步显示
- 思路内容流式更新
- 步骤列表逐项显示
7. 完成,用户可查看完整内容
```
## 🔄 兼容性
-**向后兼容**: 不影响现有的非深度思考模式
-**渐进增强**: 功能仅在有推理内容时激活
-**优雅降级**: 在不支持的环境中正常显示
## 🚀 效果总结
这次优化显著提升了用户体验:
1. **更流畅的过渡**: 从思考到计划的切换更加自然
2. **保持流式效果**: 计划内容保持了原有的流式输出特性
3. **视觉连贯性**: 整个过程的视觉效果更加连贯统一
4. **性能提升**: 减少了不必要的组件重新渲染
用户现在可以享受到完整的流式体验,从深度思考到计划展示都保持了一致的流畅感。

View File

@@ -0,0 +1,78 @@
# 测试思考块功能
## 快速测试
### 方法 1: 使用模拟数据
1. 在浏览器中访问应用并添加 `?mock=reasoning-example` 参数
2. 发送任意消息
3. 观察计划卡片上方是否出现思考块
### 方法 2: 启用深度思考模式
1. 确保配置了 reasoning 模型(如 DeepSeek R1
2. 在聊天界面点击"Deep Thinking"按钮
3. 发送一个需要规划的问题
4. 观察是否出现思考块
## 预期行为
### 思考块外观
- 深度思考开始时自动展开显示
- 思考阶段使用 primary 主题色(边框、背景、文字、图标)
- 带有 18px 大脑图标和"深度思考过程"标题
- 使用 `font-semibold` 字体权重,与 CardTitle 保持一致
- `rounded-xl` 圆角设计,与其他卡片组件统一
- 标准的 `px-6 py-4` 内边距
### 交互行为
- 思考阶段:自动展开,蓝色高亮,显示加载动画
- 计划阶段:自动折叠,切换为默认主题
- 用户可随时手动展开/折叠
- 平滑的展开/折叠动画和主题切换
### 分阶段显示
- 思考阶段:只显示思考块,不显示计划卡片
- 计划阶段:思考块折叠,显示完整计划卡片
### 内容渲染
- 支持 Markdown 格式
- 中文内容正确显示
- 保持原有的换行和格式
## 故障排除
### 思考块不显示
1. 检查消息是否包含 `reasoningContent` 字段
2. 确认 `reasoning_content` 事件是否正确处理
3. 验证消息合并逻辑是否正常工作
### 内容显示异常
1. 检查 Markdown 渲染是否正常
2. 确认 CSS 样式是否正确加载
3. 验证动画效果是否启用
### 流式传输问题
1. 检查 WebSocket 连接状态
2. 确认事件流格式是否正确
3. 验证消息更新逻辑
## 开发调试
### 控制台检查
```javascript
// 检查消息对象
const messages = useStore.getState().messages;
const lastMessage = Array.from(messages.values()).pop();
console.log('Reasoning content:', lastMessage?.reasoningContent);
```
### 网络面板
- 查看 SSE 事件流
- 确认 `reasoning_content` 字段存在
- 检查事件格式是否正确
### React DevTools
- 检查 ThoughtBlock 组件状态
- 验证 props 传递是否正确
- 观察组件重新渲染情况

View File

@@ -0,0 +1,155 @@
# 思考块设计系统规范
## 🎯 设计目标
确保思考块组件与整个应用的设计语言保持完全一致,提供统一的用户体验。
## 📐 设计规范
### 字体系统
```css
/* 标题字体 - 与 CardTitle 保持一致 */
font-weight: 600; /* font-semibold */
line-height: 1; /* leading-none */
```
### 尺寸规范
```css
/* 图标尺寸 */
icon-size: 18px; /* 与文字比例协调 */
/* 内边距 */
padding: 1.5rem; /* px-6 py-4 */
/* 外边距 */
margin-bottom: 1.5rem; /* mb-6 */
/* 圆角 */
border-radius: 0.75rem; /* rounded-xl */
```
### 颜色系统
#### 思考阶段(活跃状态)
```css
/* 边框和背景 */
border-color: hsl(var(--primary) / 0.2);
background-color: hsl(var(--primary) / 0.05);
/* 图标和文字 */
color: hsl(var(--primary));
/* 阴影 */
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
```
#### 完成阶段(静态状态)
```css
/* 边框和背景 */
border-color: hsl(var(--border));
background-color: hsl(var(--card));
/* 图标 */
color: hsl(var(--muted-foreground));
/* 文字 */
color: hsl(var(--foreground));
```
#### 内容区域
```css
/* 思考阶段 */
.prose-primary {
color: hsl(var(--primary));
}
/* 完成阶段 */
.opacity-80 {
opacity: 0.8;
}
```
### 交互状态
```css
/* 悬停状态 */
.hover\:bg-accent:hover {
background-color: hsl(var(--accent));
}
.hover\:text-accent-foreground:hover {
color: hsl(var(--accent-foreground));
}
```
## 🔄 状态变化
### 状态映射
| 状态 | 边框 | 背景 | 图标颜色 | 文字颜色 | 阴影 |
|------|------|------|----------|----------|------|
| 思考中 | primary/20 | primary/5 | primary | primary | 有 |
| 已完成 | border | card | muted-foreground | foreground | 无 |
### 动画过渡
```css
transition: all 200ms ease-in-out;
```
## 📱 响应式设计
### 间距适配
- 移动端:保持相同的内边距比例
- 桌面端:标准的 `px-6 py-4` 内边距
### 字体适配
- 所有设备:保持 `font-semibold` 字体权重
- 图标尺寸:固定 18px确保清晰度
## 🎨 与现有组件的对比
### CardTitle 对比
| 属性 | CardTitle | ThoughtBlock |
|------|-----------|--------------|
| 字体权重 | font-semibold | font-semibold ✅ |
| 行高 | leading-none | leading-none ✅ |
| 颜色 | foreground | primary/foreground |
### Card 对比
| 属性 | Card | ThoughtBlock |
|------|------|--------------|
| 圆角 | rounded-lg | rounded-xl |
| 边框 | border | border ✅ |
| 背景 | card | card/primary ✅ |
### Button 对比
| 属性 | Button | ThoughtBlock Trigger |
|------|--------|---------------------|
| 内边距 | 标准 | px-6 py-4 ✅ |
| 悬停 | hover:bg-accent | hover:bg-accent ✅ |
| 圆角 | rounded-md | rounded-xl |
## ✅ 设计检查清单
### 视觉一致性
- [ ] 字体权重与 CardTitle 一致
- [ ] 圆角设计与卡片组件统一
- [ ] 颜色使用 CSS 变量系统
- [ ] 间距符合设计规范
### 交互一致性
- [ ] 悬停状态与 Button 组件一致
- [ ] 过渡动画时长统一200ms
- [ ] 状态变化平滑自然
### 可访问性
- [ ] 颜色对比度符合 WCAG 标准
- [ ] 图标尺寸适合点击/触摸
- [ ] 状态变化有明确的视觉反馈
## 🔧 实现要点
1. **使用设计系统变量**: 所有颜色都使用 CSS 变量,确保主题切换正常
2. **保持组件一致性**: 与现有 Card、Button 组件的样式保持一致
3. **响应式友好**: 在不同设备上都有良好的显示效果
4. **性能优化**: 使用 CSS 过渡而非 JavaScript 动画
这个设计系统确保了思考块组件与整个应用的视觉语言完全统一,提供了一致的用户体验。

View File

@@ -0,0 +1,108 @@
# 思考块功能 (Thought Block Feature)
## 概述
思考块功能允许在计划卡片之前展示 AI 的深度思考过程,以可折叠的方式呈现推理内容。这个功能特别适用于启用深度思考模式时的场景。
## 功能特性
- **智能展示逻辑**: 深度思考过程初始展开,当开始接收计划内容时自动折叠
- **分阶段显示**: 思考阶段只显示思考块,思考结束后才显示计划卡片
- **流式支持**: 支持推理内容的实时流式展示
- **视觉状态反馈**: 思考阶段使用蓝色主题突出显示
- **优雅的动画**: 包含平滑的展开/折叠动画效果
- **响应式设计**: 适配不同屏幕尺寸
## 技术实现
### 数据结构更新
1. **Message 类型扩展**:
```typescript
export interface Message {
// ... 其他字段
reasoningContent?: string;
reasoningContentChunks?: string[];
}
```
2. **API 事件类型扩展**:
```typescript
export interface MessageChunkEvent {
// ... 其他字段
reasoning_content?: string;
}
```
### 组件结构
- **ThoughtBlock**: 主要的思考块组件
- 使用 Radix UI 的 Collapsible 组件
- 支持流式内容展示
- 包含加载动画和状态指示
- **PlanCard**: 更新后的计划卡片
- 在计划内容之前展示思考块
- 自动检测是否有推理内容
### 消息处理
消息合并逻辑已更新以支持 `reasoning_content` 字段的流式处理:
```typescript
function mergeTextMessage(message: Message, event: MessageChunkEvent) {
// 处理常规内容
if (event.data.content) {
message.content += event.data.content;
message.contentChunks.push(event.data.content);
}
// 处理推理内容
if (event.data.reasoning_content) {
message.reasoningContent = (message.reasoningContent || "") + event.data.reasoning_content;
message.reasoningContentChunks = message.reasoningContentChunks || [];
message.reasoningContentChunks.push(event.data.reasoning_content);
}
}
```
## 使用方法
### 启用深度思考模式
1. 在聊天界面中,点击"Deep Thinking"按钮
2. 确保配置了支持推理的模型
3. 发送消息后,如果有推理内容,会在计划卡片上方显示思考块
### 查看推理过程
1. 深度思考开始时,思考块自动展开显示
2. 思考阶段使用 primary 主题色,突出显示正在进行的推理过程
3. 推理内容支持 Markdown 格式渲染,实时流式更新
4. 在流式传输过程中会显示加载动画
5. 当开始接收计划内容时,思考块自动折叠
6. 计划卡片以优雅的动画效果出现
7. 计划内容保持流式输出效果,逐步显示标题、思路和步骤
8. 用户可以随时点击思考块标题栏手动展开/折叠
## 样式特性
- **统一设计语言**: 与页面整体设计风格保持一致
- **字体层次**: 使用与 CardTitle 相同的 `font-semibold` 字体权重
- **圆角设计**: 采用 `rounded-xl` 与其他卡片组件保持一致
- **间距规范**: 使用标准的 `px-6 py-4` 内边距
- **动态主题**: 思考阶段使用 primary 色彩系统
- **图标尺寸**: 18px 图标尺寸,与文字比例协调
- **状态反馈**: 流式传输时显示加载动画和主题色高亮
- **交互反馈**: 标准的 hover 和 focus 状态
- **平滑过渡**: 所有状态变化都有平滑的过渡动画
## 测试数据
可以使用 `/mock/reasoning-example.txt` 文件测试思考块功能,该文件包含了模拟的推理内容和计划数据。
## 兼容性
- 向后兼容:没有推理内容的消息不会显示思考块
- 渐进增强:功能仅在有推理内容时激活
- 优雅降级:如果推理内容为空,组件不会渲染