[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-3c192478-4848-489b-b160-71b75e226c82":3,"$fzcPX6dx2eDeVbkK4J8CDx2OTT3g_NBJEtNQmOsQeyQc":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"3c192478-4848-489b-b160-71b75e226c82","pydantic-ai","使用PydanticAI构建生产就绪的AI代理——类型安全工具使用、结构化输出、依赖注入和多模型支持。","cat_coding_backend","mod_coding","sickn33,coding","---\nname: pydantic-ai\ndescription: \"Build production-ready AI agents with PydanticAI — type-safe tool use, structured outputs, dependency injection, and multi-model support.\"\ncategory: ai-agents\nrisk: safe\nsource: community\ndate_added: \"2026-03-18\"\nauthor: suhaibjanjua\ntags: [pydantic-ai, ai-agents, llm, openai, anthropic, gemini, tool-use, structured-output, python]\ntools: [claude, cursor, gemini]\n---\n\n# PydanticAI — Typed AI Agents in Python\n\n## Overview\n\nPydanticAI is a Python agent framework from the Pydantic team that brings the same type-safety and validation guarantees as Pydantic to LLM-based applications. It supports structured outputs (validated with Pydantic models), dependency injection for testability, streamed responses, multi-turn conversations, and tool use — across OpenAI, Anthropic, Google Gemini, Groq, Mistral, and Ollama. Use this skill when building production AI agents, chatbots, or LLM pipelines where correctness and testability matter.\n\n## When to Use This Skill\n\n- Use when building Python AI agents that call tools and return structured data\n- Use when you need validated, typed LLM outputs (not raw strings)\n- Use when you want to write unit tests for agent logic without hitting a real LLM\n- Use when switching between LLM providers without rewriting agent code\n- Use when the user asks about `Agent`, `@agent.tool`, `RunContext`, `ModelRetry`, or `result_type`\n\n## How It Works\n\n### Step 1: Installation\n\n```bash\npip install pydantic-ai\n\n# Install extras for specific providers\npip install 'pydantic-ai[openai]'       # OpenAI \u002F Azure OpenAI\npip install 'pydantic-ai[anthropic]'    # Anthropic Claude\npip install 'pydantic-ai[gemini]'       # Google Gemini\npip install 'pydantic-ai[groq]'         # Groq\npip install 'pydantic-ai[vertexai]'     # Google Vertex AI\n```\n\n### Step 2: A Minimal Agent\n\n```python\nfrom pydantic_ai import Agent\n\n# Simple agent — returns a plain string\nagent = Agent(\n    'anthropic:claude-sonnet-4-6',\n    system_prompt='You are a helpful assistant. Be concise.',\n)\n\nresult = agent.run_sync('What is the capital of Japan?')\nprint(result.data)  # \"Tokyo\"\nprint(result.usage())  # Usage(requests=1, request_tokens=..., response_tokens=...)\n```\n\n### Step 3: Structured Output with Pydantic Models\n\n```python\nfrom pydantic import BaseModel\nfrom pydantic_ai import Agent\n\nclass MovieReview(BaseModel):\n    title: str\n    year: int\n    rating: float  # 0.0 to 10.0\n    summary: str\n    recommended: bool\n\nagent = Agent(\n    'openai:gpt-4o',\n    result_type=MovieReview,\n    system_prompt='You are a film critic. Return structured reviews.',\n)\n\nresult = agent.run_sync('Review Inception (2010)')\nreview = result.data  # Fully typed MovieReview instance\nprint(f\"{review.title} ({review.year}): {review.rating}\u002F10\")\nprint(f\"Recommended: {review.recommended}\")\n```\n\n### Step 4: Tool Use\n\nRegister tools with `@agent.tool` — the LLM can call them during a run:\n\n```python\nfrom pydantic_ai import Agent, RunContext\nfrom pydantic import BaseModel\nimport httpx\n\nclass WeatherReport(BaseModel):\n    city: str\n    temperature_c: float\n    condition: str\n\nweather_agent = Agent(\n    'anthropic:claude-sonnet-4-6',\n    result_type=WeatherReport,\n    system_prompt='Get current weather for the requested city.',\n)\n\n@weather_agent.tool\nasync def get_temperature(ctx: RunContext, city: str) -> dict:\n    \"\"\"Fetch the current temperature for a city from the weather API.\"\"\"\n    async with httpx.AsyncClient() as client:\n        r = await client.get(f'https:\u002F\u002Fwttr.in\u002F{city}?format=j1')\n        data = r.json()\n        return {\n            'temp_c': float(data['current_condition'][0]['temp_C']),\n            'description': data['current_condition'][0]['weatherDesc'][0]['value'],\n        }\n\nimport asyncio\nresult = asyncio.run(weather_agent.run('What is the weather in Tokyo?'))\nprint(result.data)\n```\n\n### Step 5: Dependency Injection\n\nInject services (database, HTTP clients, config) into agents for testability:\n\n```python\nfrom dataclasses import dataclass\nfrom pydantic_ai import Agent, RunContext\nfrom pydantic import BaseModel\n\n@dataclass\nclass Deps:\n    db: Database\n    user_id: str\n\nclass SupportResponse(BaseModel):\n    message: str\n    escalate: bool\n\nsupport_agent = Agent(\n    'openai:gpt-4o-mini',\n    deps_type=Deps,\n    result_type=SupportResponse,\n    system_prompt='You are a support agent. Use the tools to help customers.',\n)\n\n@support_agent.tool\nasync def get_order_history(ctx: RunContext[Deps]) -> list[dict]:\n    \"\"\"Fetch recent orders for the current user.\"\"\"\n    return await ctx.deps.db.get_orders(ctx.deps.user_id, limit=5)\n\n@support_agent.tool\nasync def create_refund(ctx: RunContext[Deps], order_id: str, reason: str) -> dict:\n    \"\"\"Initiate a refund for a specific order.\"\"\"\n    return await ctx.deps.db.create_refund(order_id, reason, ctx.deps.user_id)\n\n# Usage\nasync def handle_support(user_id: str, message: str):\n    deps = Deps(db=get_db(), user_id=user_id)\n    result = await support_agent.run(message, deps=deps)\n    return result.data\n```\n\n### Step 6: Testing with TestModel\n\nWrite unit tests without real LLM calls:\n\n```python\nfrom pydantic_ai.models.test import TestModel\n\ndef test_support_agent_escalates():\n    with support_agent.override(model=TestModel()):\n        # TestModel returns a minimal valid response matching result_type\n        result = support_agent.run_sync(\n            'I want to cancel my account',\n            deps=Deps(db=FakeDb(), user_id='user-123'),\n        )\n    # Test the structure, not the LLM's exact words\n    assert isinstance(result.data, SupportResponse)\n    assert isinstance(result.data.escalate, bool)\n```\n\n**FunctionModel** for deterministic test responses:\n\n```python\nfrom pydantic_ai.models.function import FunctionModel, ModelContext\n\ndef my_model(messages, info):\n    return ModelResponse(parts=[TextPart('Always this response')])\n\nwith agent.override(model=FunctionModel(my_model)):\n    result = agent.run_sync('anything')\n```\n\n### Step 7: Streaming Responses\n\n```python\nimport asyncio\nfrom pydantic_ai import Agent\n\nagent = Agent('anthropic:claude-sonnet-4-6')\n\nasync def stream_response():\n    async with agent.run_stream('Write a haiku about Python') as result:\n        async for chunk in result.stream_text():\n            print(chunk, end='', flush=True)\n    print()  # newline\n    print(f\"Total tokens: {result.usage()}\")\n\nasyncio.run(stream_response())\n```\n\n### Step 8: Multi-Turn Conversations\n\n```python\nfrom pydantic_ai import Agent\nfrom pydantic_ai.messages import ModelMessagesTypeAdapter\n\nagent = Agent('openai:gpt-4o', system_prompt='You are a helpful assistant.')\n\n# First turn\nresult1 = agent.run_sync('My name is Alice.')\nhistory = result1.all_messages()\n\n# Second turn — passes conversation history\nresult2 = agent.run_sync('What is my name?', message_history=history)\nprint(result2.data)  # \"Your name is Alice.\"\n```\n\n## Examples\n\n### Example 1: Code Review Agent\n\n```python\nfrom pydantic import BaseModel, Field\nfrom pydantic_ai import Agent\nfrom typing import Literal\n\nclass CodeReview(BaseModel):\n    quality: Literal['excellent', 'good', 'needs_work', 'poor']\n    issues: list[str] = Field(default_factory=list)\n    suggestions: list[str] = Field(default_factory=list)\n    approved: bool\n\ncode_review_agent = Agent(\n    'anthropic:claude-sonnet-4-6',\n    result_type=CodeReview,\n    system_prompt=\"\"\"\n    You are a senior engineer performing code review.\n    Evaluate code quality, identify issues, and provide actionable suggestions.\n    Set approved=True only for good or excellent quality code with no security issues.\n    \"\"\",\n)\n\ndef review_code(diff: str) -> CodeReview:\n    result = code_review_agent.run_sync(f\"Review this code:\\n\\n{diff}\")\n    return result.data\n```\n\n### Example 2: Agent with Retry Logic\n\n```python\nfrom pydantic_ai import Agent, ModelRetry\nfrom pydantic import BaseModel, field_validator\n\nclass StrictJson(BaseModel):\n    value: int\n\n    @field_validator('value')\n    def must_be_positive(cls, v):\n        if v \u003C= 0:\n            raise ValueError('value must be positive')\n        return v\n\nagent = Agent('openai:gpt-4o-mini', result_type=StrictJson)\n\n@agent.result_validator\nasync def validate_result(ctx, result: StrictJson) -> StrictJson:\n    if result.value > 1000:\n        raise ModelRetry('Value must be under 1000. Try again with a smaller number.')\n    return result\n```\n\n### Example 3: Multi-Agent Pipeline\n\n```python\nfrom pydantic_ai import Agent\nfrom pydantic import BaseModel\n\nclass ResearchSummary(BaseModel):\n    key_points: list[str]\n    conclusion: str\n\nclass BlogPost(BaseModel):\n    title: str\n    body: str\n    meta_description: str\n\nresearcher = Agent('openai:gpt-4o', result_type=ResearchSummary)\nwriter = Agent('anthropic:claude-sonnet-4-6', result_type=BlogPost)\n\nasync def research_and_write(topic: str) -> BlogPost:\n    # Stage 1: research\n    research = await researcher.run(f'Research the topic: {topic}')\n\n    # Stage 2: write based on research\n    post = await writer.run(\n        f'Write a blog post about: {topic}\\n\\nResearch:\\n' +\n        '\\n'.join(f'- {p}' for p in research.data.key_points) +\n        f'\\n\\nConclusion: {research.data.conclusion}'\n    )\n    return post.data\n```\n\n## Best Practices\n\n- ✅ Always define `result_type` with a Pydantic model — avoid returning raw strings in production\n- ✅ Use `deps_type` with a dataclass for dependency injection — makes agents testable\n- ✅ Use `TestModel` in unit tests — never hit a real LLM in CI\n- ✅ Add `@agent.result_validator` for business-logic checks beyond Pydantic validation\n- ✅ Use `run_stream` for long outputs in user-facing applications to show progressive results\n- ❌ Don't put secrets (API keys) in `Agent()` arguments — use environment variables\n- ❌ Don't share a single `Agent` instance across async tasks if deps differ — create per-request instances or use `agent.run()` with per-call `deps`\n- ❌ Don't catch `ValidationError` broadly — let PydanticAI retry with `ModelRetry` for recoverable LLM output errors\n\n## Security & Safety Notes\n\n- Set API keys via environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.) — never hardcode them.\n- Validate all tool inputs before passing to external systems — use Pydantic models or manual checks.\n- Tools that mutate data (write to DB, send emails, call payment APIs) should require explicit user confirmation before the agent invokes them in production.\n- Log `result.all_messages()` for audit trails when agents perform consequential actions.\n- Set `retries=` limits on `Agent()` to prevent runaway loops on persistent validation failures.\n\n## Common Pitfalls\n\n- **Problem:** `ValidationError` on every LLM response — structured output never validates\n  **Solution:** Simplify `result_type` fields. Use `Optional` and `default` where appropriate. The model may struggle with overly strict schemas.\n\n- **Problem:** Tool is never called by the LLM\n  **Solution:** Write a clear, specific docstring for the tool function — PydanticAI sends the docstring as the tool description to the LLM.\n\n- **Problem:** `RunContext` dependency is `None` inside a tool\n  **Solution:** Pass `deps=` when calling `agent.run()` or `agent.run_sync()`. Dependencies are not set globally.\n\n- **Problem:** `asyncio.run()` error when calling `agent.run()` inside FastAPI\n  **Solution:** Use `await agent.run()` directly in async FastAPI route handlers — don't wrap in `asyncio.run()`.\n\n## Related Skills\n\n- `@langchain-architecture` — Alternative Python AI framework (more flexible, less type-safe)\n- `@llm-application-dev-ai-assistant` — General LLM application development patterns\n- `@fastapi-templates` — Serving PydanticAI agents via FastAPI endpoints\n- `@agent-orchestration-multi-agent-optimize` — Orchestrating multiple PydanticAI agents\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,71,1629,"2026-05-16 13:35:47",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":42},"d8a24dc5-e9c6-4bad-8302-beb7f6b60eb4","1.0.0","pydantic-ai.zip",4705,"uploads\u002Fskills\u002F3c192478-4848-489b-b160-71b75e226c82\u002Fpydantic-ai.zip","da1de99b4c060e03c9b19d967e3a59453ba5309d34399dbe01e2adf931209f9d","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":12133}]","2026-05-16 13:35:48",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]