-
Notifications
You must be signed in to change notification settings - Fork 2.2k
docs: Add comprehensive instruction_proposer documentation and examples for GEPA #8775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
docs: Add comprehensive instruction_proposer documentation and examples for GEPA #8775
Conversation
@LakshyAAAgrawal wip will add the docstring updates in another commit please LMK if you have feedback so far in the docs |
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
### Default Implementation | ||
|
||
By default, GEPA uses the built-in instruction proposer from the [GEPA library](https://github.com/gepa-ai/gepa), which implements the `InstructionProposalSignature`. This default proposer: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to InstructionProposalSignature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
- **Multi-modal handling**: Process images (dspy.Image) alongside textual information in your inputs | ||
- **Nuanced control on limits and length constraints**: Have more fine-grained control over instruction length, format, and structural requirements | ||
- **Domain-specific information**: Inject specialized knowledge, terminology, or context that the default proposer lacks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and cannot be provided via feedback_func. Highlight that this is an advanced feature, and most users shouldn't need to use this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
- **Nuanced control on limits and length constraints**: Have more fine-grained control over instruction length, format, and structural requirements | ||
- **Domain-specific information**: Inject specialized knowledge, terminology, or context that the default proposer lacks | ||
- **Provider-specific prompting guides**: Optimize instructions for specific LLM providers (OpenAI, Anthropic, etc.) with their unique formatting preferences | ||
- **Coupled component updates**: Handle situations where 2 or more components need to be updated together in a coordinated manner, rather than optimizing each component independently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add "(Refer to section X for component selection)"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Will fix this after rebasing with #8765
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
docs/docs/api/optimizers/GEPA.md
Outdated
) | ||
``` | ||
|
||
We invite community contributions of new instruction proposers for specialized domains as the [GEPA library](https://github.com/gepa-ai/gepa) continues to grow. The GEPA repository contains multiple adapters (like `DefaultAdapter`, `DSPyFullProgramAdapter`, `TerminalBenchAdapter`, etc.) that, while not instruction proposers themselves, provide good examples and inspiration for implementing your own instruction proposer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not bring in adapters here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
```python | ||
def __call__( | ||
self, | ||
candidate: dict[str, str], # Current component name -> instruction mapping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop "Current". Or maybe say candidate to be updated in this round.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
def __call__( | ||
self, | ||
candidate: dict[str, str], # Current component name -> instruction mapping | ||
reflective_dataset: dict[str, list[dict[str, Any]]], # Component -> failed examples |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These aren't just failed examples. These could be good examples too! In fact, contrasting failed and good examples is how GEPA finds the right balance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also include the key values (Inputs, Generated Outputs, Feedback) that are present in reflective_dataset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point
Took the liberty to create a TypedDict:
class ReflectiveExample(TypedDict):
"""
Structure of individual examples in the reflective dataset.
Each example contains the predictor inputs, generated outputs, and feedback from evaluation.
"""
Inputs: dict[str, Any] # Predictor inputs (may include str, dspy.Image, etc.)
Generated_Outputs: dict[str, Any] | str # Success: dict with output fields, Failure: error message string
Feedback: str # Always a string - from metric function or parsing error message
I believe this makes it more clear. But please LMK if you prefer me to revert
docs/docs/api/optimizers/GEPA.md
Outdated
self, | ||
candidate: dict[str, str], # Current component name -> instruction mapping | ||
reflective_dataset: dict[str, list[dict[str, Any]]], # Component -> failed examples | ||
components_to_update: list[str] # Which components to improve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function should return new prompts, only for these components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
"""Given a current instruction and feedback examples, generate an improved instruction with word limit constraints.""" | ||
|
||
current_instruction = dspy.InputField(desc="The current instruction that needs improvement") | ||
issues_found = dspy.InputField(desc="Feedback and issues identified from failed examples") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar, this isn't issues_found. There are 3 keys in "reflective_dataset" (Inputs, Generated Outputs, Feedback)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
improved_instruction = dspy.OutputField(desc="A new instruction that fixes the issues while staying under the word limit") | ||
|
||
class WordLimitedInstructionImprover(dspy.Module): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, but seems too complicated for docs. Let's move this to instruction proposal library, but here, let's just have dspy.CoT(signature)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point.
Simplified.
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
**Best Practices:** | ||
- **Use the full power of DSPy**: Leverage DSPy components like `dspy.Module`, `dspy.Signature`, and `dspy.Predict` to create your instruction proposer rather than direct LM calls. Consider `dspy.Refine` for constraint satisfaction, `dspy.ChainOfThought` for complex reasoning tasks, and compose multiple modules for sophisticated instruction improvement workflows | ||
- **Validate component existence**: Always validate that required components exist in `candidate` and `reflective_dataset` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They do always exist. No need for asserts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
- **Validate component existence**: Always validate that required components exist in `candidate` and `reflective_dataset` | ||
- **Enable holistic feedback analysis**: While dspy.GEPA's `GEPAFeedbackMetric` processes one (gold, prediction) pair at a time, instruction proposers receive all examples for a component in batch, enabling cross-example pattern detection and systematic issue identification. | ||
- **Mind data serialization**: Serializing everything to strings might not be ideal - handle complex input types (like `dspy.Image`) by maintaining their structure for better LM processing | ||
- **Create detailed signatures**: Write comprehensive signature docstrings with step-by-step analysis guidance and clear requirements for the instruction improvement task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/docs/api/optimizers/GEPA.md
Outdated
- **Mind data serialization**: Serializing everything to strings might not be ideal - handle complex input types (like `dspy.Image`) by maintaining their structure for better LM processing | ||
- **Create detailed signatures**: Write comprehensive signature docstrings with step-by-step analysis guidance and clear requirements for the instruction improvement task | ||
- **Test thoroughly**: Test your custom proposer with representative failure cases | ||
- **Control context size**: Mind the number of examples analyzed to prevent context overflow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This too is not in control of instruction proposer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Feedback ready, and GEPA docstring implemented Will also update with "component selection" when #8765 is merged |
I also have this other branch https://github.com/andressrg/dspy/tree/feat/verbosity-aware-instruction-proposer Haven't created the PR yet because it is supposed to be stacked on top of this one. I'm excited about the verbosity aware proposer! Hope we can merge it soon 🚀 |
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
By default, GEPA uses the built-in instruction proposer from the [GEPA library](https://github.com/gepa-ai/gepa), which implements the [`ProposalFn`](https://github.com/gepa-ai/gepa/blob/main/src/gepa/core/adapter.py). This default proposer: | ||
|
||
- Uses a comprehensive prompt template that analyzes task context, inputs, outputs, and feedback |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the tradeoffs with having this list vs actually reproducing the default prompt directly? I feel like showing the default prompt could enable the end-user to judge whether they want to use it or not. Writing it this way makes it seem like there is no need to use custom instruction proposal!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good question!
I think it does work better showing the default prompt. It might be a bit more verbose than what we had before, but it's a lot more clear / explicit.
Hi @andressrg , feel free to continue working on this branch, or create a PR with the other branch whichever is updated! |
sure! |
fb68a16
to
278e83e
Compare
docs/docs/api/optimizers/GEPA.md
Outdated
|
||
**Built-in Options:** | ||
- **Default Proposer**: The standard GEPA instruction proposer (used when `instruction_proposer=None`). The default instruction proposer IS an instruction proposer as well! It is the most general one, that was used for the diverse experiments reported in the GEPA paper and tutorials. | ||
- **MultiModalInstructionProposer**: Handles `dspy.Image` inputs and structured multimodal content. This proposer has been specifically optimized for tasks that include one or more `dspy.Image` inputs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any run with the MultiModalInstructionProposer? I would avoid writing This proposer has been specifically optimized for tasks that include one or more
dspy.Image inputs.
till we have at least one benchmark/result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense.
Me and the team I work with have been using it with multi image usecases, but don't have any public benchmark/results yet.
Will update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
docs/docs/api/optimizers/GEPA.md
Outdated
```python | ||
from dspy.teleprompt.gepa.gepa_utils import ReflectiveExample | ||
|
||
def __call__( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be within a class? Or if it is a function, then it needs to be named differently. I don;'t think a top-level fn can be named call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point.
Just made it clearer by explaining the class and function form
docs/docs/api/optimizers/GEPA.md
Outdated
@@ -68,6 +68,432 @@ highest_score_achieved_per_task = new_prog.detailed_results.highest_score_achiev | |||
best_outputs = new_prog.detailed_results.best_outputs_valset | |||
``` | |||
|
|||
## Custom Instruction Proposers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading through the documentation, first of all, this is superb! Very detailed, and filled with great examples.
I feel like since this is a very advanced topic, it would be better to create a separate file/location for this, so that a first time user visiting the GEPA documentation does not immediately see this. It should come up as a thing that a new GEPA user should discover after they have become comfortable with the other GEPA concepts. Can you bring out both the instruction proposer and component selection outside?
Another thing, all of the great examples of instruction proposer that you provide, should probably also live in the library so that an end user can directly import and use it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like since this is a very advanced topic, it would be better to create a separate file/location for this, so that a first time user visiting the GEPA documentation does not immediately see this. It should come up as a thing that a new GEPA user should discover after they have become comfortable with the other GEPA concepts. Can you bring out both the instruction proposer and component selection outside?
sure man!
Can you point me to a sample file / location that has "advanced" docs for one of the dspy components?
it's not clear to me where should I create it or how to call it 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about replace GEPA.md with a directory GEPA/ which contains index.md (all the current GEPA content) and "GEPA_Advanced.md"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
directory done 🚀
a13f673
to
3415127
Compare
3415127
to
0a4df4f
Compare
@LakshyAAAgrawal new folder structure ready
good idea! but should we do this on a different PR? would love to merge this one with the docs on how to use instruction_proposer and component_selector |
ah wait. fixing the failing test |
docs/mkdocs.yml
Outdated
@@ -123,7 +123,8 @@ nav: | |||
- BootstrapRS: api/optimizers/BootstrapRS.md | |||
- COPRO: api/optimizers/COPRO.md | |||
- Ensemble: api/optimizers/Ensemble.md | |||
- GEPA: api/optimizers/GEPA.md | |||
- GEPA: api/optimizers/GEPA/index.md | |||
- GEPA - Advanced Features: api/optimizers/GEPA/GEPA_Advanced.md |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not the most elegant way to render the sidebar for the advanced features docs 🤔
But I'm not sure how another nested level will behave here
Let me know your thoughts please
If we don't like it, I can figure out how the UI looks with the extra nesting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you do mkdocs and check how it is rendered? https://github.com/stanfordnlp/dspy/tree/main/docs#building-docs-locally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
### Default Implementation | ||
|
||
By default, GEPA uses the built-in instruction proposer from the [GEPA library](https://github.com/gepa-ai/gepa), which implements the [`ProposalFn`](https://github.com/gepa-ai/gepa/blob/main/src/gepa/core/adapter.py). The default proposer uses this prompt template: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to the default proposer as well https://github.com/gepa-ai/gepa/blob/main/src/gepa/proposer/reflective_mutation/reflective_mutation.py#L53-L75
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
- **Nuanced control on limits and length constraints**: Have more fine-grained control over instruction length, format, and structural requirements | ||
- **Domain-specific information**: Inject specialized knowledge, terminology, or context that the default proposer lacks and cannot be provided via feedback_func. This is an advanced feature, and most users should not need to use this. | ||
- **Provider-specific prompting guides**: Optimize instructions for specific LLM providers (OpenAI, Anthropic, etc.) with their unique formatting preferences | ||
- **Coupled component updates**: Handle situations where 2 or more components need to be updated together in a coordinated manner, rather than optimizing each component independently (refer to component_selector parameter, in Custom Component Selection section, for related functionality) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to the component selection section?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR is amazing overall. Left some minor comments. If you can build the docs and see if the sidebar renders properly, looks good to merge!
@andressrg let me know once ready to merge |
@LakshyAAAgrawal ready to merge 🚀 I think the extra indentation in the nav bar is good! Tested it and it does work. How it looks when you are in another optimizer: I've also made it so the base link |
Summary
Resolves #8767 - Adds comprehensive documentation and working examples for GEPA's
instruction_proposer
parameter.What's Changed
Documentation Enhancements
docs/docs/api/optimizers/GEPA.md
covering whatinstruction_proposer is, when to use custom implementations, available options, and step-by-step implementation
guidance
Working Examples Added
dspy.Refine
Key Features
dspy.Module
,dspy.Signature
,dspy.ChainOfThought
)dspy.LM
)Testing
Files Modified
docs/docs/api/optimizers/GEPA.md
- Added comprehensive instruction_proposer section (~200 lines)