You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询pydantic_ai配置llama3.1实现结构化输出的问题

本地Llama3.1结合Pydantic-AI Agent无法返回指定结构化输出问题

问题概述

使用本地Llama3.1模型时,Pydantic-AI Agent可以正确调用通过tools属性注册的工具,但不会使用启用结构化输出时自动生成的final_result工具,导致无法返回指定类型的结构化输出。需要确认:

  • 该问题是否由Llama3.1无法稳定返回final_result工具调用导致
  • 是否存在Pydantic-AI配置项可强制模型触发final_result工具调用

已知Pydantic-AI提供Prompted Output模式,但文档说明默认的Tool Output模式更稳定,因此优先排查配置是否存在问题。

Agent配置代码

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.ollama import OllamaProvider
from pydantic import BaseModel, Literal, Union


class SyncResult(BaseModel):
    message: str


class AsyncResult(BaseModel):
    workflow_name: str


class MainAgentOutput(BaseModel):
    mode: Literal["sync", "async"]
    result: Union[SyncResult, AsyncResult]

main_agent = Agent(
    model=OpenAIChatModel(
        model_name="llama3.1:latest",
        provider=OllamaProvider(
           base_url="http://localhost:11434/v1", 
           api_key="somekey"
        )
    ),
    output_type=MainAgentOutput,
    tools=get_tools(),
    system_prompt=build_system_prompt(),
)

系统提示内容

You are a routing agent.

You can either:
1. Execute one or more synchronous tools (mode="sync")
2. Select an async workflow (mode="async")

Information available to you:
- Synchronous tools: Their names, parameters, and docstrings are provided separately by the system.
  Use those tool descriptions to understand exactly what each tool can do.
- Asynchronous workflows (with routing descriptions):
{workflow_descriptions}

Output contract:
- When you choose mode="sync":
  - Call the appropriate synchronous tools as needed.
  - Populate result as a SyncResult.
  - Set result.message to a clear, user-facing text answer that summarizes
    the tool outputs and directly answers the request.
- When you choose mode="async":
  - Populate result as an AsyncResult.
  - Set result.workflow_name to exactly one of the keys listed in the async workflows.
  - Do not start or run the workflow yourself; you only suggest which
    workflow should be used.

Routing rules:
- Read the user request and compare it to:
  • The capabilities described by the synchronous tools (their names, arguments, and docstrings).
  • The routing_description of each async workflow above.
- Choose mode="sync" when one or more synchronous tools can fully satisfy the request.
- Choose mode="async" when the request clearly matches a workflow's routing_description
  or requires the type of processing that workflow is designed for.
- Do NOT base the decision purely on whether the task seems long or short;
  use the described capabilities instead.
- Never invent workflow names.
- If both a tool and a workflow could handle the request, prefer mode="sync" unless
  the workflow description explicitly makes it the better fit.

测试流程与错误日志

测试提示语:How many entries are in the database

消息流程

  • ModelRequest(系统提示+用户提示)
  • ModelResponse(正确调用注册工具get_number_of_entries,参数符合预期)
  • ModelRequest(工具调用响应返回结果42)
  • ModelResponse(返回文本答案,未调用final_result工具)
  • ModelRequest(返回格式错误提示:Invalid JSON: expected ident at line 1 column 2)
  • ModelResponse(再次调用get_number_of_entries工具,误解了错误信息)
  • ModelRequest(工具再次返回结果42)
  • ModelResponse(再次返回文本答案)

最终错误

Exceeded maximum retries (1) for output validation

完整消息日志

[
    ModelRequest(
        parts=[
            SystemPromptPart(
                content=...
            ),
            UserPromptPart(
                content="How many proteins are in the database?",
            ),
        ],
    ),
    ModelResponse(
        parts=[
            ToolCallPart(
                tool_name="get_number_of_entries",
                args='{"entry_type": ...}',
            )
        ],
        model_name="llama3.1:latest",
        provider_name="ollama",
        provider_url="http://localhost:11434/v1/",
        provider_details={
            "finish_reason": "tool_calls",
        },
        finish_reason="tool_call",
    ),
    ModelRequest(
        parts=[
            ToolReturnPart(
                tool_name="get_number_of_entries",
                content=42,
            )
        ],
    ),
    ModelResponse(
        parts=[
            TextPart(
                content=...
            )
        ],
        provider_details={
            "finish_reason": "stop",
        },
        finish_reason="stop",
    ),
    ModelRequest(
        parts=[
            RetryPromptPart(
                content=[
                    {
                        "type": "json_invalid",
                        "loc": (),
                        "msg": "Invalid JSON: expected ident at line 1 column 2",
                        "input": ...,
                        "ctx": {"error": "expected ident at line 1 column 2"},
                    }
                ],
                tool_call_id="pyd_ai_286c9b4a75114705b6dbfc44f0f585ed",
            )
        ],
    ),
    ModelResponse(
        parts=[
            ToolCallPart(
                tool_name="get_number_of_entries",
                args=...,
                tool_call_id="call_9ono7lfu",
            )
        ],
        usage=RequestUsage(input_tokens=969, output_tokens=20),
        model_name="llama3.1:latest",
        provider_name="ollama",
        provider_url="http://localhost:11434/v1/",
        provider_details={
            "finish_reason": "tool_calls",
        },
        finish_reason="tool_call",
    ),
    ModelRequest(
        parts=[
            ToolReturnPart(
                tool_name="get_number_of_entries",
                content=42,
            )
        ],
    ),
    ModelResponse(
        parts=[
            TextPart(
                content=...
            )
        ],
        finish_reason="stop",
    ),
]

内容的提问来源于stack exchange,提问作者C. Zeil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 13:05:06