ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LlamaIndex 结构化预测(Structured Prediction)实战指南:用 structured_predict 细粒度控制 LLM 输出

LlamaIndex 结构化预测(Structured Prediction)实战指南:用 structured_predict 细粒度控制 LLM 输出 LlamaIndex 结构化预测Structured Prediction实战指南用 structured_predict 细粒度控制 LLM 输出【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index本文是 LlamaIndex 结构化数据抽取系列教程的第三篇聚焦于比 Structured LLM 更底一层的structured_predictAPI。通过本文你将掌握如何绕过自动提示词、直接向 LLM 传入自定义PromptTemplate完成 Pydantic 结构化输出理解其底层FunctionCallingProgram与LLMTextCompletionProgram两套执行引擎的分发逻辑并学会在需要时直接调用或子类化这些预测类来获得更低级的控制能力。从一个需求说起为什么需要 structured_predict在系列上一篇《使用结构化 LLM》中我们通过llm.as_structured_llm(Invoice)创建了一个结构化 LLM所有提示词的构造都由 LlamaIndex 自动完成。这在大多数场景下开箱即用但当你希望对「LLM 如何被提示」拥有更细粒度的控制时——例如在提示词中加入业务规则、兜底逻辑或领域指令——structured_predict提供了更直接的途径。structured_predict是每一个 LLM 类上都具备的方法定义于 llm.py它接收一个 Pydantic 类和一个PromptTemplate作为参数外加提示词模板中出现的任意变量作为关键字参数。与 Structured LLM 不同提示词完全由你书写LLM 的调用与输出解析则由 LlamaIndex 替你完成。前置准备模型、依赖与 Invoice 定义我们沿用整个系列相同的示例一张 Uber 电子发票uber_receipt.pdf以及同一个InvoicePydantic 模型完整定义与 JSON Schema 展开见系列开篇的 结构化数据抽取入门from datetime import datetime from pydantic import BaseModel, Field class LineItem(BaseModel): A line item in an invoice. item_name: str Field(descriptionThe name of this item) price: float Field(descriptionThe price of this item) class Invoice(BaseModel): A representation of information from an invoice. invoice_id: str Field( descriptionA unique identifier for this invoice, often a number ) date: datetime Field(descriptionThe date this invoice was created) line_items: list[LineItem] Field( descriptionA list of all the items in this invoice )依赖与环境与上一篇一致pip install llama-index-core llama-index-llms-openai安装核心库与 OpenAI LLM也可替换为其他 LLM 集成设置环境变量OPENAI_API_KEYpip install llama-index-readers-file以使用PDFReader该读取器实现在 llama-index-readers-file 中。加载发票文本from llama_index.readers.file import PDFReader from pathlib import Path pdf_reader PDFReader() documents pdf_reader.load_data(filePath(./uber_receipt.pdf)) text documents[0].text核心用法向 LLM 直接调用 structured_predict与as_structured_llm不同这次我们不再让 LlamaIndex 代写提示词而是自己构造PromptTemplate把「当发票 ID 缺失时如何兜底」这类业务规则直接写进提示词from llama_index.core.prompts import PromptTemplate prompt PromptTemplate( Extract an invoice from the following text. If you cannot find an invoice ID, use the company name {company_name} and the date as the invoice ID: {text} ) response llm.structured_predict( Invoice, prompt, texttext, company_nameUber )这正是structured_predict的价值所在当 Pydantic 模型本身不足以指导 LLM 正确解析数据时你可以在提示词层面补充额外方向。text与company_name是提示词模板中的两个变量以关键字参数形式传入。注意该方法签名见 llm.py第一个参数output_cls是目标 Pydantic 类第二个参数prompt是PromptTemplate此外还可选传入llm_kwargs透传给底层 LLM 调用的参数如 temperature、max_tokens 等。方法内部会先派发LLMStructuredPredictStartEvent调用结束后派发LLMStructuredPredictEndEvent并且会校验返回结果必须是BaseModel实例否则抛出TypeError提示「LLM 未能产生有效的结构化输出」。返回值与 JSON 序列化与as_structured_llm(...).complete(...)返回CompletionResponse不同structured_predict的返回值直接就是 Pydantic 对象本身。因此无需访问.raw属性可以直接调用 Pydantic 的model_dump_json()得到 JSONimport json json_output response.model_dump_json() print(json.dumps(json.loads(json_output), indent2))输出示例注意兜底逻辑生效invoice_id被拼成了Uber-2024-10-10{ invoice_id: Uber-2024-10-10, date: 2024-10-10T19:49:00, line_items: [ {item_name: Trip fare, price: 12.18}, {item_name: Access for All Fee, price: 0.1}, ..., ], }四个变体同步、异步与流式structured_predict并不是孤立的方法它提供了一套覆盖同步/异步、普通/流式的完整变体全部定义于 llm.py方法签名位置适用场景structured_predictL307同步、一次性获取完整 Pydantic 对象astructured_predictL374异步await llm.astructured_predict(...)stream_structured_predictL461同步流式返回生成器逐个产出部分填充的 Pydantic 对象astream_structured_predictL539异步流式流式变体适用于需要边生成边展示结果的场景。其核心机制位于 program/utils.py 的process_streaming_objects流式解析时先通过create_flexible_model生成一个允许任意字段的FlexibleModel副本随着 token 逐步到达不断尝试model_validate/model_validate_json解析并借助_repair_incomplete_json修复残缺的 JSON补全缺失的引号与花括号解析出的部分对象按「有效字段数更多则替换」num_valid_fields递归统计非 None 字段的策略持续更新最终再尝试把 FlexibleModel 转换回严格的output_cls。若设置了allow_parallel_tool_callsTrue还会返回对象列表而非单个对象。Under the hood两套底层执行引擎structured_predict并不自己直接解析输出而是根据所用 LLM 的能力分发到两个不同的 Program 类。分发逻辑集中在 program/utils.py 的 get_program_for_llmif pydantic_program_mode PydanticProgramMode.DEFAULT: if llm.metadata.is_function_calling_model: return FunctionCallingProgram.from_defaults(...) else: return LLMTextCompletionProgram.from_defaults( output_parserPydanticOutputParser(output_clsoutput_cls), ...)也就是说默认模式下判断依据是 LLM 元数据中的is_function_calling_model标志。同时该分发函数还支持PydanticProgramMode的显式覆盖OPENAI、FUNCTION、LLM、LM_FORMAT_ENFORCER等模式其中LM_FORMAT_ENFORCER需要额外安装llama-index-program-lmformatenforcer包。FunctionCallingProgram函数调用路径更可靠当 LLM 具备函数调用function callingAPI 时走 function_program.py 中的FunctionCallingProgram其流程为把 Pydantic 对象转换为工具get_function_toolL37-L64调用output_cls.model_json_schema()生成 JSON Schema并用FunctionTool.from_defaults(fnmodel_fn, name..., description..., fn_schemaoutput_cls)将其包装成一个函数工具提示 LLM 并强制其使用该工具from_defaults中校验llm.metadata.is_function_calling_model必须为真并通过tool_choice默认强制该工具与tool_requiredTrue约束 LLM 只能调用这个工具还支持allow_parallel_tool_calls以便一次返回多个对象返回生成的 Pydantic 对象从工具调用的参数中还原出output_cls实例。由于输出被约束为结构化工具调用这一路径通常更可靠也是默认优先选用的方案。LLMTextCompletionProgram纯文本路径通用兜底当 LLM 是纯文本模型无函数调用 API时走 llm_program.py 中的LLMTextCompletionProgram其流程为输出 Pydantic Schema 为 JSON由PydanticOutputParserpydantic.py生成其默认模板PYDANTIC_FORMAT_TMPL为Heres a JSON schema to follow: {schema} / Output a valid JSON object but do not repeat the schema.并把该模板附加到用户提示词末尾把 Schema 与数据一起发送给 LLM并指示其按 Schema 格式返回在__call__L98-L120中若 LLM 是对话模型则走chat并取message.content否则走complete并取response.text调用 Pydantic 的model_validate_json()解析PydanticOutputParser.parse先通过extract_json_str从文本中提取 JSON 片段再执行self._output_cls.model_validate_json(json_str)。这一路径依赖 LLM 自己按格式输出可靠性明显低于函数调用路径但所有基于文本的 LLM 都支持因此是覆盖面最广的兜底方案。直接调用预测类更低级的控制实践上structured_predict对任何 LLM 都应当开箱即用但若你需要更低级的控制完全可以绕过structured_predict直接实例化LLMTextCompletionProgram或FunctionCallingProgram并进一步定制行为。直接使用 LLMTextCompletionProgram下面这段代码与在无函数调用 API 的 LLM 上调用structured_predict完全等价返回的同样是 Pydantic 对象from llama_index.core.program import LLMTextCompletionProgram from llama_index.core.prompts import PromptTemplate textCompletion LLMTextCompletionProgram.from_defaults( output_clsInvoice, llmllm, promptPromptTemplate( Extract an invoice from the following text. If you cannot find an invoice ID, use the company name {company_name} and the date as the invoice ID: {text} ), ) output textCompletion(company_nameUber, texttext)从from_defaults的实现llm_program.py可以看到几个细节llm缺省时回退到全局Settings.llmprompt与prompt_template_str必须二选一output_cls未指定时会从PydanticOutputParser中反推未传output_parser时会自动构造PydanticOutputParser(output_cls...)。子类化 PydanticOutputParser 定制解析逻辑直接调用预测类的真正优势在于你可以通过子类化PydanticOutputParser并覆写get_pydantic_object方法来自定义输出解析例如为低能力low-poweredLLM 编写更聪明的纠错解析from llama_index.core.output_parsers import PydanticOutputParser class MyOutputParser(PydanticOutputParser): def get_pydantic_object(self, text: str): # do something more clever than this return self.output_parser.model_validate_json(text) textCompletion LLMTextCompletionProgram.from_defaults( llmllm, promptPromptTemplate( Extract an invoice from the following text. If you cannot find an invoice ID, use the company name {company_name} and the date as the invoice ID: {text} ), output_parserMyOutputParser(output_clsInvoice), )注意PydanticOutputParser.__init__pydantic.py会把传入的output_cls保存在self._output_cls属性中因此子类内部应通过self._output_cls.model_validate_json(...)而非self.output_parser访问目标模型示例中的self.output_parser仅为演示骨架实际覆写时请直接使用self._output_cls。这一机制对于解析能力较弱、容易输出脏文本的小型模型尤为实用你可以在这里加入去噪、字段重映射或基于规则的修补逻辑而完全不影响 LLM 调用部分。小结与下一步structured_predict家族方法位于「Structured LLM全自动提示」与「底层 Program 调用全手动」之间的关键位置它把提示词控制权交还给你同时替你处理 Pydantic Schema 生成、工具转换与输出解析。从源码看它的可靠性差异完全取决于底层引擎——函数调用路径FunctionCallingProgram与纯文本路径LLMTextCompletionProgram的分发逻辑清晰记录在 get_program_for_llm 中。如果你还想进一步下探——例如在一次调用中同时抽取多个结构体、完全绕过 Program 抽象——请继续阅读系列的最后一篇更低层的结构化数据调用。与之互补的内容还包括 结构化输入使用RichPromptTemplate将输入格式化为 XML以及开篇的 Pydantic 与 Schema 基础。【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表