ARTICLE DETAIL

资讯详情

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

Haystack Validators 组件实战:用 JsonSchemaValidator 校验 LLM 输出并构建自愈重试回路

Haystack Validators 组件实战:用 JsonSchemaValidator 校验 LLM 输出并构建自愈重试回路 Haystack Validators 组件实战用 JsonSchemaValidator 校验 LLM 输出并构建自愈重试回路【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystackHaystack 的 Validators校验器是一类专门用于验证 LLM 输出的组件。在生成式应用中模型返回的 JSON 常常不满足下游代码的预期结构而 JsonSchemaValidator 可以将这种不确定性转化为可控的管道分支符合 JSON Schema 的消息进入validated输出不符合的进入validation_error输出并将格式化后的错误提示回传给 LLM从而构成自动纠错的 recovery loop恢复回路。读完本文你将掌握is_valid_json与JsonSchemaValidator的完整 API、其在 Haystack 管道中的接线方式以及源码层级的校验机制与 OpenAl 函数调用function calling场景的适配细节。一、Validators 在 Haystack 中的定位在 Haystack 2.x 的组件体系中Validators 位于haystack/components/validators/目录目前核心实现集中在 json_schema.py 一个模块中并通过init.py 对外暴露JsonSchemaValidator。其 API 参考文档即本篇文章所依据的 validators_api.md由 pydoc 工具根据源码自动生成对应的 pydoc/validators_api.yml 声明了加载路径为../haystack/components/validators下的json_schema模块。Validators 的典型管道位置在 Generator如OpenAIChatGenerator之后属于输出质量把关环节。结合用户指南 jsonschemavalidator.mdx 的速查表项目说明常见管道位置Generator 之后必填运行参数messages待校验的ChatMessage列表列表中最后一条消息才是真正被校验的对象输出变量validated最后一条消息合法时输出validation_error最后一条消息非法时输出所属包haystack-ai二、模块级工具函数is_valid_json在进入组件之前先看模块级函数is_valid_json它负责最基本的 JSON 语法检查def is_valid_json(s: str) - bool参数s要检查的字符串。返回值字符串是合法 JSON 时返回True否则返回False。从源码看它的实现非常简单——直接调用json.loads(s)捕获ValueError后返回False否则返回True见 json_schema.py。它只验证能否被解析不关心解析后的结构是否符合业务语义结构层面的约束交给 JSON Schema 完成。这个函数同样被JsonSchemaValidator.run内部使用作为先验语法关。三、核心组件 JsonSchemaValidator 概览JsonSchemaValidator负责将ChatMessage的 JSON 内容与指定的 JSON Schema 进行比对核心行为如下若消息的 JSON 内容符合给定 schema消息沿validated输出口传出若不符合消息沿validation_error输出口传出出现校验失败时使用构造时传入的error_template若未提供则使用内置默认模板构造错误消息这些错误ChatMessage可用于 Haystack 2.x 的 recovery loop即让 LLM 读取错误并重新生成合规的 JSON。官方文档给出的标准使用示例管道版如下from haystack import Pipeline from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.joiners import BranchJoiner from haystack.components.validators import JsonSchemaValidator from haystack import component from haystack.dataclasses import ChatMessage component class MessageProducer: component.output_types(messageslist[ChatMessage]) def run(self, messages: list[ChatMessage]) - dict: return {messages: messages} p Pipeline() p.add_component(llm, OpenAIChatGenerator(modelgpt-4-1106-preview, generation_kwargs{response_format: {type: json_object}})) p.add_component(schema_validator, JsonSchemaValidator()) p.add_component(joiner_for_llm, BranchJoiner(list[ChatMessage])) p.add_component(message_producer, MessageProducer()) p.connect(message_producer.messages, joiner_for_llm) p.connect(joiner_for_llm, llm) p.connect(llm.replies, schema_validator.messages) p.connect(schema_validator.validation_error, joiner_for_llm) result p.run(data{ message_producer: { messages:[ChatMessage.from_user(Generate JSON for person with name John and age 30)]}, schema_validator: { json_schema: { type: object, properties: {name: {type: string}, age: {type: integer} } } } }) print(result) {schema_validator: {validated: [ChatMessage(_roleChatRole.ASSISTANT: assistant, _content[TextContent(text\n{\n name: John,\n age: 30\n})], _nameNone, _meta{model: gpt-4-1106-preview, index: 0, finish_reason: stop, usage: {completion_tokens: 17, prompt_tokens: 20, total_tokens: 37}})]}}该示例在 json_schema.py 的类文档字符串中同样存在二者内容一致可放心作为可复现脚本使用。示例中generation_kwargs{response_format: {type: json_object}}用于强制 OpenAI 返回 JSON 对象BranchJoiner(list[ChatMessage])负责把初始用户消息与校验失败后的错误消息合并为单一输入流喂给 LLM——这正是 recovery loop 得以闭合的关键。四、构造与运行 API 详解4.1 构造函数__init__def __init__(json_schema: Optional[dict[str, Any]] None, error_template: Optional[str] None)参数类型默认值说明json_schemadict[str, Any]None用于校验消息内容的 JSON Schema 字典error_templatestrNone校验失败时用于格式化错误消息的自定义模板字符串两个参数都允许在构造时预置也允许在每次run调用时临时覆盖详见下文。4.2 运行方法runcomponent.output_types(validatedlist[ChatMessage], validation_errorlist[ChatMessage]) def run(messages: list[ChatMessage], json_schema: Optional[dict[str, Any]] None, error_template: Optional[str] None) - dict[str, list[ChatMessage]]参数语义messages待校验的ChatMessage列表只校验列表中的最后一条消息其余消息原样旁路不参与校验、也不会被输出json_schema本次运行使用的 JSON Schema未提供时回退到__init__中设置的 schemaerror_template本次运行使用的错误模板未提供时回退到__init__中设置的模板再回退到内置默认模板。返回字典包含两个键validated最后一条消息校验通过时返回包含该消息的列表validation_error最后一条消息校验失败时返回包含错误提示消息的列表构造为ChatMessage.from_user(...)即角色为 user 的消息便于直接回喂给 LLM。可能抛出的异常RaisesValueError未提供任何 JSON Schemarun与__init__都未设置ValueError消息内容不是字典object或字典列表。源码中的具体实现是若最后一条消息的text为None无文本内容直接抛出ValueError(fThe provided ChatMessage has no text. ChatMessage: {last_message})见 json_schema.py。4.3 从 run 到输出的内部执行链结合源码 json_schema.pyrun的实际执行分五步取末条消息last_message messages[-1]若其text为空则抛ValueErrorJSON 语法检查调用is_valid_json(last_message.text)失败则直接返回一条validation_error消息提示消息不是合法的 JSON 对象请只提供合法的 JSON 字符串不要使用 markdown 或注释结构预处理通过json.loads解析内容并用_recursive_json_to_object递归把字符串形式的 JSON 子结构还原为真正的 dict/list 对象schema 归一化调用_is_openai_function_calling_schema判断传入 schema 是否为 OpenAI function calling 风格若是则取出其parameters字段作为实际校验 schema执行校验基于jsonschema库的validate逐一校验支持单个对象或对象列表全部通过返回{validated: [last_message]}捕获ValidationError后进入错误恢复分支。五、错误恢复机制默认模板与自定义模板校验失败时组件不会只返回一句干巴巴的校验失败而是生成一条信息密度很高的恢复提示指导 LLM 修正输出。源码中内置的默认模板default_error_template见 json_schema.py如下The following generated JSON does not conform to the provided schema. Generated JSON: {failing_json} Error details: - Message: {error_message} - Error Path in JSON: {error_path} - Schema Path: {error_schema_path} Please match the following schema: {json_schema} and provide the corrected JSON content ONLY. Please do not output anything else than the raw corrected JSON string, this is the most important part of the task. Dont use any markdown and dont add any comment.模板支持的占位符由_construct_error_recovery_message在 json_schema.py 中通过error_template.format(...)填充占位符含义{error_message}jsonschema 库返回的错误描述字符串{error_path}错误在 JSON 内容中的绝对路径e.absolute_path无则显示N/A{error_schema_path}错误在 JSON Schema 中的绝对路径e.absolute_schema_path无则显示N/A{json_schema}实际用于校验的 schema{failing_json}原始出错的 JSON 字符串自定义模板只需包含同样的占位符即可例如测试 test_json_schema.py 中验证的自定义模板new_error_template其中省略了提示只输出原始 JSON的指令但依然保留了{error_message}、{error_path}、{error_schema_path}、{json_schema}、{failing_json}五个占位符。测试断言_construct_error_recovery_message返回的字符串与手工拼接的期望值完全一致说明模板格式化是确定性的字符串替换。注意一个细节默认模板末尾明确要求 LLM只输出修正后的原始 JSON 字符串不要使用 markdown、不要添加任何注释。这是为 recovery loop 设计的——下一轮 LLM 的输出将再次进入JsonSchemaValidator如果模型在 JSON 外包了 代码块is_valid_json会直接判定非法循环将无法收敛。六、从源码与测试看三个关键设计6.1 只校验最后一条消息run内部对传入的messages列表只取messages[-1]进行校验。测试 test_json_schema.py 验证了这一点第一条 user 消息不参与校验即使它显然不是合法 JSON第二条 assistant 消息才被校验并进入validated输出。因此把完整对话历史传入组件是安全的组件天然兼容校验当前最新回复的语义。6.2 递归还原字符串化的 JSON 子结构LLM尤其是 function calling 场景常常把嵌套的 JSON 以字符串形式内嵌在 JSON 字段里。_recursive_json_to_object见 json_schema.py会递归遍历 dict/list把值为合法 JSON 字符串的字段解析为真正的 dict/list从而让jsonschema.validate能按结构化 schema 校验。测试 test_json_schema.py 中的genuine_fc_messagefixture 是一个典型的 function calling 载荷function.arguments是字符串形式的 JSON经递归还原后其basehead字段可以被 schema 中的pattern校验。测试同时覆盖了顶层标量hello、42、True等与标量列表等边界情况确认它们会被原样保留、不被破坏。6.3 兼容 OpenAI function calling schema_is_openai_function_calling_schema见 json_schema.py通过判断 schema 是否同时包含name、description、parameters三个键来识别 OpenAI 风格 schema识别后自动改用json_schema[parameters]作为校验基准并从消息内容中提取content[function][arguments]进行校验见 json_schema.py。测试 test_json_schema.py 使用json_schema_github_compare_openaifixture 验证了该分支一个仅含name/description/parameters的 schema 可以直接用于校验 function calling 消息。这意味着同一组件无需额外配置即可同时服务普通 JSON 输出校验与Agent 工具调用参数校验两种场景。七、在管道中实现 recovery loop完整接线与测试佐证recovery loop 是JsonSchemaValidator最具价值的应用模式。完整的接线方式如下用BranchJoiner(list[ChatMessage])把两个输入源合并成一路初始用户消息 校验失败产生的错误消息joiner_for_llm→llm把合并后的消息发给生成器llm.replies→schema_validator.messages把生成结果送入校验器schema_validator.validation_error→joiner_for_llm校验失败的消息回流触发下一轮生成。BranchJoiner的语义在此处至关重要它接收多个同类型数据连接只把第一个收到的值传给唯一输出见 branchjoiner.mdx从而保证循环中每一轮只有一个消息进入 LLM。这种分支合并 校验回环的结构在测试 test_json_schema.py 中得到验证test_schema_validator_in_pipeline_validated合法 JSON 进入validated且输出的ChatMessage.text与原始消息一致test_schema_validator_in_pipeline_validation_error非法 JSON如{key: value}不满足 schema进入validation_error且错误消息文本包含默认模板中的 Error details 片段。更精细的测试见 test_json_schema.py还覆盖了顶层标量 JSON 的边界当 schema 为{type: string}时hello带引号的字符串字面量校验通过而42、true、null等非字符串 JSON 均落入validation_error——说明组件遵循严格的 JSON Schema 类型语义不会把数字、布尔值隐式转换为字符串。八、最佳实践与使用建议配合 JSON 模式生成使用 OpenAI 系生成器时建议在generation_kwargs中设置{response_format: {type: json_object}}从源头提高首轮合规率减少 recovery loop 迭代次数该用法与官方示例一致。优先在__init__固化 schema在run中动态覆盖固定 schema如人物信息结构、工具参数结构适合构造时传入需要按输入动态变化的结构如不同请求对应不同 schema则适合在run的json_schema参数中传入。不要忽略错误消息的纯 JSON指令默认模板要求模型只输出原始 JSON若自定义error_template丢失该指令可能因 markdown 代码块包裹导致循环无法收敛。利用错误路径定位问题{error_path}与{error_schema_path}分别指向 JSON 内容侧和 schema 侧的出错位置调试复杂嵌套结构时能显著降低排查成本。注意消息列表语义传入的消息列表越长被旁路的消息越多——组件只返回最后一条消息其他消息既不会被输出也不会被校验请勿在validated输出中期待完整历史。九、进一步阅读API 参考validators_api.md本篇文章依据的官方参考文档用户指南jsonschemavalidator.mdx源码实现haystack/components/validators/json_schema.py单元测试test/components/validators/test_json_schema.py消息数据结构haystack/dataclasses/chat_message.pyfrom_user、from_assistant、from_system、from_tool等工厂方法以及text/texts访问器循环闭合组件branchjoiner.mdx【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表