☰
用Dify工作流打造财务报销审核智能助手:从违规检测到汇总生成
2026/10/20 12:07:27 网站建设 项目流程

1. 项目概述与整体设计思路

1.1 财务报销审核的真实痛点

先聊一个我踩了很久的坑。财务报销审核这个场景,说大不大,说小不小,但痛点非常真实:报销单数量多、字段琐碎、业务场景五花八门,尤其到了月底季末,报销单堆积如山,全靠人工逐单核对,光是发票抬头、报销限额、差旅标准这些基础项就能耗掉一个财务大半天的精力。更麻烦的是,每个部门、每个项目组的报销规则还不太一样,很多时候审核人员需要在企业制度、项目预算和现实情况之间来回斟酌,纯靠人脑记住所有规则,既不现实也容易出错。

我的团队成员在做月度报销审核时,经常遇到三类问题:一是超标准报销和违规项漏检,比如住宿费超标、餐饮报销限额突破,这些数字藏在各种单据的角落,肉眼扫过很容易忽略;二是报销单字段不完整,常见的就是缺少发票号码、没有填写费用归属项目、日期格式不规范,打回去重新补又来回拉扯好几轮;三是管理层需要看汇总数据,人工从几十张单子里筛出问题项、算总和,既慢又容易漏。这三个痛点合在一起,就是我想用大模型应用平台去解决的出发点。

1.2 为什么选 Dify 而不是纯代码或纯 Prompt

有人可能会说,这种需求直接调大模型 API 写个脚本不就行了,何必用 Dify。我的看法是:如果只是做个一次性实验脚本确实可以,但财务报销审核是典型的需要规则可维护、流程可追踪、结果可复核的场景。纯代码方案里,提示词、规则库、模型参数全混在代码里,财务同事想调整一条报销标准,还得来找开发改代码,沟通成本和出错概率都很高。纯 Prompt 方案更不靠谱,把审核规则全塞进一个提示词里既容易超出上下文窗口,规则更新也没法追溯。

Dify 作为 LLM 应用开发平台,正好把这些问题都兜住了。它的工作流编排可视化,审核规则可以通过知识库独立维护,业务人员也能看懂流程的每一步做了什么,在哪个节点判定违规,在哪个环节补全字段,都是透明的。另外 Dify 对多模型的支持比较友好,既可以用闭源商用模型,也可以接开源模型,方便做成本控制。这个项目我把核心业务逻辑拆成三个模块:违规检测、字段补全、汇总生成,三个模块既独立又串联,最终组合成一个完整的自动化审核流程。

1.3 系统整体架构与工作流设计

整个助手的核心是一个多阶段工作流,处理一条报销数据的过程大概是这样的:先接收原始报销输入(可以是手工录入的结构化字段,也可以是不太规整的自然语言描述),然后进入第一个判断节点,提取和规范化关键字段;接着通过知识库检索获取相关的报销制度要求和历史案例,进行违规检测判定,输出问题和原因;再针对缺失字段,结合已有信息和规则配置,给出补全建议;最后把所有处理过的单据汇集成一份结构化的审核汇总,包括通过项、问题项、金额统计、风险提示等。

工作流会做成四个主要阶段:输入解析与字段提取、制度知识检索、逐一检测与补全、汇总生成。这样做的好处是把复杂的审核逻辑拆成标准化步骤,每一步都可以单独测试和调优。比如字段补全效果不好,我可以单独调试补全节点的提示词,而不影响其他模块的运行。整体链路中用到了 LLM 节点、知识检索节点、条件分支节点、变量聚合节点和代码节点,这也是 Dify 工作流编排里最主要的几种节点类型。

2. 核心功能拆解与实现逻辑

2.1 违规检测:当知识库遇上语义判断

违规检测是三个模块里最核心的,也是最容易踩坑的。财务报销规则虽然看着是硬性标准,但真正执行起来有很多模糊地带,比如"住宿费标准是每晚不超过500元",但一线城市的酒店普遍贵,制度里又会加一句"旺季或特殊情况可视实际情况上浮",这种规则维度组合起来,单纯靠正则匹配关键词根本不现实。所以我用的是知识库 + 大模型语义判断的组合方式。

具体做法是,把公司报销制度、各类费用限额表、差旅标准、常见违规案例说明全部沉淀到一个知识库中,按照费用类型、部门差异、城市等级等维度做好文档切分。违规检测节点的输入是第一步提取出来的报销字段信息,LLM 会先根据报销项的费用类别和业务场景,从知识库检索最相关的制度段落,再结合具体数值和上下文做综合判定,输出是否有违规嫌疑、违规类型、涉及制度条款、置信度评估这几个结构化结果。

这里有个关键点要重点说明:违规检测节点不能只做二分类说"合规"还是"违规",而是要输出违规原因 + 相关依据,方便后续人工复核。我见过不少类似的助手项目就是把判定结果粗暴地输出成"存在违规"几个字,毫无解释性,审核人员根本不放心直接用。所以我在提示词里明确要求必须引用制度条款原文,并说明金额或条件是如何超标的,把判定依据落回到可查证的文本上。

2.2 字段补全:不瞎猜,有依据地填

报销单字段不全是最烦人的问题,常见缺失项有发票号码、开票日期、费用归属部门、供应商名称等。字段补全的难点在于,很多缺失字段没法靠报销单本身推断出来,比如缺发票号,就只能靠历史开票记录或关联数据去关联。所以补全策略要区分场景,我不能让模型在毫无依据的情况下瞎编一个发票号出来,那比缺失还严重。

我的设计思路是:先做字段缺失类型识别,区分"可补全字段"和"需人工补充字段"两大类。可补全字段比如日期格式、费用归属大类、项目名称缩写等,这些可以根据上下文逻辑推断;需人工补充字段比如发票号码、对方税号这类唯一性标识,如果历史数据里有匹配记录就走代码节点关联补全,没有就直接标记为"待人工确认",绝不让模型编造。

在 Dify 中实现时,我用了条件分支节点。LLM 补全节点先分析缺失字段集合,输出每个字段是"可推断"还是"需人工",然后工作流根据这个判断走不同的处理路径。可推断的字段继续走 LLM 补全子流程,需人工的字段则直接进入最终报告的问题清单,标注为红色风险项,这就有效避免了模型幻觉问题。

2.3 汇总生成:结构化报告,而不是一段话

汇总生成模块解决的是"一堆单据怎么呈报给领导"的问题。人工做汇总通常是先算总金额,再按费用类型分一下类,把有问题的单据挑出来说明情况,最后给一个总体结论。整套逻辑放到 LLM 上,最忌讳的就是让它"自由发挥",把结果输出成一段流畅的散文,那样反而不利于阅读和后续处理。

我的做法是在汇总节点前定义一套严格的输出 JSON Schema,包括汇总统计(总单数、总金额、通过率、问题单数)、违规明细列表(单据编号、违规类型、问题描述、涉及金额、风险等级)、待补全清单(单据编号、缺失字段、当前状态)、整体审核建议这四个核心区块。LLM 严格按照这个结构输出,方便下游做自动格式化或导入BI看板。

这里我要提醒一句:JSON Schema 一定要写死在提示词中,而且配合 few-shot 示例效果会好很多。不给出示例的话,模型偶尔会在数组下标、字段命名上出偏差,比如把"items"写成"item",虽然格式检查报错能拦住,但来回重试不仅浪费时间还会增加 token 成本。加了两个 few-shot 示例之后,输出格式的稳定性明显提升。

2.4 为什么拆成四个阶段而不是一个完整 Prompt

写到这里我得专门解释一下架构取舍。最初我确实试过把整个审核流程放进一个超长 Prompt,让模型一次性完成提取、检测、补全、汇总,结果效果很不理想。最大的问题是上下文污染:前面步骤的推理过程会干扰后面步骤的判断,比如模型在检测阶段已经认定某单"疑似违规",到汇总阶段就倾向于把这些单子都算成违规,而不是重新审核数据本身。

拆成四个独立阶段后,每个阶段可以单独用不同的模型、不同的温度参数,甚至不同节点的上下文可以过滤干净。提取字段节点不需要关心报销制度,违规检测节点不需要关心输出格式。这也让整个工作流的调试体验好了很多,出了问题我能很快定位到具体节点,而不是在一个巨型 Prompt 里大海捞针。如果你对 Dify 还不算太熟,我觉得这个"拆解为主、串联为辅助"的思路,是比任何具体配置技巧都更重要的一种设计习惯。

3. 实操搭建流程:从零开始配置工作流

3.1 第一步:准备环境与配置知识库

实操环境这块,我使用的是 Docker Compose 方式部署的开源 Dify 社区版,模型方面配置了两种大语言模型:主推理模型使用通用能力较强的商用模型,另配了一个响应更快的轻量模型处理简单分类任务,这样能在不牺牲精度的前提下控制成本。Dify 的模型供应商接入很简单,在"设置-模型供应商"里填 API Key 即可,关键是做好不同节点的模型分配。

知识库配置是整个项目前期工作量最大的部分。我整理了公司三份核心文档:费用报销管理制度、差旅费管理办法、部门预算执行细则,加上过去半年内典型违规案例的脱敏整理,总共大约 40 多页内容。这里要特别强调文档切分策略:不能简单按字数硬切,而是按语义章节和条款边界切分,每条制度条款保持独立。我建议切分参数中使用 300-500 字符的分块大小,重叠区域设置 50 字符左右,这样既能保证单块语义完整,又不至于让检索结果碎片化。

3.2 第二步:设计输入变量和输出结构

进入工作流编排前,先把变量的定义想清楚,这是避免后期返工的关键一步。我为这个项目定义了四类变量。

输入变量主要包括:报销单号、报销人、部门、费用类型、报销金额、费用发生日期、发票号码、备注信息。其中备注信息是最有意思的,因为员工填报销单时经常会把真实情况写在备注里,比如"因客户临时到访,住宿超标一晚",这段话对后续违规判断非常重要,如果只提取结构化字段会完全丢失信息。

中间变量则是各阶段节点产生的临时数据,比如字段提取节点输出的"规范化的费用对象",违规检测节点输出的"违规判定结果",字段补全节点输出的"补全建议列表"。

最终输出变量统一成一个结构化的 JSON 字符串,包含汇总统计、违规明细、待补全清单、审核建议四部分。我强烈建议输出变量不要拆散了,因为最终报告是整体生成的,拆散反而会增加聚合复杂度。

Dify 的变量引用机制比较直观,在 LLM 节点的提示词里可以直接输入变量名来引用上下文的值。但这里有个值得注意的细节:不同节点产生的输出如果要被下游节点引用,得在节点配置里把输出类型设置好,尤其是代码节点的输出需要明确指定输出格式,否则下游 LLM 节点拿到的是乱糟糟的字符串,解析质量会很差。

3.3 第三步:编排工作流节点

我先说一下完整的节点链路,然后逐个讲解关键节点的配置要点。

整个工作流从"开始"节点进入,第一个节点是 LLM 节点负责字段提取和规范化,第二个是知识库检索节点负责命中相关制度条款,第三个是 LLM 节点负责违规检测,接着是条件分支判断是否存在缺失字段,如果有缺失就走字段补全子流程,之后是聚合节点合并所有信息,最后 LLM 汇总节点输出报告,再到"结束"节点输出最终结果。

字段提取节点的提示词设计,重点是让模型输出结构化的字段集合。我会在系统提示词里写明:你是财务报销数据标准化助手,从用户输入中提取报销相关信息,输出为 JSON 格式,字段取值只能从给定枚举中选择,未明确出现的字段留空。同时给了一个示例输入和示例输出。这里特别要强调字段枚举的限制,因为报销单里的费用类型非常容易写乱,"差旅费"可能被写成"出差打车"、"交通费"、"车费"等等,如果不做枚举限制,后续检测节点匹配制度时会出现严重偏差。

知识库检索节点使用 Dify 的"知识检索"节点,模式选择"多路召回",检索策略可以根据文档数量选择"语义检索"或"全文检索"。我的经验是语义检索在这类制度性内容上表现更好,因为制度条款和报销单描述用的词汇差别较大,比如报销单写"客户吃饭",制度里写的是"业务招待费",语义检索能更好地建立这种跨表达的关联。召回数量我设置为 6 个段落,太少容易漏关键条款,太多会引入无关内容干扰判断。

违规检测节点的提示词是项目成功最核心的环节,我在系统提示词里写入了这样的逻辑框架:

你是企业财务合规审核专家。用户将提供报销单的规范化信息以及相关制度条款,请基于以下步骤进行审核: 第一步分析报销单字段完整性; 第二步逐项核对制度条款中的限制条件; 第三步判断是否违规,违规类型包括:超标准报销、无发票报销、费用滥用、缺少审批、重复报销等; 第四步输出结构化结果,包含是否违规、风险等级(高/中/低)、违规原因、涉及条款原文、建议处理方式。

这个节点直接用字符串模板方式引用知识检索结果的变量,我试过直接把"{{#sys.knowledge#}}"整块塞进去,效果还算稳定,但偶尔会出现模型把检索到的多条不相关内容都当成依据的情况。所以后来我在提示词里加了一行非常关键的约束:"只依据上述制度内容进行判断,如果制度内容中没有明确提及该费用类型的限制规定,则默认视为无明确违规依据,标注为需人工复核。"

这条约束帮我规避了模型最常见的"生搬硬套"问题。之前测试时,模型时不时会把一个旅游类报销的证据链生搬硬套到差旅规定里,给出荒谬的违规结论。加入上述约束后,这种情况基本消失了。

3.4 第四步:代码节点处理特殊逻辑

虽然这个项目主要靠 LLM 节点驱动,但有两个环节我用了代码节点:一个是金额阈值的前置校验,一个是汇总阶段的数据聚合。

金额阈值校验我放在知识检索之后、违规检测 LLM 之前。这是一个相对轻量的判断逻辑,用 Python 对报销金额和制度中配置的限额做快速比对,命中明显超标的场景会直接打上"疑似超标"标签,再交给 LLM 做深度判断。这么做的好处是给 LLM 一个强提示,避免模型在大量文本中漏看关键数字。

数据聚合的代码节点放在工作流倒数第二步,作用是把前面所有节点产生的明细数据列表整理成统一的 JSON。在 Dify 中,多轮处理后的变量可能是一个对象数组,不同轮次的输出分散在各自的变量里,代码节点需要把这些数据规整到一个数组或对象里,才能作为汇总 LLM 的上下文。

写代码节点时我最常犯的错就是变量名引用不准确,Dify 的代码节点里通过变量绑定来引用上游数据,如果不注意绑定关系,代码运行时会直接报变量为空。调试时要善用节点日志功能,一步步查看变量实时值,确认代码逻辑操作的数据结构和预期一致。

3.5 第五步:配置输出与报告生成

汇总生成的提示词是这个项目里我迭代次数最多的部分。最初版本输出的是纯文本报告,虽然读起来连贯,但没法直接接入下游系统做二次分析。后来我强制要求输出严格 JSON 格式,并给了完整示例。

我设计的目标输出 JSON 结构大概长这样:顶层包含 summary、violations、pending_items、suggestions 四个字段。summary 是一个对象,包含 total_count、total_amount、passed_count、flagged_count、pass_rate 等指标;violations 是数组,每个元素包含 report_id、person、violation_type、description、reference_policy、amount、risk_level;pending_items 是数组,包含 report_id、missing_fields、reason、action_needed;suggestions 是数组,保存审核建议。在实际工作中,我会把这个 JSON 再接一层前端展示,或者直接导入企业微信机器人发送给相关负责人。

这样设计的好处不只在于标准化,更在于审计追溯:领导可以点开一条违规记录直接看到违规类型和制度依据,员工被退回报销单时也清楚问题出在哪,而不是只看到冷冰冰的"审核未通过"四个字。

4. 常见问题与排查技巧实录

4.1 模型幻觉:编造不存在的发票信息

这是我测试早期踩得最深的一个坑。字段补全节点在没有明确上下文的情况下,会很有"想象力"地给缺失发票号编一个类似"INV-2024-001234"的编号,而且格式看起来还很合理。这个问题的危害性在于,发票号是要连到税务系统验真的字段,一旦编造进系统后面会引发连锁问题。

我的解决方案是从两个层面入手。第一个层面是提示词约束,明确写死:当且仅当输入信息或检索文档中存在明确的发票号信息时才填该字段,否则输出为空字符串。第二个层面是架构层面隔离,用条件分支把所有发票号、合同号这类"唯一性标识字段"直接划入需人工补充的路径,完全不进 LLM 补全流程。只有费用类型、项目归属这类具备逻辑推断基础的字段才交给 LLM。

4.2 知识库内容召回不准:报销单词汇与制度词汇的断层

报销单里写"王总上海出差住酒店谈项目",制度里写"差旅费-住宿费-一线城市标准",这两个文本在字面上几乎没有重合,语义检索如果配置不好就会漏召回。我调试时发现默认向量模型对这类专业名词的语义理解不够好,导致经常召回到接待费、办公费之类不相关的条款。

解决办法是优化文档切分和检索策略。我在切分制度文档时,给每个块加了元数据标签,比如在文档内容前加一行"费用类型:差旅费;约束对象:住宿费;适用场景:出差"。这样切分出来的文本块包含更密集的业务上下文,检索命中率明显提升。另外我把检索的 TopK 从 3 提升到 6,召回范围增大后由 LLM 来筛选相关性,准确率反而更稳定。

4.3 工作流运行超时与成本失控

财务审核是批处理场景,一次处理 20 张报销单时,工作流总耗时会明显增加。后来排查发现,主要瓶颈出现在补全节点上,因为有缺失字段的单据多次触发了 LLM 调用,大模型节点在 20 单场景下被调用了 20 次。这个场景下控制成本非常关键,我的调整是:先用代码节点对全部 20 单做一次快速预检,只把确实存在缺失且可通过逻辑推断的少数单据送入 LLM 补全节点,大部分没问题的单据直接进入汇总结点。

另外在 LLM 节点上开启"流式输出"会减轻首字延迟的感知,但批处理场景其实更建议关闭流式,因为流式模式在大批量时反而可能因为连接管理产生额外开销。对超时问题,优先检查上游 SQL 或外部 API 调用是否阻塞,内部 LLM 调用一般不会是唯一瓶颈。

4.4 常见问题速查表

我把调试过程里碰到的高频问题整理成了表,方便参考:

问题现象可能原因排查思路与解决方案
检测节点漏判超标项知识库没命中对应条款或 LLM 没有严格比对数值得出结论检查检索日志确认召回了哪些段落;在提示词中增加"逐项比对数限制"的指令
补全字段出现编造值LLM 没有遵循约束,自行推导出不确定信息把不可推断字段直接分流到人工补充路径,不进 LLM 节点
输出 JSON 格式频繁报错提示词缺少示例或 Schema 不够明确给出 2-3 个 few-shot 示例,并在提示词中写明字段取值枚举
检索召回了大量无关内容切分块粒度不匹配或检索相似度阈值过低调整分块大小,增加元数据标签,提升相似度阈值
大模型输出结果不稳定温度参数过大或多模型混用导致行为不一致审核类场景温度设置在 0.2 以下,尽量固定同一模型做同类任务
代码节点引用变量报空上游节点未执行或输出变量名绑定错误查看工作流运行日志中的节点输入输出,确认变量路径

4.5 提示词版本管理的重要性

调试提示词的过程中,让我最觉得"运营层面"收获大的是:给每个工作流节点的提示词做版本管理。Dify 平台本身有版本管理功能,每次重要修改我都在备注里写上修改原因,例如"增加制度未提及则默认需人工复核的约束,解决模型生搬硬套问题"。

随着修改次数增多,版本记录的价值会越来越明显。有时候改了明天效果变差,翻一翻版本记录很快就能对比出是哪个改动引入的问题。如果你在团队里协作,建议让财务同事也参与提示词的评审,因为制度约束的表述是否准确,他们比技术人员更敏感。

5. 配套资源设计与扩展建议

5.1 配套资源应该包含什么

做这类项目,产出物不能只有一个工作流配置,一定要配一套可复用的资源包,否则换个人接手或者换一套制度,项目就废了。我最终交付的配套资源包括四部分:标准化的制度文档模板、预置的知识库配置说明、工作流导入的 DSL 文件、一组测试用例集。

制度文档模板的价值在于把杂乱的企业制度快速整理成知识库合适的格式。我设计的模板按费用大类分类,每类下细分费用类型,约束条件统一写成四个字段:金额上限、适用对象、适用场景、特殊备注。这样一来,Dify 知识库的搭建成本会大幅下降。

测试用例集有 20 条左右的模拟报销数据,覆盖合规、超标准、缺字段、重复报销等典型场景,每条都标清楚预期审核结果。有了这套用例,后续调整提示词或改模型配置时,只要跑一遍自动化测试就能快速发现问题。

5.2 从单张审核到批量场景的演进

如果只是处理单张报销单,这个项目可以说已经完成了。但在实际业务里,批量处理才是刚需。我后来做了一个扩展:把工作流改造成了"批量审核模式",通过一个代码节点先做数据分组,20 张单子聚合成一个批次再送入后续审核节点,汇总输出按批次维度生成报告。

批量模式还有一个额外好处,就是能做横向对比。比如同一个人有多张差旅报销单连续超标,或者某个部门的业务招待费支出比例异常偏高,这些单张审核发现不了的规律性风险,在汇总结论里很容易被 LLM 提炼出来,变成一条管理层面的建议。这个效果算是我做这个项目时没预料到的惊喜,实际汇报给管理层时很加分。

5.3 与其他系统对接的思考

Dify 工作流本身支持通过 API 对外暴露,这意味着报销助手可以接入企业现有的 OA 或 ERP 系统。我的设想是:OA 系统提交报销单后自动触发工作流,审核结果回传到 OA 里作为流程审批的前置判断,通过的自动进下一环节,有问题的直接打回并附带修改建议。这套对接逻辑用代码实现其实不算太复杂,核心是把工作流输入输出转换为与 OA 系统匹配的字段结构。

Dify 的 API 文档中有详细的接口定义,可以在编排应用页面直接查看调用方式,用简单的 POST 请求传参数,返回结果就走报告 JSON 结构化对象,对接效率非常高。

写在最后的一点体会

做完整个项目,我最大的体会是:把这类偏规则型的业务流程交给大模型去跑,关键不是模型有多聪明,而是边界划得有多清楚。哪些字段模型说了算,哪些字段模型只能提供建议,哪些路径必须人工介入,这三类判断全在工作流设计的取舍里。Dify 的可视化编排让我能和财务同事坐在一起讨论这些边界问题,这是以往写脚本时代做不到的协作体验。

如果你正准备在团队里做类似的应用,我建议不要一上来就追求全流程自动化,先把违规检测和字段补全这两个模块单独跑起来,人工复核一段时间积累信心,再逐步放量到全量单据。这个节奏走下来,推广阻力会小很多,模型的表现也能在真实数据的检验中迭代得越来越好。

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

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

立即咨询