Skip to content

2.4 Pydantic:数据验证的利器

为什么选择 Pydantic?

TypedDict 提供类型提示,但不做运行时验证。Pydantic 提供:

  • ✅ 运行时数据验证
  • ✅ 自动类型转换
  • ✅ 详细的错误信息
  • ✅ JSON 序列化/反序列化

LangChain 和 LangGraph 大量使用 Pydantic!

🎯 小白理解指南:TypedDict vs Pydantic 有什么区别?

想象你在开一家餐厅:

TypedDict 就像菜单上写着"价格是数字"

  • 顾客看到了知道应该填数字
  • 但如果顾客非要写"五十块",系统不会阻止
  • 只是一个"提示",不强制执行

Pydantic 就像收银系统

  • 必须是数字才能结账
  • 写"五十块"会报错:"请输入数字!"
  • 写"50.0"会自动转成 50
  • 真正的"验证",确保数据正确

为什么 LangChain/LangGraph 用 Pydantic? 因为 AI 工具需要接收各种用户输入,必须确保数据格式正确才能正常工作。比如:温度必须在 0-2 之间,API Key 不能为空……

基础用法

🎯 小白理解指南:Pydantic 代码怎么读?

python
class AgentConfig(BaseModel):
    temperature: float = Field(default=0.7, ge=0, le=2)

这行代码的意思是:

  • temperature:字段名叫"温度"
  • float:类型是小数
  • default=0.7:如果不填,默认是 0.7
  • ge=0:必须大于等于(greater or equal)0
  • le=2:必须小于等于(less or equal)2

所以 temperature 必须是 0 到 2 之间的小数,否则报错!

python
from pydantic import BaseModel, Field, validator
from typing import Optional

class AgentConfig(BaseModel):
    """Agent 配置模型"""
    model: str = Field(description="模型名称")
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: int = Field(default=2000, gt=0)
    api_key: Optional[str] = None

    @validator("model")
    def validate_model(cls, v):
        """验证模型名称"""
        allowed = ["gpt-3.5-turbo", "gpt-4", "claude-3-opus"]
        if v not in allowed:
            raise ValueError(f"模型必须是 {allowed} 之一")
        return v

# 创建实例(自动验证)
config = AgentConfig(
    model="gpt-4",
    temperature=0.5,
    max_tokens=3000
)

print(config.model_dump())  # 转为字典
print(config.model_dump_json())  # 转为 JSON

字段验证

🎯 小白理解指南:@validator 和 @field_validator 是什么?

这些是自定义验证器——当内置的验证规则不够用时,你可以写自己的验证逻辑。

比如:

  • Field(ge=0) 只能检查"大于等于0"
  • 但"内容不能是纯空格"这种规则,需要自己写

@field_validator("content") 的意思是:"当设置 content 字段时,先执行下面这个函数检查一下"。

python
from pydantic import BaseModel, Field, field_validator

class Message(BaseModel):
    role: str = Field(pattern="^(user|assistant|system)$")
    content: str = Field(min_length=1, max_length=10000)
    timestamp: float = Field(gt=0)

    @field_validator("content")
    @classmethod
    def content_not_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError("内容不能为空白")
        return v.strip()

# 使用
msg = Message(
    role="user",
    content="  Hello  ",
    timestamp=1234567890.0
)
print(msg.content)  # "Hello" (已去除空格)

在 LangChain 中的应用

🎯 小白理解指南:为什么 LangChain Tool 需要 Pydantic?

AI Agent 在调用工具时,需要知道:

  1. 工具需要什么参数?(参数名、类型)
  2. 参数有什么限制?(最小值、最大值、格式)

Pydantic 的 args_schema 帮 AI 理解"这个工具怎么用",同时确保 AI 传入的参数是合法的。

比如搜索工具:AI 必须传入一个至少 2 个字符的查询词,最多返回 20 条结果。

Tool 参数验证

python
from langchain.tools import tool
from pydantic import BaseModel, Field

class SearchInput(BaseModel):
    """搜索工具输入"""
    query: str = Field(description="搜索查询", min_length=2)
    max_results: int = Field(default=5, ge=1, le=20)
    language: str = Field(default="zh", pattern="^(zh|en)$")

@tool(args_schema=SearchInput)
def search_web(query: str, max_results: int = 5, language: str = "zh") -> str:
    """搜索网络"""
    return f"搜索 '{query}': {max_results} 个结果 ({language})"

# Pydantic 自动验证参数!

实战:完整的 Agent 配置系统

python
from pydantic import BaseModel, Field, field_validator
from typing import Optional, Literal
import os

class LLMConfig(BaseModel):
    """LLM 配置"""
    provider: Literal["openai", "anthropic"] = "openai"
    model: str = Field(description="模型名称")
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: int = Field(default=2000, gt=0, le=100000)
    api_key: Optional[str] = None
    
    @field_validator("api_key")
    @classmethod
    def load_api_key(cls, v: Optional[str], info) -> str:
        """从环境变量加载 API 密钥"""
        if v:
            return v
        
        provider = info.data.get("provider", "openai")
        env_var = f"{provider.upper()}_API_KEY"
        key = os.getenv(env_var)
        
        if not key:
            raise ValueError(f"未找到 {env_var} 环境变量")
        return key

class AgentConfig(BaseModel):
    """完整的 Agent 配置"""
    name: str = Field(description="Agent 名称")
    llm: LLMConfig
    system_prompt: str = Field(default="You are a helpful assistant.")
    tools: list[str] = Field(default_factory=list)
    max_iterations: int = Field(default=10, gt=0, le=50)
    
    class Config:
        # 允许从环境变量读取
        env_prefix = "AGENT_"

# 使用
config = AgentConfig(
    name="ResearchBot",
    llm=LLMConfig(
        provider="openai",
        model="gpt-4",
        temperature=0.5
    ),
    tools=["search", "calculator"]
)

print(config.model_dump_json(indent=2))

下一节:2.5 实战:LangGraph 状态系统

基于 MIT 许可证发布。内容版权归作者所有。