尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Dify财务审核助手实战:工作流+知识库+DSL全流程拆解

Dify财务审核助手实战:工作流+知识库+DSL全流程拆解 简介在LLM应用开发持续升温的当下如何将大模型能力与业务规则有效结合成为企业智能化升级的关键。Dify作为开源LLM应用开发平台通过可视化工作流编排、知识库检索与模型调用让复杂业务流程的自动化搭建变得简单高效。本文从财务审核这一典型场景出发剖析如何基于Dify构建报销审核助手利用对话流完成票据信息提取结合RAG知识库引用制度条款并借助DSL实现应用跨环境迁移。同时覆盖测试用例设计、多模型效果对比、部署避坑与性能优化等工程实践为规则常变、单据非标的企业流程自动化提供可落地的参考方案。1. 为什么拿Dify做财务审核而不是直接写一套业务系统先说项目背景。我所在的团队经常要处理大量费用报销单据每个月少则几百笔多则上千笔财务小姐姐一边核对发票信息一边查公司报销制度还要盯着预算余额效率低不说不同审核人对同一张单据的判断标准还经常不一致。有人卡得严有人放得松员工那边也有怨言。我们一开始也想过找开发做一套审核系统但你要知道很多公司的报销规则是动态的——这个月差旅标准调整了下个月新增了合规红线开发排期至少两周起步等系统上线制度又变了。所以我把目光转向了Dify。Dify是开源LLM应用开发平台1.11.2这个版本能通过可视化工作流编排、知识库检索、模型调用把这些规则串起来不需要专门的前端开发。“财务报销审核助手”这个项目本质上做的是三件事读取报销单和发票信息、对照公司制度检索、生成带理由的审核结论。整个工作流用节点连起来规则变了就改节点制度变了就更新知识库不用发版不用等排期。当时我评估了几条路线。用扣子Coze也能做但数据要么进云端、要么被平台绑定私有化部署不灵活让开发写一套Python脚本做关键词匹配遇到“餐费超标的住宿发票”这种组合场景就很难写规则用Dify搭工作流的好处在于判断逻辑不是写死在if-else里而是交给LLM去理解和推理加上知识库检索做兜底既保留了灵活性又不容易跑偏。我的结论是如果你的需求是“规则常变、单据非标、需要人工复核兜底”的审核类场景Dify工作流是性价比很高的方案。这个助手做出来之后财务那边只需要把报销单图片或文本丢进去几秒钟就能拿到初审结论和理由再决定是否放行。2. 工作流骨架拆解一张报销单是怎么走完审核闭环的2.1 入口设计对话流比工作流更适合审核场景创建应用时Dify会问你用“聊天助手”还是“工作流”。我做报销审核时选的是“聊天助手”原因很直接财务审核员面对的是多张形态各异的凭证有的人直接拍照有的人粘文本有的人上传PDF对话流可以多轮交互先问用户“发票是什么类型”“金额多少”再逐项补充容错率高。纯工作流更适合“一批数据进去、一个结果出来”的批处理场景比如每天晚上的定时批量审核。复盘一下如果你只是做单张单据的快速核验聊天助手的最简体验是用户在对话框输入一段报销描述和发票关键信息助手直接给结论。但我做了增强——入口节点支持上传发票图片截图的URL自动走OCR识别省去手敲发票号、开票日期和金额的功夫。2.2 三个核心节点的职责划分整个工作流我分成四个区块输入处理区、知识检索区、模型评判区、结果输出区。节点连线非常直观没有一行代码但每个节点的提示词和参数配置都得花心思。第一块是票据信息提取。我用HTTP请求节点接了一个OCR服务把图片里的发票号、开票日期、销售方名称、金额、税额提取出来返回结构化JSON。如果你没有现成的OCR服务也可以让LLM直接读图片在1.11.2版本里多模态模型比如带视觉能力的模型可以直接识别上传的图片效果在关键字段上基本够用只是速度慢一些。第二块是制度知识库检索。我把公司最新的《费用报销管理制度》《差旅费管理办法》《业务招待费合规指引》三份文档导入了Dify知识库开启向量检索。知识库在Dify里创建之后需要选择嵌入模型再用分段模式做切分切分长度我调试下来300到500个字符比较适合制度条款这种结构化的文本太长容易把好几个条款混在一起太短又失去上下文。第三块是LLM综合评判节点这是核心。系统提示词我写了很长但核心逻辑就一句话任何结论必须引用具体制度条款作为依据。我们后面对抗测试时发现如果提示词里不强制“引用条款”大模型很容易凭生活常识乱下判断例如认为“四星级酒店超标了”事实上公司制度里允许一线城市住四星。2.3 分支逻辑通过、拒绝、人工复核三出口综合评判节点出来之后我接了一个条件分支节点根据结论类型把流程分流到三条线。通过汇总输出一句“单据合规建议批准”附上核验理由和对应条款。拒绝输出“不符合XX条款”列出问题项和修改建议。人工复核输出“以下字段无法自动核验请人工处理”这类主要遇到发票图片模糊、金额字段残缺、或者报销描述与发票品名明显不匹配但制度里没有明确定义的情况。一开始我只做了通过和拒绝两个出口跑了一轮测试发现很多单据处于灰色地带没有明确规则支撑硬判会出大问题。所以“人工复核”这个出口不是妥协而是审核助手能够真正落地的前提——你不可能指望一个LLM应用完全替代人的判断它的价值是把80%的标准单据自动消化剩下20%的疑难杂症才需要上升到人工。2.4 输出设计不是给一句话就完事我让最后的输出节点生成一个结构化审核意见格式类似这样单据编号BX-20240512-001 审核结论拒绝 问题列表 1. 住宿费单价超过标准实际800元/晚制度上限600元/晚《费用报销管理制度》第3.2条 2. 发票日期晚于出差申请日期属先出差后申请 建议按制度标准重新填报补齐出差申请审批单后再次提交。为什么这样设计因为如果只输出一个“拒绝”用户不清楚是哪里出了问题财务这边还得逐项解释。把结论、理由、条款依据全部结构化列出来用户能直接截图发给报销人沟通成本一下子降低了很多。3. DSL导入导出把整个项目从我的控制台搬到你的环境3.1 DSL到底是什么为什么Dify要用它DSL是指Dify的领域特定语言文件本质上是一个YAML或JSON格式的结构化描述把整个应用的应用配置、节点定义、连线关系、模型参数、变量声明都打包在一个文件里。Dify之所以把所有配置定义成DSL而不是存数据库里是为了让应用资产可版本化、可迁移、可共享。我自己的理解是它相当于把“项目源码”和“部署配置”合二为一导出之后通过Git追踪变更每次调整工作流都提交一份DSL比截图记录配置靠谱得多。你拿到一个Dify项目的DSL就能在另一个Dify环境上快速复现一个一模一样的应用不需要从零开始拖节点。这个特性对做方案交付、内部共享、跨环境迁移都特别重要。3.2 导入时的完整操作步骤先说说最简单的情况——我拿到一份财务审核助手的DSL文件要在自己的Dify实例上导入使用。操作路径是登录Dify控制台在应用列表页点击右上角“导入DSL”按钮1.11.x版本在“创建应用”下拉菜单里。选择下载好的DSL文件通常是YAML格式文件名形如dify-财务报销审核助手-20250512.yml。系统会解析文件内容如果你的目标环境缺少应用依赖的插件弹窗会提醒你安装。我遇到过提示缺少“网页抓取”插件的情况遇到就装一下插件装好后重新导入通常就能通过。导入成功后检查应用的关键配置模型供应商是否已配置DSL里记录的模型名称是否在当前环境中存在。如果之前用的是某个特定模型而新环境没配这个供应商所有LLM节点运行时会报错需要重新绑定模型。知识库是否与本地关联。DSL文件里记录的是知识库的描述和文件来源不会直接打包一段向量数据所以导入之后要回到知识库列表确认关联的知识库存在不存在的话要重新创建并上传制度文档。变量和表单字段是否与预期一致比如配置的开房城市变量、报销类型选项等。3.3 导入后最容易踩的三个坑第一个坑是版本兼容。Dify的DSL格式跟着版本迭代1.10之后多租户架构做了调整1.11的DSL拿到1.9的环境里导入很大概率报“未知节点类型”或“字段不合法”。所以我建议要么保持版本一致要么看导入报错信息把旧环境升级到同版本。标题中的1.11.2版本对DSL的兼容性处理得不错我测试过从1.10.1导出的文件在1.11.2上也能正确解析。第二个坑是“插件依赖”的幻觉。DSL里经常引用一些增强节点你看着导入成功运行到某个节点才报“插件不存在”。这不是导入工具的锅而是节点属性里带了插件类型但插件市场里对应插件没装。踩了两次之后我会在导入后先做一次“冒烟测试”——把一条标准合规的报销单发进去看整个流程能不能走通。第三个坑是环境变量。如果你的DSL里某个HTTP节点用了外部APIURL硬编码在一个绝对地址里导到测试环境就访问不了。我的实践是让所有外部服务地址通过环境变量注入DSL里写占位符导入后手工更新。3.4 DSL文件内容长什么样为了让你心里有底我贴一段简化过的工作流DSL片段这是结构化理解的关键app: name: 财务报销审核助手 mode: chat description: 报销单据自动审核 version: 1.11.2 workflow: nodes: - id: node_start type: start title: 开始 variables: - expense_description - invoice_img - id: node_ocr type: http-request title: 票据OCR识别 config: url: ${OCR_API_URL} method: POST body: image: {{#node_start.invoice_img#}} - id: node_retrieval type: knowledge-retrieval title: 制度知识检索 config: query: {{#node_start.expense_description#}} dataset_ids: - 制度文档 top_k: 4 - id: node_llm type: llm title: 综合评判 config: model: gpt-4o-mini prompt: | 你是财务审核专家... 结合上下文{{#node_retrieval.result#}} edges: - source: node_start target: node_ocr - source: node_start target: node_retrieval - source: node_ocr target: node_llm - source: node_retrieval target: node_llm不用纠结这段代码的每个字段重点是想让你明白DSL把整个应用的编排逻辑都明明白白写出来了。所以当你拿到别人的DSL时先打开扫一眼看它引用了什么类型的节点、哪个模型、哪些外部API心里有个底再导入比闷头导入之后一脸懵强得多。4. 测试用例设计与验证从“能出结果”到“结果可信”4.1 为什么LLM应用的测试比普通软件难普通软件的测试用例很好写输入一个数程序返回一个数结果确定。但LLM应用的输出是概率性的同样一张报销单昨天跑一次是“通过”今天跑一次可能还是“通过”但两个通过的描述理由可能完全不同甚至偶尔会给出“拒绝”的错误判断。这意味着我们不能用传统的断言方式期望输出等于某个精确值而是要学会给“输出语义”做判定。我们定义了一套自己的测试方法准备一批标注好预期结论的报销单用例让工作流批量跑一遍然后把输出结果与预期做对比。对比的时候不要求措辞完全一致只判断三个维度结论类型是否一致通过/拒绝/人工复核关键事实是否抓对金额、发票号、日期理由引用是否合理是否引用了正确的制度条款4.2 测试用例的分层设计我设计用例时分成五层每一层覆盖一种风险层级用例类型示例预期结论L1 基础合规标准单据所有字段合法差旅费800元有发票标准内通过L2 规则边界金额恰好等于标准上限住宿费600元/晚标准上限600元通过L3 单一违规仅一项字段超标招待费人均超预算拒绝L4 复合违规多个字段同时不合规超标的且无出差审批单拒绝L5 灰色场景规则未覆盖但事实可疑报销物品品名模糊同一商家多笔相近金额人工复核这套分层的好处是每次修改工作流之后我可以快速定位是哪一层出了问题。比如改了知识库检索的Top K值如果L2边界用例开始误判说明检索出来的制度片段把边界条件弄丢了。4.3 用Dify API做批量回归测试手工一条条在对话框里发太慢了我写了一个简单的Python脚本调用Dify的工作流API做批量测试。Dify每个应用都可以创建API密钥在控制台“访问API”页面拿到密钥后通过HTTP接口触发应用运行。脚本逻辑是这样的import csv import json import time import requests API_KEY app-xxxxxxx API_URL https://your-dify.example.com/v1/workflows/run # 或 /chat-messages HEADERS { Authorization: fBearer {API_KEY}, Content-Type: application/json } def run_case(case): payload { inputs: { expense_description: case[desc], invoice_img: case[img_url] }, response_mode: blocking, user: qa-tester } resp requests.post(API_URL, headersHEADERS, jsonpayload) data resp.json() # 解析结果从工作流的输出节点提取结论 outputs data.get(data, {}).get(outputs, {}) return outputs.get(audit_result, 没有输出) with open(test_cases.csv, encodingutf-8) as f: for row in csv.DictReader(f): result run_case(row) passed judge_result(row[expected], result) print(f{row[case_id]} {row[desc]} - 预期{row[expected]} 实际{result} {PASS if passed else FAIL}) time.sleep(0.5)judge_result函数里可以写一个简单的关键词匹配或者再调一次LLM做语义对比我日常是关键词匹配加人工抽检。这套脚本让“回归测试”从半小时手动操作缩短到几分钟每次改了提示词或知识库我都全量跑一遍。4.4 测试中发现的高频问题测试阶段我发现了三类典型问题分享出来供你参考。第一类是“正例误杀”。最开始提示词里写了“所有报销必须提供发票图片”结果一张合规的公共交通小额报销因为没有发票图片被判成拒绝。实际制度里明确写着“单笔低于100元的交通费无需发票”。这个问题的根因是规则理解不够细致我在知识库里补充了这段话同时调整了提示词声明“如无发票图片请依据报销描述和制度中的豁免条款综合判断”。第二类是“边界漂移”。有一张差旅住宿费615元/晚的用例公司标准是600元模型有时给“拒绝”有时给“人工复核”很不稳定。原因是知识库检索时模型没有引用到标准条款的精确数字。解决方案是在提示词中强制要求金额相关判断必须从检索结果中提取数字依据如果检索结果不包含明确的金额上限请输出“需要人工复核”这相当于把不确定性问题显式地踢给了人工出口。第三类是“幻觉条款”。有次模型给出拒绝结论时引用了一条不存在的制度条款比如“根据《费用报销管理制度》第5.1条单张发票金额超过5000元需总经理审批”。我在知识库里搜了一下根本没有这条。这是LLM的通病它会把相近的条款措辞重组成一个看似合理的表述。应对方式是在提示词最后加了一行“如你无法在检索结果中找到对应条款原文禁止编造条款编号只能引用检索结果中实际出现的文本。”4.5 多模型测评让模型选择有数据支撑Dify支持在同一个应用里快速切换不同模型我用同一个测试集分别跑了三个模型输出一张对比表帮你从另一个角度理解“DifyLLM应用”的评价思路模型准确率人工复核率平均响应时间主要问题模型A92%8%4.2s偶尔幻觉条款模型B95%10%6.8s响应偏慢复杂单据表现稳模型C88%15%1.9s快但规则边界判断粗糙最终线上我选了模型B准确率最高慢一点可以接受财务审核本来就是异步场景。如果你对速度敏感可以选模型A加上一轮人工抽检。5. 部署环境准备本地安装Dify 1.11.2的实操要点5.1 部署方式选型Dify有多种部署方式我强烈建议用Docker Compose方式部署到自己的服务器。Dify官方提供了一份完整的docker-compose.yaml文件包含了api、worker、web、dbPostgreSQL、redis、sandbox和向量数据库等组件。1.11.2版本的部署结构和之前的版本基本一致主要变化是增加了多租户相关组件以及一些插件市场的配置项。如果只是在本机快速试玩Windows/Linux/macOS都可以用Docker Desktop直接拉取镜像启动。但如果是公司内部使用建议部署在一个2核8G以上的Linux服务器上存储空间预留50G以上因为知识库的向量数据会随着文档增长一直在膨胀。5.2 部署中的两个常见报错部署过程中我碰到过两个问题说出来帮你避坑。第一个是“内部服务器错误”。明明Docker容器都起来了打开控制台登录后创建应用时报500错误。排查了一圈发现是worker容器没有正常启动API服务和worker之间通过Redis做任务队列如果worker挂掉数据写入和异步任务全部失败。用docker compose logs worker看一眼日志多半能定位到原因。我那次是数据库连接数满了重启一下PostgreSQL容器解决。第二个是插件的安装问题。Dify的插件需要通过插件市场安装有些环境因为网络原因下载插件总是失败。1.11版本支持离线安装插件包在“插件”页面可以上传本地插件文件安装。遇到插件装不上不用反复重试直接找离线包上传。5.3 在线升级与数据备份Dify社区版是支持在线升级的但我的实践是别急着点“在线升级”。先备份数据库和挂载目录再拉新版本镜像执行迁移。Dify的数据都存在PostgreSQL里工作流配置也在数据库里所以备份数据库基本等于备份了整个项目资产。DSL文件相当于额外的保险每隔一段时间从控制台手动导出一次就算服务器数据全没了也能靠DSL快速重建。6. 知识库搭建制度文档如何切分和检索才能让模型少犯错6.1 制度文档入库前的处理有人直接把一份几十页的PDF扔进知识库检索效果一言难尽。我的做法是先把PDF转成Word或Markdown人工检查一遍文字是否乱码再按照“章节-条款”结构把文档拆成小文件或分段。制度类的文档特征是条款之间经常互相引用比如“报销标准参照本办法第三章”如果直接把整篇文档切成几百个片段模型检索时很可能只看某一截片段找不到“被引用的第三章”判断就会出现偏差。我把每一条报销标准做成了一个独立条目并加上元数据标签比如“差旅-住宿-一线城市-上限600”。Dify知识库的元数据过滤可以在检索时非常精准地缩小范围减少无关片段的干扰。这样做之后检索的Top 4命中率明显提升模型拿到正确条款的可能性大大增加。6.2 检索参数调优知识库检索有两个关键参数召回数量和相似度阈值。自己搭的时候我把Top K从默认的3调到4多给模型一条候选依据它在不确定时可以自己对比引用。相似度阈值则调低一些宁可多召回一点噪声也尽量不要漏掉正确的条款。因为模型最终还要综合判断多一点噪声问题不大但漏掉关键条款模型就容易放飞自我。相似度阈值这个东西在不同嵌入模型下表现不一样我建议你直接做一轮测试取几个档位用第4节里的测试用例集跑一拍看哪个阈值下“准确率人工复核率”的综合指标最好。6.3 知识库的持续更新制度文档不是静态的公司隔几个月就会更新一版。我的习惯是每次制度修订后把旧的文档片段停用上传新文档重新跑一遍回归测试。不要直接在原文档上编辑因为Dify知识库的分段是基于上传时的文档内容生成的改原文件不会自动重新分段。最稳妥的做法是删除旧文档、上传新文档、重建分段。还有一个细节报销制度文档最好和日常政策答疑文档分开建不同的知识库。因为政策答疑里有很多口语化的解释跟正式制度混在一起检索时容易把模型的判断依据带偏。分开之后在应用里可以设置优先引用正式制度库答疑文档作为兜底。7. 进阶玩法把审核结果汇总回写业务系统7.1 用HTTP节点回写审批流在Dify工作流里最后一步可以接一个HTTP请求节点把审核结论推送到自己的业务系统。比如你们的财务系统提供审批接口节点里把audit_result和reason作为JSON字段POST过去业务系统接收到这条记录生成待办事项。我做的版本里还接了一个企业微信机器人webhook审核结论一出来自动把结构化审核意见推送给报销人。报销人不用登录财务系统就能看到拒绝原因。这个体验在团队内部测试时反馈很好因为以前被拒绝报销人都是被财务单独通知现在系统自动跟进效率高了不止一个量级。7.2 用代码节点做二次清洗Dify有代码节点可以写Python代码对数据做二次处理我有一次碰到的问题是OCR识别出的金额字段偶尔带有逗号或货币符号直接传给LLM会干扰判断。我在代码节点写了一段正则清洗逻辑把1,200.00标准化为1200.00然后再进入评判节点。这类“脏数据清洗”的工作放到代码节点里比在提示词里反复强调“忽略逗号”要可靠得多。7.3 多轮对话增强让财务人员追问“为什么”聊天助手模式天然支持多轮对话我做了两个增强。第一个是历史记录聚合用户问“为什么拒绝这张单子”时程序把上一轮的单据信息和审核结论作为上下文传给LLM让它根据已有的判断条件追加解释。第二个是“如果改成合规金额会通过吗”这类假设性问题LLM可以根据知识库里的标准当场计算一个合规金额范围反馈给用户。这两个增强虽然在技术上就是提示词工程但用户感知明显提升财务那边愿意把助手当成一个真正的工具在用。7.4 插件生态的利用1.11.2的插件市场里有不少好用的东西我在项目里用了两个一个是网页内容抓取插件用来定期抓公司内网制度更新页面自动检测制度版本另一个是文本转语音插件审核完成后可选语音播报结果适合移动端碎片化场景。你要是有更复杂的需求也可以自己在Dify里写插件基于Python的插件SDK难度不大。8. 项目上线后的排障经验三个让我差点崩溃的问题8.1 “模型突然变笨了”是怎么排查的项目上线两周后有一天财务反馈“同样的单据之前都通过今天全被拒了”。我第一反应是知识库出问题了但打开检索测试发现知识库响应正常。后来查了模型服务商的控制台发现是模型方那边做了在线升级导致输出行为发生了变化。这个问题的本质是LLM应用对外部模型版本的不可控。规避方案有两个一个是在Dify里锁定模型的快照版本另一个是在提示词里写更详细的指令把判断逻辑的约束条件说明得更死降低模型换代带来的漂移风险。我后来把提示词里所有“模棱两可”的表述都改成了“如果……则……”的硬条件让模型可发挥的空间变小再遇到模型升级影响就小多了。8.2 知识库检索结果为空的问题上线初期遇到过几次检索结果为空模型直接基于常识输出结论的情况。排查发现知识库里上传的文档是PDF格式Dify自带解析器对扫描版PDF的支持不好里面的文字全部变成了图像没有可检索的文本。解决办法是先做OCR预处理把扫描版PDF转成文本版文档再重新上传。这个问题不解决知识库就形同虚设模型对制度的理解全凭记忆当然不可靠。8.3 多人同时使用时性能下降当财务部门五个人同时用助手审核单据时响应时间明显变长。看监控发现是单机部署的Dify同时处理多个工作流时LLM调用全部排队。优化方向有两个第一是所有大模型请求升级到更高并发规格第二是在Dify的api和worker容器上配置进程数调优。实际做下来把worker的并发数调大再给服务器加了两核CPU明显缓解。如果你预估并发量很高部署时就要考虑多实例部署了。9. 最后再分享几个实战细节第一个细节是提示词里一定要说“输出JSON”。这个看起来基础但它能极大简化下游解析。我的输出节点要求LLM返回一个严格JSON对象包含conclusion、reasons、base_articles三个字段。后续接HTTP节点回写系统时JSON直接透传不用写复杂的解析逻辑。第二个细节是妥善管理API密钥。Dify的API密钥可以在控制台创建多个我给不同的调用方测试脚本、业务系统、人工测试分别创建了不同的密钥如果某个来源调用异常能直接在日志里定位。密钥权限要尽量小只给它绑定这一个应用。第三个细节是定期导出DSL备份。我吃过一次亏某次修改工作流时不小心把关键节点删了保存之后运行一路报错。幸好有前一天的DSL备份重新导入几分钟就恢复了。从那之后我养成了每次重大调整前手动导出DSL的习惯这个习惯推荐你也有。整个项目从立项到上线用了不到一周大多数时间花在测试用例的调优上单纯搭建工作流本身半天就能跑通。Dify这类平台的最大价值在于它把模型应用的产品化过程压缩到极致让业务人员和技术人员可以坐在一起对着工作流画布讨论规则怎么定、分支怎么走。财务审核助手落地之后审核效率提升明显更重要的是制度更新后我能在一小时内完成知识库替换和回归测试这在以前想都不敢想。如果你也打算做类似的审核类助手希望这篇从工作流设计到DSL移植再到测试落地的全流程拆解可以帮你少走一些弯路。本文还有配套的精品资源点击获取
返回列表