大语言模型结构化输出实战:从Pydantic到Function Calling的数据提取指南

📅 2026/8/9 20:25:25
大语言模型结构化输出实战:从Pydantic到Function Calling的数据提取指南
1. 项目概述从“文本对话”到“数据接口”的范式转变如果你已经用了一段时间的大语言模型LLM比如 ChatGPT 或者 Claude你肯定经历过这种抓狂时刻你问它“帮我分析一下这份合同里的关键条款和截止日期”它确实给你洋洋洒洒写了一大段格式还挺漂亮。但当你兴冲冲地想把这些信息自动录入到你的合同管理系统或者日历里时傻眼了——你得一个字一个字地从那段文本里把“甲方”、“付款金额”、“2024年12月31日”这些关键信息给抠出来。这个过程费时费力还容易出错本质上你是在用“人眼”和“人脑”去解析 AI 生成的“非结构化”文本这完全违背了我们使用 AI 提升效率的初衷。这正是“结构化输出与数据提取”要解决的核心痛点。这个项目标题听起来有点技术化但它的目标非常直接让 AI 不再仅仅是一个“聊天机器人”而是变成一个能直接返回规整、标准数据的“数据接口”。想象一下你问 AI “明天北京的天气如何”它不再回复“明天北京晴转多云气温15-25度南风3-4级”而是直接返回一个 JSON 对象{“city”: “北京”, “date”: “2024-10-27”, “weather”: “晴转多云”, “temp_low”: 15, “temp_high”: 25, “wind”: “南风3-4级”}。你的程序拿到这个 JSON可以直接解析、存储、触发后续流程整个过程全自动化。这背后的技术正是当前 AI 应用开发特别是基于 LangChain、LlamaIndex 等框架构建 AI Agent 或自动化工作流时必须掌握的核心技能。它关乎可靠性、可集成性和生产效率。本章我们就来彻底拆解如何利用 Pydantic、函数调用Function Calling等工具驯服 AI 这匹“野马”让它乖乖地输出我们想要的、机器可读的数据格式。2. 核心需求与价值为什么“结构化”如此重要在深入技术细节之前我们必须先搞清楚为什么费这么大劲让 AI 输出结构化数据这不仅仅是“看起来整齐”那么简单它关乎整个 AI 应用落地的成败。2.1 从“信息展示”到“流程集成”的跨越传统的人机对话AI 的输出终点是人的眼睛和大脑。信息以自然语言呈现人类阅读理解后再手动进行下一步操作。而结构化输出意味着 AI 的输出终点是另一个程序、数据库或 API。它实现了从“信息展示层”到“业务逻辑层”的无缝衔接。一个典型场景是智能客服工单自动创建非结构化旧模式用户描述问题“我的账户无法登录提示密码错误账号是 exampleemail.com”。AI 客服回复“已收到您关于账户 exampleemail.com 登录失败的问题初步判断可能是密码错误建议您尝试重置密码或联系管理员。” 客服人员需要阅读这条回复手动在工单系统选择问题类型登录问题、填写用户邮箱、摘要描述然后创建工单。结构化新模式同样是用户的描述AI 在回复的同时同步输出一个结构体{“ticket_type”: “登录故障”, “user_email”: “exampleemail.com”, “priority”: “中”, “summary”: “用户反馈密码错误导致无法登录”}。这个结构体可以通过 webhook 直接调用工单系统的创建接口工单瞬间自动生成客服人员只需处理后续跟进。效率提升不是一点半点。2.2 提升数据处理的准确性与一致性自然语言充满歧义和变体。“五千块”、“5k”、“5000元”指的是同一个金额。“下周一下午”可能因上下文而异。当 AI 以自由文本回答时后续程序需要写非常复杂的正则表达式或 NLP 规则来提取和归一化这些信息鲁棒性极差。结构化输出强制 AI 在生成时就必须进行“归一化”思考。你定义好字段amount的类型是float那么无论用户说“五千”、“5千”还是“5000”AI 在生成这个字段值时都必须将其推理并转化为5000.0这个浮点数。你定义meeting_time的类型是datetimeAI 就必须把“下周一下午三点”解析成一个具体的 ISO 时间戳。这相当于把数据清洗和规范化的压力前移给了 AI保证了输出数据“出生即标准”极大降低了后续处理链路的复杂度。2.3 赋能复杂、多步骤的智能体Agent工作流在 LangChain 或 LangGraph 构建的 AI Agent 系统中一个复杂的任务比如“调研某公司并撰写投资报告”会被拆解成多个子任务搜索信息、分析财报、总结风险、生成报告。这些子任务之间的信息传递如果靠自然语言会像一场“传话游戏”信息在多次传递中极易失真、丢失关键数据。结构化输出在这里扮演了“标准化数据总线”的角色。例如负责“搜索信息”的 Agent 输出一个结构化的CompanyProfile对象包含统一字段的营收、利润、人员规模。负责“分析财报”的 Agent 接收这个对象进行分析后再输出一个结构化的FinancialAnalysis对象。整个工作流的数据流转清晰、可靠每个环节都可以对输入输出的数据结构进行严格校验通过 Pydantic确保了整个复杂系统运行的稳定性和可调试性。3. 核心技术栈深度解析Pydantic 与 Function Calling 如何协同实现结构化输出目前业界主流且最有效的方法是结合Pydantic 模型定义与 LLM 的函数调用Function Calling能力。理解这两者如何协同工作是掌握这项技术的关键。3.1 Pydantic不只是数据验证更是“数据契约”Pydantic 是一个 Python 库它利用 Python 的类型注解type hints来进行数据验证和设置管理。在结构化输出的上下文中它的核心价值在于为 AI 和我们自己定义了一份清晰的“数据契约”。这份契约明确了要输出哪些数据通过定义模型的字段Field。每个数据是什么类型字符串str、整数int、浮点数float、布尔值bool、列表list甚至是嵌套的其他 Pydantic 模型。每个数据有什么约束字符串的最大/最小长度、数值的范围、是否可选、默认值是什么。数据应该如何被解释通过字段描述description用自然语言告诉 AI 这个字段的含义和填写要求。from pydantic import BaseModel, Field from typing import List, Optional from datetime import date class Book(BaseModel): 书籍信息 title: str Field(description书籍的名称) author: str Field(description书籍的作者格式为‘姓氏名字’) publication_year: int Field(ge1800, ledate.today().year, description书籍的出版年份) genres: List[str] Field(min_items1, description书籍所属的体裁列表如[科幻, 小说]) isbn: Optional[str] Field(None, patternr‘^\d{13}$‘, description书籍的13位ISBN号可能没有) # 这个 Book 类就是一份“契约”AI请按照这个格式给我返回一本书的信息。实操心得字段描述description至关重要不要写得太简略。把它当作你在给一个实习生布置任务要清晰、无歧义。好的描述能极大提高 AI 输出字段的准确率。例如author字段的“格式为‘姓氏名字’”就比单纯的“作者”要好得多。3.2 Function Calling让 LLM 学会“填空”有了“契约”Pydantic 模型我们怎么让 LLM 遵守它呢这就需要用到 LLM 的函数调用Function Calling或工具调用Tool Calling能力。以 OpenAI 的 GPT 系列为例。传统的聊天补全Chat CompletionAPI你发送消息列表它返回文本消息。而当你启用函数调用功能时流程发生了变化定义工具函数你在 API 请求中除了消息还会附带一个tools参数里面描述了一个或多个“工具”。每个工具都有名字、描述以及最重要的——parameters。这个parameters就是一个符合 JSON Schema 格式的对象描述它和我们的 Pydantic 模型 schema 在本质上是一回事。LLM 的决策LLM 分析用户的请求和上下文。如果它认为需要调用某个工具来完成用户的请求它就不会生成普通的文本回复而是生成一个特殊的“工具调用”响应。结构化响应这个响应里包含了它决定调用的工具名称以及一个arguments对象——这就是一个已经填充了具体值的、符合我们定义的parameters结构的 JSON关键点LLM 本身并不真正执行函数。它只是根据你的描述“理解”了这个函数是干什么的、需要什么参数然后在认为合适的时候生成一个符合参数格式的 JSON 数据。这个 JSON就是我们的“结构化输出”。3.3 LangChain 的集成简化流程的利器手动构造 OpenAI 的函数调用请求、处理响应比较繁琐。LangChain 提供了更高层的抽象让这个过程变得异常简单。其核心组件是create_structured_output_runnable或with_structured_output方法。它的工作原理是内部转换LangChain 将你的 Pydantic 模型自动转换为 LLM 能理解的 JSON Schema即函数调用的parameters。封装请求它帮你构造好包含工具定义的 API 请求。解析响应它接收 LLM 返回的argumentsJSON并利用 Pydantic 对其进行验证和解析最终返回一个你的模型类的实例对象。异常处理如果 LLM 返回的 JSON 不符合模型定义或者验证失败LangChain 可以提供重试机制通过RetryOutputParser等自动将错误信息反馈给 LLM让它重新生成。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import PydanticOutputParser llm ChatOpenAI(model“gpt-4o”, temperature0) prompt ChatPromptTemplate.from_template(“请从以下文本中提取书籍信息{input_text}”) # 方法1使用 with_structured_output (LangChain 较新版本推荐) structured_llm llm.with_structured_output(Book) chain prompt | structured_llm result: Book chain.invoke({“input_text”: “我最近读了《三体》刘慈欣写的2008年出版的科幻小说ISBN是9787536692930。”}) print(result.title) # 输出三体 print(result.dict()) # 输出结构化字典 # 方法2使用 PydanticOutputParser (传统方法) parser PydanticOutputParser(pydantic_objectBook) prompt_with_format ChatPromptTemplate.from_messages([ (“system”, “你是一个信息提取助手。请严格按以下格式输出{format_instructions}”), (“human”, “{input_text}”) ]) chain prompt_with_format | llm | parser result chain.invoke({ “format_instructions”: parser.get_format_instructions(), # 这里会自动生成模型格式说明 “input_text”: “...” })注意事项temperature参数建议设置为 0 或接近 0。结构化输出追求的是确定性和准确性而不是创造性。较高的温度值会增加输出的随机性可能导致字段格式错误或产生幻觉Hallucination生成不存在的字段值。4. 实战演练构建一个多层级信息提取管道理论说得再多不如亲手实现一个。我们构建一个稍微复杂点的场景从一个混合了公司介绍、产品信息和招聘需求的自由文本中提取出结构化的数据。4.1 定义复杂的数据模型我们要提取三类信息公司概况、产品列表、招聘岗位。它们之间存在关联适合用嵌套模型来定义。from pydantic import BaseModel, Field, validator from typing import List, Optional from enum import Enum class JobType(str, Enum): FULL_TIME “全职” PART_TIME “兼职” INTERN “实习” class Product(BaseModel): name: str Field(description“产品名称”) category: str Field(description“产品类别如‘SaaS软件’、‘硬件设备’、‘咨询服务’”) description: Optional[str] Field(None, description“产品的简要描述”) class JobPosting(BaseModel): role: str Field(description“招聘职位名称如‘后端开发工程师’”) type: JobType Field(description“职位类型”) department: Optional[str] Field(None, description“所属部门”) # 使用 validator 进行复杂校验 validator(‘department’) def department_must_contain_keyword(cls, v): if v and ‘技术’ not in v and ‘研发’ not in v and ‘产品’ not in v: raise ValueError(‘部门名称应包含“技术”、“研发”或“产品”等关键词’) return v class CompanyExtraction(BaseModel): 从文本中提取的公司综合信息 company_name: str Field(description“公司的全称”) core_business: str Field(description“公司的核心业务描述一句话概括”) founding_year: Optional[int] Field(None, ge1900, description“公司成立年份”) products: List[Product] Field(default_factorylist, description“公司的主要产品列表”) active_jobs: List[JobPosting] Field(default_factorylist, description“公司正在招聘的职位列表”) # 计算字段示例不依赖LLM输出由Pydantic后处理 property def product_count(self) - int: return len(self.products) property def is_hiring(self) - bool: return len(self.active_jobs) 0这个模型体现了几个高级技巧枚举类型EnumJobType限制了职位类型只能是我们定义的几种LLM 必须从中选择保证了数据的一致性。嵌套模型CompanyExtraction包含了Product和JobPosting的列表可以表达复杂的一对多关系。验证器validator在JobPosting中我们对department字段添加了自定义校验逻辑确保部门名称符合一定的业务规则。注意这个校验发生在 LLM 输出之后、Pydantic 解析之时。如果校验失败会抛出ValidationError。我们可以捕获这个错误并将其作为反馈让 LLM 重试。计算属性propertyproduct_count和is_hiring不是需要 LLM 填充的字段而是基于已有数据计算得出的展示了 Pydantic 模型作为数据容器的强大处理能力。4.2 设计提示词Prompt与构建执行链好的模型需要好的引导。我们需要设计一个清晰的系统提示词告诉 LLM 它的角色和任务。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser, PydanticOutputParser import json llm ChatOpenAI(model“gpt-4”, temperature0) # 方法使用 with_structured_output structured_llm llm.with_structured_output(CompanyExtraction) # 构建提示词模板 system_prompt “““你是一个专业的商业信息提取助手。你的任务是从用户提供的文本中精确地提取出关于公司的结构化信息。 请特别注意 1. 对于‘成立年份’如果文本中没有明确提及请留空null不要猜测。 2. ‘产品’和‘招聘职位’可能有多项请全部找出。 3. 所有提取的信息必须严格基于文本内容不要添加任何文本中不存在的信息。 4. 如果文本中信息模糊或不完整请在对应字段中留空或使用最合理的推断但必须在最终输出的‘note’字段中说明我们稍后为模型添加这个字段。 ””” prompt_template ChatPromptTemplate.from_messages([ (“system”, system_prompt), (“human”, “请分析以下文本并提取信息\n{text}”) ]) # 构建链 extraction_chain prompt_template | structured_llm # 测试文本 input_text “““ 创新科技有限公司InnovTech成立于2015年专注于企业级人工智能解决方案。我们目前主打两款产品1. ‘智析’SaaS平台提供数据智能分析服务2. ‘守卫者’硬件安防系统。公司正处于快速发展期现诚聘后端开发工程师全职技术部、机器学习实习生实习AI实验室。 ””” try: result: CompanyExtraction extraction_chain.invoke({“text”: input_text}) print(“提取成功”) print(f“公司名称: {result.company_name}”) print(f“核心业务: {result.core_business}”) print(f“成立年份: {result.founding_year}”) print(f“产品数量: {result.product_count}”) for product in result.products: print(f“ - 产品: {product.name}, 类别: {product.category}”) print(f“是否在招聘: {result.is_hiring}”) for job in result.active_jobs: print(f“ - 职位: {job.role}, 类型: {job.type}, 部门: {job.department}”) # 转换为标准JSON便于存储或传输 json_output result.json(indent2) print(“\nJSON输出:”, json_output) except Exception as e: print(f“提取过程中发生错误: {e}”) # 在这里可以加入重试逻辑4.3 处理模糊、缺失与冲突信息现实世界的文本很少是完美的。LLM 可能会遇到信息模糊“几年前成立”、缺失没提产品或冲突文本前后矛盾的情况。我们的结构化提取流程必须具备鲁棒性。策略一字段可选性与默认值如上例所示将可能缺失的字段定义为Optional[...]并设置defaultNone。在 Pydantic 模型中可以添加一个note字段来记录任何不确定性。class RobustCompanyExtraction(CompanyExtraction): note: Optional[str] Field(None, description“记录提取过程中的任何不确定性、假设或文本中的矛盾之处”)策略二使用验证器提供默认逻辑对于模糊信息可以在验证器里提供一些启发式逻辑但需谨慎。from pydantic import validator class RobustCompanyExtraction(CompanyExtraction): validator(‘founding_year’, preTrue, alwaysTrue) def handle_vague_year(cls, v, values): if v is not None: return v # 如果LLM没提取到这里可以尝试从文本其他部分推断但最好还是留空 # 例如检查文本是否有‘成立于十年前’之类的描述 # 这里为了安全我们返回None return None策略三实现自动重试Retry机制当 LLM 的输出无法通过 Pydantic 验证时比如类型错误、缺少必填字段最有效的策略是让 LLM 重试。LangChain 提供了RetryOutputParser。from langchain.output_parsers import RetryWithErrorOutputParser from langchain_core.prompts import PromptTemplate # 1. 首先定义一个基础解析器会失败 parser PydanticOutputParser(pydantic_objectCompanyExtraction) # 2. 定义重试解析器 retry_parser RetryWithErrorOutputParser.from_llm( parserparser, llmllm, max_retries2 # 最大重试次数 ) # 3. 构建一个包含错误反馈提示的链 prompt PromptTemplate( template“““请根据以下用户输入和之前的错误信息重新生成正确的输出格式。\n 原始查询: {query}\n 上次解析错误: {error}\n 请只输出符合格式的JSON不要有其他任何内容。\n 格式要求: {format_instructions}”””, input_variables[“query”, “error”], partial_variables{“format_instructions”: parser.get_format_instructions()} ) retry_chain prompt | llm | retry_parser # 使用这个 chain 进行调用初始错误可以设为空字符串实操心得重试机制非常有用但不宜设置过多次数通常1-2次。如果多次重试仍失败很可能是指令不清、模型能力不足或任务本身过于复杂。此时应该将错误和原始输入记录下来进行人工分析并考虑优化你的 Pydantic 模型定义或提示词。5. 高级技巧与性能优化掌握了基础流程后我们来看看如何提升结构化提取的可靠性、效率和处理复杂情况的能力。5.1 处理列表类型与不确定数量的项提取列表如List[Product]是一大挑战。LLM 可能漏项也可能把非项目内容塞进来。提升列表提取质量的方法在字段描述中明确数量提示Field(description“产品列表请找出文本中提到的所有产品可能有多项也可能没有。”)使用更具体的指令在系统提示词中强调“请仔细扫描全文确保不遗漏任何提到的产品。”后处理清洗对提取出的列表可以写一个简单的后处理函数过滤掉名称过于模糊如“各种服务”或明显不符合产品定义的项。5.2 利用思维链Chain-of-Thought提升复杂字段准确率对于一些需要推理的字段比如从“我们是一家有十年历史的公司”推断founding_year可以引导 LLM 在输出结构化数据的同时附带一个简单的推理过程。虽然我们最终只要结构化数据但这个“思考空间”能提升准确性。这可以通过在提示词中要求 LLM “逐步思考”来实现或者使用支持 JSON 模式且能保留“推理痕迹”的模型如 Claude 3 系列。system_prompt_cot “““你是一个信息提取助手。请按以下步骤工作 1. 首先仔细阅读文本找出所有相关信息。 2. 然后对于需要推断的字段如成立年份进行简要推理。 3. 最后严格根据推理结果生成最终的结构化JSON输出。 请将最终输出放在 ‘output’ 字段中将你的简要推理步骤放在 ‘reasoning’ 字段中。 ””” # 然后定义一个包含 output 和 reasoning 字段的 Pydantic 模型来接收5.3 批量处理与异步优化当需要从大量文档中提取信息时顺序调用 API 会非常慢。我们需要批量处理和异步编程。import asyncio from langchain_openai import ChatOpenAI from langchain_core.output_parsers import PydanticOutputParser from typing import List async def extract_from_documents_async(doc_texts: List[str], model_class, max_concurrency: int 5): “”“异步批量提取文档信息”“” llm ChatOpenAI(model“gpt-4o”, temperature0, max_retries2) structured_llm llm.with_structured_output(model_class) prompt ChatPromptTemplate.from_template(“提取信息{text}”) chain prompt | structured_llm semaphore asyncio.Semaphore(max_concurrency) # 控制并发数避免触发速率限制 async def process_one(text: str): async with semaphore: try: result await chain.ainvoke({“text”: text}) return result except Exception as e: print(f“处理文本时出错: {e}”) return None tasks [process_one(text) for text in doc_texts] results await asyncio.gather(*tasks, return_exceptionsTrue) # 处理结果和异常 valid_results [r for r in results if isinstance(r, model_class)] return valid_results # 使用示例 documents [“文档1文本...”, “文档2文本...”, ...] # 假设有很多文档 extracted_data asyncio.run(extract_from_documents_async(documents, CompanyExtraction, max_concurrency10))注意事项批量调用时务必关注 API 的速率限制RPM, TPM和成本。max_concurrency不宜设置过高。对于超大批量任务可以考虑结合队列和分布式处理。5.4 模型选择与成本考量不是所有任务都需要 GPT-4。进行结构化输出时高精度、复杂结构、强推理需求选择能力最强的模型如 GPT-4、Claude 3 Opus。它们对指令遵循和复杂格式的理解更好。中等复杂度、常规提取GPT-3.5-Turbo、Claude 3 Haiku/Sonnet 通常是性价比之选在大多数场景下表现足够好。简单、固定格式的提取甚至可以考虑使用更小、更快的开源模型通过 LangChain 集成如果其指令跟随能力经过微调能满足要求可以大幅降低成本。一个实用的策略是“分层处理”先用一个快而便宜的模型如 GPT-3.5-Turbo做初筛和简单提取对于它置信度低或提取失败的案例再用更强的模型如 GPT-4进行复核和精提取。6. 常见问题排查与实战避坑指南在实际操作中你会遇到各种各样的问题。下面是我踩过坑后总结出来的“避坑清单”。6.1 LLM 不按格式输出或返回无关内容症状LLM 返回了纯文本解释而不是 JSON或者在 JSON 外面包裹了 Markdown 代码块标记json ...或者添加了额外的说明文字。根因提示词指令不够强硬或者模型“太有礼貌”总想解释它在做什么。解决方案强化系统指令在系统提示词开头使用强有力的命令如“你必须只输出 JSON 对象不要有任何额外的解释、前言、后语或 Markdown 标记。”“你的响应有且仅有一个合法的 JSON 对象。”使用 LangChain 的with_structured_output这是最推荐的方法因为它从机制上强制 LLM 走函数调用路径极大降低了“乱说话”的概率。后处理清洗如果仍有杂音可以在解析前用简单的字符串处理如正则表达式r‘json\n?(.*?)\n?’提取 JSON 部分。6.2 字段值提取错误或产生幻觉Hallucination症状文本中明明没有的信息被 AI“编造”出来填入了字段。例如文本没提成立年份但模型输出了一个 2020。根因模型倾向于“完成”任务当信息缺失时它可能基于训练数据中的模式进行猜测或者字段描述不够清晰导致模型理解偏差。解决方案明确“留空”指令在字段描述和系统提示中反复强调“如果文本中没有明确提及请将该字段设置为null或留空”。使用Optional类型确保你的 Pydantic 模型将可能缺失的字段定义为可选并设置合理的默认值如None。提供负面示例Few-Shot在提示词中给出一个例子展示当信息缺失时对应字段应该输出null。降低temperature如前所述将其设为 0。6.3 处理枚举Enum类型时LLM 返回了不在枚举值中的内容症状你定义了JobType枚举为[“全职”, “兼职”, “实习”]但 LLM 返回了“合同工”。根因LLM 可能没有严格约束在枚举范围内选择或者你的枚举值未能覆盖所有实际情况。解决方案在描述中明确枚举值Field(description“职位类型必须是‘全职’、‘兼职’或‘实习’中的一个。”)使用 Pydantic 的validator进行修正写一个验证器尝试将常见变体映射到标准值。validator(‘type‘, preTrue) def normalize_job_type(cls, v): if v in [“全职”, “full-time”, “Full Time”]: return JobType.FULL_TIME elif v in [“兼职”, “part-time”, “Part Time”]: return JobType.PART_TIME # ... 其他映射 else: # 如果无法映射可以抛错或返回一个默认值 raise ValueError(f“不支持的职位类型: {v}”)考虑使用字符串类型后处理如果类别动态变化或难以穷举可以先让 LLM 输出字符串然后用自己的业务逻辑进行归类。6.4 性能瓶颈与速率限制Rate Limit症状批量处理时速度慢或频繁收到429 Too Many Requests错误。解决方案异步并发如上文所示使用asyncio和信号量控制并发数。指数退避重试实现重试逻辑时加入随机延迟如time.sleep(2**retry_count random.random())避免雪崩式重试。缓存结果对于相同的或极其相似的输入文本可以将提取结果缓存起来例如使用functools.lru_cache或 Redis避免重复调用 API节省成本和时间。监控与告警记录调用次数、耗时和错误率设置阈值告警。6.5 复杂文本中关系提取的挑战症状当文本中实体关系复杂时如“A 产品由 X 部门负责B 产品由 Y 部门负责”简单的扁平化列表提取可能丢失这种对应关系。解决方案升级你的数据模型使其能表达关系。class ProductWithOwner(BaseModel): name: str category: str owning_department: str # 明确关联部门 class CompanyExtractionAdvanced(BaseModel): company_name: str departments: List[str] Field(description“文中提到的所有部门列表”) products: List[ProductWithOwner] # 产品直接关联部门同时在提示词中明确要求建立这种关联“请提取产品信息并指明每个产品由哪个部门负责。如果文中未明确说明请将 owning_department 字段留空。”结构化输出与数据提取是将大语言模型从“玩具”变为“生产力工具”的关键一步。它消除了人机交互的最后一道手动屏障让 AI 生成的数据可以直接流入下游系统驱动自动化流程。掌握 Pydantic 与 Function Calling 的结合使用并灵活运用提示工程、错误处理和性能优化技巧你就能构建出强大、可靠的 AI 数据提取管道。