Contextual Retrieval¶
varagity.context.contextual
¶
situate_context() — the heart of Contextual Retrieval (spec §9.4, §11.1).
For each chunk, the LLM produces a short blurb situating the chunk within its whole document; the blurb is prepended to the chunk before embedding and BM25 indexing, which is what lifts retrieval out of the vanilla-RAG baseline (Anthropic: ≈35% fewer retrieval failures from contextual embeddings alone).
Callers process a document's chunks sequentially, grouped per document
(the loader already iterates this way), fitting the document into its prompt
budget once with :func:fit_document_preamble and handing that preamble
to every :func:situate_context call for the document: every call then
shares an identical prompt prefix, so llama.cpp reuses its KV/prompt cache —
a throughput concern with a local server, not a billing one (spec §9.4).
doc_token_budget(settings)
¶
Token budget for the document preamble of one situating prompt.
What's left of the model's context window after reserving space for the
blurb generation (CONTEXTUALIZE_MAX_TOKENS — llama.cpp needs prompt
plus generation to fit, or the blurb is cut off), the chunk allowance,
and the prompt scaffolding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Settings
|
The application settings ( |
required |
Returns:
| Type | Description |
|---|---|
int
|
The budget in the served model's tokens (what |
int
|
func: |
int
|
non-positive when the configured window is very small — callers |
int
|
degrade rather than crash. |
Source code in varagity/context/contextual.py
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
fit_document_preamble(document_text, *, llm=None)
¶
Fit one document into the situating prompt's budget — once per document.
The :func:doc_token_budget is held in the served model's tokens.
The cl100k approximation makes the cheap first cut, and the served
tokenizer has the last word: the served model gives every digit its own
token where cl100k packs up to three, so a digit-dense document
(timestamps, coordinates, tables) runs far over its cl100k estimate —
1.45× on a location-history export, enough for a cl100k-sized preamble
to overflow the window by itself.
- A document of at most
budgetUTF-8 bytes is returned whole, without a count: every token spans at least one byte, so it fits under any tokenizer. - A document over the budget by cl100k is cut to it, with a warning. The cut also bounds what step 3 sends to the server.
- The (possibly whole) text is counted with
:meth:
~varagity.models.llm.LLMClient.count_served_tokensand, while still over, re-cut in proportion (up to :data:_MAX_RECUTStimes), each re-cut warned. - If the server cannot count, or the re-cuts never land, the preamble
is the document's first
budgetUTF-8 bytes — step 1's any-tokenizer bound, so the fit holds regardless. That costs a shorter preamble, never a failed file.
Pass the result to every :func:situate_context call for the
document's chunks: the preamble is then byte-identical across them
(llama.cpp's prompt cache), and the served count is paid per document,
not per chunk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document_text
|
str
|
The parent document's full extracted text. |
required |
llm
|
LLMClient | None
|
Chat client whose server does the counting; resolved via the model registry when omitted, and only once a count is needed. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The document preamble: the whole document when it fits, otherwise |
str
|
its head; |
Source code in varagity/context/contextual.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
situate_context(preamble, chunk_text, *, llm=None, verbose=None)
¶
Generate the blurb situating one chunk within its parent document.
The LLM sees the document preamble and the chunk under the verbatim
cookbook prompt (:data:CONTEXTUAL_PROMPT); the response is
post-processed with :func:~varagity.models.llm.clean_response to strip
reasoning-model <think>…</think> stages.
The preamble is sent as given, so it must already fit: make it with
:func:fit_document_preamble, once per document. A document over
the budget is then situated within its head, which still beats no
context at all. Generation runs under CONTEXTUALIZE_MAX_TOKENS (not
the chat-sized MAX_TOKENS): a blurb is short, and reserving a
chat-sized generation against the context window would reject any
document over a few thousand tokens. A reasoning preamble that overruns
the cap cleans to an empty blurb (see Returns) — degraded context,
never a failed file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
preamble
|
str
|
The parent document's text as fitted by
:func: |
required |
chunk_text
|
str
|
The chunk to situate. |
required |
llm
|
LLMClient | None
|
Chat client; resolved via the model registry when omitted. Callers contextualizing many chunks should pass one client. |
None
|
verbose
|
int | None
|
Console verbosity (0–2); defaults to
|
None
|
Returns:
| Type | Description |
|---|---|
str
|
The situating blurb (may be empty if the model returned nothing |
str
|
usable — logged as a warning, never raised). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
APIError
|
If the LLM request still fails after retries. |
Source code in varagity/context/contextual.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |