feat(ai-sdk): authority-aware re-ranking for legal RAG (Phase 1) (#31)
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 5s
CI / validate-canonical-controls (push) Successful in 4s
CI / loc-budget (push) Successful in 28s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 58s
CI / iace-gt-coverage (push) Successful in 16s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 5s
CI / validate-canonical-controls (push) Successful in 4s
CI / loc-budget (push) Successful in 28s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 58s
CI / iace-gt-coverage (push) Successful in 16s
CI / test-python-backend (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
This commit was merged in pull request #31.
This commit is contained in:
@@ -399,8 +399,9 @@ func TestHybridSearch_UsesQueryAPI(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fallback: should not reach dense search
|
||||
t.Error("Unexpected dense search call when hybrid succeeded")
|
||||
// /points/search is now the stratified binding-law augmentation query (it AUGMENTS
|
||||
// the hybrid pool, it is not a dense fallback). Return empty so the hybrid hit
|
||||
// remains the sole result for this test.
|
||||
json.NewEncoder(w).Encode(qdrantSearchResponse{Result: []qdrantSearchHit{}})
|
||||
}))
|
||||
defer qdrantMock.Close()
|
||||
@@ -446,6 +447,59 @@ func TestHybridSearch_UsesQueryAPI(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSearch_StratifiedBindingRerank verifies that the binding-law pool augments the
|
||||
// semantic pool and that authority re-ranking lifts binding law above higher-semantic guidance.
|
||||
func TestSearch_StratifiedBindingRerank(t *testing.T) {
|
||||
ollamaMock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(ollamaEmbeddingResponse{Embedding: make([]float64, 1024)})
|
||||
}))
|
||||
defer ollamaMock.Close()
|
||||
|
||||
qdrantMock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.URL.Path, "/index") {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"result":{"status":"completed"}}`))
|
||||
return
|
||||
}
|
||||
if strings.Contains(r.URL.Path, "/points/query") {
|
||||
json.NewEncoder(w).Encode(qdrantQueryResponse{Result: []qdrantSearchHit{
|
||||
{ID: "g1", Score: 0.72, Payload: map[string]interface{}{
|
||||
"chunk_text": "ENISA guidance", "regulation_short": "ENISA",
|
||||
"article_label": "ENISA CRA Mapping", "source_class": "supervisory_guidance",
|
||||
"authority_weight": float64(70), "jurisdiction": "EU",
|
||||
}},
|
||||
}})
|
||||
return
|
||||
}
|
||||
// /points/search = stratified binding-law pool (source_class=binding_law)
|
||||
json.NewEncoder(w).Encode(qdrantSearchResponse{Result: []qdrantSearchHit{
|
||||
{ID: "b1", Score: 0.66, Payload: map[string]interface{}{
|
||||
"chunk_text": "CRA Anhang I requirement", "regulation_short": "CRA",
|
||||
"article_label": "CRA Anhang I", "source_class": "binding_law",
|
||||
"authority_weight": float64(100), "jurisdiction": "EU",
|
||||
}},
|
||||
}})
|
||||
}))
|
||||
defer qdrantMock.Close()
|
||||
|
||||
client := &LegalRAGClient{
|
||||
qdrantURL: qdrantMock.URL, ollamaURL: ollamaMock.URL, embeddingModel: "bge-m3",
|
||||
collection: "bp_compliance_ce", textIndexEnsured: make(map[string]bool),
|
||||
hybridEnabled: true, httpClient: http.DefaultClient,
|
||||
}
|
||||
|
||||
results, err := client.Search(context.Background(), "Was gilt hier?", nil, 5)
|
||||
if err != nil {
|
||||
t.Fatalf("search failed: %v", err)
|
||||
}
|
||||
if len(results) != 2 {
|
||||
t.Fatalf("expected 2 merged results (guidance + binding), got %d", len(results))
|
||||
}
|
||||
if results[0].RegulationShort != "CRA" {
|
||||
t.Errorf("binding CRA must rank first over higher-semantic guidance, got %q", results[0].RegulationShort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybridSearch_FallbackToDense(t *testing.T) {
|
||||
var requestedPaths []string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user