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
@@ -42,6 +42,12 @@ func (a *IntentAnalyzer) Analyze(ctx context.Context, userMessage string) (*mode
return result, nil
}
// 快速通道:强 IoT 关键词直接使用规则匹配,跳过 LLM 调用(节省 2-3s)
if a.isStrongIoTCommand(userMessage) {
log.Printf("[intent] 快速通道: 检测到 IoT 操控命令,跳过 LLM 分析")
return a.keywordAnalyze(userMessage), nil
}
// 如果 LLM 不可用,直接使用关键词匹配
if !a.enabled || a.llmAdapter == nil {
log.Printf("[intent] LLM 不可用,使用关键词规则分析意图")
@@ -119,6 +125,33 @@ func (a *IntentAnalyzer) isSimpleGreeting(userMessage string) bool {
return false
}
// isStrongIoTCommand 检测是否为明确的 IoT 操控命令,可直接跳过 LLM 意图分析
func (a *IntentAnalyzer) isStrongIoTCommand(userMessage string) bool {
msgLower := strings.TrimSpace(strings.ToLower(userMessage))
// 控制类关键词 + 设备类关键词组合出现,即可判断为 IoT 命令
controlWords := []string{"打开", "关闭", "调到", "设置", "开关", "调节", "调高", "调低", "开一下", "关一下"}
deviceWords := []string{"灯", "空调", "窗帘", "电视", "风扇", "加湿器", "插座", "门锁", "传感器"}
hasControl := false
for _, w := range controlWords {
if strings.Contains(msgLower, w) {
hasControl = true
break
}
}
hasDevice := false
for _, w := range deviceWords {
if strings.Contains(msgLower, w) {
hasDevice = true
break
}
}
return hasControl && hasDevice
}
// keywordAnalyze 基于关键词的意图分析(降级方案)
func (a *IntentAnalyzer) keywordAnalyze(userMessage string) *model.IntentResult {
result := &model.IntentResult{
@@ -133,9 +133,10 @@ func (o *Orchestrator) ProcessInput(
// 对于 simple greeting,跳过子会话分派,直接合成回复
var resultCh <-chan model.SubSessionResult
skipSubSessions := intent.Primary == "greeting"
skipSubSessions := intent.Primary == "greeting" ||
(intent.Primary == "chat" && !intent.NeedsIoT && !intent.NeedsMemory)
if skipSubSessions {
log.Printf("[orchestrator] 快速通道: 简单问候,跳过子会话分派")
log.Printf("[orchestrator] 快速通道: 简单消息(primary=%s),跳过子会话分派", intent.Primary)
// 创建一个已关闭的空通道
emptyCh := make(chan model.SubSessionResult)
close(emptyCh)
@@ -212,7 +213,7 @@ func (o *Orchestrator) ProcessInput(
// 子会话结果还没完成,先带着空上下文开始合成
// 大部分情况下子会话结果会在 LLM 调用前完成
// 等待一小段时间让快速子会话(如 IoT)完成
timeout := time.After(500 * time.Millisecond)
timeout := time.After(200 * time.Millisecond)
select {
case enriched := <-enrichedCh:
synthParams.MemorySummary = enriched.memorySummary