110 lines
3.3 KiB
Go
110 lines
3.3 KiB
Go
package ctxmgr
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRollingSummarizer_LifecycleAndFactPreservation(t *testing.T) {
|
|
mgr := NewContextManager(nil, nil, DefaultTimeDecayConfig())
|
|
ctx := context.Background()
|
|
sessID := "sess_sum_test_001"
|
|
|
|
// 模拟首批 4 条早期消息(将被淘汰出窗口)
|
|
batch1 := []ChatMessageRecord{
|
|
{
|
|
ID: 1,
|
|
Role: "user",
|
|
Content: "我们准备研发高频超声手术刀系统,请教立项建议",
|
|
CreatedAt: time.Now().Add(-10 * time.Minute),
|
|
},
|
|
{
|
|
ID: 2,
|
|
Role: "assistant",
|
|
Content: "超声手术设备属于二类或三类器械,需着重关注电气安全与空化热效应控制。",
|
|
CreatedAt: time.Now().Add(-9 * time.Minute),
|
|
},
|
|
{
|
|
ID: 3,
|
|
Role: "user",
|
|
Content: "目标市场是国内及欧洲CE,项目预算大约在200万左右,型检周期通常需要多久?",
|
|
CreatedAt: time.Now().Add(-8 * time.Minute),
|
|
},
|
|
{
|
|
ID: 4,
|
|
Role: "assistant",
|
|
Content: "国内型检通常预估4-6个月,需符合GB 9706.1-2020标准。",
|
|
CreatedAt: time.Now().Add(-7 * time.Minute),
|
|
},
|
|
}
|
|
|
|
sum1, err := mgr.GenerateRollingSummary(ctx, sessID, nil, batch1)
|
|
if err != nil {
|
|
t.Fatalf("GenerateRollingSummary failed: %v", err)
|
|
}
|
|
|
|
if sum1.CoveredCount != 4 {
|
|
t.Errorf("expected covered_count 4, got %d", sum1.CoveredCount)
|
|
}
|
|
if sum1.Facts["device_type"] != "超声手术设备" {
|
|
t.Errorf("expected device_type extracted, got %v", sum1.Facts)
|
|
}
|
|
if sum1.Facts["target_market"] != "国内及欧洲CE" {
|
|
t.Errorf("expected target_market extracted, got %v", sum1.Facts)
|
|
}
|
|
if sum1.Facts["budget"] != "200万元" {
|
|
t.Errorf("expected budget extracted, got %v", sum1.Facts)
|
|
}
|
|
if len(sum1.OpenQuestions) == 0 {
|
|
t.Errorf("expected at least 1 open question extracted")
|
|
}
|
|
|
|
snippet1 := sum1.RenderPromptSnippet()
|
|
if !strings.Contains(snippet1, "【早期对话摘要】(已压缩前 4 条对话内容)") {
|
|
t.Errorf("snippet missing header: %s", snippet1)
|
|
}
|
|
if !strings.Contains(snippet1, "device_type=超声手术设备") {
|
|
t.Errorf("snippet missing device_type: %s", snippet1)
|
|
}
|
|
|
|
// 模拟第二批消息追加(增量滚动压缩)
|
|
batch2 := []ChatMessageRecord{
|
|
{
|
|
ID: 5,
|
|
Role: "user",
|
|
Content: "临床评价路径该怎么走?",
|
|
CreatedAt: time.Now().Add(-5 * time.Minute),
|
|
},
|
|
{
|
|
ID: 6,
|
|
Role: "assistant",
|
|
Content: "可优先考虑同品种比对路径以节省费用。",
|
|
CreatedAt: time.Now().Add(-4 * time.Minute),
|
|
},
|
|
}
|
|
|
|
sum2, err := mgr.GenerateRollingSummary(ctx, sessID, sum1, batch2)
|
|
if err != nil {
|
|
t.Fatalf("incremental GenerateRollingSummary failed: %v", err)
|
|
}
|
|
|
|
if sum2.CoveredCount != 6 {
|
|
t.Errorf("expected covered_count 6, got %d", sum2.CoveredCount)
|
|
}
|
|
// 验证硬事实依然完整保留(永不丢失)
|
|
if sum2.Facts["device_type"] != "超声手术设备" || sum2.Facts["budget"] != "200万元" {
|
|
t.Errorf("hard facts lost during incremental roll: %v", sum2.Facts)
|
|
}
|
|
|
|
// 验证 ContextManager 的读取
|
|
saved, err := mgr.GetChatSummary(ctx, sessID)
|
|
if err != nil || saved == nil {
|
|
t.Fatalf("GetChatSummary failed: %v", err)
|
|
}
|
|
if saved.CoveredCount != 6 {
|
|
t.Errorf("saved summary covered count mismatch: %d", saved.CoveredCount)
|
|
}
|
|
}
|