☰
【Dify自动化实战】用代码节点校验缺失与异常字段
2026/10/19 2:10:15 网站建设 项目流程

用代码节点校验缺失与异常字段

课程归属:Dify自动化实战 · 第 9 节

在“资料报告助手”中,参数提取节点可以把材料整理成source_name、summary、key_points、source_refs和warnings,但模型输出仍可能缺字段、把数组写成字符串,或生成无法在原文中找到的引用。本文在提取节点后增加一个 Dify 代码节点,用 Python 检查字段是否齐全、类型是否正确,并把问题整理成可供 IF/ELSE 节点判断的结果。完成后,工作流能区分“节点执行成功”和“数据通过验收”;代码校验结构,不负责证明内容真实。

一、本文要交付什么

本篇沿用课程项目“资料报告助手”,只解决一个问题:在报告生成前,对参数提取结果执行确定性的字段校验。不在这里实现 OCR、知识库检索或 Word 文件生成。

示例输入是教学模拟材料:

文件名:社区图书馆数字服务试点说明.txt 内容:试点计划在两家社区图书馆开展,为读者提供线上预约和活动提醒。第一阶段预计持续六周,主要观察预约完成情况、活动到场情况和读者反馈。当前尚未提供预算、样本量和对照组信息。建议先进行小范围试运行,再根据反馈决定是否扩大范围。

课程公共字段保持不变。source_refs是对象数组,每项必须含三个字符串字段;warnings用来记录资料缺项或证据不足。代码节点额外输出validation_passed与validation_errors,供流程控制使用,不替换原有业务字段。

表 1:字段契约与校验边界

字段期望类型基础校验不由本节点保证的事项
source_nameString去除首尾空白后非空文件名是否真实、来源是否可信
summaryString去除首尾空白后非空摘要是否遗漏原文重点
key_points字符串数组至少一项;元素为非空字符串要点是否覆盖所有事实
source_refs对象数组每项包含source_name、locator、excerpt三个非空字符串引文是否逐字存在于原文
warnings字符串数组每项为非空字符串;允许空数组警告是否足够全面

这里的“异常”指字段缺失、类型不符、空字符串、空数组或对象子字段不完整。即使所有检查通过,也只能说明输出符合结构契约,不能将其视为事实准确性的证明。

二、代码节点放在什么位置

代码节点(Code)允许在工作流中执行 Python 或 JavaScript,用于确定性的数据处理。使用上要配置输入变量、编写main函数,并声明返回字典中对应的输出变量;它不是可以任意访问宿主文件系统的普通脚本环境。自托管部署还依赖 Dify 的 sandbox 服务,具体部署状态应以当前实例为准。官方代码节点说明

是

否

User Input:files、report_topic

文档提取

参数提取:五类字段

代码节点:类型与必填校验

validation_passed?

报告生成节点

输出错误与警告

图 1 中,代码节点位于模型提取之后、报告生成之前。这样一来,字段错误会在消耗后续生成步骤之前暴露;如果代码节点本身报错,则应检查代码节点日志,而不是将其误认为普通校验失败。

校验规则要分层

第一层检查类型和必填值,适合用 Python 完成;第二层检查字段之间的关系,例如引用的source_name是否与主来源一致;第三层检查证据内容,例如excerpt是否确实存在于原文。本文完整实现第一层,并检查引用对象的字段形状。由于本篇代码没有拿到原文全文,因此不执行引用片段的原文匹配。

表 2:哪些检查适合放在代码节点

检查推荐位置原因
字符串是否为空代码节点规则确定、结果可重复
数组元素是否都是字符串代码节点不需要模型推理
引用对象是否缺少字段代码节点可按固定 schema 遍历
摘要是否忠实原文人工抽查或专门评测仅靠类型检查无法判断语义真实性
引文是否出现在原文取得原文的代码校验或后续验证节点需要原文作为额外输入

三、配置代码节点输入与输出

在 Dify Studio 打开“资料报告助手”的 Workflow 画布,在参数提取节点后添加 Code 节点,选择 Python 3。不同版本的节点面板文字可能略有差异,关键是输入变量的映射、代码和输出变量三部分要一致。

1. 配置输入变量

在代码节点的 Input Variables 中逐项增加下表映射。右侧值要从变量选择器里选参数提取节点对应的输出,不要把字段名作为普通文本输入。

表 3:代码节点输入映射

代码参数名变量来源预期类型
source_name参数提取节点 /source_nameString
summary参数提取节点 /summaryString
key_points参数提取节点 /key_pointsArray[String]
source_refs参数提取节点 /source_refsArray[Object]
warnings参数提取节点 /warningsArray[String]

若实际节点没有提供Array[Object]类型,先检查当前版本的参数提取节点是否支持嵌套对象数组。不要为了让画布保存成功而把source_refs偷换成含义不同的字符串字段;必要时应明确增加转换步骤,并保证最终输出契约一致。

2. 粘贴完整校验代码

将下面代码放入 Python 代码编辑器。代码不读写文件、不调用网络,也不依赖第三方库。它会保留符合格式的字段、去掉首尾空白,并把发现的问题追加到validation_errors。如果某个字段类型不正确,会以安全的空值形式输出该字段,同时将validation_passed设为False。

defmain(source_name:str,summary:str,key_points:list,source_refs:list,warnings:list)->dict:errors=[]defclean_string(value,field_name,required=True):ifnotisinstance(value,str):errors.append(f"{field_name}必须是字符串")return""value=value.strip()ifrequiredandnotvalue:errors.append(f"{field_name}不能为空")returnvalue source_name=clean_string(source_name,"source_name")summary=clean_string(summary,"summary")ifnotisinstance(key_points,list):errors.append("key_points 必须是字符串数组")key_points=[]else:cleaned_points=[]forindex,iteminenumerate(key_points):ifnotisinstance(item,str)ornotitem.strip():errors.append(f"key_points[{index}] 必须是非空字符串")else:cleaned_points.append(item.strip())key_points=cleaned_pointsifnotkey_points:errors.append("key_points 至少需要一条有效要点")ifnotisinstance(source_refs,list):errors.append("source_refs 必须是对象数组")source_refs=[]else:cleaned_refs=[]required_ref_fields=("source_name","locator","excerpt")forindex,iteminenumerate(source_refs):ifnotisinstance(item,dict):errors.append(f"source_refs[{index}] 必须是对象")continuecleaned_item={}item_valid=Trueforfieldinrequired_ref_fields:value=item.get(field)ifnotisinstance(value,str)ornotvalue.strip():errors.append(f"source_refs[{index}].{field}必须是非空字符串")item_valid=Falseelse:cleaned_item[field]=value.strip()ifitem_valid:cleaned_refs.append(cleaned_item)source_refs=cleaned_refsifnotsource_refs:errors.append("source_refs 至少需要一条完整来源证据")ifnotisinstance(warnings,list):errors.append("warnings 必须是字符串数组")warnings=[]else:cleaned_warnings=[]forindex,iteminenumerate(warnings):ifnotisinstance(item,str)ornotitem.strip():errors.append(f"warnings[{index}] 必须是非空字符串")else:cleaned_warnings.append(item.strip())warnings=cleaned_warningsreturn{"source_name":source_name,"summary":summary,"key_points":key_points,"source_refs":source_refs,"warnings":warnings,"validation_passed":len(errors)==0,"validation_errors":errors}

3. 声明输出变量

在 Output Variables 中声明下表字段,名称必须与return字典的键完全一致。数组类型应与节点实际支持的类型匹配;若 UI 的类型命名不同,以对应版本的选项为准。

表 4:代码节点输出定义

输出变量类型用途
source_nameString清理后的来源名称
summaryString清理后的摘要
key_pointsArray[String]合法要点列表
source_refsArray[Object]字段齐全的来源对象
warningsArray[String]原始警告列表
validation_passedBoolean是否没有结构校验错误
validation_errorsArray[String]可读的校验错误清单

请注意:warnings是材料本身的警告,validation_errors是程序发现的结构问题,两者用途不同,不应合并成一个字段。输出保留课程公共字段,同时增加本章控制字段。

四、把校验结果接入分支

在 Code 节点后添加 IF/ELSE 节点。IF 条件选择 Code 节点的validation_passed,判断是否为true。通过分支连接到后续报告生成节点;失败分支连接到输出节点,返回validation_errors,并保留warnings供用户理解资料限制。

是

否

Code 输出

validation_passed 为 true?

使用校验后的五类字段

生成 report_markdown

输出 validation_errors

停止正式报告生成

图 2 强调失败分支不是“模型再说一遍已完成”,而是明确返回机器检测到的问题。若要让失败任务自动重试参数提取,应另行设置有限重试和停止条件;不要把无限循环当作修复机制。

五、测试输入与预期结果

先用教学模拟材料跑正常用例,再通过节点的单步测试或工作流 Test Run 检查异常输入。以下结果是根据代码逻辑整理的预期结果,不是某个 Dify 实例的实测截图或运行记录。本地 Python 语法与函数逻辑可独立测试,但最终仍需在目标 Dify 实例中确认变量类型、输出 schema 和 sandbox 状态。

正常用例

输入参数示例:

{"source_name":"社区图书馆数字服务试点说明.txt","summary":"试点计划在两家社区图书馆开展线上预约和活动提醒服务,第一阶段预计持续六周,并观察预约完成、活动到场和读者反馈。","key_points":["试点范围为两家社区图书馆。","第一阶段预计持续六周。"],"source_refs":[{"source_name":"社区图书馆数字服务试点说明.txt","locator":"原文第1句","excerpt":"试点计划在两家社区图书馆开展,为读者提供线上预约和活动提醒。"}],"warnings":["材料未提供预算、样本量和对照组信息。"]}

按代码逻辑,预期validation_passed为true,validation_errors为空数组,五个公共字段以校验后的类型返回。需要再次强调:此结果只证明结构符合规则,不能单凭它判断excerpt是否确实出现在原文中。

正常用例的关键输出可以概括为:

{"validation_passed":true,"validation_errors":[],"source_name":"社区图书馆数字服务试点说明.txt","key_points":["试点范围为两家社区图书馆。","第一阶段预计持续六周。"]}

这是为了便于读者对照的局部预期输出,不是完整运行日志;实际 Code 节点还会返回summary、source_refs和warnings。如果 UI 展示了其他节点变量或内部运行元数据,不要把它们误认为本代码return中声明的业务字段。

异常用例:引用缺字段且摘要为空

把summary改为空字符串,并把source_refs[0]的locator删除。预期结果是validation_passed为false,validation_errors至少包含summary 不能为空和source_refs[0].locator 必须是非空字符串。工作流应进入失败分支,不继续生成正式报告。按当前代码,错误数组还会包含“source_refs 至少需要一条完整来源证据”,因为不完整对象不会被保留为有效引用。该行为是明确的失败策略,不是模型生成内容的修改。

异常输出的关键部分应类似下面这样:

{"validation_passed":false,"validation_errors":["summary 不能为空","source_refs[0].locator 必须是非空字符串","source_refs 至少需要一条完整来源证据"]}

错误消息是供开发和排查使用的稳定文本。若下游只需要做分支判断,应该读取布尔值validation_passed;不要用“错误数组是不是恰好等于某段中文”来控制流程,因为后续增加校验规则时,错误条数和顺序可能变化。

表 5:测试矩阵与通过标准

用例故障注入预期检测通过标准
T1 正常输入五类字段格式正确validation_passed=true错误数组为空,字段类型正确
T2 摘要为空summary=""提示摘要不能为空分支停止正式报告生成
T3 要点类型错误key_points传入字符串提示必须是字符串数组错误被明确列出,不静默当作单项要点
T4 引用缺字段删除locator指出具体引用索引和字段不把不完整引用传给报告生成节点
T5 警告类型错误warnings传入字符串提示警告必须是字符串数组错误路径可从运行日志定位

如果 T1 未通过,先看代码节点的输入映射和输出变量声明,再检查参数提取节点是否真的返回数组或对象数组。若代码节点显示执行异常而不是返回validation_passed=false,重点查看 LAST RUN 中的错误信息;这通常属于变量映射、运行环境或代码异常,而不是普通业务校验失败。

六、常见故障与边界

代码编辑器保存失败

检查是否定义了main函数、是否返回字典,以及输出变量是否与返回键一一对应。代码节点不是完整的 Python 项目环境,不要假设可以直接安装任意包、访问本机路径或发起网络请求。自托管部署时还需确认 sandbox 服务正常运行。

数组被传成字符串

例如key_points收到"第一条;第二条",代码会报告类型不符,而不会自行猜测分隔符并拆分。这是有意设计:静默转换可能把原文中的标点误当作字段边界。如果业务确实需要兼容字符串输入,应增加明确的预处理规则,并为转换后的结果增加测试。

字段完整但内容不可信

类型校验不是事实核查。更严格的做法是把文档提取节点的原文一并传入代码节点,对每条excerpt做规范化后的子串匹配;匹配失败时加入证据错误。即便匹配成功,也只证明片段存在,不证明摘要完整或推论合理。高风险报告仍需要人工复核。

没有输出错误,但下游仍失败

核对 IF/ELSE 的条件是不是引用了 Code 节点的validation_passed,而不是同名文本;同时确认失败分支和成功分支连接正确。若通过分支引用了参数提取节点的原始字段而不是 Code 节点的校验后字段,校验清理结果就可能被绕过。

七、完成验收

  • Code 节点的五个输入映射指向参数提取节点的实际输出。
  • 输出变量名称和类型与return字典匹配。
  • 正常用例通过,validation_errors为空数组。
  • 空摘要、错误数组类型、引用缺字段等异常用例被拦截。
  • IF/ELSE 成功分支使用 Code 节点的校验后字段。
  • 失败分支输出明确的validation_errors,不生成正式报告。
  • 在目标 Dify 实例中检查运行详情,并确认 sandbox / 节点配置可用。

本篇完成后,“资料报告助手”具备了结构化字段的基础质量门槛。下一节可以在此基础上继续检查缺失与异常字段的业务规则,例如要点数量、来源名称一致性,以及引用片段是否能在原文中找到。

参考资料

  1. Dify 官方文档:Code 节点
  2. Dify 官方文档:30-Minute Quick Start(Workflow 与节点配置示例)
  3. Dify 官方仓库:Code 节点配置实现
  4. Mermaid 官方文档:Flowcharts

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询