mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-04 23:00:30 +08:00
Port Python rag/advanced_rag agentic search to Go: ES-backed dataset-nav service, agentic-search harness, and agent tools. Includes agentic-search port plan and self-review docs.
136 lines
5.4 KiB
Go
136 lines
5.4 KiB
Go
package harness
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
// TestCrossCheckClaim_NumberMatch asserts a verified report whose numbers appear
|
|
// in the evidence chunk passes the cross-check.
|
|
func TestCrossCheckClaim_NumberMatch(t *testing.T) {
|
|
agent := &AgentResult{ClaimID: "c0", IsVerified: true, Report: "speed is 88 and 12", EvidenceIDs: []int{0}}
|
|
chunks := map[int]map[string]interface{}{0: {"content_with_weight": "speed is 88 and 12 here"}}
|
|
r := CrossCheckClaim(agent, chunks)
|
|
if !r.CrossCheckPassed {
|
|
t.Errorf("cross-check should pass, got mismatches %v", r.Mismatches)
|
|
}
|
|
}
|
|
|
|
// TestKbinfosMerge_GlobalIndices asserts Merge returns the GLOBAL indices of the
|
|
// contributed chunks in the accumulated list, so a later claim's EvidenceIDs
|
|
// still resolve correctly after earlier claims pushed more chunks in.
|
|
func TestKbinfosMerge_GlobalIndices(t *testing.T) {
|
|
kb := &Kbinfos{}
|
|
// First claim's search returns chunks a,b.
|
|
first := kb.Merge([]map[string]interface{}{
|
|
{"chunk_id": "a", "content_with_weight": "alpha 7"},
|
|
{"chunk_id": "b", "content_with_weight": "beta"},
|
|
}, nil)
|
|
// a->0, b->1 in the global list.
|
|
if len(first) != 2 || first[0] != 0 || first[1] != 1 {
|
|
t.Fatalf("first merge global indices = %v, want [0 1]", first)
|
|
}
|
|
// Second claim's search returns chunk c (now global index 2) and a dup of a.
|
|
second := kb.Merge([]map[string]interface{}{
|
|
{"chunk_id": "c", "content_with_weight": "gamma 9"},
|
|
{"chunk_id": "a", "content_with_weight": "alpha 7"},
|
|
}, nil)
|
|
// c->2, a(dup)->0; NOT per-search [0 1].
|
|
if len(second) != 2 || second[0] != 2 || second[1] != 0 {
|
|
t.Fatalf("second merge global indices = %v, want [2 0]", second)
|
|
}
|
|
// CrossCheckClaim must resolve both claims' evidence against the global list.
|
|
allChunks := map[int]map[string]interface{}{}
|
|
for i, c := range kb.Chunks {
|
|
allChunks[i] = c
|
|
}
|
|
r1 := CrossCheckClaim(&AgentResult{ClaimID: "c1", IsVerified: true, Report: "alpha 7", EvidenceIDs: first}, allChunks)
|
|
if !r1.HasEvidence {
|
|
t.Error("claim 1 should have evidence at global indices")
|
|
}
|
|
r2 := CrossCheckClaim(&AgentResult{ClaimID: "c2", IsVerified: true, Report: "gamma 9", EvidenceIDs: second}, allChunks)
|
|
if !r2.HasEvidence {
|
|
t.Error("claim 2 should have evidence at global index 2 (not per-search 0)")
|
|
}
|
|
}
|
|
|
|
// TestCrossCheckClaim_Unverified asserts an unverified agent fails the check.
|
|
func TestCrossCheckClaim_Unverified(t *testing.T) {
|
|
r := CrossCheckClaim(&AgentResult{ClaimID: "c0", IsVerified: false}, nil)
|
|
if r.CrossCheckPassed {
|
|
t.Error("unverified agent must fail cross-check")
|
|
}
|
|
}
|
|
|
|
// TestComputeFusionScore_Sufficient asserts a fully-verified high-score set is
|
|
// SUFFICIENT.
|
|
func TestComputeFusionScore_Sufficient(t *testing.T) {
|
|
agents := []AgentResult{{ClaimID: "c0", IsVerified: true, Report: "value 42", EvidenceIDs: []int{0}}}
|
|
cross := []ClaimCrossCheckResult{{ClaimID: "c0", CrossCheckPassed: true, CrossCheckScore: 1.0, HasEvidence: true}}
|
|
v := ComputeFusionScore(agents, cross, THINKING_MODES["medium"])
|
|
if v.Status != "SUFFICIENT" {
|
|
t.Errorf("status = %q, want SUFFICIENT", v.Status)
|
|
}
|
|
}
|
|
|
|
// TestComputeFusionScore_NoEvidence asserts a claim with no examined evidence is
|
|
// UNANSWERABLE (empty-evidence guard).
|
|
func TestComputeFusionScore_NoEvidence(t *testing.T) {
|
|
cross := []ClaimCrossCheckResult{{ClaimID: "c0", CrossCheckPassed: true, CrossCheckScore: 1.0, HasEvidence: false}}
|
|
v := ComputeFusionScore([]AgentResult{{ClaimID: "c0", IsVerified: true}}, cross, THINKING_MODES["medium"])
|
|
if v.Status != "UNANSWERABLE" {
|
|
t.Errorf("status = %q, want UNANSWERABLE", v.Status)
|
|
}
|
|
if len(v.MissingClaims) != 1 {
|
|
t.Errorf("missing claims = %v, want [c0]", v.MissingClaims)
|
|
}
|
|
}
|
|
|
|
// TestRouteSufficiencyVerdict asserts SUFFICIENT → ANSWER.
|
|
func TestRouteSufficiencyVerdict(t *testing.T) {
|
|
action, cont := RouteSufficiencyVerdict(SufficiencyVerdict{Status: "SUFFICIENT", Score: 0.9}, "medium", 0, 3)
|
|
if action != "ANSWER" || cont {
|
|
t.Errorf("got (%q,%v), want (ANSWER,false)", action, cont)
|
|
}
|
|
}
|
|
|
|
// TestDirectSearch_Merges asserts direct search merges chunks and flags empty.
|
|
func TestDirectSearch_Merges(t *testing.T) {
|
|
kb := &Kbinfos{}
|
|
res := DirectSearch(context.Background(), func(_ context.Context, _, _ string) ([]map[string]interface{}, []map[string]interface{}) {
|
|
return []map[string]interface{}{{"chunk_id": "a", "content_with_weight": "alpha"}}, nil
|
|
}, "q", "", kb)
|
|
if res.EmptyResult || !kb.HasChunks() {
|
|
t.Errorf("expected merged chunks, empty=%v chunks=%d", res.EmptyResult, len(kb.Chunks))
|
|
}
|
|
}
|
|
|
|
// TestDirectSearch_Empty asserts direct search flags empty when no chunks.
|
|
func TestDirectSearch_Empty(t *testing.T) {
|
|
kb := &Kbinfos{}
|
|
res := DirectSearch(context.Background(), func(_ context.Context, _, _ string) ([]map[string]interface{}, []map[string]interface{}) {
|
|
return nil, nil
|
|
}, "q", "", kb)
|
|
if !res.EmptyResult {
|
|
t.Error("expected empty_result=true")
|
|
}
|
|
}
|
|
|
|
// TestDecomposeAndSearch_Verifies asserts a searchable claim gets verified and
|
|
// the loop stops on ANSWER.
|
|
func TestDecomposeAndSearch_Verifies(t *testing.T) {
|
|
claims := []*ClaimTarget{{ClaimID: "c0", Description: "fact 42 about X"}}
|
|
kb := &Kbinfos{}
|
|
res := DecomposeAndSearch(context.Background(),
|
|
func(_ context.Context, _, _ string) ([]map[string]interface{}, []map[string]interface{}) {
|
|
return []map[string]interface{}{{"chunk_id": "x", "content_with_weight": "the value is 42"}}, nil
|
|
},
|
|
"Q", "", claims, "medium", kb)
|
|
if !claims[0].IsVerified {
|
|
t.Error("claim should be verified")
|
|
}
|
|
if res.Verdict == nil {
|
|
t.Error("expected a verdict")
|
|
}
|
|
}
|