fix: IoT多设备支持 + Review Pipeline审查消息 + 意图分析快速通道优化

- IoT Provider: 重写Execute()支持多设备命令批量执行,修复persona路径
- Intent Analyzer: 新增isStrongIoTCommand快速通道,跳过LLM分析节省2-3s
- Orchestrator: parseReviewMessages()内联审查 + 快速通道扩展(chat/greeting跳过子会话)
- Gateway: SSE review_messages解析→WebSocket结构化消息转发(action/chat)
- Persona: 对话风格注入action格式指令(括号包裹动作描述)
- Frontend: sessionStore历史消息msgType映射
- 新增E2E测试脚本 + 调试标准文档 + 第4轮修复报告

E2E验证: IoT设备操控 Review消息拆分 快速通道 响应时间~3.4s

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 22:51:27 +08:00
parent 773f19f009
commit a67b95cbc4
18 changed files with 1186 additions and 85 deletions
@@ -260,6 +260,8 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
Index int `json:"index"`
Text string `json:"text"`
} `json:"segments,omitempty"`
// 审查后的结构化消息
ReviewMessages []ws.ReviewMessage `json:"review_messages,omitempty"`
}
if err := json.Unmarshal([]byte(data), &chunk); err != nil {
log.Printf("[chat] 解析 SSE delta 失败: %v, raw=%s", err, data)
@@ -289,6 +291,46 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
break
}
// 处理审查后的结构化消息 (review)
if len(chunk.ReviewMessages) > 0 {
for i, rm := range chunk.ReviewMessages {
role := "assistant"
msgType := "chat"
if rm.Type == "action" {
role = "action"
msgType = "action"
}
reviewMsgID := fmt.Sprintf("%s_r%d", msgID, i)
// 持久化每条审查消息
if h.sessionStore != nil && h.sessionStore.IsAvailable() {
if err := h.sessionStore.AddMessage(client.SessionID, role, rm.Content); err != nil {
log.Printf("[chat] 持久化审查消息失败: %v", err)
}
}
h.hub.CacheMessage(client.UserID, client.SessionID, ws.Message{
ID: reviewMsgID,
Role: role,
Content: rm.Content,
Timestamp: time.Now().UnixMilli(),
})
client.SendMessage(ws.ServerMessage{
Type: "response",
MessageID: reviewMsgID,
Content: rm.Content,
Role: role,
MsgType: msgType,
SessionID: client.SessionID,
Timestamp: time.Now().UnixMilli(),
})
// 小延迟让消息逐条到达,更像真人
if i < len(chunk.ReviewMessages)-1 {
time.Sleep(200 * time.Millisecond)
}
}
fullText += "[review]"
continue
}
// 处理断句事件 (stream_segments)
if len(chunk.Segments) > 0 {
for _, seg := range chunk.Segments {