
Pydantic AI Interfaces 全解析同一个 Agent跑遍代码、终端、Web、前端与语音【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-aiPydantic AI 的核心设计理念之一是Agent 本身只是一段纯 Python 逻辑不绑定任何界面同一个 Agent 既可以无头运行在你的后端服务里也可以在终端里对话、在浏览器里聊天、通过协议流式喂给自建前端、嵌入编辑器、甚至进行实时的语音通话。本文基于仓库中的 interfaces.md 展开系统讲解这一界面解耦架构下各界面Interface的接入方式、配置细节与底层实现读完后你将掌握如何用一份 Agent 定义覆盖从agent.run()到claiCLI、再到 AG-UI / Vercel AI 前端协议与 Realtime 语音的全部实战场景。界面解耦Agent 是内核界面是可插拔的外壳Pydantic AI 的 Agent 不关心你在哪里跟它对话。无论界面形态如何背后都是同一个可等待awaitable的 Agent 运行机制同一套工具tools、依赖dependencies、指令instructions、消息历史message history与可观测性observability贯穿始终。官方文档用一张表概括了六种主要界面形态界面形态表现方式文档位置你的代码result await agent.run(...)在任何 Python 函数中都是普通可等待对象配合类型化输出运行 Agent终端agent.to_cli_sync()或对任意可导入 Agent 使用clai -a mymodule:agentCLIWeb 聊天内置浏览器聊天界面clai web或agent.to_web()Web Chat UI你的前端通过 AG-UI 或 Vercel AI 协议把 Agent 运行流式输出到自有 UI含 Vercel 的useChatReact hooksUI 事件流编辑器通过 Agent Client ProtocolACP把 Agent 提供给 Zed 等编辑器Harness实验性ACPHarness实验性语音同一个 Agent、工具与可观测性跑在实时音频会话上——语音只是另一种前端Realtime这一设计的直接收益是特性在所有界面间自动打通延迟工具与人工审批human-in-the-loop tool approval无论 Agent 跑在哪里都会呈现——CLI 里是审批提示前端里是审批 UI 事件同一个已部署的 Agent 可以同时为团队提供 Web UI、为产品提供 AG-UI 事件流一次 Realtime 语音会话的历史可以交接给文本运行继续处理反之亦然完整的 Agent 在任何界面都能直接运行clai -a pydantic_ai_harness.coder:coder_agent即可在终端里跑起 Harness 的 Coder。下文按界面逐层展开。界面一你的代码——五种编程式运行方式Agent 最朴素的界面就是普通 Python 调用。以 agent.md 为准共有五种运行方式覆盖同步/异步、流式/事件流/图迭代agent.run()——异步函数返回包含完整响应的RunResultagent.run_sync()——同步函数内部即loop.run_until_complete(self.run())agent.run_stream()——异步上下文管理器返回StreamedRunResult可流式获取文本与结构化输出run_stream_sync()是对应的同步变体agent.run_stream_events()——异步上下文管理器产出AgentStreamEvent事件流并以AgentRunResultEvent收尾agent.iter()——上下文管理器返回AgentRun可直接迭代 Agent 底层 pydantic-graph 的节点。最简单的用法from pydantic_ai import Agent agent Agent(openai:gpt-5.2) result agent.run_sync(What is the capital of Italy?) print(result.output) # The capital of Italy is Rome.这一界面是其他所有界面的地基to_cli()、to_web()、UI 适配器最终都在调用这类运行方法下文会看到源码证据。运行方式细节流式、事件、取消、图迭代可继续阅读 agent.md。界面二终端——clai 与 Agent.to_cli_sync()终端界面由 CLI 工具clai读作 clay提供既可以直接聊天也可以启动 uvicorn 服务器在浏览器里与 Agent 对话。安装 clai# 方式一不安装直接运行 uvx clai # 方式二用 uv 全局安装工具 uv tool install clai clai # 方式三用 pip 安装 pip install clai clai使用前需根据所用模型厂商设置环境变量例如 OpenAIexport OPENAI_API_KEYyour-api-key-here交互模式与特殊命令运行clai即进入交互式会话。内置的特殊命令包括/exit退出会话/markdown以 Markdown 格式显示上一条回复/multiline切换多行输入模式CtrlD 提交/cp复制上一条回复到剪贴板/usage显示会话累计 token 用量轮次、输入、输出、请求数、工具调用数追加--json输出单行 JSON默认启用流式输出Agent 调用的每个工具都会实时显示结果返回后标记完成无需离开终端即可观察工具调用过程传--no-stream则只打印最终答案。CLI 选项一览选项说明prompt一次性问答模式的提示词位置参数。省略则进入交互模式-m,--model模型provider:model格式如openai:gpt-5.2-a,--agent自定义 Agentmodule:variable格式-t,--code-theme语法高亮主题dark、light或任意 pygments 主题--no-stream关闭模型流式输出--mcp-configMCP 服务器配置文件路径JSON与 Claude Desktop / Claude Code / Cursor 的mcpServers结构一致-l,--list-models列出所有可用模型后退出--version显示版本后退出指定模型示例clai --model anthropic:claude-sonnet-4-6完整模型清单可用clai --list-models打印。连接 MCP 服务器clai --mcp-config mcp_servers.json配置文件与 Claude Desktop 等工具共用mcpServers结构{ mcpServers: { my-stdio-server: { command: uvx, args: [mcp_server] }, my-http-server: { url: http://localhost:8000/sse } } }安全警告配置文件会指定要作为子进程启动的可执行文件并把${VAR}引用展开为完整进程环境变量因此能写该文件的人可以执行任意命令、读取任意环境变量。--mcp-config只应传入你完全控制的文件。运行自定义 Agent--agent参数使用module:variable格式module是可导入的 Python 模块路径variable是该模块中的 Agent 实例名。例如custom_agent.pyfrom pydantic_ai import Agent agent Agent(openai:gpt-5.2, instructionsYou always respond in Italian.)然后clai --agent custom_agent:agent Whats the weather today?从 Agent 实例直接启动 CLIto_cli_sync() 与 to_cli()除了clai命令Agent 实例本身也暴露了 CLI 入口。同步版本from pydantic_ai import Agent agent Agent(openai:gpt-5.2, instructionsYou always respond in Italian.) agent.to_cli_sync()异步版本from pydantic_ai import Agent agent Agent(openai:gpt-5.2, instructionsYou always respond in Italian.) async def main(): await agent.to_cli()从源码看to_cli定义于 pydantic_ai_slim/pydantic_ai/agent/abstract.py#L2000内部委托给pydantic_ai._cli.run_chat带streamTrue、默认代码主题monokaito_cli_sync定义于 abstract.py#L2046本质是通过run_until_complete包一层to_cli。两者运行的是与clai完全相同的聊天界面因此带工具的 Agent 会逐个显示工具调用并标记完成。两个方法还支持prog_name、deps、model_settings、usage_limits、model等参数例如agent.to_cli_sync(prog_nameassistant)。携带消息历史启动 CLIto_cli()/to_cli_sync()都支持message_history参数用于延续既有对话或提供上下文from pydantic_ai import ( Agent, ModelMessage, ModelRequest, ModelResponse, TextPart, UserPromptPart, ) agent Agent(openai:gpt-5.2) # 构造一段对话历史 message_history: list[ModelMessage] [ ModelRequest([UserPromptPart(contentWhat is 22?)]), ModelResponse([TextPart(content22 equals 4.)]) ] # 带着历史进入 CLI agent.to_cli_sync(message_historymessage_history)CLI 会以提供的对话历史开局Agent 可以引用之前的问答、在整个会话中维持上下文。界面三Web 聊天——clai web 与 Agent.to_web()Pydantic AI 内置了一个浏览器聊天界面可用于快速调试任意 Agent。仓库文档明确说明该 Web UI 面向本地开发与调试生产环境应改用 UI 事件流集成 对接自建前端。安装 web extrapip/uv-add pydantic-ai-slim[web]该 extra 会安装 Starlette 与 Uvicorn。用 clai web 启动clai web -m openai:gpt-5.2默认在http://127.0.0.1:7932启动带聊天界面的 Web 服务器。更多用法# 服务自定义 Agent clai web --agent my_module:my_agent # 指定多个模型不传 --agent 时第一个为默认 clai web -m openai:gpt-5.2 -m anthropic:claude-sonnet-4-6 # 附带原生工具 clai web -m openai:gpt-5.2 -t web_search -t code_execution # 通用 Agent 系统指令 clai web -m openai:gpt-5.2 -i You are a helpful coding assistant # 自定义 Agent 每次运行的附加指令 clai web --agent my_module:my_agent -i Always respond in Spanish注意memory原生工具无法通过-t memory启用。若 Agent 需要记忆能力应直接在 Agent 上配置MemoryTool并通过--agent提供。Web UI 选项选项说明--agent,-a要服务的 Agentmodule:variable格式--model,-m在 UI 中列出的模型可重复--tool,-t在 UI 中列出的原生工具可重复可用工具见 web.md--instructions,-i系统指令指定了--agent时追加到 Agent 既有指令之后--host绑定主机默认127.0.0.1--port绑定端口默认7932--html-source聊天 UI HTML 的 URL 或文件路径--allowed-host除 IP 与localhost外额外应答的主机名可重复使用--agent时Agent 配置的模型成为默认模型CLI 的-m只是额外选项不传--agent时第一个-m模型为默认。运行clai web --help可查看全部选项。用 Agent.to_web() 创建 Web 应用Agent.to_web()返回一个配置好的 Starlette 应用可以用任意 ASGI 服务器启动from pydantic_ai import Agent agent Agent(openai:gpt-5.2, instructionsYou are a helpful assistant.) agent.tool_plain def get_weather(city: str) - str: return fThe weather in {city} is sunny app agent.to_web()uvicorn my_module:app --host 127.0.0.1 --port 7932从源码看to_web定义于 pydantic_ai_slim/pydantic_ai/agent/init.py#L4011签名包含models、deps、model_settings、instructions、html_source、allowed_hosts等参数内部调用pydantic_ai.ui._web.create_web_app组装 Starlette 应用返回的应用可挂载进 FastAPI也可直接用 uvicorn 运行。配置 UI 中的模型models可以是模型名/实例的列表也可以是显示标签 → 模型的字典from pydantic_ai import Agent from pydantic_ai.models.anthropic import AnthropicModel anthropic_model AnthropicModel(claude-sonnet-4-5) agent Agent(openai:gpt-5.2) app agent.to_web( models[openai:gpt-5.2, anthropic_model], ) # 或者带自定义显示标签 app agent.to_web( models{GPT 5.2: openai:gpt-5.2, Claude: anthropic_model}, )Agent 自身的模型始终包含在选项中每个模型的原生工具支持情况会自动按模型 profile 判定。原生工具支持在 Agent 上用capabilities[NativeTool(...)]配置原生工具即可让它们成为 UI 里的可选工具仅对支持该工具的模型显示from pydantic_ai import Agent from pydantic_ai.capabilities import NativeTool from pydantic_ai.native_tools import CodeExecutionTool, WebSearchTool agent Agent( openai:gpt-5.2, capabilities[NativeTool(CodeExecutionTool()), NativeTool(WebSearchTool())], ) app agent.to_web(models[anthropic:claude-sonnet-4-6])memory原生工具不支持通过to_web()或clai web启用需要记忆时应在构造 Agent 时直接配置MemoryTool。附加指令to_web(instructions...)传入的指令会注入每次 Agent 运行from pydantic_ai import Agent agent Agent(openai:gpt-5.2) app agent.to_web(instructionsAlways respond in a friendly tone.)工具审批Human-in-the-loop需要审批的工具会在 UI 中以批准/拒绝提示呈现Agent 调用此类工具时UI 渲染待处理的调用由你在运行继续前决定放行与否——开箱即用无需额外配置。安全警告聊天端点会执行由客户端转发的工具审批包括requires_approvalTrue的工具服务器信任收到的审批决定因此任何能访问该端点的客户端都可以批准任意待处理调用。仅绑定 localhost 本身并不构成安全边界——同浏览器打开的网页同样能访问http://127.0.0.1:7932。为此聊天端点只接受Content-Type: application/json浏览器无法在无预检的情况下跨源发送且应用只应答本地Host头。请把审批提示视为面向开发者的便利而非授权控制不要在没有前置认证的情况下把to_web()暴露给不可信客户端。主机名访问与 DNS 重绑定防护应用只应答Host头为 IP 地址127.0.0.1、[::1]或192.168.1.5这类局域网地址或localhost含my-app.localhost这类子域的请求其他Host一律返回421 Misdirected Request。主机名以 ASCII 形式比较国际化域名需以 punycode 形式列入。这正是抵御 DNS 重绑定攻击的机制——防止某个网站通过把自己控制的域名指向127.0.0.1来访问本机 UI。若要把 UI 服务在真实主机名下反向代理后、或经 ngrok 类隧道需在allowed_hosts中声明from pydantic_ai import Agent agent Agent(openai:gpt-5.2) app agent.to_web(allowed_hosts[ui.example.com]) # *.example.com 只匹配子域若同时服务主域需单独列出 app agent.to_web(allowed_hosts[example.com, *.example.com])CLI 等价写法clai web -m openai:gpt-5.2 --allowed-host ui.example.comclai web --host name会自动把该名字加入允许列表保证其打印的 URL 始终可用。所有路由都会做检查包括/api/health——健康检查或容器探针若在Host头里带 DNS 名同样得到421且监控系统往往只记录状态码问题原因可能根本到不了你手里所以探针应指向绑定的 IP 或localhost或把主机名加入允许列表。只有前置已有认证时才可传allowed_hosts[*]应答任意主机也不要为可被他人随意注册子域的域名开通配符否则会重新打开该问题。保留路由Web UI 应用使用以下路由不应覆盖/与/{id}——提供聊天 UI/api/chat——聊天端点POST、OPTIONS要求Content-Type: application/json其他类型返回415/api/configure——前端配置GET/api/health——健康检查GET应用目前不能挂载在子路径如/chat下因为 UI 期望这些路由位于根路径。可以给应用追加其他路由但需避开上述保留路径。自定义 HTML离线与隔离部署默认情况下 Web UI 从 CDN 拉取并在本地缓存。可通过html_source覆盖用于离线或企业内网环境。默认 UI 构建被拆成许多文件index.html引用样式表并在运行时按需懒加载语法高亮、图表和数学公式等 chunk——这些引用都指向 CDN单独下载index.html会让页面启动后一遇到代码块或公式就渲染失败。应改用离线构建offline build——把所有 chunk、字体、图标内联进单个自包含文件除自身服务器外不再需要网络from pydantic_ai.ui import OFFLINE_HTML_URL print(OFFLINE_HTML_URL) # 用这个 URL 下载自包含的 UI HTML 文件 # https://cdn.jsdelivr.net/npm/pydantic/ai-chat-ui2.1.0/offline/index.html在有网的机器上下载一次再移入隔离环境curl -o ~/pydantic-ai-ui.html chat_ui_url然后用html_source指向本地文件或自定义 URLfrom pydantic_ai import Agent agent Agent(openai:gpt-5.2) # 使用本地文件例如离线场景 app agent.to_web(html_source~/pydantic-ai-ui.html) # 或使用自定义 URL例如企业环境 app agent.to_web(html_sourcehttps://cdn.example.com/ui/index.html)离线文件约 16 MB——这并非额外体积而是搬迁默认构建把同样的资源分散在 400 多个文件里由浏览器按需从 CDN 拉取离线构建则把全部资源前置进第一次请求。默认的to_web()路径不变仍使用分体构建from pydantic_ai.ui import DEFAULT_HTML_URL print(DEFAULT_HTML_URL) # https://cdn.jsdelivr.net/npm/pydantic/ai-chat-ui2.1.0/dist/index.html界面四你的前端——AG-UI 与 Vercel AI 协议当需要把 Agent 接入自有前端聊天应用或其他交互式 UI时典型做法是让后端接收前端输入聊天消息或完整消息历史并把 Agent 运行中的事件文本、思考、工具调用等实时流回前端。Pydantic AI 原生支持两种 UI 事件流协议详见 ui/overview.mdAgent-User InteractionAG-UI协议ag-ui.md由 CopilotKit 团队提出的开放标准支持流式、前端工具、共享状态与自定义事件Vercel AI Data Stream 协议vercel-ai.md可对接 Vercel 的useChatReact hooks。两者都实现为抽象基类UIAdapter的子类AGUIAdapter/VercelAIAdapter因此它们本身就是对接其他协议时的参考实现。适配器负责把前端发来的运行输入转换为Agent.run_stream_events()的参数、运行 Agent再把 Pydantic AI 事件转换为协议事件事件流转换由协议专属的UIEventStream子类完成。Starlette/FastAPI 下的最简接入UIAdapter.dispatch_request()类方法可直接从端点处理请求并返回协议事件的流式响应from fastapi import FastAPI from starlette.requests import Request from starlette.responses import Response from pydantic_ai import Agent from pydantic_ai.ui.vercel_ai import VercelAIAdapter agent Agent(openai:gpt-5.2) app FastAPI() app.post(/chat) async def chat(request: Request) - Response: return await VercelAIAdapter.dispatch_request(request, agentagent)它接受与Agent.run_stream_events()相同的可选参数另有on_complete回调成功运行与on_cancel回调收到RunCancelled的首方取消客户端断连属外部取消不会触发。两个回调都可额外产出协议事件。非 Starlette 框架的高级用法Django、Flask 等非 Starlette 框架或需要细粒度控制时可手动链式调用适配器方法UIAdapter.build_run_input()——把请求体字节解析为协议运行输入对象也可用UIAdapter.from_request()直接从 Starlette/FastAPI 请求构建适配器UIAdapter.run_stream()——运行 Agent 并返回协议事件流支持与run_stream_events()相同的可选参数或run_stream_native()返回 Pydantic AI 原生事件流再用transform_stream()转换UIAdapter.encode_stream()——把协议事件流编码为 SSE 字符串或streaming_response()直接生成 Starlette/FastAPI 流式响应。import json from http import HTTPStatus from fastapi import FastAPI from fastapi.requests import Request from fastapi.responses import Response, StreamingResponse from pydantic import ValidationError from pydantic_ai import Agent from pydantic_ai.ui import SSE_CONTENT_TYPE from pydantic_ai.ui.vercel_ai import VercelAIAdapter agent Agent(openai:gpt-5.2) app FastAPI() app.post(/chat) async def chat(request: Request) - Response: accept request.headers.get(accept, SSE_CONTENT_TYPE) try: run_input VercelAIAdapter.build_run_input(await request.body()) except ValidationError as e: return Response( contentjson.dumps(e.json()), media_typeapplication/json, status_codeHTTPStatus.UNPROCESSABLE_ENTITY, ) adapter VercelAIAdapter(agentagent, run_inputrun_input, acceptaccept) event_stream adapter.run_stream() sse_event_stream adapter.encode_stream(event_stream) return StreamingResponse(sse_event_stream, media_typeaccept)无请求场景的事件编码当 Agent 不在服务前端的那个请求里运行例如事件经持久执行工作流、消息队列或 websocket 扇出到达时没有请求体可构造运行输入也没有适配器去运行 Agent。此时应单独使用协议专属的UIEventStream子类from collections.abc import AsyncIterator from pydantic_ai.ui import NativeEvent from pydantic_ai.ui.vercel_ai import VercelAIEventStream async def encode_events(events: AsyncIterator[NativeEvent]) - AsyncIterator[str]: event_stream VercelAIEventStream() async for sse_event in event_stream.encode_stream(event_stream.transform_stream(events)): yield sse_event注意事件流实例承载单次运行的状态当前消息 ID、正在流式的 part、等待中的工具调用因此每次运行都应新建一个。AG-UI 协议用thread_id与run_id标识每次运行——在可重放的持久执行工作流里构造流需要显式传入这两个 ID否则每次重放都会重新生成默认 UUID破坏确定性。客户端提交消息的信任模型UI 适配器端点不是认证边界。AG-UI 与 Vercel AI 协议都设计为客户端在每次请求中传输完整对话历史因此协议中的message_history助手消息、工具调用、文件 URL、工具结果都处于调用方控制之下。适配器端点应作为内部后端服务运行在你自己已认证的路由处理器内。适配器默认做了几项收紧让权威状态始终留在服务端系统提示客户端提交的SystemPromptPart默认被剔除替换为 Agent 配置的提示可用UIAdapter.manage_system_prompt控制悬空工具调用若客户端提交的历史以含未解析ToolCallPart且无匹配deferred_tool_results的ModelResponse结尾工具调用会被丢弃并告警避免 Agent 执行模型从未发出的未解析调用人工审批续跑时须显式传deferred_tool_results文件 URL scheme客户端消息中的FileUrl默认只接受http/httpss3://、gs://等非 HTTP scheme 会被丢弃否则提供方会用你服务器的 IAM 角色或服务账号去拉取对象文件 URL 下载模式客户端提交的FileUrl.force_download非False值默认重置为False防止客户端迫使服务器抓取 URL 或借allow-local绕过 SSRF 私网 IP 拦截上传文件客户端提交的UploadedFile默认被丢弃原因同上服务器会用自己的凭据解析提供方文件存储 API。另一个关键点是工具审批与结果由客户端提交审批/拒绝/外部执行结果随历史一起由客户端传入适配器不校验被批准的工具调用是否真是服务器发出的因此审批防范的是模型未经人工确认就行动而不是对客户端的授权边界。敏感操作的授权应放在工具函数内部、依据认证用户来自依赖执行或把暂停的运行持久化在服务端自行传入deferred_tool_results。界面五语音——Realtime 实时对话Realtime 支持让 Agent 进行实时语音对话把用户音频流式传给语音到语音speech-to-speech模型再把模型的口语回复沿一条持久连接流回延迟低、打断自然。语音会话使用与文本 Agent 完全相同的工具、依赖、指令、消息历史、capabilities、用量限制与可观测性——通话中 Agent 可以用同一套工具查询订单、检查库存或基于登录用户数据行动。通话本身变成普通消息历史可以交给Agent.run()做摘要或结构化跟进同一份代码支持多厂商用量限制与 Logfire 追踪内建。你的应用负责音频传输经后端桥接或 OpenAI/Azure 上浏览器直连 WebRTCPydantic AI 则运行厂商无关的 Agent 主循环。完整接入见 realtime/overview.md。编辑器与 Harness对 Zed 等编辑器可通过 Agent Client ProtocolACP把 Agent 服务到编辑器内Harness实验性。interfaces.md 特别给出一个跨界面复用的例子clai -a pydantic_ai_harness.coder:coder_agent可直接在终端运行 Harness 的 Coder——同一个 Agent 定义被不同界面直接消费无需任何改动。跨界面通用的能力界面解耦带来的核心红利是同一份特性与同一份 Agent 到处可用延迟工具与审批无论 Agent 在 CLI、Web UI 还是你的前端里运行需要人工审批的工具都会以对应形态呈现CLI 审批提示 / 前端审批事件实现见 deferred-tools.md同一部署多界面并存一个已部署的 Agent 可以同时为团队提供 Web UI、为产品提供 AG-UI 事件流界面间历史交接Realtime 语音会话的历史可以交给文本运行继续摘要或结构化跟进反之亦然完整 Agent 即插即用clai -a module:agent、agent.to_cli_sync()、agent.to_web()都直接消费同一 Agent 实例工具、依赖、输出类型无需任何界面适配代码。小结Pydantic AI 的 Interfaces 设计把Agent 内核与交互界面彻底解耦编程调用是地基clai/to_cli_sync()提供终端clai web/to_web()提供内置浏览器聊天AG-UI 与 Vercel AI 适配器UIAdapter及其子类对接自建前端Realtime 覆盖实时语音ACP 对接编辑器。所有界面共享同一套工具、依赖、审批与消息历史机制——从源码abstract.py 中的to_cli/to_cli_syncagent/init.py 中的to_web到文档cli.md、web.md、ui/overview.md、realtime/overview.md都印证了这一点。实际项目中你可以先用clai快速验证 Agent 行为再通过to_web()或协议适配器把同一个 Agent 平滑地接入产品级前端。【免费下载链接】pydantic-aiHow Python does AI. Agents, realtime voice, image generation, embeddings. Every model, every interface, typed end to end.项目地址: https://gitcode.com/GitHub_Trending/py/pydantic-ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考