Overview
A RAG session owns one corpus. You ingest documents into it, and it chunks, embeds, and indexes them. Asking a question retrieves the closest chunks and generates an answer grounded in them. Everything runs on the device.Dependencies
RAG ships inside the core SDK, so there is no separate RAG artifact. You do need a backend that provides embeddings: on Android that isrunanywhere-onnx, which is what the MiniLM embedding models
run on.
rag.open() loads rac_backend_onnx itself on first use, so its embedding operations are registered
before the session exists. You do not load it by hand.
Basic usage
open() downloads and loads both models before returning the session, so there is no separate
prepare step. Passing a null llmModel opens a retrieval-only session, where search() works and
query() throws.
Sessions are independent. Two sessions over different corpora can be open at the same time.
rag.open()
ModelRef(id) points at a registered model. It throws SDKException when either model cannot be
loaded.
RagSession
close() releases the native session and is safe to call twice. clear() drops every indexed
document but keeps the session open. Every verb throws SDKException once the session is closed.
Ingestion
RagDocument(text, metadata) takes plain text and a typed Map<String, String>, not a JSON string.
RagDocument.file(path) reads a UTF-8 text file and throws when it is missing or unreadable.
The metadata rides along onto every chunk and comes back on each Match.
Retrieval without generation
Match carries text, score (cosine similarity), and metadata. topK defaults to the session’s
configured value.
Querying
RagResult carries answer, sources: List<Match>, and the same metrics block as
GenerationResult: inputTokens, outputTokens, timeToFirstTokenMs, tokensPerSecond,
requestId, and model.
The answer is generated with the same LlmOptions the llm namespace uses, so systemPrompt,
reasoning, and the sampling knobs all apply. See generate().
Streaming
RagEvent has three arms: Retrieved(matches) with the chunks that will ground the answer, then
Token(text, kind), then Completed(result). A failure is thrown into the collector rather than
delivered as an event.
Cancelling the collector cancels that one native request. Concurrent collectors and unary queries on
the same session serialize instead of killing each other.
Statistics
RagConfig
Chunking and retrieval knobs are fixed for the life of the session. Defaults come from therac_default annotations in idl/rag.proto.
similarityThreshold null unless you have measured that a floor helps with your embedding
model. MiniLM-class sentence embeddings rarely exceed a cosine similarity of about 0.5 even for
genuinely relevant text, and chunking lowers each chunk’s score further, so a positive floor filters
out real matches and the answer model reports that it has no information. topK bounds the result
count instead.
Chunk size and overlap apply at ingestion, so changing them means opening a new session and
re-ingesting. Smaller chunks retrieve more precisely; larger ones carry more surrounding context.
RagConfig.DEFAULT_TOP_K, DEFAULT_CHUNK_SIZE, and DEFAULT_CHUNK_OVERLAP expose the three
numeric defaults.
ViewModel
viewModelScope. Cancelling the scope first would cancel the close too.
Embeddings on their own
Theembeddings namespace exposes the same embedding model directly, for your own similarity search
or clustering.
embed(texts, options: EmbedOptions? = null) returns one Embedding per input in input order, each
carrying its index and a FloatArray vector. EmbedOptions has normalize
(NormalizeMode.L2 by default, or NONE) and pooling (PoolingMode.MEAN by default, or CLS or
LAST). It throws when no embedding model is loaded.
Reranking
rerank scores documents against a query with a cross-encoder, which is more accurate than the
cosine similarity retrieval uses and much slower. It needs a rerank model loaded.
RankedResult carries index, pointing back at the input list, and relevanceScore. Results are
sorted best first. topN is optional and null returns everything.
Set RagConfig(rerank = true) to have a session rerank its retrieved chunks before generating,
instead of calling this yourself.
Errors
category, not on message text. queryStream throws into the collector rather than
emitting an error event. See Error handling.
Related
LLM generation
Text generation API
LoRA adapters
Adapt model behavior
Configuration
Register and download models
Best practices
Memory and lifecycle