返回资源广场

Skills 资源 / 技能包

extracting-structured-output

让 LangChain Agent 不返回自由文本,而是返回经 Pydantic 校验、下游程序可直接按字段取值的结构化对象。Use when 需要从文本里抽字段(评论分类、订单要素、简历解析、工单分级)、要把模型输出接进统计或数据库、或排查「让模型输出 JSON 结果却是中文键名与字符串数字」「ProviderStrategy 报 400 This response_format type is unavailable now」这类问题时。涵盖 schema 定义、response_format 配置、structured_response 消费、两种策略选型与兼容边界、批量抽取;不含工具调用循环本身(见 building-tool-calling-agent)。

SKILL.md 技能文档

能力目标

给 create_agent 传一个 response_format,让每次调用除消息流外再返回一个经校验的 Python 对象:下游程序直接 .字段名 取值、拿到的整数就是 int、键名由 schema 锁定,无需任何字符串解析,可直接进统计、报表或自动化流程。

前置

  • 已能用 create_agent 组装 Agent(见 building-tool-calling-agent)。
  • schema 用 Pydantic 定义,pydantic 随 langchain 一并装好,无需单独安装。
  • 模型需支持工具调用——结构化输出的通用策略正是借工具调用协议实现的。

实操流程

  1. 定义 schema:继承 BaseModel,每个字段给类型注解与 Field(description=...)。描述文字会被传给模型,直接引导它「这个字段该填什么」,是抽取质量的关键:

    # schemas.py
    from pydantic import BaseModel, Field
    
    class ReviewAnalysis(BaseModel):
        """客户评论分析结果"""
        sentiment: str = Field(description="情感极性:positive / negative / neutral")
        category: str = Field(description="问题类别:logistics / product_quality / refund 等")
        urgency: int = Field(description="紧急程度,1-5 的整数,5 最紧急")
    
    python3 schemas.py    # 跑一次 __main__ 块,确认字段列表正确、能实例化
    
  2. 把 schema 用策略类包一层传给 response_format。默认走 ToolStrategy——它把 schema 的字段封装成一个工具的参数,让模型以「填参数」的方式产出结构化结果,适用于任何支持工具调用的模型:

    # step3_create_agent_structured.py
    from langchain.agents import create_agent
    from langchain.agents.structured_output import ToolStrategy
    from schemas import ReviewAnalysis
    
    agent = create_agent(
        model="deepseek:deepseek-chat",
        tools=[],
        response_format=ToolStrategy(ReviewAnalysis),
    )
    

    纯抽取任务 tools 传空列表即可。返回类型仍是 CompiledStateGraph,只是在生成最终回答前多走一道按 schema 约束输出的环节。

  3. 调用并读结构化结果。开启后 result 多出 structured_response 这个 key:

    result = agent.invoke({"messages": [{"role": "user", "content": review_text}]})
    print("result keys:", list(result.keys()))     # ['messages', 'structured_response']
    sr = result["structured_response"]
    print(type(sr).__name__, sr.sentiment, sr.category, sr.urgency)
    

    sr 是真正的 Python 对象(类型就是你定义的类),不是字符串也不是字典;urgency 拿到的是整数 5 而非字符串 "5"。

  4. 批量处理时一次组装、循环调用,结果可直接计算:

    from collections import Counter
    
    results = [agent.invoke({"messages": [{"role": "user", "content": t}]})["structured_response"]
               for t in reviews]
    print("情感分布:", Counter(r.sentiment for r in results))
    print("平均紧急度:", round(sum(r.urgency for r in results) / len(results), 1))
    
  5. 换业务只换 schema 类,其余代码不动:

    from schemas import OrderInfo
    agent = create_agent(model="deepseek:deepseek-chat", tools=[],
                         response_format=ToolStrategy(OrderInfo))
    

校验回路

  1. 单条抽取:result 里有 structured_response key,且它的类型是你定义的 schema 类。
  2. 字段取值:逐个 .字段名 取值,确认值与类型都符合声明(整数字段是 int 而不是字符串)。
  3. 批量复用:循环处理多条文本全部返回实例,能直接用 Counter / sum 统计而不做任何字符串解析。

三项都过,说明结构化输出在你的业务上闭环。

常见陷阱

  • 靠提示词让模型「输出 JSON」当作结构化:即便提示了 JSON,模型也会自由发挥——实测拿到的是中文键名「情感极性」、值是字符串「高」,类型不安全、键名不可控,下游还得手写解析。真正的结构化必须走 response_format + schema 校验。
  • 在 DeepSeek 上用 ProviderStrategy:会直接报 BadRequestError 400: This response_format type is unavailable now。这不是代码写错,是该提供方没有原生结构化输出端点。选型按兼容性:DeepSeek 与本地 Ollama 只能用 ToolStrategy;OpenAI、Anthropic 两种都可用,原生策略在 API 层硬约束、更稳。默认写 ToolStrategy,只有确认提供方支持原生端点时才换。
  • 直接把 schema 类裸传 response_format:可以,框架会自动选策略,在不支持原生端点的提供方上自动降级到 ToolStrategy,结果与显式写完全一致。想让选型意图可读就显式写。
  • 字段取值不受控:没加枚举约束的字段,模型可能填中文而非预期英文;同一段文本多次调用的分类也可能有细微差异。要锁死取值范围就用 Literal 类型注解,或在字段描述里明确列出可选项。
  • 误以为模型填的值一定合法:有两层保护——字段描述在源头引导(描述写「1-5 的整数」时,模型面对「10 级紧急」的文本仍会收敛到 5),Pydantic 校验在末端拦截(越界值抛 ValidationError 并指明字段)。要强约束就把范围写进字段描述并加校验器,别只靠模型自觉。

适用范围与前置条件

  • 已能用 create_agent 组装 Agent(见 building-tool-calling-agent)。
  • schema 用 Pydantic 定义,pydantic 随 langchain 一并装好,无需单独安装。
  • 模型需支持工具调用——结构化输出的通用策略正是借工具调用协议实现的。

怎么使用

使用步骤

  1. 定义 schema:继承 BaseModel,每个字段给类型注解与 Field(description=...)。描述文字会被传给模型,直接引导它「这个字段该填什么」,是抽取质量的关键:

    # schemas.py
    from pydantic import BaseModel, Field
    
    class ReviewAnalysis(BaseModel):
        """客户评论分析结果"""
        sentiment: str = Field(description="情感极性:positive / negative / neutral")
        category: str = Field(description="问题类别:logistics / product_quality / refund 等")
        urgency: int = Field(description="紧急程度,1-5 的整数,5 最紧急")
    
    python3 schemas.py    # 跑一次 __main__ 块,确认字段列表正确、能实例化
    
  2. 把 schema 用策略类包一层传给 response_format。默认走 ToolStrategy——它把 schema 的字段封装成一个工具的参数,让模型以「填参数」的方式产出结构化结果,适用于任何支持工具调用的模型:

    # step3_create_agent_structured.py
    from langchain.agents import create_agent
    from langchain.agents.structured_output import ToolStrategy
    from schemas import ReviewAnalysis
    
    agent = create_agent(
        model="deepseek:deepseek-chat",
        tools=[],
        response_format=ToolStrategy(ReviewAnalysis),
    )
    

    纯抽取任务 tools 传空列表即可。返回类型仍是 CompiledStateGraph,只是在生成最终回答前多走一道按 schema 约束输出的环节。

  3. 调用并读结构化结果。开启后 result 多出 structured_response 这个 key:

    result = agent.invoke({"messages": [{"role": "user", "content": review_text}]})
    print("result keys:", list(result.keys()))     # ['messages', 'structured_response']
    sr = result["structured_response"]
    print(type(sr).__name__, sr.sentiment, sr.category, sr.urgency)
    

    sr 是真正的 Python 对象(类型就是你定义的类),不是字符串也不是字典;urgency 拿到的是整数 5 而非字符串 "5"。

  4. 批量处理时一次组装、循环调用,结果可直接计算:

    from collections import Counter
    
    results = [agent.invoke({"messages": [{"role": "user", "content": t}]})["structured_response"]
               for t in reviews]
    print("情感分布:", Counter(r.sentiment for r in results))
    print("平均紧急度:", round(sum(r.urgency for r in results) / len(results), 1))
    
  5. 换业务只换 schema 类,其余代码不动:

    from schemas import OrderInfo
    agent = create_agent(model="deepseek:deepseek-chat", tools=[],
                         response_format=ToolStrategy(OrderInfo))
    

继续探索

全部资源
Skills 资源 / 技能包

bootstrapping-deepagents-env

在一台干净机器上装好 DeepAgents 运行环境、接入一个 OpenAI 兼容大模型凭证,并跑通第一个 create_deep_agent 工具调用闭环。Use when 需要初始化 DeepAgents 开发环境、系统 Python 版本不达标装不上包、不确定装到了哪个版本、接 DeepSeek 之类国产模型报 ImportError 或 404 这类环境层故障时。涵盖解释器版本核对、虚拟环境置备、主包与提供方包安装、版本核验、凭证注入、最小示例验收;不含 Agent 各项能力的用法(见 tracking-task-progress-with-todos 等能力型 skill)。

Skills 资源 / 技能包

inspecting-agent-graph-and-tools

把一个 create_deep_agent 建出来的智能体拆开看:列出执行图节点、列出实际挂载的工具、捕获框架预装的中间件清单、抓取每轮真正发给模型的工具集。Use when 需要确认某项能力是否真的挂上了、排查「我的工具去哪了 / 这些工具哪来的 / 内置工具到底几个」、验证自定义中间件是否进了图、或要在改配置前后做结构对照时。涵盖图节点自省、工具清单反查、中间件清单捕获、编译期与运行期工具集差异;不含具体能力的用法。

Skills 资源 / 技能包

tracking-task-progress-with-todos

让智能体把多步任务拆成结构化待办清单写进状态,并从调用结果里取出清单、渲染成实时进度、兜底检测「勾完清单却没给答案」的失败形态。Use when 需要给长任务做进度面板、想稳定触发 write_todos、发现规划没被触发、或要把 todos 推给前端 UI 与日志时。涵盖稳定触发写法、取清单的两条路径、三态进度渲染、失败形态检测;不含子任务委派(见 delegating-subtasks-to-subagents)。