LlamaIndex: Interactive Notes
If LangChain is a general toolbox, LlamaIndex is a specialist for one job: connecting LLMs to your data. It shines at loading, parsing, indexing and querying documents, and adds Workflows and agents on top. These notes cover the core ideas with runnable, key-free examples.
In this session
- The LlamaIndex pipeline: Documents → Nodes → Index → Query
- Retrievers, query engines and chat engines
- Settings, persistence and LlamaHub connectors
- Event-driven Workflows
- Agents, and LlamaIndex vs LangChain
01Documents, nodes and indexes
| Concept | Meaning | LangChain equivalent |
|---|---|---|
| Document | a whole source file or record | Document |
| Node | a chunk of a document, with metadata and links | a split Document |
| Index | a searchable structure over nodes (usually vectors) | vector store |
| Retriever | returns the top matching nodes | retriever |
| Query engine | retriever + prompt + LLM in one object | a RAG chain |
| Chat engine | a query engine that remembers the conversation | RAG + memory |
"""Key-free stand-ins for LlamaIndex. Real code: Settings.llm = OpenAI(model="gpt-4o-mini"); Settings.embed_model = OpenAIEmbedding()."""
import re, math
from llama_index.core.embeddings import BaseEmbedding
class KeywordEmbedding(BaseEmbedding):
def _vec(self, text, dim=256):
v = [0.0] * dim
for w in re.findall(r"[a-z]+", text.lower()): v[sum(map(ord, w[:5])) % dim] += 1
n = math.sqrt(sum(x * x for x in v)) or 1
return [x / n for x in v]
def _get_text_embedding(self, text): return self._vec(text)
def _get_query_embedding(self, query): return self._vec(query)
async def _aget_query_embedding(self, query): return self._vec(query)MockLLM stand in for real models. LlamaIndex may print a warning that the chunks are small; that is expected with this tiny demo text.# pip install llama-index-core (plus llama-index-llms-openai etc. for real models)
from llama_index.core import Document, VectorStoreIndex, Settings
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.llms import MockLLM
from li_fake import KeywordEmbedding
Settings.embed_model = KeywordEmbedding() # real: OpenAIEmbedding()
Settings.llm = MockLLM(max_tokens=12) # real: OpenAI(model="gpt-4o-mini")
docs = [Document(text="Premature withdrawal of an FD reduces the interest rate by 1%. "
"Senior citizens get an extra 0.50% on all FD tenures.", metadata={"file": "fd_policy.pdf"}),
Document(text="A home loan EMI is due on the 5th of every month. Late payment costs ₹500.",
metadata={"file": "loan_policy.pdf"})]
nodes = SentenceSplitter(chunk_size=25, chunk_overlap=0).get_nodes_from_documents(docs) # Documents -> Nodes
print(len(nodes), "nodes; first:", nodes[0].text, "|", nodes[0].metadata)
index = VectorStoreIndex(nodes) # embed + store
retriever = index.as_retriever(similarity_top_k=1)
for hit in retriever.retrieve("What is the penalty for withdrawing an FD early?"):
print(f"retrieved ({hit.score:.2f}):", hit.node.text, "<-", hit.node.metadata["file"])
engine = index.as_query_engine(similarity_top_k=1) # retrieve + prompt + LLM in one call
resp = engine.query("When is the EMI due?")
print("sources used:", [n.node.metadata["file"] for n in resp.source_nodes])The splitter turned 2 documents into 4 nodes (one per sentence here), the retriever found the right sentence for the FD question, and the query engine used loan_policy.pdf for the EMI question. source_nodes is how you build citations.
02Retrievers, query engines and chat engines
from llama_index.core import Settings, StorageContext, load_index_from_storage
from llama_index.llms.openai import OpenAI # pip install llama-index-llms-openai
from llama_index.embeddings.openai import OpenAIEmbedding # pip install llama-index-embeddings-openai
Settings.llm = OpenAI(model="gpt-4o-mini")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
index.storage_context.persist("./storage") # save once ...
index = load_index_from_storage(StorageContext.from_defaults(persist_dir="./storage")) # ... reload later- LlamaHub has hundreds of readers and connectors (Google Drive, Notion, SQL, Slack) installed as small packages.
- LlamaParse is LlamaIndex’s hosted document parser for complex PDFs with tables and charts.
- Any vector database (Chroma, Qdrant, pgvector, Pinecone…) can back a
VectorStoreIndex.
03Workflows and agents
Workflows are LlamaIndex’s way to build multi-step apps. Instead of drawing edges, each @step says which event it listens for and which event it emits; LlamaIndex connects them by type:
import asyncio
from llama_index.core.workflow import Workflow, step, Event, StartEvent, StopEvent
class Classified(Event):
category: str
text: str
class TicketFlow(Workflow):
@step
async def classify(self, ev: StartEvent) -> Classified: # each step listens for an event type
cat = "card" if "card" in ev.text.lower() else "general"
return Classified(category=cat, text=ev.text)
@step
async def respond(self, ev: Classified) -> StopEvent: # ...and emits the next event
reply = {"card": "Your card is blocked; a new one is on its way.",
"general": "Thanks, an agent will reply within 24 hours."}[ev.category]
return StopEvent(result=f"[{ev.category}] {reply}")
async def main():
flow = TicketFlow(timeout=10)
for text in ["My card was stolen", "I want to update my address"]:
print(await flow.run(text=text))
asyncio.run(main())from llama_index.core.agent.workflow import FunctionAgent
def fd_rate(years: int) -> str:
"""Return the FD interest rate for a tenure in years."""
return {1: "6.8%", 3: "7.1%"}.get(years, "not offered")
agent = FunctionAgent(tools=[fd_rate], llm=Settings.llm, # needs a real model that supports tool calling
system_prompt="You are NovaBank's assistant.")
# inside an async function: response = await agent.run("What is the 3-year FD rate?")| Choose LlamaIndex when… | Choose LangChain / LangGraph when… |
|---|---|
| the app is mostly “chat with documents” | the app is mostly tools, actions and workflows |
| you need strong parsing and indexing of messy files | you need fine control of agent loops and approvals |
| you want query and chat engines out of the box | you want the widest set of integrations and LangSmith tooling |
04Summary
- LlamaIndex specialises in connecting LLMs to your data.
- Pipeline: Documents → Nodes → Index → Retriever → Query engine.
- Use a query engine for one-off questions and a chat engine for conversations;
source_nodesgives citations. - Configure models once with
Settings; persist indexes to disk. - Workflows link async steps by event type; FunctionAgent adds tool-using agents.
05Quick quiz
1. In LlamaIndex, a Node is…
2. Which object answers a question with retrieval + LLM in one call?
3. How do you get citations from a query response?
4. How are Workflow steps connected?
5. A good reason to choose LlamaIndex?