Skip to content

Add PydanticFieldGEPA: Per-Field Description Evolution for Data Extraction#18

Open
mango-panther wants to merge 6 commits into
swe-productivity:mainfrom
mango-panther:GEPA_adapter
Open

Add PydanticFieldGEPA: Per-Field Description Evolution for Data Extraction#18
mango-panther wants to merge 6 commits into
swe-productivity:mainfrom
mango-panther:GEPA_adapter

Conversation

@mango-panther
Copy link
Copy Markdown

@mango-panther mango-panther commented Mar 19, 2026

closes #12
Adds Pydantic field description evolution as a mode within the existing GEPA optimizer. When a pydantic_model is provided, GEPA treats each field description as a separate evolvable component instead of evolving predictor instructions.

Usage:

from pydantic import BaseModel, Field                                                                                                    
import dspy                                                                                                                              
                                                                                                                                         
class Contact(BaseModel):                                                                                                                
    name: str = Field(description="Contact's full name")                                                                                 
    email: str = Field(description="Email address")                                                                                      
                                                                                                                                         
optimizer = dspy.GEPA(                                                                                                                   
    metric=extraction_metric,                                                                                                            
    pydantic_model=Contact,                                                                                                              
    evolvable_fields="all",                                                                                                              
    reflection_lm=dspy.LM("openai/gpt-4o-mini"),                                                                                         
    max_metric_calls=500,                                                                                                                
)                                                                                                                                        
                                                                                                                                         
optimized = optimizer.compile(extractor, trainset=examples)      

New GEPA Parameters:

  • pydantic_model: Pydantic model defining extraction schema (triggers pydantic mode)
  • evolvable_fields: "all", list of field names, or None for seed_prompt only
  • field_scorers: Optional per-field scorer functions
  • field_weights: Optional weights for field score aggregation
  • input_field_name, output_field_name, base_instruction: Extraction configuration

@mango-panther
Copy link
Copy Markdown
Author

@TomeHirata Could you also review this one when you get time

Comment thread dspy/teleprompt/gepa/pydantic_field/__init__.py Outdated
Comment thread dspy/teleprompt/gepa/pydantic_field/__init__.py Outdated
Comment thread dspy/teleprompt/gepa/pydantic_field/adapter.py Outdated
Comment thread dspy/teleprompt/gepa/pydantic_field/adapter.py Outdated
Comment thread dspy/teleprompt/gepa/gepa.py Outdated
]


def __getattr__(name):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary if we import them lazily where needed. Where does the circular import occur?

Copy link
Copy Markdown
Author

@mango-panther mango-panther Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. dspy/teleprompt/init.py imports from .gepa.gepa import GEPA
  2. This triggers loading of dspy/teleprompt/gepa/init.py first (package init)
  3. With eager imports, it loads pydantic_field which uses dspy.LM in type hints
  4. But dspy isn't fully loaded yet → circular import

@TomeHirata
Copy link
Copy Markdown
Collaborator

Can we make the Pydantic field evolution another mode of the existing GEPA optimiser instead of introducing PydanticFieldGEPA? We can add a new argument to GEPA and switch the GEPA adapter class used internally based on the argument.

@mango-panther
Copy link
Copy Markdown
Author

Can we make the Pydantic field evolution another mode of the existing GEPA optimiser instead of introducing PydanticFieldGEPA? We can add a new argument to GEPA and switch the GEPA adapter class used internally based on the argument.

Made these change. I have also upated PR description based on this new implementation.

@mango-panther mango-panther requested a review from TomeHirata April 1, 2026 05:37
@mango-panther
Copy link
Copy Markdown
Author

@TomeHirata, can you review this again? I have incorporated all suggested changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] GEPA should be able to evolve all components of the signature, not just docstring

2 participants