addrkit: strict ordinal matching, LLM-variant guard, externalized prompt
- match: require candidate ordinal to equal the query ordinal in fuzzy search (deterministic typo recall 73% -> 80%, no wrong houses) - resolver: compatibleVariant guard — LLM may only fix street spelling, keeping the same words, ordinal and house unit; damerau distance for transpositions - llm: prompt moved out of code (go:embed default_prompt.txt) with llm.system_prompt / llm.system_prompt_file overrides; guided JSON parsing tolerant of thinking blocks - address: recognize ordinals appearing after the street name - tests: first coverage for the LLM adapter and config prompt loading; README Measured (sample 200): deterministic 94.7-95.8% exact / 0 wrong across 4 seeds; LLM+guard typo 90.7-89.8% / 0 wrong. LLM fallback latency ~1.2-1.9s.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
package match
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.totmin.ru/en2zmax/addrkit/internal/domain/address"
|
||||
)
|
||||
|
||||
// TestCompatibleVariant encodes the safety contract for LLM rewrites: only a
|
||||
// spelling fix of the same street, with the same ordinal and house unit, may be
|
||||
// considered.
|
||||
func TestCompatibleVariant(t *testing.T) {
|
||||
orig := address.Parse("2-я Сухарная улица 95")
|
||||
tests := []struct {
|
||||
name string
|
||||
variant string
|
||||
want bool
|
||||
}{
|
||||
{"spelling fix (transposition)", "2-я Сухраная улица 95", true},
|
||||
{"reordered words", "Сухарная 2-я улица 95", true},
|
||||
{"ordinal dropped", "Сухарная улица 95", false},
|
||||
{"different street", "Королева улица 95", false},
|
||||
{"house changed", "2-я Сухарная улица 96", false},
|
||||
{"building added", "2-я Сухарная улица 95 к1", false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := compatibleVariant(orig, address.Parse(tt.variant))
|
||||
if got != tt.want {
|
||||
t.Errorf("compatibleVariant(%q) = %v, want %v", tt.variant, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompatibleVariantProtectsApartment ensures "кв 5" is not folded into a
|
||||
// corpus "к5" by the model.
|
||||
func TestCompatibleVariantProtectsApartment(t *testing.T) {
|
||||
orig := address.Parse("ул. Елоховская, д. 43 кв. 5")
|
||||
if compatibleVariant(orig, address.Parse("ул. Елоховская 43 к5")) {
|
||||
t.Fatal("apartment must not be rewritten as a corpus")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDamerau(t *testing.T) {
|
||||
if got := damerau("гоглоя", "гоголя"); got != 1 {
|
||||
t.Errorf("transposition distance = %d, want 1", got)
|
||||
}
|
||||
if got := damerau("сееврный", "северная"); got < 2 {
|
||||
t.Errorf("expected a larger distance for a different word, got %d", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user