x results above similarity score y?
That delivers mediocre results for everyone instead of good ones for each.
Intent classification controls three things at once:
- the retrieval parameters,
- which section types are preferred, and
- which semantic groups are prioritized during embedding.
The classification logic builds on two concepts that run through the entire RAG pipeline.
top_k is the maximum number of text passages (sections) that the retrieval step passes to the language model as context. A higher top_k delivers more context — but also more noise. A lower top_k is more precise, but risks missing relevant passages.
min_score is the similarity threshold. Internally, the database works with cosine distance: two identical vectors have a distance of 0, completely different vectors a distance of 1. min_score corresponds to the maximum allowed value of this distance — a passage that is further away than min_score is not included in the context, even if top_k hasn't been reached yet. The lower the value, the stricter the filter.
Both parameters are set per intent:
The nine intent types
The “how” problem
In English, “How do I...” is a strong signal for an instruction. In German, “Wie” (“how”) is radically ambiguous:
Our LLM initially classified many of these questions as how_to.
The English training prior — “how” → process — was too strong.
The fix: a heuristic that checks whether a personal subject of action (I, one, we) or a concrete action verb is present:
“What is” is not a definition
The pattern “What is X?” intuitively triggers definition. German knowledge questions build the same syntactic scaffold for semantically completely different intents:
The fix: specific shortcuts fire before the general definition shortcut:
The navigation trap and the umlaut problem
navigation is meant for spatial orientation: “Where do I find X?”. The LLM extended the scope to conceptual orientation: “How is orientation established within the flow of knowledge?” landed as navigation. The fix: a shortcut catches the pattern how is X established/created/achieved and classifies it as structure — before the navigation rules even get a chance to fire.
German uses umlauts — and these behave unpredictably in regex matching depending on encoding and Unicode normalization. On top of that, there's the non-breaking space ( ) from copied Kompendium text.
Every matching operation therefore runs through:
The three-stage classification architecture
temperature: 0.0 and a fixed seed ensure reproducibility — classification is a decision task, not a creative one. num_predict: 6 limits the output to the label.