Repository Public
1LlamaIndex is a framework for building knowledge agents using LLMs connected to2your data. This example shows you how to build a multi-agent workflow for a3Research Agent. In LlamaIndex, [`Workflows`](https://docs.llamaindex.ai/en/stable/module_guides/workflow/)4are the building blocks of agent and multi-agent systems.56You need a Gemini API key. If you don't already have one, you can7[get one in Google AI Studio](https://aistudio.google.com/apikey).8First, install all required LlamaIndex libraries. LlamaIndex uses9the `google-genai` package under the hood.1011 pip install llama-index llama-index-utils-workflow llama-index-llms-google-genai llama-index-tools-google1213## Set up Gemini in LlamaIndex1415The engine of any LlamaIndex agent is an LLM that handles reasoning and text16processing. This example uses Gemini 3 Flash. Make sure you [set your API key as17an environment variable](https://ai.google.dev/gemini-api/docs/api-key).1819 import os20 from llama_index.llms.google_genai import GoogleGenAI2122 # Set your API key in the environment elsewhere, or with os.environ['GEMINI_API_KEY'] = '...'23 assert 'GEMINI_API_KEY' in os.environ2425 llm = GoogleGenAI(model="gemini-3.8-flash")2627## Build tools2829Agents use tools to interact with the outside world, like searching the web or30storing information. [Tools in LlamaIndex](https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/tools/)31can be regular Python functions, or imported from pre-existing `ToolSpecs`.32Gemini comes with a built-in tool for using Google Search, which is used here.3334 from google.genai import types3536 google_search_tool = types.Tool(37 google_search=types.GoogleSearch()38 )3940 llm_with_search = GoogleGenAI(41 model="gemini-3.8-flash",42 generation_config=types.GenerateContentConfig(tools=[google_search_tool])43 )4445Now test the LLM instance with a query that requires search. This guide assumes46a running event loop (such as `python -m asyncio` or Google Colab).4748 response = await llm_with_search.acomplete("What's the weather like today in Biarritz?")49 print(response)5051The Research Agent will use Python functions as tools. There are a lot of ways52you could go about building a system to perform this task. In this example, you53will use the following:54551. `search_web` uses Gemini with Google Search to search the web for information on the given topic.562. `record_notes` saves research found on the web to the state so that the other tools can use it.573. `write_report` writes the report using the information found by the `ResearchAgent`584. `review_report` reviews the report and provides feedback.5960The `Context` class passes the state between agents/tools, and each agent will61have access to the current state of the system.6263 from llama_index.core.workflow import Context6465 async def search_web(ctx: Context, query: str) -> str:66 """Useful for searching the web about a specific query or topic"""67 response = await llm_with_search.acomplete(f"""Please research given this query or topic,68 and return the result\n<query_or_topic>{query}</query_or_topic>""")69 return response7071 async def record_notes(ctx: Context, notes: str, notes_title: str) -> str:72 """Useful for recording notes on a given topic."""73 current_state = await ctx.store.get("state")74 if "research_notes" not in current_state:75 current_state["research_notes"] = {}76 current_state["research_notes"][notes_title] = notes77 await ctx.store.set("state", current_state)78 return "Notes recorded."7980 async def write_report(ctx: Context, report_content: str) -> str:81 """Useful for writing a report on a given topic."""82 current_state = await ctx.store.get("state")83 current_state["report_content"] = report_content84 await ctx.store.set("state", current_state)85 return "Report written."8687 async def review_report(ctx: Context, review: str) -> str:88 """Useful for reviewing a report and providing feedback."""89 current_state = await ctx.store.get("state")90 current_state["review"] = review91 await ctx.store.set("state", current_state)92 return "Report reviewed."9394## Build a multi-agent assistant9596To build a multi-agent system, you define the agents and their interactions.97Your system will have three agents:98991. A `ResearchAgent` searches the web for information on the given topic.1002. A `WriteAgent` writes the report using the information found by the `ResearchAgent`.1013. A `ReviewAgent` reviews the report and provides feedback.102103This example uses the `AgentWorkflow` class to create a multi-agent system that104will execute these agents in order. Each agent takes a `system_prompt` that105tells it what it should do, and suggests how to work with the other agents.106107Optionally, you can help your multi-agent system by specifying which other108agents it can talk to using `can_handoff_to` (if not, it will try to figure this109out on its own).110111 from llama_index.core.agent.workflow import (112 AgentInput,113 AgentOutput,114 ToolCall,115 ToolCallResult,116 AgentStream,117 )118 from llama_index.core.agent.workflow import FunctionAgent, ReActAgent119120 research_agent = FunctionAgent(121 name="ResearchAgent",122 description="Useful for searching the web for information on a given topic and recording notes on the topic.",123 system_prompt=(124 "You are the ResearchAgent that can search the web for information on a given topic and record notes on the topic. "125 "Once notes are recorded and you are satisfied, you should hand off control to the WriteAgent to write a report on the topic."126 ),127 llm=llm,128 tools=[search_web, record_notes],129 can_handoff_to=["WriteAgent"],130 )131132 write_agent = FunctionAgent(133 name="WriteAgent",134 description="Useful for writing a report on a given topic.",135 system_prompt=(136 "You are the WriteAgent that can write a report on a given topic. "137 "Your report should be in a markdown format. The content should be grounded in the research notes. "138 "Once the report is written, you should get feedback at least once from the ReviewAgent."139 ),140 llm=llm,141 tools=[write_report],142 can_handoff_to=["ReviewAgent", "ResearchAgent"],143 )144145 review_agent = FunctionAgent(146 name="ReviewAgent",147 description="Useful for reviewing a report and providing feedback.",148 system_prompt=(149 "You are the ReviewAgent that can review a report and provide feedback. "150 "Your feedback should either approve the current report or request changes for the WriteAgent to implement."151 ),152 llm=llm,153 tools=[review_report],154 can_handoff_to=["ResearchAgent","WriteAgent"],155 )156157The Agents are defined, now you can create the `AgentWorkflow` and run it.158159 from llama_index.core.agent.workflow import AgentWorkflow160161 agent_workflow = AgentWorkflow(162 agents=[research_agent, write_agent, review_agent],163 root_agent=research_agent.name,164 initial_state={165 "research_notes": {},166 "report_content": "Not written yet.",167 "review": "Review required.",168 },169 )170171During execution of the workflow, you can stream events, tool calls and updates172to the console.173174 from llama_index.core.agent.workflow import (175 AgentInput,176 AgentOutput,177 ToolCall,178 ToolCallResult,179 AgentStream,180 )181182 research_topic = """Write me a report on the history of the web.183 Briefly describe the history of the world wide web, including184 the development of the internet and the development of the web,185 including 21st century developments"""186187 handler = agent_workflow.run(188 user_msg=research_topic189 )190191 current_agent = None192 current_tool_calls = ""193 async for event in handler.stream_events():194 if (195 hasattr(event, "current_agent_name")196 and event.current_agent_name != current_agent197 ):198 current_agent = event.current_agent_name199 print(f"\n{'='*50}")200 print(f"🤖 Agent: {current_agent}")201 print(f"{'='*50}\n")202 elif isinstance(event, AgentOutput):203 if event.response.content:204 print("📤 Output:", event.response.content)205 if event.tool_calls:206 print(207 "🛠️ Planning to use tools:",208 [call.tool_name for call in event.tool_calls],209 )210 elif isinstance(event, ToolCallResult):211 print(f"🔧 Tool Result ({event.tool_name}):")212 print(f" Arguments: {event.tool_kwargs}")213 print(f" Output: {event.tool_output}")214 elif isinstance(event, ToolCall):215 print(f"🔨 Calling Tool: {event.tool_name}")216 print(f" With arguments: {event.tool_kwargs}")217218After the workflow is complete, you can print the final output of the report, as219well as the final review state from then review agent.220221 state = await handler.ctx.store.get("state")222 print("Report Content:\n", state["report_content"])223 print("\n---\nFinal Review:\n", state["review"])224225## Go further with custom workflows226227The `AgentWorkflow` is a great way to get started with multi-agent systems. But228what if you need more control? You can build a workflow from scratch. Here are229some reasons why you might want to build your own workflow:230231- **More control over the process**: You can decide the exact path your agents take. This includes creating loops, making decisions at certain points, or having agents work in parallel on different tasks.232- **Use complex data**: Go beyond plain text. Custom workflows let you use more structured data, like JSON objects or custom classes, for your inputs and outputs.233- **Work with different media**: Build agents that can understand and process not just text, but also images, audio, and video.234- **Smarter planning**: You can design a workflow that first creates a detailed plan before the agents start working. This is useful for complex tasks that require multiple steps.235- **Enable self-correction**: Create agents that can review their own work. If the output isn't good enough, the agent can try again, creating a loop of improvement until the result is perfect.236237To learn more about LlamaIndex Workflows, see the [LlamaIndex Workflows238Documentation](https://docs.llamaindex.ai/en/stable/module_guides/workflow/).