PythonTypeScriptHigh — roles/crews/agents out of the box

LlamaIndex

Ingesting, indexing, and querying private documents with LLMs — RAG as a first-class product rather than a chain you assemble.

Architecture

  • Documents → Nodes: loaders (SimpleDirectoryReader, LlamaHub connectors) produce documents; node parsers chunk them with metadata and relationships.
  • Indexes: VectorStoreIndex, keyword, summary, knowledge-graph indexes over a StorageContext that abstracts vector stores and doc stores.
  • Retrievers → Query engines → Chat engines: retrieval, optional node postprocessors (reranking, metadata filters), and a response synthesizer (compact, refine, tree_summarize).
  • Agents and Workflows: FunctionAgent/ReActAgent wrap tools (a query engine can be a tool); Workflow is an event-driven step system for custom orchestration.
  • Ingestion pipelines with transformations and caching for repeatable, incremental indexing.

Best use cases

  • Document Q&A and knowledge assistants where retrieval quality is the product.
  • Teams that want reranking, hybrid retrieval, and metadata filtering available as configuration.
  • Structured data plus text (SQL + documents) routed through one query interface.

Weaknesses

  • Defaults hide critical choices: chunk size 1024, top-k 2, a specific response synthesizer — good demos, surprising production behaviour until you read every default (RAG Evaluation).
  • Response synthesizers (refine in particular) issue multiple hidden LLM calls; latency and cost are non-obvious from the calling code.
  • The class hierarchy is deep; customising one step often means subclassing or reading source.
  • Agent and workflow layers are newer and have churned (legacy AgentRunner vs FunctionAgent), so docs and examples mix eras.
  • Heavy install with many optional extras; llama-index-* package fragmentation makes version pinning fiddly.

When NOT to use it

  • Your problem is not retrieval — a general agent runtime or plain SDK code fits better.
  • You already have a search service (Elasticsearch, pgvector with your own queries) and only need to pass results to a model.
  • You need to control exactly which chunks and how many tokens reach the prompt on every call.

Code example

Illustrative — APIs change between versions.

1from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings
2from llama_index.core.node_parser import SentenceSplitter
3from llama_index.core.postprocessor import SimilarityPostprocessor
4
5Settings.chunk_size = 512 # override the defaults deliberately
6
7docs = SimpleDirectoryReader("./handbook").load_data()
8index = VectorStoreIndex.from_documents(
9 docs, transformations=[SentenceSplitter(chunk_size=512, chunk_overlap=64)]
10)
11
12query_engine = index.as_query_engine(
13 similarity_top_k=6,
14 node_postprocessors=[SimilarityPostprocessor(similarity_cutoff=0.7)],
15 response_mode="compact", # one synthesis call, not 'refine'
16)
17resp = query_engine.query("What is the on-call escalation policy?")
18print(resp.response)
19for n in resp.source_nodes: # citations come for free
20 print(n.metadata.get("file_name"), round(n.score, 3))

Alternatives

Related lessons