ONTO vs LlamaIndex: Agents vs RAG, Explained
LlamaIndex is the most popular RAG framework. ONTO is an agent SDK. They solve adjacent problems — but treating them as substitutes leads to bad architecture. Here's how to pick.
The first thing to get straight: LlamaIndex and ONTO are not really competitors. They solve adjacent problems that look similar from far away.
LlamaIndex is the leading framework for retrieval-augmented generation (RAG) — indexing documents, retrieving the relevant chunks, and synthesizing answers from them. It’s deep, well-engineered, and has an enormous integration ecosystem on the data side.
ONTO is an agent SDK — typed memory, Plan Mode, consent scopes, tool execution. The thing that does work on behalf of a user, often with side effects.
You can use them together. Most non-trivial real systems do.
When LlamaIndex is the right primary tool
If your application looks like this:
- Index a corpus of documents.
- A user asks a question.
- Retrieve the relevant chunks.
- Synthesize an answer with citations.
- Repeat.
LlamaIndex is the answer. It will save you months of work over building this from scratch. Plain LlamaIndex (no agent layer) is the right shape for:
- Document Q&A applications
- Internal knowledge-base assistants
- Customer-facing FAQ bots backed by a corpus
- Research assistants that summarize a known body of text
In these cases ONTO doesn’t add a lot — there’s no durable user state to manage, no side effects to gate, no Plan Mode flow.
When ONTO is the right primary tool
If your application looks like this:
- A user has an ongoing relationship with the assistant.
- The assistant has to remember things across sessions.
- The assistant takes actions (books, refunds, orders, writes).
- Some actions need human approval; others are auto-approved by policy.
- The assistant runs in a regulated environment (HIPAA, SOC 2, GDPR, etc.).
ONTO is the answer. The typed memory layer, Plan Mode, and Policy Guard scopes are designed for exactly this shape.
When you need both
The interesting case is the overlap: an agent that also needs to retrieve from a document corpus. A research copilot. A legal assistant that pulls from case law. A support bot that searches a knowledge base.
Here the right architecture is:
- LlamaIndex for the retrieval layer. Index your corpus, build the right retrievers, expose them as tools.
- ONTO for the agent layer. Typed memory of the user / case / customer, Plan Mode for any actions, consent scopes for tool calls.
- The LlamaIndex retrievers are ONTO tools. Wrap them in
Tool(...)calls with appropriaterequired_consent(e.g.,["search:legal"]).
The two ecosystems compose cleanly. You get RAG quality from LlamaIndex and agent guarantees from ONTO.
# Wrap a LlamaIndex retriever as an ONTO tool.
from llama_index.core import VectorStoreIndex
from onto import Onto, Tool
case_index = VectorStoreIndex.from_documents(legal_docs)
@Tool(name="search_case_law", required_consent=["search:legal"])
def search_case_law(query: str) -> list[dict]:
nodes = case_index.as_retriever().retrieve(query)
return [{"source": n.metadata["source"], "text": n.text} for n in nodes]
onto = Onto(tools=[search_case_law])
The agent now has a typed memory of the user and the case (ONTO’s UPO), and a tool that retrieves from the LlamaIndex-managed corpus.
The mistake people make
The wrong pattern is treating LlamaIndex’s vector store as your agent memory. Embedding “Alice is in UTC” and retrieving it later by similarity is the typed-memory-vs-embeddings mistake covered in a separate article.
A vector store should hold documents. An agent memory should hold facts. LlamaIndex is the right tool for the first; ONTO is the right tool for the second.
If you use a vector store as agent memory, you’ll find:
- The agent re-derives the user’s profile every session.
- Facts that should have a single current value get duplicated and conflict.
- “Is this true now” questions return confidently wrong answers.
- Compliance audits become very hard, because the audit trail doesn’t carry provenance per fact.
The fix is layered storage: vector for content, typed for state.
Where LlamaIndex Agents fit
LlamaIndex now ships an Agents layer and a Workflows system. Both are good, and they’re getting better fast. They’re optimized for retrieval-driven workflows — the use case where the agent’s job is mostly “retrieve and synthesize.”
If your agent’s job is mostly retrieval, LlamaIndex Agents is a fine choice. If your agent’s job is to act — book, refund, order, write — the retrieval-centric framing is a poor fit, and ONTO’s primitives (Plan Mode, consent scopes, durable typed memory) map better to the problem.
The pragmatic recommendation
- Document Q&A: LlamaIndex alone.
- Agent that acts on the world: ONTO, with LlamaIndex retrievers as tools when you need them.
- Agent that lives in a regulated domain: ONTO. Add LlamaIndex retrievers for any document corpora you have to search.
- Pure RAG over a fixed corpus: LlamaIndex. ONTO would be over-engineering.
Use each for what it’s good at. Stop treating “framework” as a single layer; treat it as a stack.
The features page walks through ONTO’s primitives in detail. The full comparison page covers ONTO vs Claude / OpenAI / Google ADK SDKs.
Frequently asked questions
Can I use ONTO with LlamaIndex?
Yes — and you probably should if you have an existing LlamaIndex retrieval layer. LlamaIndex handles 'find me the relevant document'; ONTO handles 'remember what is true about this user and gate what the agent can do.' They compose.
Doesn't LlamaIndex have agents now?
It does — LlamaIndex Agents and the Workflows system are real. They're built primarily around retrieval workflows. ONTO is built around typed memory and execution gates. The two agent layers solve different problems.
If I only need RAG, do I need ONTO?
Probably not. Plain LlamaIndex is great if your application is 'retrieve documents, answer questions, repeat.' ONTO becomes useful when your agent has to act on the world or maintain state across sessions.
The agent SDK where humans drive the state.
Plan Mode, typed memory, per-call consent scopes, and open-weight defaults. Open source under MIT or Apache-2.0.