Files
smartmate/backend/service/agent_quick_note_route_test.go
Losita 0b7d1b999c Version: 0.5.4.dev.260313
feat(agent): 重构随口记为模型控制码分流 + 单请求聚合规划,关闭非流式thinking并修复假成功,将随口记全流程从10s+缩短到5s左右,显著提升用户体验

路由层改为“模型控制码协议”分流(quick_note|chat),替换关键词/置信度猜测
路由命中 quick_note 时信任路由,graph 跳过二次意图判定(减少一次 LLM 调用)
新增单请求聚合规划:一次返回 title/deadline_at/priority_group/priority_reason/banter
快路径优先复用聚合结果;优先级缺失时本地兜底,避免再次触发优先级模型调用
最终回复优先使用聚合 banter,聚合路径缺失时使用固定文案,不再额外润色调用
非流式 Generate 全面显式关闭 thinking,并收紧 max_tokens/temperature(路由、JSON规划、banter)
保留并强化写库成功门槛:task_id > 0 才允许成功回包,修复“回复成功但未落库”风险
增加/更新测试:控制码解析、nonce 校验、标题提取、banter 复用与无效 task_id 防假成功
保持 OpenAI 兼容 SSE 格式与现有流式聊天链路不变
2026-03-13 18:17:57 +08:00

73 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"strings"
"testing"
"github.com/LoveLosita/smartflow/backend/agent"
)
// TestParseQuickNoteRouteControlTag_QuickNote
// 目的:验证模型控制码在 action=quick_note 时可被稳定解析,
// 并且会校验 nonce避免历史脏内容或伪造片段误命中。
func TestParseQuickNoteRouteControlTag_QuickNote(t *testing.T) {
nonce := "abc123nonce"
raw := `<SMARTFLOW_ROUTE nonce="abc123nonce" action="quick_note"></SMARTFLOW_ROUTE>
<SMARTFLOW_REASON>用户明确在请求未来提醒</SMARTFLOW_REASON>`
decision, err := parseQuickNoteRouteControlTag(raw, nonce)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
if decision == nil {
t.Fatalf("decision 不应为空")
}
if decision.Action != quickNoteRouteActionQuickNote {
t.Fatalf("action 解析错误,期望=%s 实际=%s", quickNoteRouteActionQuickNote, decision.Action)
}
if strings.TrimSpace(decision.Reason) == "" {
t.Fatalf("reason 不应为空")
}
}
// TestParseQuickNoteRouteControlTag_NonceMismatch
// 目的:确保 nonce 不匹配时直接报错,避免把非本次请求的控制码当作有效路由。
func TestParseQuickNoteRouteControlTag_NonceMismatch(t *testing.T) {
raw := `<SMARTFLOW_ROUTE nonce="wrongnonce" action="chat"></SMARTFLOW_ROUTE>`
if _, err := parseQuickNoteRouteControlTag(raw, "expectednonce"); err == nil {
t.Fatalf("期望 nonce 不匹配时报错,但未报错")
}
}
// TestBuildQuickNoteFinalReply_NoFalseSuccessWithoutTaskID
// 目的:即使 state.Persisted 被错误置为 true只要 task_id 无效,也不能返回“安排成功”文案。
func TestBuildQuickNoteFinalReply_NoFalseSuccessWithoutTaskID(t *testing.T) {
state := &agent.QuickNoteState{
Persisted: true,
PersistedTaskID: 0,
ExtractedTitle: "去下馆子",
}
reply := buildQuickNoteFinalReply(nil, nil, "我今天晚上6点要去下馆子记得喊我", state)
if strings.Contains(reply, "给你安排上了") || strings.Contains(reply, "已安排") {
t.Fatalf("不应返回成功文案,实际回复=%s", reply)
}
}
// TestBuildQuickNoteFinalReply_UseExtractedBanter
// 目的:当聚合规划阶段已经产出 banter 时,最终回复应直接复用,避免再次调用润色模型。
func TestBuildQuickNoteFinalReply_UseExtractedBanter(t *testing.T) {
state := &agent.QuickNoteState{
Persisted: true,
PersistedTaskID: 12,
ExtractedTitle: "明天去取快递",
ExtractedPriority: 2,
ExtractedBanter: "取件路上注意保暖,别被风吹懵了。",
}
reply := buildQuickNoteFinalReply(nil, nil, "明天上午12点我要去取快递到时候记得q我", state)
if !strings.Contains(reply, "取件路上注意保暖") {
t.Fatalf("期望复用 ExtractedBanter实际回复=%s", reply)
}
}