[dify]从 Word 到条款 JSON:一次 Dify 工作流实践总结
最近做了一条基于 Dify 的工作流,主要解决一个比较具体的问题:把企业制度文档解析成结构化条款数据,并沉淀到数据库中,为后续制度与外规的条款级合规性匹配做准备。
一开始看,这件事像是在做“文档解析”。但真正做下来以后,我的感受是,难点除了ya“把文档拆开”,还要把解析结果真正变成后续系统能持续使用的数据。
如果只停留在“模型能看懂文档”“模型能输出一段 JSON”,这件事其实还没有真正落地。只有当这些结果被规范化、入库、可以被后续条款级检索和比对直接使用时,这条链路才算真正闭环。
这篇文章就把这次实践的思路和关键点做一个总结。
一、为什么会有这个需求
这次工作的出发点,并不是单纯想做一个“文档解析小工具”,而是为了支撑后续更具体的业务目标:
对企业内部制度和外部监管规定做条款级别的合规性匹配。
如果要做到这一点,原始的 Word 或 PDF 文档其实并不好直接使用。因为对人来说,制度文档当然是可读的;但对系统来说,它仍然是大段的非结构化文本。
而后续真正想做的事情,往往已经不是“把全文显示出来”,而是更细粒度的问题,比如:
-
某项外规要求,在企业制度里有没有对应条款覆盖 -
企业制度中的某一条,与哪一条外规最接近 -
哪些监管要求在制度中缺失 -
哪些制度条款表述不完整或者偏差较大
要支撑这些能力,前提不是“有文档”,而是:
文档内容必须先被拆成条款级、结构化的数据。
所以这次实践的本质,不是做一个解析流程本身,而是为后续条款级合规性匹配,准备可用的数据底座。
二、整体思路:模型负责解析,工作流负责入库
这次采用的方案并不复杂,核心就是把上下游职责拆开。
上游:大模型负责把 Word 文档解析成标准 JSON
原始制度文档先交给 AI 大模型,通过提示词约束输出格式,把文档解析成统一结构的 JSON。
下游:Dify 工作流负责把 JSON 落到数据库
工作流接收大模型输出的 JSON,完成文件匹配、状态判断、条款入库和主表状态更新。
整条链路可以概括为:
原始 Word 文档 → 大模型按提示词解析 → 输出标准 JSON → Dify 工作流入库
这套方案里,我觉得比较关键的一点是:
模型负责理解内容,工作流负责沉淀数据。
三、提示词:本质上是在定义输出规范
这次实践里,一个感受很深的点是:
真正让后续流程变得可控的,不只是模型能力,而是提示词把输出格式约束住了。
这里并不是简单地让模型“提取条款”,而是明确要求模型输出固定字段:
titlearticleSeqidNumberparentTitlecontent
同时要求:
-
字段顺序固定 -
不允许增删字段 -
不允许调换顺序
输出结果大致如下:
{"articles":[{"title":"文档标题","articleSeq":1,"idNumber":"第一条","parentTitle":"第一章 总则","content":"文档内容"}]}
这件事看起来像个小细节,但实际上非常关键。
因为如果没有这层约束,大模型输出就会很容易出现各种不稳定情况,比如字段命名不一致、顺序变化、缺少字段、混入解释说明,甚至把条款内容和模型自己的总结放在一起。从人工阅读角度看,这些都不一定是大问题;但从程序处理角度看,任何一点小变化都可能让后面的工作流变得不稳。
所以这次做下来,我更愿意把提示词理解成一份面向下游程序的输出接口规范。正因为这份规范足够明确,后面的工作流逻辑才能尽量简单。
四、数据库为什么拆成两张表
为了支撑后续条款级合规性匹配,这次数据库没有把所有内容直接堆进一张表,而是拆成了两张。
1. 文档基本信息表
这张表记录文档级信息,主要包括:
-
文档标题 -
是否完成解析 -
是否已抽取条款 -
条款数量
它更像“主表”,负责描述一份制度文档当前所处的处理状态。比如某个制度文档有没有处理过、当前是否已经完成结构化、是否已经抽取过条款,这些都通过这张表管理。
2. 文档条款数据表
另一张表记录条款级明细。也就是把 JSON 中的 articles 数组逐条展开,每一条都存成独立记录。
这张表里保存的核心内容,基本就是:
-
文档标题 -
条款顺序号 articleSeq -
条款编号 idNumber -
父级标题 parentTitle -
条款正文 content
这样拆分以后,结构会更清楚:
-
主表回答的是:这份文档处理到哪一步了 -
明细表回答的是:这份文档具体拆出了哪些条款
从后续条款级检索、相似度匹配、覆盖分析这些应用场景来看,这种“一张主表 + 一张明细表”的设计是比较合适的。
五、这条 Dify 工作流在做什么
如果只看这条工作流本身,它的职责其实很明确:
把大模型输出的条款 JSON,按文档逐个匹配主档,并批量写入条款明细表,同时更新文档主表状态。
它不是做 OCR,不是做全文理解,也不是直接做合规比对。它做的是中间这一步很关键的事情:
把结构化结果变成正式业务数据。
从流程上看,整条链路大致是这样的:
读取 JSON 文件 → 根据文件名匹配制度主档 → 判断是否已入库 → 提取 articles → 转换字段 → 写入条款明细表 → 更新文档基本信息表
换句话说,它做的核心工作其实只有两件事:
第一,把条款 JSON 和正确的制度主档对应起来; 第二,把这些条款正式沉淀到数据库里。
六、几个关键dify节点的作用
这条工作流整体不复杂,但几个关键节点还是很值得记一下。
1. 查询制度主档映射
流程开始后,会先从数据库里取出文档标题和对应主档编号的映射关系。因为条款不能孤立入库,必须明确它属于哪一份制度文档。
2. 文件名清洗和标题提取
上传的 JSON 文件名,往往不一定完全规范。所以流程里专门做了一层处理:
-
去掉括号里的“修订版”“最终稿”等说明 -
去掉 .json扩展名
这样得到一个相对标准的标题,再去和数据库中的文档标题做匹配。
这一层看起来很朴素,但很实用。因为实际工作里,文件命名差异是很常见的,如果不先清洗,后面的匹配成功率会低很多。
3. 主档匹配
清洗完文件名后,流程会根据 title 去匹配主表中的文档标题,找到对应的主档记录。
如果匹配不到,后面就不能继续,因为条款数据没有归属。这也说明当前这条流程对文件命名规范还是有一定依赖的。
4. 入库状态判断
在真正写库之前,流程会先查主表状态,判断这份文档是否已经完成条款抽取。
如果已经入库,就直接跳过;如果还没入库,才继续往下走。
这一层的作用很明确,就是避免重复写库。对于批量处理场景来说,这一步是必须的。
5. JSON 数据转换
这是整条流程里最核心的业务节点。
这一节点会读取 JSON 中的 articles 数组,把每一条 article 转换成数据库需要的结构,并补充与主档相关的字段。
简单说,就是把:
articleSeqidNumberparentTitlecontent
这些字段,变成条款明细表中的正式记录。
这里还有一个小处理:如果发现条款编号重复,会做简单去重,避免后续入库时出现问题。
6. 条款表入库与主表状态更新
流程真正写库时分两步:
第一步,把条款列表批量写入条款明细表; 第二步,更新文档基本信息表中的状态字段,比如:
-
是否已抽取条款 -
条款数量 -
当前处理状态
这样做的好处是,既保留了条款级数据,也同步维护了文档级状态。后续不管是查看处理进度,还是再次触发流程,都更方便。
总结
这次基于 Dify 的工作流实践,本质上做成了一件事情:
把企业制度 Word 文档,通过大模型解析成标准条款 JSON,再通过工作流沉淀成可用于条款级合规性匹配的结构化数据。
如果只看某一步,这件事并不算复杂;但把“文档解析—结构约束—数据落库”这几步真正串起来,才能形成一条能支撑后续业务应用的完整链路。
从这个角度看,这条流程真正的意义,不只是“自动化处理了文档”,而是:
为制度与外规的条款级合规性匹配,准备了一个可持续、可复用、可扩展的数据基础。
夜雨聆风