Skip to content
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

Add result_type to run methods #565

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

SYNchroACK
Copy link

Fix: #564

@SYNchroACK SYNchroACK closed this Dec 29, 2024
@SYNchroACK SYNchroACK force-pushed the enh/result_type-on-run branch from a7976b2 to e9bdb04 Compare December 29, 2024 22:26
@SYNchroACK SYNchroACK reopened this Dec 29, 2024
@SYNchroACK SYNchroACK force-pushed the enh/result_type-on-run branch 2 times, most recently from bedb980 to 733750b Compare December 29, 2024 23:07
@SYNchroACK
Copy link
Author

Example

from pydantic import BaseModel
from pydantic_ai import Agent


class City(BaseModel):
    name: str

class Country(BaseModel):
    name: str

class Community(BaseModel):
    name: str

agent = Agent(
    model='openai:gpt-4o',
    system_prompt='You are a tour guide assistant.',
    result_type=list[City | Country | Community],
)

result = agent.run_sync(
    user_prompt='Provide me the best communities to hang out.',
    result_type=list[Community],
)

result = agent.run_sync(
    user_prompt='Provide me the best countries to visit.',
    result_type=list[Country],
)

result = agent.run_sync(
    user_prompt='I have no idea about what should I visit this winter, give me some ideas.. countries, cities, communities',
    # It will use the `result_type` defined in the agent
)

@samuelcolvin samuelcolvin changed the title Add result_type on run method Add result_type to run methods Dec 30, 2024
Comment on lines 93 to 94
_default_result_schema: _result.ResultSchema[ResultData] | None = field(repr=False)
_current_result_schema: _result.ResultSchema[ResultData] | None = field(repr=False)
Copy link
Member

Choose a reason for hiding this comment

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

ha, this would break a lot of cases since agents can be run concurrently, they need to be static.

You'll need to pass the result_schema around everywhere you need to use it.

I suspect a better approach would be to move all the run logic from Agent into a new AgentRun (data)class, to avoid argument overload.

Copy link
Member

Choose a reason for hiding this comment

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

This seems like a good idea structurally to implement sooner rather than later

@samuelcolvin
Copy link
Member

Actually, the correct way to do this is to add the result_schema to RunContext, see #570.

system_prompt: str | Sequence[str] = (),
deps_type: type[AgentDeps] = NoneType,
name: str | None = None,
model_settings: ModelSettings | None = None,
retries: int = 1,
result_type: type[ResultData] = str,
Copy link

Choose a reason for hiding this comment

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

I think this needs a different TypeVar (+overloads)? Its not the same type as Agent´s generic TResult, its basically a type override.

Copy link
Member

Choose a reason for hiding this comment

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

@SYNchroACK SYNchroACK force-pushed the enh/result_type-on-run branch from 733750b to 874d4ba Compare January 2, 2025 21:21
@SYNchroACK SYNchroACK marked this pull request as draft January 2, 2025 21:24
@phil65
Copy link

phil65 commented Jan 3, 2025

After having played around with it for while, I would strongly suggest to drop the generic return type for the Agent itself completely. I think having the typing for return type stricly "call-based" is the favourable approach, mixed approaches lead to weird ambiguities.

Copy link

sonarqubecloud bot commented Jan 3, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
4.7% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@SYNchroACK
Copy link
Author

After having played around with it for while, I would strongly suggest to drop the generic return type for the Agent itself completely. I think having the typing for return type stricly "call-based" is the favourable approach, mixed approaches lead to weird ambiguities.

In case you have chance, take over this feature. ;)

@phil65
Copy link

phil65 commented Jan 4, 2025

No, sorry, I didnt mean to intervene, but Just tryin to provide some input since I ran into the same initial issues you had. I now solved it by getting rid of TResult for the "main" Agent and then introducing a second StructuredAgent.

class StructuredAgent[TDeps, TResult]:
    """Wrapper for Agent that enforces a specific result type.
    """

    def __init__(
        self,
        agent: Agent[TDeps],
        result_type: type[TResult],
        final_tool_name: str = "final_result",
        final_tool_description: str | None = None,
    ):

That allows to have a "flexible" Agent as well as a fixed "structured" agent.
SInce the interface of Agent is quite small, perhaps it could be enforced by a shared base class or a Protocol.

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.

Provide result_type on each user_prompt.
4 participants