feat(parties): selection-step evaluation against document-anchored truth (#2169)
* feat(parties): selection-step evaluation against document-anchored truth Scores which similar keys are the same party without human labels: every key in the set carries an org number OCR-read from a linked invoice, so two keys are the same party exactly when the org numbers agree. Rules and the Bedrock model both land at 0.91 pair precision; the residual false merges are different legal entities sharing a trade name, which text cannot and should not separate. Results and caveats in the README. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(parties): make the model selector opt-in in the selection eval Sending voucher key text to the AI provider now requires --llm; the default run scores the rules selector only and makes no network call. Documents that the opt-in path uses the same configured provider the production categorizer already sends the same text to. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
Jakob Wennberg
parent
5291806c37
commit
69d3bba587
@@ -96,6 +96,38 @@ the default for that reason. The model's remaining party misses are text
|
||||
with a person's name or a card descriptor, exactly where a hard key from a
|
||||
document would decide instead.
|
||||
|
||||
## Selection-step evaluation against document-anchored truth, 2026-09-02
|
||||
|
||||
`eval-selection.ts` scores the selection step (which similar keys in the same
|
||||
company are the same party) without human labels: every key in the set has an
|
||||
org number read by OCR from an invoice linked to its voucher, so two keys are
|
||||
the same party exactly when the org numbers agree. Keys mapping to several
|
||||
org numbers are excluded. 225 anchors, 1,038 candidate pairs (747 same, 291
|
||||
different), 44 anchors with no true match. Draw: `draw-selection-gold.sql`.
|
||||
The model selector is opt-in (`--llm`): it sends the same voucher text the
|
||||
production categorizer already sends to the configured AI provider (Bedrock EU
|
||||
on hosted), so run it only with an env file whose AI settings you have checked.
|
||||
|
||||
| Selector | Pair precision | Pair recall | Non-match recall | Anchors fully right | "None" precision / recall |
|
||||
|---|---|---|---|---|---|
|
||||
| Rules (same core name) | 0.909 | 0.776 | 0.801 | 0.547 | 0.40 / 0.86 |
|
||||
| Sonnet 5 on Bedrock EU, zero-shot | 0.910 | 0.904 | 0.770 | 0.756 | 0.68 / 0.77 |
|
||||
|
||||
What the false merges are: both selectors merge "Levfakt Fortnox (325)" with
|
||||
"Levfakt Fortnox (154)", "Vattenfall Kundservice" with "Vattenfall
|
||||
Eldistribution", "Jämtkraft" with "Jämtkraft" under another org number. Those
|
||||
are different legal entities sharing a trade name, or OCR variance in the org
|
||||
number. Text cannot separate them and should not try: the hard key from the
|
||||
document is the referee, which is exactly the resolver's precedence order.
|
||||
What the model catches that the rules miss: "lån themax" versus "lån från
|
||||
themax", and paraphrases with a changed word order.
|
||||
|
||||
Read with one caveat: sales-side vouchers ("kundbet ...") contribute noisy
|
||||
truth because the org number on the linked document can be the customer's;
|
||||
the next draw restricts to expense-side vouchers.
|
||||
|
||||
Cost: about 1,300 input tokens per anchor, 298k tokens for the run.
|
||||
|
||||
## Still to confirm in this phase
|
||||
|
||||
- SCB access: the free Företagsregistret API carries F-skattstatus,
|
||||
|
||||
Reference in New Issue
Block a user