文章目录1. 概述2. 两条技术路线2.1 通用大模型文本补全 API2.2 大模型函数调用 API3. Pydantic3.1 什么是 Pydantic 3.2 将 Pydantic 对象转为 JSON Schema3.3 使用注解4. 入门案例4.1 定义 Pydantic 模型Schema4.2 依赖安装4.3 文档加载4.4 实例化大模型阿里云百炼4.5 调用提取4.6 接入查询引擎1. 概述大模型生成结构化输出的能力对下游需要可靠解析返回结果的应用而言至关重要。LlamaIndex在不少场景中本身就依赖结构化输出文档检索LlamaIndex内部不少数据结构在检索阶段会要求大模型按照固定范式返回内容。例如树索引就需要大模型输出形如ANSWER: (数字)的结果。答案合成用户有时希望最终结果具备结构化形式比如JSON、格式化SQL查询语句等。LlamaIndex提供了多类组件来支持大模型生成结构化输出。默认的大模型封装类自带结构化输出能力同时还提供了底层工具模块Pydantic Programs通用组件把提示词输入映射为以Pydantic对象承载的结构化输出。它既可以使用模型函数调用接口也支持文本补全接口搭配输出解析器还能直接与查询引擎集成。预定义 Pydantic Programs内置封装好的Pydantic程序用于将输入映射到特定目标类型如DataFrame。输出解析器Output Parsers在调用大模型文本补全接口的前后环节生效。该组件不适用于函数调用接口函数调用本身原生返回结构化数据无需额外文本解析。2. 两条技术路线大模型结构化输出分两条技术路线项目通用文本补全API函数调用API约束来源写在Prompt里的文本格式要求传给API的Pydantic自动生成的JSON SchemaPydanticOutputParser必须使用前后都参与不需要LLM返回内容自由自然语言文本可能混解释规范JSONPydantic用途生成prompt格式规则 解析后校验生成函数Schema 结果实例化校验2.1 通用大模型文本补全 API本质大模型只懂文本所有结构化约束靠 Prompt 后置解析完整流程Raw input原始输入 Prompt template提示模板 → 合并得到raw input调用前送入Pydantic OutputParser追加格式指令例如你必须输出JSON字段xxx不能有多余文字→ 生成Input w/ format instr带格式要求的完整prompt传给Generic LLM通用大模型模型返回自由文本Raw output调用后再次送入Pydantic OutputParser提取文本中的JSON、校验格式、转换成Pydantic对象输出Structured output结构化对象✅ 特点依赖PydanticOutputParser调用前后都要工作模型输出是自由文本容易出现格式错误、多余解释文字解析器负责容错提取兼容性强任何能做文本补全的大模型都能用2.2 大模型函数调用 API本质模型原生支持输出结构化工具消息不是靠 Prompt 哄出来的完整流程Raw inputPrompt template→raw input同时把预先定义好的Pydantic class转成JSON Schema作为函数定义一起传给OpenAI接口Function/callOpenAI底层根据Schema约束直接返回符合规范的结构化JSONRaw output直接把返回JSON加载、实例化为Pydantic class对象得到最终Structured output✅ 特点不需要OutputParser做文本提取模型底层按Schema生成结构化数据稳定性更高很少出现JSON语法错误Pydantic在这里主要作用生成Schema传给模型 校验返回结果、实例化成对象3. Pydantic大语言模型擅长理解数据由此诞生了一个最重要的应用场景将普通人类语言我们称之为非结构化数据转换成计算机程序可读取的、固定规范的目标格式。我们把该过程输出的结果称为结构化数据。由于转换过程中会舍弃大量无关冗余信息因此我们将这项任务叫做提取。在LlamaIndex中结构化数据提取的核心依托Pydantic 类实现使用Pydantic定义数据结构LlamaIndex配合Pydantic强制大语言模型的输出符合你定义的这套结构。3.1 什么是 Pydantic Pydantic是一款广泛使用的数据校验与数据转换库重度依赖Python类型注解。项目官方文档中有详尽教程本文只介绍基础用法。创建Pydantic类需要继承 Pydantic 的BaseModel基类frompydanticimportBaseModelclassUser(BaseModel):id:intname:strJane Doe本例定义了User类包含两个字段id和name。id定义为整数类型name为字符串类型默认值为Jane Doe。也可以通过模型嵌套构建更复杂的数据结构fromtypingimportList,OptionalfrompydanticimportBaseModelclassFoo(BaseModel):count:intsize:Optional[float]NoneclassBar(BaseModel):apple:strxbanana:stryclassSpam(BaseModel):foo:Foo bars:List[Bar]这里Spam对象包含foo和bars。Foo包含count和可选字段sizebars是一个列表列表内每个对象都拥有apple、banana属性。3.2 将 Pydantic 对象转为 JSON SchemaPydantic支持把Pydantic类转换为符合通用标准的JSON序列化规约对象。以上面User类为例序列化后得到如下内容{properties:{id:{title:Id,type:integer},name:{default:Jane Doe,title:Name,type:string}},required:[id],title:User,type:object}这个特性至关重要这类JSON格式的规约经常传给大模型大模型会以此作为指令按照规约要求返回数据。3.3 使用注解前面提到大模型会使用Pydantic生成的JSON Schema作为返回数据的指令。为了辅助模型、提升返回数据准确率建议为对象和字段添加自然语言描述说明字段含义与用途。Pydantic支持通过**文档字符串docstrings**和Field实现该能力。后续所有示例都会使用下面这套Pydantic类fromdatetimeimportdatetimefrompydanticimportField,BaseModelclassLineItem(BaseModel):发票内的一行明细条目item_name:strField(description商品名称)price:floatField(description商品价格)classInvoice(BaseModel):发票信息的数据模型invoice_id:strField(description发票唯一编号通常为数字)date:datetimeField(description发票开具日期)line_items:list[LineItem]Field(description发票中所有商品明细列表)该模型会展开为更复杂的JSON Schema{$defs:{LineItem:{description:发票内的一行明细条目,properties:{item_name:{description:商品名称,title:Item Name,type:string},price:{description:商品价格,title:Price,type:number}},required:[item_name,price],title:LineItem,type:object}},description:发票信息的数据模型,properties:{invoice_id:{description:发票唯一编号通常为数字,title:Invoice Id,type:string},date:{description:发票开具日期,format:date-time,title:Date,type:string},line_items:{description:发票中所有商品明细列表,items:{$ref:#/$defs/LineItem},title:Line Items,type:array}},required:[invoice_id,date,line_items],title:Invoice,type:object}4. 入门案例基于大模型函数调用 API实现。底层让大模型输出JSON再自动用Pydantic做反序列化 类型校验对外直接给Pydantic实例。4.1 定义 Pydantic 模型Schema用BaseModel定义你想要提取的数据结构Field(description...)非常关键描述会注入到给LLM的Prompt里告诉模型每个字段该提取什么信息。示例两层嵌套LineItem单行商品明细Invoice外层发票包含invoice_id、date、明细列表line_items类型声明可以直接写datetime、list[LineItem]LlamaIndex会自动处理JSON字符串 ↔Python类型转换。fromdatetimeimportdatetimefrompydanticimportBaseModel,FieldclassLineItem(BaseModel):发票中的一条明细项item_name:strField(description商品名称)price:floatField(description商品价格)classInvoice(BaseModel):发票信息的数据模型invoice_id:strField(description发票的唯一标识通常是编号)date:datetimeField(description发票开具日期)line_items:list[LineItem]Field(description发票中所有明细项的列表)4.2 依赖安装# 核心库 OpenAI LLMpipinstallllama-index-core llama-index-llms-openai# 文件读取PDFpipinstallllama-index-readers-filellama-index-coreLlamaIndex核心llama-index-llms-openaiOpenAI模型适配器llama-index-readers-file基础PDF读取简单文本提取复杂PDF推荐LlamaParse4.3 文档加载使用PDFReader读取PDF得到Document对象取出原始文本作为提取任务输入。短板基础PDFReader只提取纯文本扫描件/图片PDF必须用LlamaParse或OCR。接下来加载真实发票的文本内容fromllama_index.readers.fileimportPDFReaderfrompathlibimportPath pdf_readerPDFReader()documentspdf_reader.load_data(filePath(./uber_receipt.pdf))textdocuments[0].text文档内容4.4 实例化大模型阿里云百炼实例化基础大模型对象fromllama_index.llms.openai_likeimportOpenAILike# noqa: E402PROJECT_ROOTPath(__file__).resolve().parent load_dotenv(PROJECT_ROOT/.env)llmOpenAILike(modelqwen-plus,api_keyos.environ[DASHSCOPE_API_KEY],api_basehttps://ws-jfb8j8mx0n7e2k6a.cn-beijing.maas.aliyuncs.com/compatible-mode/v1,is_chat_modelTrue,is_function_calling_modelTrue,# 关键结构化输出靠函数调用兜底见文件头注释timeout180.0,# 专属端点偶发慢响应默认 60s 会超时max_retries2,)as_structured_llm(你的Pydantic类)包装得到结构化大模型实例sllmllm.as_structured_llm(Invoice)sllm和普通llm接口一致支 持chat/stream/achat/astream流式异步调用返回结果同样自动解析为Pydantic对象。4.5 调用提取complete()传入原始文本执行结构化提取。responsesllm.complete(请提取以下发票文本中的结构化信息\ntext)Response是LlamaIndex的CompletionResponse对象两个核心属性response.textJSON字符串可json.loads解析成dict适合序列化保存response.raw原生Pydantic实例最常用invresponse.rawprint(f类型检查response.raw 是{type(inv).__name__}实例\n)print(f发票号码 invoice_id {inv.invoice_id!r})# 类型自动转换date 已是 datetime 对象不是字符串print(f开票日期 date {inv.date!r}(类型:{type(inv.date).__name__}))print(f明细项数量 line_items {len(inv.line_items)}条)fori,iteminenumerate(inv.line_items,1):# 明细可直接按字段访问price 已是 floatprint(f 明细{i}:{item.item_name}价格{item.price}({type(item.price).__name__}))print(f\n--- response.textJSON 字符串可 json.loads / 存库 ---\n{response.text})输出示例类型检查response.raw 是 Invoice 实例 发票号码 invoice_id253177881234567890开票日期 datedatetime.datetime(2026,9,18,0,0)(类型:datetime)明细1:*运输服务*快车人民广场 → 虹桥机场 价格86.5(float)明细2:*运输服务*高速通行费 价格20.0(float)明细3:*运输服务*候时费12分钟 价格6.0(float)4.6 接入查询引擎RAG 结构化大模型查询引擎直接返回Pydantic对象。建索引 查询引擎docsSimpleDirectoryReader(input_files[str(PROJECT_ROOT/data/invoice/invoice_demo.pdf)]).load_data()indexVectorStoreIndex.from_documents(docs)# 切块 嵌入query_engineindex.as_query_engine(llmsllm)查询respquery_engine.query(提取发票中的结构化信息)print(fresp 类型 :{type(resp).__name__})# PydanticResponseprint(fresp.response 类型 :{type(resp.response).__name__})# Invoice 实例print(fresp.source_nodes 数 :{len(resp.source_nodes)})# 检索引用照常附带invresp.response# 直接就是 Invoice无需再 model_validate_jsonprint(f\n发票号码 :{inv.invoice_id})print(f开票日期 :{inv.date!r}(类型:{type(inv.date).__name__}))fori,iteminenumerate(inv.line_items,1):print(f明细{i}:{item.item_name}价格{item.price})