Autonomous research multi agent Product Requirement Document (PRD) creation system - Day 2
Day 2: Building the Agent's Toolbox and Managing state
For our ResearchAgent, we need two primary capabilities:
- A tool to search the web.
- A tool to record its findings.
The Search Tool:
Leveraging Native Capabilities
Instead of complex web scraping, I'm tapping directly into Gemini's built-in function calling for Google Search.
The process:
- Define a google_types.Tool that enables the Google Search capability.
- Create a special llm_with_search instance that knows about this tool.
- Wrap this in a Python async function that the FunctionAgent* (e.g. Research Agent) can call.
*The FunctionAgent is a type of agent that uses an LLM provider's function/tool calling capabilities to execute tools.
from google.genai import types as google_types
1. Define the native tool:
google_search_tool = google_types.Tool(google_search=google_types.GoogleSearch())
2. Create a specialized LLM instance for it:
llm_with_search = GoogleGenAI(
model=" gemini-2.5-pro",
generation_config=google_types.GenerateContentConfig(tools=[google_search_tool]))
3. Wrap it in a Python function for the agent:
async def search_web(query: str) -> str: # ... logic to call llm_with_search ...
Managing state
Now for the most critical part: how does the WriteAgent get the notes from the ResearchAgent?
This is where LlamaIndex's state management shines. We create a record_notes tool that doesn't just return data. It writes to a shared "whiteboard" called the Context.
The ctx.store.edit_state() method is the key. It gives any tool secure write-access to the central workflow state.
Here’s the code:
# Any tool can get the context and edit the shared state
async def record_notes(ctx: Context, notes: str, notes_title: str) -> str:
async with ctx.store.edit_state() as state:
# 'state' is a direct reference to the workflow's state
if "research_notes" not in state:
state["research_notes"] = {}
state["research_notes"][notes_title] = notes
return "Notes recorded."
Notice how the ctx: Context is passed in. This is how LlamaIndex provides the tool with access to the shared state.
When this runs, it adds the notes to the research_notes dictionary in our main state object, ready for the next agent.
Now that our agents can act (search) and communicate (record_notes).
Posted Aug 5, 2025, 6:59 PM UTC