LlamaIndex agents: FunctionAgent & ReActAgent
Turn a LlamaIndex index into a tool an agent can call. FunctionAgent (native function-calling) vs ReActAgent (text-based ReAct), both built on Workflows, plus the QueryEngineTool that makes RAG agentic.
What you'll learn
- How to expose an index to an agent as a QueryEngineTool
- FunctionAgent vs ReActAgent — when to use each
- Why both are Workflows under the hood
Before you start
A plain query engine answers a single question from your data. An agent can decide when to query, query multiple sources, call other tools, and loop until it has a complete answer. LlamaIndex makes that jump small: wrap your index as a tool, hand it to an agent, done. This is how RAG becomes agentic.
Your index becomes a tool
The bridge is the QueryEngineTool — it turns any query engine into a callable tool with a name and description the agent reads to decide when to use it.
Two agent types
LlamaIndex gives you two agents, differing only in how they decide on actions:
- FunctionAgent — uses the model’s native function/tool calling. Cleaner, more reliable, and the default for any model that supports tool calling (most do now). Reach for this first.
- ReActAgent — uses text-based ReAct (Thought / Action / Observation written as text). Useful for models without native tool calling, or when you want the reasoning trace visible as text.
Both are Workflows under the hood — the agent loop is a Workflow with steps for “call the LLM,” “run the tool,” and “check if done.” So everything you learned about Workflows applies: you can add custom steps, stream events, and trace the run.
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.tools import QueryEngineTool
# Wrap two indexes as tools the agent can choose between
docs_tool = QueryEngineTool.from_defaults(
docs_index.as_query_engine(),
name="product_docs",
description="Answers questions about product features and pricing.",
)
policy_tool = QueryEngineTool.from_defaults(
policy_index.as_query_engine(),
name="policies",
description="Answers questions about refunds, SLAs, and terms.",
)
agent = FunctionAgent(tools=[docs_tool, policy_tool], llm=llm)
# response = await agent.run("Is the Pro plan refundable after 20 days?")
# → the agent picks 'policies', queries it, and answers — citing the source nodes.
The agent reads each tool’s description to decide which to call — so write descriptions like you’re writing for a smart colleague: clear, specific, and honest about what each tool does and doesn’t cover.
Quick check
Quick check
Next
Agents are only as good as the documents they index. LlamaParse solves the messy-PDF problem that wrecks naive ingestion.
Practice this in an interview
All questionsIn LlamaIndex a Node is a chunk of a source document with metadata and relationships, indexed for retrieval; a query engine wraps an index to take a natural-language query, retrieve relevant nodes, and synthesize an answer. RAG-as-a-tool wraps a query engine in a QueryEngineTool so an agent can call it like any other tool, deciding when to retrieve from that knowledge source as part of its reasoning loop.
Tool calling extends the LLM's output space to include structured function invocations. The model emits a JSON object naming a tool and its arguments; the runtime executes the tool and feeds the result back as a new message. An agent is a loop that repeats this cycle — observe, think, act — until the task is complete or a stopping condition is met.
Function calling lets an LLM output a structured request to invoke an external function with arguments, which the runtime executes and feeds back, enabling agents to act in the world. Good tool design uses clear names and descriptions, minimal well-typed parameters, narrow single-purpose scope, least privilege, and informative error messages so the model can choose and call them reliably.
An agent is an LLM placed in a loop where it reasons, chooses and calls tools or actions, observes the results, and repeats until a goal is met, rather than producing one response and stopping. The key differences are autonomy, tool use, memory and state, and multi-step control flow driven by the model's own decisions.