Knowledge base
Upload your policies and price lists. A Tamil caller gets an answer from an English document, because retrieval works across scripts.
Endpoints
| Method | Path | Does |
|---|---|---|
POST | /v1/agents/{id}/knowledge | Upload PDF, DOCX, TXT or Markdown. 20MB cap |
GET | /v1/agents/{id}/knowledge | List documents and chunk counts |
DELETE | /v1/agents/{id}/knowledge/{doc} | Remove it and its chunks |
POST | /v1/agents/{id}/knowledge/search | See 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:
| Method | Recall@1 | Recall@3 | Time | Note |
|---|---|---|---|---|
| Keyword search | 32% | 58% | 0.2ms | 0% on Kannada, Malayalam and Marathi |
| Cross-lingual embeddings | 90% | 100% | 26.5ms | chosen |
| A larger embedding model | 100% | 100% | 87.8ms | ties 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:
| Signal | Relevant, lowest | Irrelevant, highest | Separates? |
|---|---|---|---|
| absolute top similarity | 0.7748 | 0.7779 | no — overlaps |
| margin over the rest | 0.0244 | 0.0472 | no — overlaps |
| ratio to the rest | 1.0326 | 1.0646 | no — 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.
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}'