這是用戶在 2025-7-12 15:08 為 https://ai.pydantic.dev/output/ 保存的雙語快照頁面,由 沉浸式翻譯 提供雙語支持。了解如何保存?
Skip to content

Output  輸出

"Output" refers to the final value returned from running an agent. This can be either plain text, structured data, or the result of a function called with arguments provided by the model.
「輸出」指的是執行代理程式後回傳的最終值。這可以是純文字、結構化資料,或是使用模型提供的參數呼叫函式的結果。

The output is wrapped in AgentRunResult or StreamedRunResult so that you can access other data, like usage of the run and message history.
輸出包裹在 AgentRunResultStreamedRunResult 中,讓您可以存取其他資料,例如執行的使用情況和訊息歷史記錄。

Both AgentRunResult and StreamedRunResult are generic in the data they wrap, so typing information about the data returned by the agent is preserved.
AgentRunResultStreamedRunResult 包裝的資料皆為泛型,因此代理回傳資料的型別資訊得以保留。

A run ends when the model responds with one of the structured output types, or, if no output type is specified or str is one of the allowed options, when a plain text response is received. A run can also be cancelled if usage limits are exceeded, see Usage Limits.
當模型回應其中一種結構化輸出類型時,或是如果未指定輸出類型或 str 是允許選項之一時,收到純文字回應即結束執行。若超過使用限制,執行也會被取消,詳見使用限制。

Here's an example using a Pydantic model as the output_type, forcing the model to respond with data matching our specification:
以下是一個使用 Pydantic 模型作為 output_type 的範例,強制模型回應符合我們規範的資料:

olympics.py
from pydantic import BaseModel

from pydantic_ai import Agent


class CityLocation(BaseModel):
    city: str
    country: str


agent = Agent('google-gla:gemini-1.5-flash', output_type=CityLocation)
result = agent.run_sync('Where were the olympics held in 2012?')
print(result.output)
#> city='London' country='United Kingdom'
print(result.usage())
#> Usage(requests=1, request_tokens=57, response_tokens=8, total_tokens=65)

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Output data  輸出資料

The Agent class constructor takes an output_type argument that takes one or more types or output functions. It supports simple scalar types, list and dict types (including TypedDicts and StructuredDicts), dataclasses and Pydantic models, as well as type unions -- generally everything supported as type hints in a Pydantic model. You can also pass a list of multiple choices.
Agent 類別的建構子接受一個 output_type 參數,該參數可包含一種或多種型別或輸出函式。它支援簡單的標量型別、清單與字典型別(包括 TypedDictStructuredDict )、資料類別與 Pydantic 模型,以及型別聯合——基本上涵蓋 Pydantic 模型中作為型別提示所支援的所有類型。您也可以傳入多個選項的清單。

By default, Pydantic AI leverages the model's tool calling capability to make it return structured data. When multiple output types are specified (in a union or list), each member is registered with the model as a separate output tool in order to reduce the complexity of the schema and maximise the chances a model will respond correctly. This has been shown to work well across a wide range of models. If you'd like to change the names of the output tools, use a model's native structured output feature, or pass the output schema to the model in its instructions, you can use an output mode marker class.
預設情況下,Pydantic AI 利用模型的工具呼叫功能,使其回傳結構化資料。當指定多種輸出類型(以聯合類型或清單形式)時,每個成員都會被註冊為模型的獨立輸出工具,以降低結構的複雜度並最大化模型正確回應的機率。這種方法已被證明在多種模型中效果良好。如果您想更改輸出工具的名稱、使用模型原生的結構化輸出功能,或將輸出結構傳遞給模型作為指令,您可以使用輸出模式標記類別。

When no output type is specified, or when str is among the output types, any plain text response from the model will be used as the output data. If str is not among the output types, the model is forced to return structured data or call an output function.
當未指定輸出類型,或當 str 在輸出類型中時,模型的任何純文字回應都會被用作輸出資料。如果 str 不在輸出類型中,模型將被強制返回結構化資料或呼叫輸出函式。

If the output type schema is not of type "object" (e.g. it's int or list[int]), the output type is wrapped in a single element object, so the schema of all tools registered with the model are object schemas.
如果輸出類型的結構不是 "object" 類型(例如是 intlist[int] ),輸出類型會被包裝在單一元素物件中,因此所有註冊於模型的工具結構都是物件結構。

Structured outputs (like tools) use Pydantic to build the JSON schema used for the tool, and to validate the data returned by the model.
結構化輸出(如工具)使用 Pydantic 建立工具所使用的 JSON 結構,並驗證模型返回的資料。

Type checking considerations
型別檢查注意事項

The Agent class is generic in its output type, and this type is carried through to AgentRunResult.output and StreamedRunResult.output so that your IDE or static type checker can warn you when your code doesn't properly take into account all the possible values those outputs could have.
Agent 類別的輸出類型是泛型,這個類型會傳遞到 AgentRunResult.outputStreamedRunResult.output ,讓您的 IDE 或靜態型別檢查器在您的程式碼未正確考慮所有可能的輸出值時發出警告。

Static type checkers like pyright and mypy will do their best the infer the agent's output type from the output_type you've specified, but they're not always able to do so correctly when you provide functions or multiple types in a union or list, even though PydanticAI will behave correctly. When this happens, your type checker will complain even when you're confident you've passed a valid output_type, and you'll need to help the type checker by explicitly specifying the generic parameters on the Agent constructor. This is shown in the second example below and the output functions example further down.
像 pyright 和 mypy 這類靜態型別檢查器會盡力從您指定的 output_type 推斷 agent 的輸出類型,但當您提供函式或多種類型的聯合或清單時,它們不一定能正確推斷,儘管 PydanticAI 會正確運作。當發生這種情況時,即使您確信已傳入有效的 output_type ,型別檢查器仍會抱怨,您需要透過在 Agent 建構子上明確指定泛型參數來協助型別檢查器。這在下面的第二個範例以及稍後的輸出函式範例中有示範。

Specifically, there are three valid uses of output_type where you'll need to do this:
具體來說,有三種有效的 output_type 用法需要這麼做:

  1. When using a union of types, e.g. output_type=Foo | Bar, or in older Python, output_type=Union[Foo, Bar]. Until PEP-747 "Annotating Type Forms" lands in Python 3.15, type checkers do not consider these a valid value for output_type. In addition to the generic parameters on the Agent constructor, you'll need to add # type: ignore to the line that passes the union to output_type. Alternatively, you can use a list: output_type=[Foo, Bar].
    當使用聯合類型,例如 output_type=Foo | Bar ,或在較舊的 Python 版本中, output_type=Union[Foo, Bar] 。直到 PEP-747「註解類型形式」在 Python 3.15 中實現之前,型別檢查器不會將這些視為 output_type 的有效值。除了在 Agent 建構子上的泛型參數外,您還需要在將聯合類型傳遞給 output_type 的那一行加上 # type: ignore 。或者,您也可以使用列表: output_type=[Foo, Bar]
  2. With mypy: When using a list, as a functionally equivalent alternative to a union, or because you're passing in output functions. Pyright does handle this correctly, and we've filed an issue with mypy to try and get this fixed.
    使用 mypy:當使用列表作為聯合類型的功能等效替代方案,或因為您正在傳遞輸出函數。Pyright 能正確處理此情況,我們已向 mypy 提出問題以嘗試修正此問題。
  3. With mypy: when using an async output function. Pyright does handle this correctly, and we've filed an issue with mypy to try and get this fixed.
    使用 mypy:當使用非同步輸出函數時。Pyright 能正確處理此情況,我們已向 mypy 提出問題以嘗試修正此問題。

Here's an example of returning either text or structured data:
以下是一個回傳文字或結構化資料的範例:

box_or_error.py
from pydantic import BaseModel

from pydantic_ai import Agent


class Box(BaseModel):
    width: int
    height: int
    depth: int
    units: str


agent = Agent(
    'openai:gpt-4o-mini',
    output_type=[Box, str], 
    system_prompt=(
        "Extract me the dimensions of a box, "
        "if you can't extract all data, ask the user to try again."
    ),
)

result = agent.run_sync('The box is 10x20x30')
print(result.output)
#> Please provide the units for the dimensions (e.g., cm, in, m).

result = agent.run_sync('The box is 10x20x30 cm')
print(result.output)
#> width=10 height=20 depth=30 units='cm'

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Here's an example of using a union return type, which will register multiple output tools and wrap non-object schemas in an object:
以下是一個使用聯合返回類型的範例,該類型將註冊多個輸出工具並將非物件結構包裝在物件中:

colors_or_sizes.py
from typing import Union

from pydantic_ai import Agent

agent = Agent[None, Union[list[str], list[int]]](
    'openai:gpt-4o-mini',
    output_type=Union[list[str], list[int]],  
    system_prompt='Extract either colors or sizes from the shapes provided.',
)

result = agent.run_sync('red square, blue circle, green triangle')
print(result.output)
#> ['red', 'blue', 'green']

result = agent.run_sync('square size 10, circle size 20, triangle size 30')
print(result.output)
#> [10, 20, 30]

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Output functions  輸出函數

Instead of plain text or structured data, you may want the output of your agent run to be the result of a function called with arguments provided by the model, for example to further process or validate the data provided through the arguments (with the option to tell the model to try again), or to hand off to another agent.
除了純文字或結構化資料外,您可能希望代理執行的輸出是由模型提供的參數調用函數的結果,例如進一步處理或驗證透過參數提供的資料(並可選擇告訴模型重試),或是交由另一個代理處理。

Output functions are similar to function tools, but the model is forced to call one of them, the call ends the agent run, and the result is not passed back to the model.
輸出函數類似於函數工具,但模型被強制呼叫其中一個,呼叫結束代理運行,且結果不會回傳給模型。

As with tool functions, output function arguments provided by the model are validated using Pydantic, they can optionally take RunContext as the first argument, and they can raise ModelRetry to ask the model to try again with modified arguments (or with a different output type).
與工具函式相同,模型提供的輸出函式參數會使用 Pydantic 進行驗證,它們可以選擇性地以 RunContext 作為第一個參數,並且可以拋出 ModelRetry 以要求模型使用修改後的參數(或不同的輸出類型)重新嘗試。

To specify output functions, you set the agent's output_type to either a single function (or bound instance method), or a list of functions. The list can also contain other output types like simple scalars or entire Pydantic models. You typically do not want to also register your output function as a tool (using the @agent.tool decorator or tools argument), as this could confuse the model about which it should be calling.
要指定輸出函數,您可以將代理的 output_type 設定為單一函數(或綁定的實例方法),或函數列表。該列表也可以包含其他輸出類型,如簡單標量或完整的 Pydantic 模型。通常您不會想同時將輸出函數註冊為工具(使用 @agent.tool 裝飾器或 tools 參數),因為這可能會讓模型混淆應該呼叫哪一個。

Here's an example of all of these features in action:
以下是一個展示所有這些功能的範例:

output_functions.py
import re
from typing import Union

from pydantic import BaseModel

from pydantic_ai import Agent, ModelRetry, RunContext
from pydantic_ai.exceptions import UnexpectedModelBehavior


class Row(BaseModel):
    name: str
    country: str


tables = {
    'capital_cities': [
        Row(name='Amsterdam', country='Netherlands'),
        Row(name='Mexico City', country='Mexico'),
    ]
}


class SQLFailure(BaseModel):
    """An unrecoverable failure. Only use this when you can't change the query to make it work."""

    explanation: str


def run_sql_query(query: str) -> list[Row]:
    """Run a SQL query on the database."""

    select_table = re.match(r'SELECT (.+) FROM (\w+)', query)
    if select_table:
        column_names = select_table.group(1)
        if column_names != '*':
            raise ModelRetry("Only 'SELECT *' is supported, you'll have to do column filtering manually.")

        table_name = select_table.group(2)
        if table_name not in tables:
            raise ModelRetry(
                f"Unknown table '{table_name}' in query '{query}'. Available tables: {', '.join(tables.keys())}."
            )

        return tables[table_name]

    raise ModelRetry(f"Unsupported query: '{query}'.")


sql_agent = Agent[None, Union[list[Row], SQLFailure]](
    'openai:gpt-4o',
    output_type=[run_sql_query, SQLFailure],
    instructions='You are a SQL agent that can run SQL queries on a database.',
)


async def hand_off_to_sql_agent(ctx: RunContext, query: str) -> list[Row]:
    """I take natural language queries, turn them into SQL, and run them on a database."""

    # Drop the final message with the output tool call, as it shouldn't be passed on to the SQL agent
    messages = ctx.messages[:-1]
    try:
        result = await sql_agent.run(query, message_history=messages)
        output = result.output
        if isinstance(output, SQLFailure):
            raise ModelRetry(f'SQL agent failed: {output.explanation}')
        return output
    except UnexpectedModelBehavior as e:
        # Bubble up potentially retryable errors to the router agent
        if (cause := e.__cause__) and hasattr(cause, 'tool_retry'):
            raise ModelRetry(f'SQL agent failed: {cause.tool_retry.content}') from e
        else:
            raise


class RouterFailure(BaseModel):
    """Use me when no appropriate agent is found or the used agent failed."""

    explanation: str


router_agent = Agent[None, Union[list[Row], RouterFailure]](
    'openai:gpt-4o',
    output_type=[hand_off_to_sql_agent, RouterFailure],
    instructions='You are a router to other agents. Never try to solve a problem yourself, just pass it on.',
)

result = router_agent.run_sync('Select the names and countries of all capitals')
print(result.output)
"""
[
    Row(name='Amsterdam', country='Netherlands'),
    Row(name='Mexico City', country='Mexico'),
]
"""

result = router_agent.run_sync('Select all pets')
print(repr(result.output))
"""
RouterFailure(explanation="The requested table 'pets' does not exist in the database. The only available table is 'capital_cities', which does not contain data about pets.")
"""

result = router_agent.run_sync('How do I fly from Amsterdam to Mexico City?')
print(repr(result.output))
"""
RouterFailure(explanation='I am not equipped to provide travel information, such as flights from Amsterdam to Mexico City.')
"""

Text output  文字輸出

If you provide an output function that takes a string, Pydantic AI will by default create an output tool like for any other output function. If instead you'd like the model to provide the string using plain text output, you can wrap the function in the TextOutput marker class. If desired, this marker class can be used alongside one or more ToolOutput marker classes (or unmarked types or functions) in a list provided to output_type.
如果您提供一個接受字串的輸出函式,Pydantic AI 預設會像處理其他輸出函式一樣建立一個輸出工具。如果您希望模型以純文字輸出提供字串,可以將該函式包裝在 TextOutput 標記類別中。若需要,這個標記類別可以與一個或多個 ToolOutput 標記類別(或未標記的類型或函式)一起放在提供給 output_type 的清單中使用。

text_output_function.py
from pydantic_ai import Agent, TextOutput


def split_into_words(text: str) -> list[str]:
    return text.split()


agent = Agent(
    'openai:gpt-4o',
    output_type=TextOutput(split_into_words),
)
result = agent.run_sync('Who was Albert Einstein?')
print(result.output)
#> ['Albert', 'Einstein', 'was', 'a', 'German-born', 'theoretical', 'physicist.']

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Output modes  輸出模式

Pydantic AI implements three different methods to get a model to output structured data:
Pydantic AI 實作了三種不同的方法來讓模型輸出結構化資料:

  1. Tool Output, where tool calls are used to produce the output.
    工具輸出,使用工具呼叫來產生輸出。
  2. Native Output, where the model is required to produce text content compliant with a provided JSON schema.
    原生輸出,要求模型產生符合提供 JSON 架構的文字內容。
  3. Prompted Output, where a prompt is injected into the model instructions including the desired JSON schema, and we attempt to parse the model's plain-text response as appropriate.
    提示輸出,將提示注入模型指令中,包括所需的 JSON 架構,並嘗試將模型的純文字回應解析為適當格式。

Tool Output  工具輸出

In the default Tool Output mode, the output JSON schema of each output type (or function) is provided to the model as the parameters schema of a special output tool. This is the default as it's supported by virtually all models and has been shown to work very well.
在預設的工具輸出模式中,每個輸出類型(或函數)的輸出 JSON 架構會作為特殊輸出工具的參數架構提供給模型。這是預設設定,因為幾乎所有模型都支援此方式,且已證明效果非常好。

If you'd like to change the name of the output tool, pass a custom description to aid the model, or turn on or off strict mode, you can wrap the type(s) in the ToolOutput marker class and provide the appropriate arguments. Note that by default, the description is taken from the docstring specified on a Pydantic model or output function, so specifying it using the marker class is typically not necessary.
如果您想更改輸出工具的名稱、傳遞自訂描述以協助模型,或開啟或關閉嚴格模式,可以將類型包裝在 ToolOutput 標記類別中並提供適當的參數。請注意,預設情況下,描述會從 Pydantic 模型或輸出函數上指定的 docstring 取得,因此通常不需要使用標記類別來指定描述。

tool_output.py
from pydantic import BaseModel

from pydantic_ai import Agent, ToolOutput


class Fruit(BaseModel):
    name: str
    color: str


class Vehicle(BaseModel):
    name: str
    wheels: int


agent = Agent(
    'openai:gpt-4o',
    output_type=[ 
        ToolOutput(Fruit, name='return_fruit'),
        ToolOutput(Vehicle, name='return_vehicle'),
    ],
)
result = agent.run_sync('What is a banana?')
print(repr(result.output))
#> Fruit(name='banana', color='yellow')

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Native Output  原生輸出

Native Output mode uses a model's native "Structured Outputs" feature (aka "JSON Schema response format"), where the model is forced to only output text matching the provided JSON schema. Note that this is not supported by all models, and sometimes comes with restrictions. For example, Anthropic does not support this at all, and Gemini cannot use tools at the same time as structured output, and attempting to do so will result in an error.
原生輸出模式使用模型的原生「結構化輸出」功能(又稱「JSON Schema 回應格式」),模型被強制只能輸出符合所提供 JSON schema 的文字。請注意,並非所有模型都支援此功能,且有時會有使用限制。例如,Anthropic 完全不支援此功能,而 Gemini 無法在使用結構化輸出的同時使用工具,嘗試這樣做會導致錯誤。

To use this mode, you can wrap the output type(s) in the NativeOutput marker class that also lets you specify a name and description if the name and docstring of the type or function are not sufficient.
要使用此模式,您可以將輸出類型包裹在 NativeOutput 標記類別中,該類別也允許您指定 namedescription ,以防類型或函式的名稱和說明文字不足。

native_output.py
from tool_output import Fruit, Vehicle

from pydantic_ai import Agent, NativeOutput

agent = Agent(
    'openai:gpt-4o',
    output_type=NativeOutput(
        [Fruit, Vehicle], 
        name='Fruit or vehicle',
        description='Return a fruit or vehicle.'
    ),
)
result = agent.run_sync('What is a Ford Explorer?')
print(repr(result.output))
#> Vehicle(name='Ford Explorer', wheels=4)

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Prompted Output  提示輸出

In this mode, the model is prompted to output text matching the provided JSON schema through its instructions and it's up to the model to interpret those instructions correctly. This is usable with all models, but is often the least reliable approach as the model is not forced to match the schema.
在此模式中,模型會根據指令輸出符合提供的 JSON 架構的文字,並由模型自行正確解讀這些指令。此模式適用於所有模型,但通常是最不可靠的方法,因為模型並未被強制符合該架構。

While we would generally suggest starting with tool or native output, in some cases this mode may result in higher quality outputs, and for models without native tool calling or structured output support it is the only option for producing structured outputs.
雖然我們通常建議從工具或原生輸出開始,但在某些情況下,此模式可能產生較高品質的輸出,且對於不支援原生工具呼叫或結構化輸出的模型來說,這是產生結構化輸出的唯一選擇。

If the model API supports the "JSON Mode" feature (aka "JSON Object response format") to force the model to output valid JSON, this is enabled, but it's still up to the model to abide by the schema. Pydantic AI will validate the returned structured data and tell the model to try again if validation fails, but if the model is not intelligent enough this may not be sufficient.
如果模型 API 支援「JSON 模式」功能(又稱「JSON 物件回應格式」)以強制模型輸出有效的 JSON,則會啟用此功能,但仍需模型遵守架構。Pydantic AI 會驗證回傳的結構化資料,若驗證失敗會告訴模型重新嘗試,但若模型智慧不足,這可能仍不夠。

To use this mode, you can wrap the output type(s) in the PromptedOutput marker class that also lets you specify a name and description if the name and docstring of the type or function are not sufficient. Additionally, it supports an template argument lets you specify a custom instructions template to be used instead of the default.
要使用此模式,您可以將輸出類型包裹在 PromptedOutput 標記類別中,該類別還允許您指定 namedescription ,以防類型或函式的名稱和說明字串不足。此外,它支援一個 template 參數,讓您可以指定自訂的指令範本,以取代預設範本。

prompted_output.py
from pydantic import BaseModel
from tool_output import Vehicle

from pydantic_ai import Agent, PromptedOutput


class Device(BaseModel):
    name: str
    kind: str


agent = Agent(
    'openai:gpt-4o',
    output_type=PromptedOutput(
        [Vehicle, Device], 
        name='Vehicle or device',
        description='Return a vehicle or device.'
    ),
)
result = agent.run_sync('What is a MacBook?')
print(repr(result.output))
#> Device(name='MacBook', kind='laptop')

agent = Agent(
    'openai:gpt-4o',
    output_type=PromptedOutput(
        [Vehicle, Device],
        template='Gimme some JSON: {schema}'
    ),
)
result = agent.run_sync('What is a Ford Explorer?')
print(repr(result.output))
#> Vehicle(name='Ford Explorer', wheels=4)

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Custom JSON schema  自訂 JSON 架構

If it's not feasible to define your desired structured output object using a Pydantic BaseModel, dataclass, or TypedDict, for example when you get a JSON schema from an external source or generate it dynamically, you can use the StructuredDict() helper function to generate a dict[str, Any] subclass with a JSON schema attached that Pydantic AI will pass to the model.
如果無法使用 Pydantic BaseModel 、dataclass 或 TypedDict 定義您想要的結構化輸出物件,例如當您從外部來源取得 JSON 架構或動態產生它時,您可以使用 StructuredDict() 輔助函式來產生一個附帶 JSON 架構的 dict[str, Any] 子類別,Pydantic AI 將會將此架構傳遞給模型。

Note that Pydantic AI will not perform any validation of the received JSON object and it's up to the model to correctly interpret the schema and any constraints expressed in it, like required fields or integer value ranges.
請注意,Pydantic AI 不會對接收到的 JSON 物件進行任何驗證,模型必須正確解讀該架構及其中表達的任何限制條件,如必填欄位或整數值範圍。

The output type will be a dict[str, Any] and it's up to your code to defensively read from it in case the model made a mistake. You can use an output validator to reflect validation errors back to the model and get it to try again.
輸出類型將會是 dict[str, Any] ,您的程式碼必須防禦性地從中讀取,以防模型出錯。您可以使用輸出驗證器將驗證錯誤反映回模型,讓它重新嘗試。

Along with the JSON schema, you can optionally pass name and description arguments to provide additional context to the model:
除了 JSON 架構之外,您還可以選擇傳遞 namedescription 參數,以提供額外的上下文給模型:

from pydantic_ai import Agent, StructuredDict

HumanDict = StructuredDict(
    {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "age": {"type": "integer"}
        },
        "required": ["name", "age"]
    },
    name="Human",
    description="A human with a name and age",
)

agent = Agent('openai:gpt-4o', output_type=HumanDict)
result = agent.run_sync("Create a person")
#> {'name': 'John Doe', 'age': 30}

Output validators  輸出驗證器

Some validation is inconvenient or impossible to do in Pydantic validators, in particular when the validation requires IO and is asynchronous. PydanticAI provides a way to add validation functions via the agent.output_validator decorator.
有些驗證在 Pydantic 驗證器中不便或無法完成,特別是當驗證需要 IO 且為非同步時。PydanticAI 提供了一種透過 agent.output_validator 裝飾器新增驗證函式的方法。

If you want to implement separate validation logic for different output types, it's recommended to use output functions instead, to save you from having to do isinstance checks inside the output validator. If you want the model to output plain text, do your own processing or validation, and then have the agent's final output be the result of your function, it's recommended to use an output function with the TextOutput marker class.
如果您想為不同的輸出類型實作獨立的驗證邏輯,建議改用輸出函式,這樣可以避免您必須在輸出驗證器中進行 isinstance 檢查。如果您希望模型輸出純文字,自行進行處理或驗證,然後讓代理的最終輸出成為您函式的結果,建議使用帶有 TextOutput 標記類別的輸出函式。

Here's a simplified variant of the SQL Generation example:
以下是 SQL 生成範例的簡化版本:

sql_gen.py
from typing import Union

from fake_database import DatabaseConn, QueryError
from pydantic import BaseModel

from pydantic_ai import Agent, RunContext, ModelRetry


class Success(BaseModel):
    sql_query: str


class InvalidRequest(BaseModel):
    error_message: str


Output = Union[Success, InvalidRequest]
agent = Agent[DatabaseConn, Output](
    'google-gla:gemini-1.5-flash',
    output_type=Output,  # type: ignore
    deps_type=DatabaseConn,
    system_prompt='Generate PostgreSQL flavored SQL queries based on user input.',
)


@agent.output_validator
async def validate_sql(ctx: RunContext[DatabaseConn], output: Output) -> Output:
    if isinstance(output, InvalidRequest):
        return output
    try:
        await ctx.deps.execute(f'EXPLAIN {output.sql_query}')
    except QueryError as e:
        raise ModelRetry(f'Invalid query: {e}') from e
    else:
        return output


result = agent.run_sync(
    'get me users who were last active yesterday.', deps=DatabaseConn()
)
print(result.output)
#> sql_query='SELECT * FROM users WHERE last_active::date = today() - interval 1 day'

(This example is complete, it can be run "as is")
(此範例完整,可直接執行)

Streamed Results  串流結果

There two main challenges with streamed results:
串流結果有兩個主要挑戰:

  1. Validating structured responses before they're complete, this is achieved by "partial validation" which was recently added to Pydantic in pydantic/pydantic#10748.
    在結構化回應尚未完成前進行驗證,這是透過最近在 Pydantic 中新增的「部分驗證」(pydantic/pydantic#10748)來實現的。
  2. When receiving a response, we don't know if it's the final response without starting to stream it and peeking at the content. PydanticAI streams just enough of the response to sniff out if it's a tool call or an output, then streams the whole thing and calls tools, or returns the stream as a StreamedRunResult.
    在接收回應時,我們無法在開始串流並窺視內容前判斷是否為最終回應。PydanticAI 會串流足夠的回應內容以判斷是否為工具呼叫或輸出,然後串流整個內容並呼叫工具,或將串流作為 StreamedRunResult 回傳。

Streaming Text  串流文字

Example of streamed text output:
串流文字輸出範例:

streamed_hello_world.py
from pydantic_ai import Agent

agent = Agent('google-gla:gemini-1.5-flash')  


async def main():
    async with agent.run_stream('Where does "hello world" come from?') as result:  
        async for message in result.stream_text():  
            print(message)
            #> The first known
            #> The first known use of "hello,
            #> The first known use of "hello, world" was in
            #> The first known use of "hello, world" was in a 1974 textbook
            #> The first known use of "hello, world" was in a 1974 textbook about the C
            #> The first known use of "hello, world" was in a 1974 textbook about the C programming language.

(This example is complete, it can be run "as is" — you'll need to add asyncio.run(main()) to run main)
(此範例已完整,可直接執行 — 你需要加入 asyncio.run(main()) 以執行 main

We can also stream text as deltas rather than the entire text in each item:
我們也可以串流傳輸增量文字,而非每個項目傳送整段文字:

streamed_delta_hello_world.py
from pydantic_ai import Agent

agent = Agent('google-gla:gemini-1.5-flash')


async def main():
    async with agent.run_stream('Where does "hello world" come from?') as result:
        async for message in result.stream_text(delta=True):  
            print(message)
            #> The first known
            #> use of "hello,
            #> world" was in
            #> a 1974 textbook
            #> about the C
            #> programming language.

(This example is complete, it can be run "as is" — you'll need to add asyncio.run(main()) to run main)
(此範例已完整,可直接執行 — 你需要加入 asyncio.run(main()) 以執行 main

Output message not included in messages
輸出訊息未包含在 messages

The final output message will NOT be added to result messages if you use .stream_text(delta=True), see Messages and chat history for more information.
如果您使用 .stream_text(delta=True) ,最終輸出訊息將不會被加入結果訊息中,詳情請參閱訊息與聊天記錄。

Streaming Structured Output
串流結構化輸出

Not all types are supported with partial validation in Pydantic, see pydantic/pydantic#10748, generally for model-like structures it's currently best to use TypeDict.
並非所有類型在 Pydantic 中都支援部分驗證,詳見 pydantic/pydantic#10748,通常對於類模型結構,目前最佳做法是使用 TypeDict

Here's an example of streaming a use profile as it's built:
以下是一個串流使用者檔案建立過程的範例:

streamed_user_profile.py
from datetime import date

from typing_extensions import TypedDict

from pydantic_ai import Agent


class UserProfile(TypedDict, total=False):
    name: str
    dob: date
    bio: str


agent = Agent(
    'openai:gpt-4o',
    output_type=UserProfile,
    system_prompt='Extract a user profile from the input',
)


async def main():
    user_input = 'My name is Ben, I was born on January 28th 1990, I like the chain the dog and the pyramid.'
    async with agent.run_stream(user_input) as result:
        async for profile in result.stream():
            print(profile)
            #> {'name': 'Ben'}
            #> {'name': 'Ben'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the '}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyr'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyramid'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyramid'}

(This example is complete, it can be run "as is" — you'll need to add asyncio.run(main()) to run main)
(此範例已完整,可直接執行 — 你需要加入 asyncio.run(main()) 以執行 main

If you want fine-grained control of validation, particularly catching validation errors, you can use the following pattern:
如果您想要對驗證進行細緻的控制,特別是捕捉驗證錯誤,可以使用以下模式:

streamed_user_profile.py
from datetime import date

from pydantic import ValidationError
from typing_extensions import TypedDict

from pydantic_ai import Agent


class UserProfile(TypedDict, total=False):
    name: str
    dob: date
    bio: str


agent = Agent('openai:gpt-4o', output_type=UserProfile)


async def main():
    user_input = 'My name is Ben, I was born on January 28th 1990, I like the chain the dog and the pyramid.'
    async with agent.run_stream(user_input) as result:
        async for message, last in result.stream_structured(debounce_by=0.01):  
            try:
                profile = await result.validate_structured_output(  
                    message,
                    allow_partial=not last,
                )
            except ValidationError:
                continue
            print(profile)
            #> {'name': 'Ben'}
            #> {'name': 'Ben'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the '}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyr'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyramid'}
            #> {'name': 'Ben', 'dob': date(1990, 1, 28), 'bio': 'Likes the chain the dog and the pyramid'}

(This example is complete, it can be run "as is" — you'll need to add asyncio.run(main()) to run main)
(此範例已完整,可直接執行 — 你需要加入 asyncio.run(main()) 以執行 main

Examples  範例

The following examples demonstrate how to use streamed responses in PydanticAI:
以下範例展示如何在 PydanticAI 中使用串流回應: