LlamaIndex × Guidance 集成实战:用约束式结构化输出生成 Pydantic 对象并加固子问题查询引擎
【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
本篇技术指南围绕 LlamaIndex 官方社区集成文档 guidance.md 展开,系统讲解如何将微软开源的 Guidance 语言嵌入 LlamaIndex,利用其"强制约束"能力让 LLM 直接产出符合 JSON Schema / Pydantic 模型的结构化对象,并把这一能力注入SubQuestionQueryEngine的中间环节以提升子问题生成的鲁棒性。读完本文,你将掌握GuidancePydanticProgram的完整用法、handlebars 模板转换原理,以及GuidanceQuestionGenerator的接入方式。
为什么需要 Guidance:从"建议结构"到"强制结构"
常规的 LLM 结构化输出做法是在提示词里"请求"模型输出一段 JSON,再交给解析器处理。这种模式有两个隐患:一是模型可能产出畸形 JSON(例如缺少括号、字段错位),二是解析失败时整个链路报错,需要重试或容错逻辑。
Guidance 提供了一条不同的路径:它把生成(generation)、提示(prompting)和逻辑控制(logical control)交织进同一个连续流程,与语言模型实际逐 token 处理文本的方式对齐。最关键的是,它可以强制LLM 输出遵循指定 schema 的结构,而不是仅仅"建议"——模型只需专注于内容本身,语法层面的错误被彻底排除,输出解析问题因此完全消失。
这种能力对参数量较小、训练语料中源代码数据不足的弱模型尤其有价值:它们难以稳定地生成格式良好、层级正确的结构化输出,而 Guidance 的约束机制恰好弥补了这一短板。
GuidancePydanticProgram:一行代码生成 Pydantic 对象
LlamaIndex 将 Guidance 的约束能力封装为GuidancePydanticProgram,用于直接产出 Pydantic 对象。该实现位于 program/guidance/base.py,继承自核心库中的BaseLLMFunctionProgram(见 llm_prompt_program.py),其单元测试 test_program_guidance.py 验证了类的继承关系。
定义目标 schema
假设我们要生成一张"专辑",包含歌名与时长,schema 如下:
from pydantic import BaseModel from typing import List class Song(BaseModel): title: str length_seconds: int class Album(BaseModel): name: str artist: str songs: List[Song]注意 handlebars 模板约定
Guidance 使用 handlebars 风格模板:双花括号{{}}用于变量替换,单花括号{}表示字面花括号——这与 Python format string 的约定恰好相反(Python 中单花括号是变量占位符,双花括号才是转义后的字面括号)。
好在 LlamaIndex 提供了convert_to_handlebars工具函数(位于 guidance_utils.py),可把 Python format string 风格的提示模板一键转换为 Guidance 的 handlebars 模板。该函数的转换逻辑是:先将双花括号替换为临时占位符,再把所有单花括号翻倍,最后把占位符还原为单花括号,从而完成两种约定之间的互转。
创建并运行程序
from llama_index.program.guidance import GuidancePydanticProgram from guidance.llms import OpenAI as GuidanceOpenAI program = GuidancePydanticProgram( output_cls=Album, prompt_template_str="Generate an example album, with an artist and a list of songs. Using the movie {{movie_name}} as inspiration", guidance_llm=GuidanceOpenAI("text-davinci-003"), verbose=True, )然后像调用函数一样传入额外输入运行程序:
output = program(movie_name="The Shining")得到的就是一个结构完整的AlbumPydantic 对象:
Album( name="The Shining", artist="Jack Torrance", songs=[ Song(title="All Work and No Play", length_seconds=180), Song(title="The Overlook Hotel", length_seconds=240), Song(title="The Shining", length_seconds=210), ], )说明:
GuidancePydanticProgram内部通过user()/assistant()会话块包裹提示并追加gen(stop=".")生成调用;执行完成后,会用parse_pydantic_from_guidance_program从返回文本中提取最后一个 markdown 格式的 JSON 代码块,再经model_validate反序列化为目标 Pydantic 对象。由于当前 Guidance 版本尚不支持从Program.variables直接提取嵌套对象,源码中对此采用了"解析最终文本"的临时方案(注释中已明确标注),详情见 guidance_utils.py。
参数要点与 from_defaults 入口
output_cls:目标 Pydantic 模型类,决定强制输出的 schema;prompt_template_str:handlebars 风格的提示模板,其中的{{变量}}会在调用时以关键字参数传入;guidance_llm:Guidance 侧的 LLM 实例,例如GuidanceOpenAI("text-davinci-003");若未提供,源码中会默认回退到OpenAI("gpt-3.5-turbo");verbose:是否打印原始输出,便于调试。
此外还提供了from_defaults类方法,允许以prompt(PromptTemplate对象)或prompt_template_str二选一的方式初始化;两者都传或都不传会抛出ValueError。完整的可交互示例见 guidance_pydantic_program.ipynb。
底层:JSON Schema 到 Guidance 模板的自动转换
在 guidance_utils.py 中,json_schema_to_guidance_output_template负责把 Pydantic 模型的 JSON Schema 递归转换为 Guidance 约束模板:
object类型:输出字面{...}结构,逐字段展开;array类型:使用{{#geneach ...}}循环块,配合stop=']'与可选的max_iterations(对应 schema 的max_items)控制列表长度,元素间用{{#unless @first}}, {{/unless}}插入逗号;string类型:使用{{gen 'key' stop='"'}}生成带结束符约束的字符串;integer/number类型:默认同样以stop='"'约束,可开启use_pattern_control用pattern='[0-9\.]'限定数字字符;boolean类型:使用{{#select 'key'}}True{{or}}False{{/select}}强制二选一。
该实现基于微软 guidance 仓库的 jsonformer 思路,并扩展支持了嵌套 Pydantic 模型(通过$ref解析到$defs)。这也解释了为何弱模型也能稳定输出层级正确的 JSON——语法路径已被模板锁死。
用 Guidance 加固 SubQuestionQueryEngine 的子问题生成
LlamaIndex 提供了一系列高级查询引擎,其中不少依赖中间步骤的结构化输出。若中间响应结构不稳定,后续解析就会失败。Guidance 正好可以在此处发挥价值:确保中间响应具备预期结构,从而可被可靠地解析为结构化对象。
集成文档给出了一个典型实践:实现GuidanceQuestionGenerator并替换SubQuestionQueryEngine默认的问题生成器。其源码位于 question_gen/guidance/base.py,对应单元测试见 test_question_gen_guidance_generator.py。
from llama_index.question_gen.guidance import GuidanceQuestionGenerator from guidance.llms import OpenAI as GuidanceOpenAI # 定义基于 guidance 的问题生成器 question_gen = GuidanceQuestionGenerator.from_defaults( guidance_llm=GuidanceOpenAI("text-davinci-003"), verbose=False ) # 定义查询引擎工具 query_engine_tools = ... # 构建子问题查询引擎 s_engine = SubQuestionQueryEngine.from_defaults( question_gen=question_gen, # 使用上面定义的 guidance 版 question_gen query_engine_tools=query_engine_tools, )内部实现剖析
GuidanceQuestionGenerator继承自核心库的BaseQuestionGenerator,其from_defaults内部以SubQuestionList为output_cls构建了一个GuidancePydanticProgram,并使用默认子问题提示模板:
DEFAULT_GUIDANCE_SUB_QUESTION_PROMPT_TMPL = convert_to_handlebars( DEFAULT_SUB_QUESTION_PROMPT_TMPL )核心的generate方法会把工具列表序列化为 JSON 文本(build_tools_text,见 prompts.py),连同用户查询一起作为关键字参数传入程序,最终返回List[SubQuestion]。默认提示模板DEFAULT_SUB_QUESTION_PROMPT_TMPL(同样位于 prompts.py)要求模型"Given a user question, and a list of tools, output a list of relevant sub-questions in json markdown",并通过 Uber/Lyft 财务对比的示例引导输出{"items": [...]}结构。
值得注意的限制:agenerate方法目前仅同步转发到generate,源码注释明确说明"guidance does not support async calls"(见 base.py),因此异步场景下仍需走同步路径。
交互式完整示例见 guidance_sub_question.ipynb。
安装与依赖
两个集成分别打包为独立发行包,对应pyproject.toml如下:
- llama-index-program-guidance:提供
GuidancePydanticProgram,依赖guidance>=0.1.16,<0.2与llama-index-core>=0.13.0,<0.15,要求 Python>=3.10,<4.0; - llama-index-question-gen-guidance:提供
GuidanceQuestionGenerator,额外依赖llama-index-program-guidance>=0.4.0,<0.5。
安装命令示例:
pip install llama-index-program-guidance llama-index-question-gen-guidance guidance两个包的[tool.llamahub]配置分别声明了import_path为llama_index.program.guidance与llama_index.question_gen.guidance,与上文代码中的导入路径一一对应。API 参考文档也可在 program/guidance.md 与 question_gen/guidance.md 中查阅。
小结
通过本文你可以看到一条清晰的集成链路:
- 约束式结构化输出:
GuidancePydanticProgram把 Pydantic 模型转换为 Guidance 模板,强制 LLM 输出合法 JSON,从而彻底消除解析失败风险,尤其适合弱模型场景; - 模板兼容层:
convert_to_handlebars解决了 Python format string 与 handlebars 模板约定的差异,让既有提示模板可以无缝迁移; - 中间环节加固:
GuidanceQuestionGenerator复用同一套约束机制,让SubQuestionQueryEngine的子问题生成结构稳定、可解析,提升整条查询链路的鲁棒性。
需要动手验证时,推荐直接运行仓库中的两个 notebook——guidance_pydantic_program.ipynb 与 guidance_sub_question.ipynb,并结合上述源码路径理解每一步的底层行为。
【免费下载链接】llama_indexLlamaIndex is the document processing platform for AI项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考