landmark-v2
116 Rechtsrecherche-Fragen mit je einer geprüften Leitentscheidung · Version 2026-08-19 · Stand 2026-08-20
Was hier gemessen wird. Zu jeder der 116 Fragen gibt es genau eine Entscheidung, die sie beantwortet — eine Leitentscheidung, von zwei unabhängigen Prüfern bestätigt. Gemessen wird, ob ein Suchsystem diese Entscheidung unter die ersten zehn beziehungsweise ersten zwanzig Treffer bringt (R@10 und R@20). Die Zahlen in der Tabelle sind Fragen von 116, keine Prozentwerte.
Die Tabelle enthält ausschließlich unsere eigenen Systeme. Fremde Systeme stehen nicht darin: wir haben sie unter diesem Maß auf diesem Korpusstand nicht gemessen, und eine Zahl, die wir nicht selbst gemessen haben, ist kein Beleg. Was wir gemessen haben — auf einem anderen Stand und mit einem anderen Maß — steht unter Einordnung, mit den Vorbehalten an der Zahl.
Ergebnisse
| System | R@10 | R@20 | nDCG@10 | Gemessen |
|---|---|---|---|---|
| lawdb dense retrieval + hits-rerank (deployed) im Einsatz | 48 · 41.4 % | 61 · 52.6 % | 0.254 | offline, nachrechenbar |
| live serving path, OVERSAMPLE=2 | 48 · 41.4 % | 61 · 52.6 % | — | Live-Pfad, Datenbank nötig |
| live serving path, OVERSAMPLE=4 (production shape) im Einsatz | 48 · 41.4 % | 61 · 52.6 % | — | Live-Pfad, Datenbank nötig |
| live serving path, OVERSAMPLE=2 with ef_search pinned to 480 | 46 · 39.7 % | 59 · 50.9 % | — | Live-Pfad, Datenbank nötig |
| lawdb dense retrieval, no hits-rerank | 36 · 31.0 % | 53 · 45.7 % | 0.199 | offline, nachrechenbar |
| live serving path, OVERSAMPLE=1 with ef_search pinned to 480 | 42 · 36.2 % | 51 · 44.0 % | — | Live-Pfad, Datenbank nötig |
| live serving path, OVERSAMPLE=1 | 41 · 35.3 % | 50 · 43.1 % | — | Live-Pfad, Datenbank nötig |
Woher jede Zeile stammt
Jede Zahl oben gehört zu einem festgehaltenen Messlauf. Hier steht, zu welchem.
- lawdb dense retrieval + hits-rerank (deployed)
-
The order recht.nulegal.eu serves. Passage-max distance discounted by matched-passage count: best_dist - min(0.1*ln(hits)/4, 0.03) (13A-146, lawdb/case_dense.py).
Messprotokoll:
benchmark/w83-recall/POOLS.json (vintage 2026-08-19 anchor); benchmark/w83-recall/gate_offline.py· Lauf:python3 eval.py --baseline - live serving path, OVERSAMPLE=2
-
Halves the ANN width (ef 240, 240 hamming candidates, rescore 240). Costs nothing on this set: same 48 / 61, 2 questions lost and 2 gained at R@20 (13A-934B).
Messprotokoll:
benchmark/934b-oversample/score.json (sets.dense['landmark-v2'].o2)· Lauf:benchmark/934b-oversample/run_arm.py --oversample 2 (needs a database) - live serving path, OVERSAMPLE=4 (production shape)
-
The full lawdb/web.py case-search path run in-process against the production database on 2026-08-19 -- a different harness from the three rows above, hitting the live ANN index rather than a dumped pool. It lands on the same 48 / 61, which is what makes the pinned pool a fair stand-in for the serving system.
Messprotokoll:
benchmark/934b-oversample/score.json (sets.dense['landmark-v2'].o4)· Lauf:benchmark/934b-oversample/run_arm.py --oversample 4 (needs a database) - live serving path, OVERSAMPLE=2 with ef_search pinned to 480
-
Narrow candidate cut, full HNSW beam. 46 / 59 (13A-934B).
Messprotokoll:
benchmark/934b-oversample/score.json (sets.dense['landmark-v2'].o2ef480)· Lauf:benchmark/934b-oversample/run_arm.py --oversample 2 --ef-search 480 (needs a database) - lawdb dense retrieval, no hits-rerank
-
The OFF arm of the same gate: pure passage-max distance, no discount. This is what the deployed row above is an improvement over (+12 R@10 / +8 R@20).
Messprotokoll:
benchmark/w83-recall/gate_offline.py· Lauf:reorder the shipped pool by best_dist alone, then: python3 eval.py --candidates <file> - live serving path, OVERSAMPLE=1 with ef_search pinned to 480
-
42 / 51 (13A-934B).
Messprotokoll:
benchmark/934b-oversample/score.json (sets.dense['landmark-v2'].o1ef480)· Lauf:benchmark/934b-oversample/run_arm.py --oversample 1 --ef-search 480 (needs a database) - live serving path, OVERSAMPLE=1
-
Quarter width (ef 120, 120 candidates, rescore 120). The only arm that clearly regresses: -7 R@10 / -11 R@20 against production (13A-934B).
Messprotokoll:
benchmark/934b-oversample/score.json (sets.dense['landmark-v2'].o1)· Lauf:benchmark/934b-oversample/run_arm.py --oversample 1 (needs a database)
Das Maß, und der Korpusstand
Ein Treffer zählt, wenn die Goldentscheidung unter den ersten k Treffern steht; jede Goldentscheidung zählt höchstens einmal, auch wenn dieselbe Entscheidung im Kandidatenfeld mehrfach vorkommt. Genau das war vorher nicht so, und die Korrektur hat die vorher festgehaltenen Zahlen bewegt — ältere Werte sind mit diesen deshalb nicht vergleichbar.
Alle Zeilen der Tabelle beruhen auf demselben Korpusstand (2026-08-19). Das ist keine Formalie: derselbe Code verliert auf demselben Fragensatz sechs Goldentscheidungen aus den ersten zwanzig Treffern, wenn man das Kandidatenfeld 25 Tage später erneut zieht — ohne jede Änderung an der Rangfolge. Zahlen aus verschiedenen Ständen gehören deshalb nicht in dieselbe Tabelle.
Einordnung: woran man diese Zahlen misst
Eine Zahl wie „48 von 116" sagt für sich genommen nicht, ob sie gut ist. Die folgenden Messungen sagen es — jede mit dem Vorbehalt, der zu ihr gehört. Nur die erste steht auf demselben Korpusstand und demselben Maß wie die Tabelle; die übrigen stammen aus der Google-Vergleichsstudie vom Juli 2026 und gehören deshalb nicht in dieselbe Tabelle, sondern hierher.
- Obergrenze des Kandidatenfelds: Gold irgendwo im Pool — 95 / 116
-
Bei wie vielen der 116 Fragen steht die Goldentscheidung überhaupt in dem Kandidatenfeld, das die Rangfolge sortiert. Gleicher Korpusstand, gleiches Maß, gleicher Fragensatz wie jede Zeile der Tabelle — die einzige Zahl hier, die das erfüllt. Sie teilt den Abstand zwischen 48 und 116 in zwei Hälften: von 48 auf 95 ist eine Frage der Rangfolge (die Entscheidung ist im Feld, sie steht nur nicht oben), von 95 auf 116 eine Frage des Abrufs und des Bestands (sie ist gar nicht erst im Feld).
Gemessen 2026-08-19 · Korpusstand 2026-08-19 · Maß 13A-933 · Messprotokoll:
benchmark/w83-recall/POOL_POLICY.md §2 (pool_baseline.py --compare) - Google-Suche auf unserer eigenen Domain (Custom Search, site-search) — 8 / 116 nicht direkt vergleichbar
-
Dieselben 116 Fragen, gestellt an eine Google-Custom-Search-Engine, die auf unsere damalige Domain gesetze.nulegal.eu eingeschränkt war. 74 der 116 Fragen lieferten überhaupt kein Ergebnis; im Median null Treffer je Frage, höchstens drei.
Vorbehalt. Misst nicht die Suchqualität von Google, sondern wie viel von unserer Seite Google damals im Index hatte — die Seite war drei Wochen alt, und die gemessene Domain ist nicht die heutige. Der Wert misst damit genau das, was diese Arbeit gerade ändert, und ist mit dem nächsten Index-Durchlauf veraltet.
Gemessen 2026-07-26 · Korpusstand 2026-07-26 · Maß vor 13A-933 · R@10 8 / R@20 8 · Messprotokoll:
benchmark/google-baseline/cse_landmark_results.json (13A-460) - Vertex AI Search über unseren exportierten Korpus — 64 / 116 nicht direkt vergleichbar
-
Googles Retrieval-Stack auf unseren eigenen Daten: 584.465 exportierte Dokumente (100.001 Normen, 484.464 Entscheidungen) aus dem Produktionsstand vom 26.07.2026. Das ist der belastbare Fremdvergleich der Studie — ein fremdes Suchsystem auf demselben Bestand.
Vorbehalt. Anderer Korpusstand und anderes Maß als die Tabelle. Nicht gegen die 48 / 61 oben lesen: im selben Lauf, im selben Messweg, am selben Tag kam unser eigenes System auf 60 / 75 — die Zeile darunter. Der Abstand zwischen 60 und 48 ist Korpusstand, Maß und Messweg, nicht Rangfolge.
Gemessen 2026-07-27 · Korpusstand 2026-07-26 · Maß vor 13A-933 · R@10 64 / R@20 72 · Messprotokoll:
benchmark/google-baseline/run_vertex_landmark_20260727.json (13A-460) - unser System im selben Lauf (Live-HTTP, 27.07.2026) — 60 / 116 nicht direkt vergleichbar
-
Die Bezugszeile für die beiden darüber, und der Grund, warum sie hier stehen müssen: ohne sie liest sich „Vertex 64" als sechzehn Fragen Vorsprung vor unseren 48. Tatsächlich lagen beide Systeme an diesem Tag gleichauf — Vertex vier Fragen vorn bei R@10, wir drei vorn bei R@20.
Vorbehalt. Derselbe Fragensatz, aber Live-HTTP gegen den damals ausgelieferten Stand, vor der Metrik-Korrektur 13A-933 und auf dem Korpus vom Juli. Auf demselben Fragensatz hat dieses Haus im Juli 45 und 60 und im August 48 gemessen, je nach Messweg, Maß und Korpusstand — und genau deshalb gehören diese Zahlen nicht in die Rangliste.
Gemessen 2026-07-27 · Korpusstand 2026-07-26 · Maß vor 13A-933 · R@10 60 / R@20 75 · Messprotokoll:
benchmark/google-baseline/run_prod_landmark_20260727.json (13A-460)
Was hier bewusst nicht steht
- The 2026-07-24 production HTTP baseline, 45 / 56 (benchmark/landmark-v2/README.md)
A different metric (normalised Aktenzeichen substring match over the /v1/case-search response, before the 13A-933 correction) on a different corpus vintage. Putting it in the same table as the rows above would be exactly the mixed-vintage comparison this dataset exists to make impossible.
- The 2026-07-25 pool vintage, 49 / 67
Same system, older corpus. Six questions lose their gold from the top 20 in 25 days of ingest with no ranking change at all (13A-932). A leaderboard row is a claim about a SYSTEM, so every row has to sit on one vintage; the vintage effect belongs in the dataset notes, not in the ranking.
- The cross-encoder rerank arms (13A-435 ph2/ph3) and the Flash promote arms (13A-444)
Not reproducible here: one needs a trained model artifact that is not in this repository, the other needs paid Vertex calls per run. Their recorded numbers also belong to an older vintage and metric.
- Third-party systems
None are listed. We have not run anyone else's system under this metric on this vintage, and a number we did not measure is not evidence.
Der Datensatz
Fragen, Goldentscheidungen, das festgeschriebene Kandidatenfeld und das Auswertungsprogramm sind als ein Paket zusammengestellt; das Auswertungsprogramm braucht nur Python und die Dateien des Pakets — keine Datenbank, kein Modell, keinen Netzzugang. Die Dokumentation des Pakets (Schema, Methode, Lizenz, Zitierweise) ist auf Englisch, weil der Datensatz sich an Forschung richtet.
Version 2026-08-19 · Korpusstand 2026-08-19 · 116 Fragen · Maß 13A-933.