Knowledge base

Upload your policies and price lists. A Tamil caller gets an answer from an English document, because retrieval works across scripts.

Endpoints

MethodPathDoes
POST/v1/agents/{id}/knowledgeUpload PDF, DOCX, TXT or Markdown. 20MB cap
GET/v1/agents/{id}/knowledgeList documents and chunk counts
DELETE/v1/agents/{id}/knowledge/{doc}Remove it and its chunks
POST/v1/agents/{id}/knowledge/searchSee exactly what a caller's question would find

That last one exists because when an agent gives a poor answer you need to know whether retrieval found the wrong passage or the passage was right and the prompt was wrong. Those need completely different fixes, and guessing between them is miserable.

Why an embedding model and not keyword search

Measured on 19 real Indic questions against 10 English documents:

MethodRecall@1Recall@3TimeNote
Keyword search32%58%0.2ms0% on Kannada, Malayalam and Marathi
Cross-lingual embeddings90%100%26.5mschosen
A larger embedding model100%100%87.8msties at Recall@3 for +61ms, so not worth it

Keyword search scoring zero on three languages is not tuning, it is mechanical: a Kannada question and an English document share no tokens at all. We inject the top three passages, so Recall@3 is what decides answer quality — and there the two embedding models tie, which makes the faster one the right choice. A small BM25 weighting is blended back in for literal strings like order ids, where dense retrieval is weak.

Retrieval is automatic, not a tool the model calls

Arithmetic: a tool call costs a whole extra model round trip, about 590ms on this stack, against roughly 27ms to embed the question and paste the best passages into the prompt. Same information, one twentieth of the delay.

The threshold is a noise floor, not a relevance test

Read this before raising knowledge_min_similarity. We tried to judge relevance from similarity and it does not work with this encoder. Measured over 12 questions, comparing real questions against small talk:

SignalRelevant, lowestIrrelevant, highestSeparates?
absolute top similarity0.77480.7779no — overlaps
margin over the rest0.02440.0472no — overlaps
ratio to the rest1.03261.0646no — overlaps

All three bands overlap, so no threshold on any of them tells a real question from “hello, are you there?”. E5 compresses similarity into roughly 0.71–0.88 and unrelated text still scores about 0.75.

So relevance is judged by the model, and the costs make that the right way roundWithholding relevant context is expensive: with retrieval suppressed the model invented “5 to 7 working days” for a policy that says 7, and invented a Singapore delivery charge. Injecting irrelevant context is cheap: asked “are you there?” with the warranty policy attached, the agent replied “Haan, main yahan hoon” and never mentioned it. The default of 0.70 drops pure noise; raising it toward 0.84 starts withholding real answers.

What happens to your file

Parsed, chunked and embedded before the upload request returns, so when the row appears the agent can already use it. Accepting the file and processing later means a customer uploads a price list, makes a test call, gets nothing, and concludes it does not work.

  • DOCX tables are included. Price lists are exactly the facts callers ask about.
  • A scanned PDF is refused with a clear message. No text layer means nothing to index, and silently storing zero chunks would look like success.
  • Chunks record which embedding model made them. Vectors from different models are not comparable, so without this, changing the model would return confident nonsense from a mixture of unrelated spaces.

Citations are suppressed on purpose

The model wanted to write “…7 working days ([1]).” A caller hears “seven working days, bracket one” and assumes the line is broken. The prompt forbids citing and a regex catches what slips through — narrowed after an earlier version ate the amount from “you owe Rs (500) today”, which is a much worse failure than a stray marker.

curl -X POST https://api.latency.cam/v1/agents/$AGENT/knowledge \
  -H "Authorization: Bearer $LATENCY_KEY" \
  -F file=@refund-policy.pdf

curl -X POST https://api.latency.cam/v1/agents/$AGENT/knowledge/search \
  -H "Authorization: Bearer $LATENCY_KEY" -H "Content-Type: application/json" \
  -d '{"query": "refund kitne din mein aayega?", "top_k": 3}'