update at 2025-10-15 15:07:45
This commit is contained in:
198
STOP_GENERATION_TEST.md
Normal file
198
STOP_GENERATION_TEST.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 停止生成功能测试指南
|
||||
|
||||
## 快速测试
|
||||
|
||||
### 测试步骤
|
||||
|
||||
1. **启动开发服务器**
|
||||
```bash
|
||||
cd web
|
||||
npm run dev
|
||||
```
|
||||
|
||||
2. **创建测试场景**
|
||||
- 打开浏览器访问应用
|
||||
- 确保已连接至少一个模型服务
|
||||
- 创建或选择一个对话
|
||||
|
||||
3. **测试停止按钮**
|
||||
|
||||
**场景 1:正常停止**
|
||||
```
|
||||
1. 输入一个较长的问题(例如:"请详细解释量子计算的原理,包括量子叠加、量子纠缠等概念")
|
||||
2. 点击"确认"按钮发送
|
||||
3. 等待 AI 开始回复(看到文字开始输出)
|
||||
4. 立即点击"停止"按钮
|
||||
5. 验证:
|
||||
- ✅ 输出立即停止
|
||||
- ✅ 消息显示"已停止"的黄色标签
|
||||
- ✅ 已生成的内容完整显示
|
||||
- ✅ 可以看到操作按钮(复制、重新生成、删除)
|
||||
- ✅ 输入框恢复可用
|
||||
```
|
||||
|
||||
**场景 2:快速停止**
|
||||
```
|
||||
1. 输入问题并发送
|
||||
2. 在 AI 输出第一个字后立即点击停止
|
||||
3. 验证:即使只输出了很少内容,也能正确停止
|
||||
```
|
||||
|
||||
**场景 3:继续对话**
|
||||
```
|
||||
1. 停止一条消息后
|
||||
2. 立即发送新消息
|
||||
3. 验证:新消息能正常发送和接收
|
||||
```
|
||||
|
||||
**场景 4:重新生成**
|
||||
```
|
||||
1. 停止一条消息
|
||||
2. 点击该消息的"重新生成"按钮
|
||||
3. 验证:能重新生成完整回复
|
||||
```
|
||||
|
||||
### 检查点
|
||||
|
||||
#### UI 检查
|
||||
- [ ] 按钮文字正确切换("确认" ↔ "停止")
|
||||
- [ ] 按钮颜色正确变化(primary ↔ error)
|
||||
- [ ] 停止的消息显示黄色"已停止"标签
|
||||
- [ ] 停止的消息能显示操作按钮
|
||||
- [ ] 输入框在发送时禁用,停止后恢复
|
||||
|
||||
#### 功能检查
|
||||
- [ ] 点击停止后流式输出立即中断
|
||||
- [ ] 已生成的内容被保留
|
||||
- [ ] 可以复制停止的消息内容
|
||||
- [ ] 可以重新生成停止的消息
|
||||
- [ ] 可以删除停止的消息
|
||||
- [ ] 停止后可以继续发送新消息
|
||||
|
||||
#### 控制台日志检查
|
||||
打开浏览器控制台,点击停止时应该看到:
|
||||
```
|
||||
🛑 [handleStopGeneration] 用户请求停止生成
|
||||
🛑 [makeChatRequestStream] 检测到中止信号,停止读取流
|
||||
⚠️ [makeChatRequestStream] 请求被中止: 用户中止操作
|
||||
⏸️ [sendMessageStream] 用户主动停止生成,保留已生成内容
|
||||
```
|
||||
|
||||
### 常见问题排查
|
||||
|
||||
#### 问题 1:点击停止按钮没反应
|
||||
**原因**:按钮事件未正确绑定
|
||||
**检查**:
|
||||
- 查看控制台是否有 JS 错误
|
||||
- 确认 `handleButtonClick` 函数存在
|
||||
- 确认 `store.state.isSending` 状态正确
|
||||
|
||||
#### 问题 2:输出没有停止
|
||||
**原因**:中止信号未正确传递或检查
|
||||
**检查**:
|
||||
- 确认 `state.abortController` 已创建
|
||||
- 确认 signal 正确传递到 API 调用
|
||||
- 确认流式读取循环中检查了 `signal.aborted`
|
||||
|
||||
#### 问题 3:停止后显示错误
|
||||
**原因**:未正确处理 AbortError
|
||||
**检查**:
|
||||
- 查看 `chatService.ts` 中的 catch 块
|
||||
- 确认区分了 `AbortError` 和其他错误
|
||||
- 确认 paused 状态设置正确
|
||||
|
||||
#### 问题 4:停止后无法发送新消息
|
||||
**原因**:`isSending` 状态未重置
|
||||
**检查**:
|
||||
- 确认 finally 块执行
|
||||
- 确认 `state.isSending = false`
|
||||
- 确认 `abortController` 被清空
|
||||
|
||||
### 调试模式
|
||||
|
||||
如需详细调试,在控制台运行:
|
||||
```javascript
|
||||
// 查看当前状态
|
||||
console.log('isSending:', store.state.isSending)
|
||||
console.log('abortController:', store.state.abortController)
|
||||
console.log('currentTopicId:', store.state.currentTopicId)
|
||||
console.log('messages:', store.state.messages)
|
||||
|
||||
// 监听状态变化
|
||||
watch(() => store.state.isSending, (val) => {
|
||||
console.log('isSending changed:', val)
|
||||
})
|
||||
```
|
||||
|
||||
### 性能验证
|
||||
|
||||
测量停止响应时间:
|
||||
```javascript
|
||||
// 在点击停止前
|
||||
const stopTime = performance.now()
|
||||
|
||||
// 点击停止
|
||||
|
||||
// 在停止完成后(看控制台日志)
|
||||
const endTime = performance.now()
|
||||
console.log('停止响应时间:', endTime - stopTime, 'ms')
|
||||
|
||||
// 预期:< 100ms
|
||||
```
|
||||
|
||||
## 自动化测试(可选)
|
||||
|
||||
如果要编写自动化测试:
|
||||
|
||||
```typescript
|
||||
describe('Stop Generation', () => {
|
||||
it('should stop streaming when stop button clicked', async () => {
|
||||
// 模拟发送消息
|
||||
const promise = store.sendMessageStream('test message')
|
||||
|
||||
// 等待开始发送
|
||||
await nextTick()
|
||||
expect(store.state.isSending).toBe(true)
|
||||
|
||||
// 停止生成
|
||||
store.stopGeneration()
|
||||
|
||||
// 验证状态
|
||||
expect(store.state.isSending).toBe(false)
|
||||
expect(store.state.abortController).toBe(null)
|
||||
})
|
||||
|
||||
it('should mark message as paused', async () => {
|
||||
// 发送并停止
|
||||
const promise = store.sendMessageStream('test')
|
||||
await nextTick()
|
||||
store.stopGeneration()
|
||||
await promise.catch(() => {}) // 忽略中止错误
|
||||
|
||||
// 检查最后一条消息
|
||||
const lastMessage = store.state.messages[store.state.messages.length - 1]
|
||||
expect(lastMessage.status).toBe('paused')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 成功标准
|
||||
|
||||
✅ **所有以下条件都满足才算修复成功**:
|
||||
1. 点击停止按钮有明显反应(按钮状态变化)
|
||||
2. 流式输出在 100ms 内完全停止
|
||||
3. 停止的消息显示"已停止"标签而非"发送失败"
|
||||
4. 已生成的内容完整保留
|
||||
5. 停止后立即可以发送新消息
|
||||
6. 可以对停止的消息进行各种操作
|
||||
7. 控制台无错误日志(AbortError 除外)
|
||||
8. 连续多次停止-发送循环不会出现问题
|
||||
|
||||
## 回归测试
|
||||
|
||||
确保修复不影响其他功能:
|
||||
- [ ] 正常发送消息仍然工作
|
||||
- [ ] 消息历史正确保存
|
||||
- [ ] 话题切换正常
|
||||
- [ ] MCP 工具调用正常
|
||||
- [ ] 多模型切换正常
|
||||
Reference in New Issue
Block a user