Context Engine
The agent doesn't guess. It searches, and you can watch.
Every question to the agent goes through the same retrieval engine. Type a question and see every stage: what BM25 found, what the embeddings found, how fusion combined them and what the reranker chose.
01
Chunking
600 atomic chunks (a flow step, a tour step, a decision), each carrying its parent's title. About 100 characters on average.
02
Tags
A controlled vocabulary of 30 tags with PL/EN stems. Covers Polish inflection without a stemmer and bridges languages.
03
BM25
Exact words, names and codes: what embeddings blur. ~1 ms.
04
Dense
paraphrase-multilingual-MiniLM-L12-v2 (ONNX), 384 dims, PL and EN in one space. ~10 ms.
05
RRF fusion
Reciprocal rank fusion merges rankings by position, so BM25 scores and cosines never need a common scale.
06
Reranking
jina-reranker-v2 multilingual (cross-encoder) reads the question together with the top 12 chunks.
07
Small-to-big
The agent receives the whole parent sections of the best chunks, not lone sentences.
Ask the engine
Evals: what each stage adds
48 questions in Polish and English, worded differently from the site. Measured per section, because sections are what the agent reads.
| Configuration | Recall@1 | Recall@3 | MRR@10 | p50 ms |
|---|---|---|---|---|
| BM25 | 0.67 | 0.75 | 0.725 | 1 |
| BM25 + tag boost | 0.60 | 0.79 | 0.720 | 1 |
| Dense (multilingual MiniLM) | 0.50 | 0.92 | 0.709 | 10 |
| Hybrid: BM25 + dense (RRF) | 0.62 | 0.94 | 0.770 | 9 |
| Hybrid + tag boost | 0.62 | 0.94 | 0.781 | 9 |
| Hybrid → rerank | 0.75 | 0.96 | 0.859 | 850 |
| Hybrid + tag boost → rerank | 0.75 | 0.94 | 0.854 | 960 |
Tag cloud of the corpus
30 tags from a controlled vocabulary shared by both languages. Size is the number of chunks.
…
Decisions
Atomic chunks, answers from sections
Line-based chunking tore steps out of context: asked about a refund, the reranker picked “it answers aloud”. Chunks built from the content structure carry their parent's title, and the agent reads the whole section.
Tags where they help
Tags as a third list in fusion lowered Recall@1. As a multiplier after fusion they help without models (R@3 0.75 → 0.79), but not after reranking, so production turns them off and the fallback turns them on.
Models in their own service
The models need ~1.5 GB and seconds to start. A separate Cloud Run service (IAM only) never slows booking, and the API keeps BM25 in reserve so it always answers.
A baked, guarded index
Vectors are computed when the image is built. The index knows the corpus digest and the model name and refuses to run if the site's content changed, instead of quietly serving wrong results.
Got a process that should run itself?
30 minutes, free. I'll tell you if it makes sense, how I'd build it and what it would cost to run.