Skip to content

A question picks its definitions instead of taking the first thirty #574

Description

@WaylandYang

Chat reads its confirmed definitions with confirmed(kb, 30): the first thirty by concept name. The seeded upper bound on the wide corpus, 27 definitions, scored 17/18 (#520) — three short of the cap. A real base with a hundred definitions leaves seventy of them, the ones later in the alphabet, outside the prompt on every question. “Twenty-seven works” does not extrapolate.

The other wall is already visible at 27: the one miss in the seeded run was the model asking which of three adjacent names (gross profit, gross margin, gross merchandise value) the person meant. More definitions in the prompt means more of that.

Shape

Definitions become retrievable, in the shape the ontology index already has: concept_mappings.embedding / embedded_model / embedded_text (migration 0048), re-embedded when the model or the text changes, refreshed lazily before a lookup so nobody has to remember to.

Two channels, RRF-fused, top k = 8 into the prompt:

  • vector — “name: summary (unit)” embedded; the question embedded once; pgvector orders. Absent when no embedding model is configured.
  • lexical — every confirmed definition pulled back and scored in Rust by how many of the question’s tokens it contains (ASCII words; CJK bigrams). A base has tens to a few hundred definitions; this is cheaper than Chinese tokenisation in SQL and needs no pg_trgm.

Degradation: vector + lexical → lexical only → the first k by name when nothing matches (today’s behaviour). No step is “no definitions”.

GET /kbs/{id}/mappings/relevant?q=&k= exposes the same lookup, so the bench can score it and a page can later show which definitions a question used.

Measured by

recall@k, without asking anything. The bench already knows which definition each question needs (by number, #520), so ask.mjs --recall 8 calls the endpoint per question and checks whether a correct row is in the top 8 — seconds per round, no chat model. Misses are annotated with the truth file’s near field: if they cluster on near-name pairs, that is the case for a reranker (a separate cut, with a third model slot and this same degradation); if they scatter, the embedded text is the thing to fix.

A base that exceeds the cap: mappings.mjs --fresh --corpus wide --also tpch mounts both sources into one base, seeding both truths gives 45 definitions across two sources. Then ask.mjs on each corpus checks that 17/18 survives selection.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions