White paper

Grounding AI Chat in a Small Business's Own Knowledge

A fact-record architecture and an evidence-based retrieval stack for assistants that must say what the business actually says.

By Ron AlterioPublished 20 min read

Download PDFAll white papers

retrieval-augmented generationfact recordsembedding modelsre-ranking

At a glance

Knowledge storage27 of 27. Scenario questions answered correctly by fact records, against 21 of 27 for model-rewritten knowledge.
Embedding modelChunk hit on our own knowledge base rose from 75% to 95% (14 gained, 2 lost, p = .004).
Re-rankingThe largest retrieval gain measured: 28 gained, 6 lost (p = .0002), used where no one is waiting.
Speed32 ms median to embed a message on one CPU thread, so live-chat retrieval stays at millisecond cost.

Executive summary

Retrieval-augmented generation is usually treated as a retrieval problem. For an assistant answering in a small business's name, that is only half of it. A business's information changes, contradicts itself and expires, and a system can retrieve perfectly and still answer wrongly if the knowledge underneath has lost track of what is true today.

This paper presents the architecture behind Xorventa's chat windows. Knowledge is stored as dated, sourced, single-detail fact records with explicit precedence, not as text rewritten by a model. Retrieval is built from components chosen by paired measurement, under a real constraint: conversation speed on CPU. In our testing, fact records answered 27 of 27 scenario questions correctly against 21 of 27 for model-rewritten knowledge. The embedding model we selected raised chunk hit from 75% to 95% on our own knowledge base for about 20 ms per question, and a small cross-encoder gave the largest retrieval gain we measured. We set out the problem, the design and the reasoning, along with what teams building similar systems can take from it.

1. The problem

When a general assistant makes a mistake, the user discounts it. When a business's assistant makes one, it has quoted a wrong price, wrong hours or a service the business does not offer, in that business's name. The bar is not plausible answers. It is the business's actual position, today.

1.1 Knowledge fails before retrieval begins

A small business's knowledge is not a corpus, it is a history. A real business accumulates a website, flyers, price sheets and the owner's direct answers, and they drift apart. Five failure modes follow, and none is a retrieval failure:

  • Precedence. The owner said $8.50 and a flyer says $10. Which one speaks for the business?
  • Time. "Open until 6 PM through December 24" is true today and false on December 27, without anyone editing anything.
  • Partial change. "Delivery within 5 miles for $5" changes to 10 miles. The fee must survive, and that requires knowing they were two facts.
  • Invention. Summarizing "open Monday to Friday" can produce "closed weekends", a statement the business never made.
  • Regression. A routine re-crawl of an unchanged website must not undo a correction the owner made last week.

1.2 Retrieval is unforgiving on small corpora

Large corpora have redundancy: if one passage is missed, another may do. In a small business's knowledge base a question often has exactly one right passage, so a single rank position can decide whether the answer exists for the model. Conversation adds to this: "the second one" and "how about yearly?" contain nothing to search for on their own.

1.3 The operating constraints are real

A multi-tenant service for small businesses cannot assume a GPU per customer. Retrieval runs on CPU, in-process, within a conversational latency budget shared by text and voice. Component choices that look free on a benchmark table are not free here.

2. Why the conventional approaches fall short

Common approachWhy it falls short for this problem
Have a model rewrite the sources into clean knowledgeThe output is well written and has no memory. It holds no dates, no provenance and no record of which source prevailed, so a contradiction is resolved implicitly, differently from run to run, and invisibly to the owner. We measured this: rewriting chose a flyer's price over the owner's direct answer in every run.
Pick the embedding model from a public benchmark, or an averageDifferences between small models are domain-specific. One model moved a single knowledge base by 20 points and three others by less than two. An average reports neither.
Add a larger re-rankerBigger was slower and no better. A cross-encoder six times slower returned a lower hit rate than a small one on the same embeddings.
Turn on hybrid search by defaultOn short, clean business text, rank fusion lost cases that vector search alone answered. Keyword search earns its place on exact identifiers and larger catalogues, not automatically.
List the phrases that count as follow-upsAny list misses the reply nobody anticipated, and that reply is then answered as if the conversation had not happened.

3. The solution

The architecture separates the two problems. A knowledge layer decides what is true today and keeps the evidence. A retrieval layer gets the right part of it to the model at conversation speed. A confidence signal between them turns every gap into a question for the owner.

SourcesFact extractionFact recordsTopic documents Visitor messageTwo-pass retrievalGrounded answerConfidence signal web, docs, answersone detail, schema-bounddated, sourced, rankedrendered for today with its contextpool, then entry capknowledge as datagap, or owner question
Figure 1. The knowledge layer (top) feeds the retrieval layer (bottom). The dashed path is the learning loop: a gap becomes an owner's question, and the answer becomes a fact.

3.1 The fact record

Every input is treated as the same kind of thing: an owner's answer, an uploaded document, a website page and a business profile form each become fact records.

FieldPurpose
TopicA short name, reused across sources, so facts on one subject are comparable and render together.
StatementOne self-contained detail. "Delivery within 10 miles for $5" is two facts, so that either can change without disturbing the other.
Learned dateWhen the system learned it, which orders replacement.
Valid from, valid toOnly when the source says the fact is temporary. A temporary fact never replaces a permanent one, which applies again afterwards.
SourceWhat it came from, and the source's kind, which determines precedence.
ReplacesThe earlier facts this one makes no longer true. A fact that only adds detail replaces nothing.

Extraction is constrained, not trusted. Each piece of text goes through a single fast-model call whose JSON schema is enforced by the API during generation, so the output can only be records. The instructions forbid inference outright: a day, price or policy the text does not mention is unknown, never "closed", "free" or "included". Source text is passed as untrusted data between markers. Numbers, names and terms are copied exactly.

3.2 The rules that decide what is true

RuleReasoning
Only what is new is processed. Sources are hashed when read.An unchanged re-crawl is not information, and so cannot undo a correction. It also keeps extraction cost proportional to change, not to library size.
Newer replaces older on the same subject.Ordinary currency: a November price update supersedes the old price.
An owner's direct answer is never replaced by a document or the website.The owner is the authority on their own business. The conflicting value is recorded as a disagreement rather than being applied or discarded.
Retiring a source retires only the facts that came only from it.Removing a document must not remove something another source also says.
Nothing is deleted. Retired facts keep their reason.Every change is explainable. An owner can read what changed and why, and reverse a wrong replacement.

3.3 Rendering knowledge for today

The assistant does not read the fact table. It reads one document per topic, rendered from live facts for the date of the question. A fact past its end date is simply not rendered, so temporary hours expire on schedule with no edit and no job to run. Adding a fact re-renders that topic alone, never the whole library. This is the structural difference from rewriting: a change has a defined, small blast radius.

Each topic document carries its own instruction: this is the business's current information on the topic, and anything not listed was not stated. Inference is deliberately split by stage. It is forbidden when storing, because a stored inference would become something the business said. It is allowed when answering, only with near certainty, because "No, we're open Monday to Friday" is more useful to a visitor than a refusal. Below that bar, the assistant says it does not have the information.

3.4 Retrieval

  • Embedding. snowflake-arctic-embed-s, 384 dimensions, with an HNSW index in Postgres (pgvector). The model is asymmetric: questions carry an instruction prefix and documents do not. It runs in process on CPU, baked into the deployed image at a pinned revision and loaded offline. A different revision is a different vector space, so a golden-vector check guards against silent drift.
  • Chunking. 900 characters with 150 overlap, each piece embedded with its entry's title, which keeps a short piece anchored to its subject.
  • Reading the turn in context. Every turn with a conversation behind it retrieves twice: once on the message alone, and once on the message blended with recent turns. The results are combined, so nothing has to recognize a follow-up. When the message's own best match reaches .61 it is treated as a question in its own right, and its documents keep reserved places. Measured on our knowledge base, follow-ups such as "the cheaper one" score .49–.59 alone and real questions .62–.74, so the threshold sits between them. Without this reserve, a blended pass on the previous topic can evict every document a new question found.
  • Repair. When the best match falls below .57, a further pass corrects likely misspellings against the business's own vocabulary and retrieves again.
  • Diversity. A candidate pool of four times the final count is ranked with at most three pieces from one entry, so that one long entry cannot crowd the others out.
  • Injection defense. Retrieved knowledge reaches the model between delimiters with a per-turn random nonce, and is treated as data, never as instructions.

3.5 Confidence as a product signal

Top similarity is kept and put to work, not discarded after ranking. Because a model's similarity scale is its own, thresholds are defined by behaviour rather than by number. When the embedding model changes, each threshold moves to the same percentile of the new distribution, so that its meaning survives:

t_new = Q_new( F_old( t_old ) )

DecisionThresholdFlags unanswerableFlags answerableDecisions unchanged by model change
Record a knowledge gap.67570%18.3%89.4%
Treat the message as a new question.6150%3.7%91.2%
Ask the owner.5931%1.3%93.5%
Repair the query.5719%0.4%96.5%
Allow a web look-up, where enabled.5511%0%97.6%

Measured on 240 answerable and 100 unanswerable questions. The thresholds rise in order of cost: recording a gap is free, so it is sensitive; a web look-up is slow, so it fires only on a clear miss.

This closes the loop in Figure 1. A question the knowledge does not cover becomes a question for the owner, and the owner's answer becomes a fact at the highest precedence. The system improves along exactly the lines its visitors ask about.

3.6 Re-ranking where it can be afforded

A cross-encoder is the most effective retrieval component we have measured and the most expensive on CPU. So the decision is about when, not whether: Xorventa applies ms-marco-MiniLM-L6, at a candidate pool of two times and 256 pieces, to email and direct-message drafts. No one is waiting on those, and it fails open if it is unavailable.

4. The evidence

4.1 How we test

QuestionCandidatesMethod
How should knowledge be stored?Model-rewritten entries; fact recordsOne business's history played through both (Appendix A): nine events and nine questions, three runs, one model at temperature 0, graded by required and forbidden patterns.
Which embedding model?all-MiniLM-L6-v2, bge-small-v1.5, e5-small-v2, snowflake-arctic-embed-s240 questions over four knowledge bases, each generated from a sampled passage that serves as its label; production ranking; chunk hit, entry hit and MRR; 25 hand-labelled questions.
Is re-ranking worth it?ms-marco-MiniLM-L6, bge-reranker-base; pools of 2× to 4×; lengths 256 and 512The same questions, timed on one CPU thread.
Does keyword search help?Vector alone; rank fusion at four weights, as introducer and as re-rankerHand-labelled questions, on about 60 short entries.
Does it work end to end?The production path217 questions through the real chat window, checked for required and forbidden content, grounding and latency.

Paired comparisons use an exact two-sided McNemar test on the questions where two setups disagree, and intervals are 95% Wilson. Test data is Xorventa's own knowledge and demonstration content.

4.2 Knowledge storage

ApproachCorrect, three runsStale or wrong answersOwner's corrected price
Dated fact records27 of 270Correct, 3 of 3 runs
Model-rewritten entries21 of 274Lost to a flyer, 3 of 3 runs

One business scenario. Rewritten knowledge also gave current hours incorrectly in one of three runs while a temporary schedule applied, and in two of three runs it could not state the hours once that schedule had ended. Which questions it missed varied between runs on identical input.

The failure that repeated is the one the design exists to prevent: the owner's direct answer lost to a later document. Fact records returned the owner's price every time and recorded the disagreement.

4.3 Embedding models

ModelChunk hitEntry hitMRRHand-labelled /25
all-MiniLM-L6-v283.3%91.7%.79322
bge-small-v1.584.6%91.3%.80623
e5-small-v286.3%92.9%.81323
snowflake-arctic-embed-s87.9%92.9%.83523
Knowledge baseMiniLM chunk hitarctic chunk hitGainedLostp
Xorventa's product knowledge75.0%95.0%142.004
Help library70.0%71.7%761.00
Demonstration business A93.3%91.7%451.00
Demonstration business B95.0%93.3%341.00

The aggregate result is not significant (27 gained, 16 lost, p =.13), and arctic is not statistically separated from e5 or bge-small. The decisive result is domain-specific, on the knowledge base closest to real use. This is why we test per corpus and read paired results rather than averages. Score separation also improved slightly, with AUC rising from.835 to.852.

4.4 Re-ranking

Setup, one CPU threadChunk hit (95% CI)Gained / lost vs MiniLMpMedian msp95 ms
MiniLM83.3% (78.1–87.5)——1224
arctic87.9% (83.2–91.5)27 / 16.133259
arctic + ms-marco, pool 2×, length 25692.5% (88.5–95.2)28 / 6.00021,2842,158
arctic + ms-marco, pool 3×, length 25692.5% (88.5–95.2)27 / 5.00011,9543,722
arctic + ms-marco, pool 4×, length 51292.9% (89.0–95.5)28 / 5.00013,0764,985
MiniLM + ms-marco, pool 2×, length 25687.9% (83.2–91.5)14 / 3.0139132,146

Pool 2× at length 256 keeps almost all the gain at 42% of the latency of the largest setup. The larger bge-reranker-base took 7.5–8 s per query with a lower chunk hit than ms-marco on the same embeddings: 87.9% against 90.0% on MiniLM, and 88.8% against 92.9% on bge-small.

4.5 Keyword search and end-to-end results

Rank fusion scored 23 of 25 at every weight and in both roles, against 25 of 25 for vector search alone. On the production path, the most recent full live run passed 144 of 150 questions, and the 25 hand-labelled questions all passed.

5. How this performs in a chat window

Every design choice above lands in one number the visitor feels: how long the answer takes. These are the costs that matter.

StepTimeWhere it applies
Embed a message, one CPU thread32 ms median, 59 ms p95Every turn, and once more with a conversation behind it
Re-rank candidates1.3 s median, 2.2 s p95Unattended email and DM drafts only
Web look-upAbout 10 sOnly windows built for it, such as Xorventa Instruct, on a clear miss

The result is a clear division of labour. Live chat gets its accuracy from choices that cost milliseconds: the embedding model, chunking, the two-pass read and the entry cap. Seconds-scale components run where nobody is waiting. And the knowledge layer, which accounts for the largest accuracy difference we measured, adds nothing to a turn at all, because its work happens when information arrives, not when a visitor asks.

The same retrieval serves text and voice, so a voice call answers from the same facts as the chat window. By default a window answers only from the business's approved knowledge.

6. Guidance for teams building similar systems

If you are decidingOur recommendationWhat would change it
How to store changing knowledgeStore dated, single-detail facts with explicit source precedence. Separate what is stored from what is inferred.A static corpus with one authoritative source may not need it.
Which small embedding modelRun a paired comparison on your own content, per corpus, with questions from real passages.Small models were close overall, so your domain decides.
Whether to re-rankEvaluate it before changing embeddings, and shrink the pool and length before rejecting it on latency.A GPU changes the trade-off and may allow it in live chat.
Whether to add keyword searchMeasure it on your corpus rather than assuming it helps.Part numbers, exact codes and large catalogues.
How to change embedding modelsMap every threshold by percentile, pin the revision, re-embed atomically, and tune as a separate step.Thresholds you already know are wrong should be re-tuned.
How to evaluateRepeat runs, keep full outputs, and read failures. Non-deterministic pipelines vary on identical input.An independent holdout set is better still.

7. Conclusion

For an assistant that speaks for a business, accuracy starts before retrieval. Storing knowledge as dated, sourced facts with explicit precedence removes a whole class of errors that better retrieval cannot reach, and it makes every change explainable to the person who owns the business. On top of that foundation, retrieval is engineered component by component, with each choice justified by paired measurement and placed according to what it costs at conversation speed.

These results come from Xorventa's own and demonstration knowledge bases, and the fact-record comparison from one detailed scenario. They should be read as measured evidence for this class of system: small knowledge bases, changing sources and CPU inference. The methods in this paper transfer directly, and we encourage teams to run them on their own content.

Appendix A: the test scenario

To reproduce the comparison, play these events in order through your system, then ask the questions. Today is November 2, 2026, except where noted. Answer with one model at temperature 0, using only the knowledge given.

#EventContent
1WebsiteSunny Bakery, fresh bread every day. Open Monday to Friday, 7 AM to 3 PM. Sourdough loaf is $8. Delivery within 5 miles for $5. Gift cards available in store.
2Owner answerDo you make wedding cakes? Yes, wedding cakes start at $250 and we need 4 weeks notice.
3Owner answerWhat are your holiday hours? We're open until 6pm Monday to Friday until Dec 24.
4DocumentSourdough is now $9 a loaf. Our delivery area has grown to 10 miles.
5Owner answerIs delivery free? Delivery is free on orders over $50, otherwise $5.
6WebsiteRe-crawl, unchanged.
7WebsiteChanged: "We no longer sell gift cards."
8Owner answerHow much is the sourdough? Sourdough is $8.50.
9DocumentHoliday flyer: Sourdough loaves $10.
QuestionCorrect answerWrong if it says
How much is a sourdough loaf?$8.50$8, $9 or $10
Do you make wedding cakes?Yes, from $250
How much notice do you need for a wedding cake?4 weeks
How late are you open on a weekday this month?6 PM3 PM as the current hours
Are you open on Saturdays?No, or that it isn't knownYes
Do you sell gift cards?NoGift cards are available
How far do you deliver?10 miles5 miles
Is delivery free?Free over $50
(Asked December 27) How late are you open on a weekday?3 PM6 PM

Appendix B: the two calculations

Threshold mapping, where old and new are each model's top similarity for the same pooled answerable and unanswerable questions:

new_threshold = numpy.quantile(new, (old < old_threshold).mean())

Paired comparison, where b and c are the questions only one of the two setups answered:

p = min(1, 2 * sum(comb(b + c, i) for i in range(min(b, c) + 1)) / 2 ** (b + c))

Research sources

Third-party material cited in this paper. Vendor documentation changes; each link goes to the source itself rather than to our summary of it.