Skip to content

Commit c4f2041

Browse files
committed
docs(gepa): clean up multi-agent example code
- Define tool functions outside class for clarity - Match structure of simple ReAct example - Add clear comments explaining architecture - Make code more readable and maintainable
1 parent 045c6cf commit c4f2041

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

docs/docs/api/optimizers/GEPA/GEPA_Advanced.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,182 @@ gepa = dspy.GEPA(
443443
auto="medium"
444444
)
445445
```
446+
447+
## Tool Description Optimization
448+
449+
### What is optimize_tool_descriptions?
450+
451+
The `optimize_tool_descriptions` parameter enables GEPA to optimize tool descriptions in addition to signature instructions. This is particularly valuable for ReAct agents and other tool-using systems, where the quality of tool descriptions directly impacts the agent's ability to select appropriate tools for each task.
452+
453+
Unlike signature instructions that guide reasoning strategies, tool descriptions serve a fundamentally different purpose: they help agents decide **which tool to use** in a given situation. GEPA recognizes this categorical difference and applies a specialized reflection prompt tailored for tool selection decisions.
454+
455+
### Default Behavior
456+
457+
By default, GEPA only optimizes signature instructions (`optimize_tool_descriptions=False`):
458+
459+
```python
460+
# Default behavior: only signature optimization
461+
gepa = dspy.GEPA(
462+
metric=my_metric,
463+
reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
464+
# optimize_tool_descriptions=False # This is the default
465+
auto="medium"
466+
)
467+
optimized_program = gepa.compile(student, trainset=examples)
468+
```
469+
470+
### When to Use optimize_tool_descriptions
471+
472+
Consider enabling `optimize_tool_descriptions=True` when:
473+
474+
- **Building ReAct agents**: ReAct agents rely on tool descriptions to make action selection decisions
475+
- **Multi-agent systems**: Systems with nested agents and delegated tools benefit from holistic optimization
476+
- **Poor tool selection**: Your agent frequently selects wrong tools or overlooks appropriate ones
477+
- **Complex tool sets**: When managing many tools with overlapping capabilities
478+
- **Domain-specific tools**: Tools requiring specialized knowledge or context for proper usage
479+
480+
### How It Works
481+
482+
When enabled, GEPA:
483+
484+
1. **Discovers all tools**: Traverses your program including nested sub-modules to find all `dspy.Tool` instances
485+
2. **Categorizes components**: Separates tools (identified by `tool:` prefix) from signature instructions
486+
3. **Routes to specialized proposers**:
487+
- Signature instructions → Default or custom instruction proposer
488+
- Tool descriptions → `ToolProposer` with tool-specific reflection prompt
489+
4. **Optimizes holistically**: Treats tool descriptions as first-class components in the optimization process
490+
491+
The tool-specific reflection prompt asks the LM to:
492+
493+
- Identify patterns in when the tool was used successfully versus when it was misused or overlooked
494+
- Extract domain-specific information about the tool's capabilities or appropriate usage
495+
- Recognize effective tool selection patterns the agent developed
496+
- Incorporate these insights into an improved tool description
497+
498+
### Usage Examples
499+
500+
#### Basic ReAct Agent
501+
502+
```python
503+
import dspy
504+
505+
def search_web(query: str) -> str:
506+
"""Search the web for information."""
507+
# Implementation here
508+
return search_results
509+
510+
def calculate(expression: str) -> float:
511+
"""Evaluate a mathematical expression."""
512+
# Implementation here
513+
return result
514+
515+
# Create ReAct agent with tools
516+
search_tool = dspy.Tool(search_web, name="search", desc="Search the web")
517+
calc_tool = dspy.Tool(calculate, name="calculator", desc="Do math")
518+
519+
agent = dspy.ReAct("question -> answer", tools=[search_tool, calc_tool])
520+
521+
# Enable tool optimization
522+
gepa = dspy.GEPA(
523+
metric=my_metric,
524+
reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
525+
optimize_tool_descriptions=True, # Enable tool optimization
526+
auto="medium"
527+
)
528+
529+
optimized_agent = gepa.compile(agent, trainset=train_examples, valset=val_examples)
530+
```
531+
532+
#### Multi-Agent System
533+
534+
For systems with nested agents, GEPA automatically discovers and optimizes all tools:
535+
536+
```python
537+
import dspy
538+
539+
def search_web(query: str) -> str:
540+
"""Search the web."""
541+
# Implementation here
542+
return results
543+
544+
def calculate(expression: str) -> float:
545+
"""Evaluate math expression."""
546+
# Implementation here
547+
return result
548+
549+
# Define tools
550+
search_tool = dspy.Tool(search_web, name="search", desc="Searches web")
551+
calc_tool = dspy.Tool(calculate, name="calculator", desc="Does math")
552+
553+
class ResearchAssistant(dspy.Module):
554+
def __init__(self):
555+
super().__init__()
556+
# Sub-agent with search tool
557+
self.researcher = dspy.ReAct("query -> findings", tools=[search_tool])
558+
559+
# Delegation tool wraps sub-agent
560+
def delegate_research(query: str) -> str:
561+
return self.researcher(query=query).findings
562+
563+
research_tool = dspy.Tool(delegate_research, name="research", desc="Research things")
564+
565+
# Main agent with calculator and research delegation
566+
self.assistant = dspy.ReAct("question -> answer", tools=[research_tool, calc_tool])
567+
568+
def forward(self, question):
569+
return self.assistant(question=question)
570+
571+
# GEPA optimizes ALL tools (calculator, research, search) together
572+
gepa = dspy.GEPA(
573+
metric=my_metric,
574+
reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
575+
optimize_tool_descriptions=True,
576+
auto="medium"
577+
)
578+
579+
optimized_system = gepa.compile(ResearchAssistant(), trainset=train, valset=val)
580+
```
581+
582+
### Inspecting Optimized Tool Descriptions
583+
584+
After optimization, tool descriptions are automatically updated in your program. Access them directly through your module structure:
585+
586+
```python
587+
optimized_agent = gepa.compile(agent, trainset=train, valset=val)
588+
589+
# Access tools directly - descriptions are already updated
590+
print(optimized_agent.tools["search"].desc)
591+
print(optimized_agent.tools["calculator"].desc)
592+
```
593+
594+
For multi-agent systems, access nested tools through your module hierarchy:
595+
596+
```python
597+
optimized_system = gepa.compile(ResearchAssistant(), trainset=train, valset=val)
598+
599+
# Access tools at different levels
600+
print(optimized_system.researcher.tools["search"].desc) # Sub-agent tool
601+
print(optimized_system.assistant.tools["research"].desc) # Main agent tool
602+
print(optimized_system.assistant.tools["calculator"].desc)
603+
```
604+
605+
### Compatibility with Custom Instruction Proposers
606+
607+
Tool optimization works seamlessly with custom instruction proposers. When both are provided:
608+
609+
- Signature instructions → Custom instruction proposer
610+
- Tool descriptions → Built-in `ToolProposer`
611+
612+
```python
613+
from dspy.teleprompt.gepa.instruction_proposal import MultiModalInstructionProposer
614+
615+
gepa = dspy.GEPA(
616+
metric=my_metric,
617+
reflection_lm=dspy.LM(model="gpt-5", temperature=1.0, max_tokens=32000, api_key=api_key),
618+
instruction_proposer=MultiModalInstructionProposer(), # For signatures
619+
optimize_tool_descriptions=True, # Enables ToolProposer for tools
620+
auto="medium"
621+
)
622+
```
623+
624+
**Note:** Tool optimization is fully backward compatible. Existing programs without tools, or with `optimize_tool_descriptions=False`, continue to work exactly as before.

0 commit comments

Comments
 (0)