Retrieval
How a search combines meaning, keywords and literal document codes into one ranking, stays inside visibility rules, and comes back as citations.
Retrieval reads the store three ways — by meaning, by keywords, and by literal document codes — and fuses them into one ranking. Visibility is applied before the query runs, and every hit reaches the model as a citationCitationTrích dẫnA numbered mark in an answer that links back to the passage it came from. Sources are saved with the answer and still open after the document changes.Open in glossary.
Key rules
- Three branches, one ranking: meaning, keywords and document codes, fused by reciprocal rank.
- Visibility first: the searchable knowledge bases are resolved before the query; a deny rule removes one before anything runs.
- The model cannot name a knowledge base: the search derives them from the turn’s bindings.
- Vietnamese tone marks are kept —
đănganddangare different words. - The portal never turns text into a vector; the agent host embeds the query.
A search, step by step
-
The runtime embeds the query
The agent runtime embeds the query and keeps its words.
-
The backend resolves what may be read
The runtime sends the embedding, the words and the turn’s bindings. The backend takes the bindings minus any knowledge base the caller is denied.
-
Postgres runs three branches
Meaning, keyword and literal branches run in the portal’s Postgres (pgvector), returning only rows under the reach predicate.
-
Results are fused
The backend fuses the branches by reciprocal rank and returns hits with their fused score.
-
The runtime merges, trims and cites
Results from several knowledge bases are merged, trimmed to a context budget, and handed to the model as citations.
The three branches
| Branch | Matches | Notes |
|---|---|---|
| Meaning | The embedding | Finds passages saying the same thing in other words, in English or Vietnamese |
| Keywords | The query’s words | Tone marks kept; grammatical words dropped, since every remaining word is demanded of every match |
| Literal codes | A form or procedure number like QT-07 | Survives neither embedding nor tokenisation; fires only when the query holds a code-shaped token |
A fused rank has no minimum score; the requested count limits a result — narrow for memory, wider for knowledge.
Tone marks: đăng vs dang
The keyword branch keeps Vietnamese tone marks, because đăng and dang are different words. Folding them would return wrong matches and also hide a transcription that misread one.
A multilingual embedding model
With an English-only model, an off-topic question and a real match to a Vietnamese document land too close to separate. Changing the model means re-embedding every passage and memory statement.
Who can see what
Every row names the knowledge base it is filed under. The knowledge bases a search may read are resolved against the caller before the query runs, from each one’s visibility rules, so the database check is a membership test on that list. Seeing a knowledge base in a listing grants no rows.
A memory statement that also names a conversation matches only a request from the same person in that conversation, so an id the caller supplies never authorises itself; it is a row in the person’s own knowledge base, expiring with the conversation.
How deep a search goes
How many passages a search answers with, and how the semantic and keyword branches are weighed against each other, are deployment configuration. Every knowledge base is searched the same way.
Retrieval in a turn
The runtime’s knowledge tool derives the searchable knowledge bases from the turn’s own bindings; the request names none, because the model composes the query, and anything it could name would be attacker-controllable under prompt injection. The bindings are intersected with what the turn’s owner may read, which carries a deny rule into the runtime.
- Each bound knowledge base is searched with the request’s count and the deployment’s weights — the runtime’s ten passages per query is ten per bound knowledge base.
- Answers are merged with each row once, at its best fused score, then trimmed to a context budget; what was withheld is recorded on the trace step.
- A hit reaches the model as a citation: the section it sits in, the document’s title, revision and ingest time, where each matched passage sits, and the fused score.
- The same hits are saved against the turn’s answer as a snapshot, because re-indexing frees a passage’s row. The source list under the answer opens each document to the passages the model was shown.
- One turn searches several times in parallel, so citation rank is allocated by the database behind a lock, and a passage already cited is skipped. The write runs outside the trace step and cannot fail the search.
Searching is billed to the searcher’s department — see knowledge pipeline → who pays.
Why it works this way
Why three branches instead of only vector search?
Meaning catches paraphrases, keywords catch exact terms, and document codes like QT-07 survive neither embedding nor tokenisation. Reciprocal-rank fusion combines them without needing comparable scores.
Why can't the model choose which knowledge base to search?
The model writes the query, and a prompt-injected document could steer it. Deriving the scope from the turn’s bindings and the owner’s access keeps a search inside what the person may read.