memoryweave/go/internal/distill/quality_engine_test.go

77 lines
3.1 KiB
Go

package distill
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
// AC-1 dev 验证 (kanban t_cc07ef4b): 构造含短对话的 episodes → 蒸馏后碎片不入库。
// 用 mock LLM 模拟真实蒸馏调用返回混合 facts(碎片+疑问句+状态汇报+合格事实),
// 断言 distillOne 返回的 facts 已按质量门槛过滤, 不会进入入库回调。
func TestDistillOne_QualityGateBlocksFragments(t *testing.T) {
// mock LLM 返回: 短对话蒸馏产物——大部分是 <20字碎片/疑问句/状态汇报
mockResp := LLMResponse{
Facts: []string{
"重启系统", // <20 碎片 → 拒
"健康检查完成", // 状态汇报 → 拒
"验证通过", // 状态汇报 → 拒
"为什么系统会重启?", // 纯疑问句 → 拒
"用户喜欢喝咖啡", // <20 碎片 → 拒
"用户对织忆系统的蒸馏质量提出了改进要求并希望尽快处理", // 24字 含实体 → 通过
},
Entities: []string{"织忆"},
IS: 0.9, SU: 0.8, PA: 0.8, VD: 0.9, RU: 0.8,
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
payload := map[string]interface{}{
"choices": []map[string]interface{}{
{"message": map[string]interface{}{"content": mustJSON(t, mockResp)}},
},
}
_ = json.NewEncoder(w).Encode(payload)
}))
defer srv.Close()
e := NewEngine(srv.URL, "mock-model", "test-key")
// 构造短对话 episode: 大量碎片式短句 (类似 openclaw bridge/闲聊/状态行)
episode := DistillInput{
EpisodeID: "ep_quality_gate_test",
Content: "[2026-09-07] user: 重启系统\n[2026-09-07] assistant: 好的\n[2026-09-07] user: 健康检查完成\n[2026-09-07] user: 为什么系统会重启?\n[2026-09-07] user: 用户喜欢喝咖啡\n[2026-09-07] user: 用户对织忆系统的蒸馏质量提出了改进要求并希望尽快处理",
Category: CatSystemFact,
Namespace: "dev-quality-gate",
AgentID: "a06",
}
res := e.distillOne(episode)
t.Logf("distillOne facts kept = %d: %v", len(res.Facts), res.Facts)
// 断言: 只有 1 条合格事实通过; 碎片/疑问/状态汇报全部被拒
if len(res.Facts) != 1 {
t.Fatalf("expected exactly 1 quality fact to survive gate, got %d: %v", len(res.Facts), res.Facts)
}
if res.Facts[0] != "用户对织忆系统的蒸馏质量提出了改进要求并希望尽快处理" {
t.Errorf("unexpected surviving fact: %q", res.Facts[0])
}
}
// TestFilterQualityFacts_AllNoise 全噪声 episode: 蒸馏产物全碎片 → 0 条入库
func TestFilterQualityFacts_AllNoise(t *testing.T) {
in := []string{"重启系统", "验证通过", "健康检查完成", "为什么?", "好的"}
got := FilterQualityFacts(in)
if len(got) != 0 {
t.Fatalf("expected 0 facts for all-noise input, got %v", got)
}
}
func mustJSON(t *testing.T, v interface{}) string {
t.Helper()
b, err := json.Marshal(v)
if err != nil {
t.Fatalf("marshal: %v", err)
}
return string(b)
}