我被财务拉着对了整整三天账,四个平台的回款流水加上内部的发货单、退货单、发票,表格开了一屏又一屏。后来我突然想明白一件事:对账难只是一个结果,根子在录入端。业务员在CRM录一遍客户信息,电商订单再手工倒进ERP,仓库又按单子逐条核销,同样的数据被不同人用不同格式反复敲进不同系统。这些重复劳动创造了大量的不一致,也把月末对账变成了体力活。
所以我做了个决定:不改造任何存量业务系统,也不搞那种动辄几十个组件的数据中台,就部署一套轻型AI中台,用大模型和工作流把重复录入、手工匹配、对账核对这些活直接接过去。整套方案跑通之后,录入工作量少了一大半,对账时间从三天压缩到半天,而且所有模型和数据都在内网,不依赖外部的服务。这篇文章就是这套方案的完整记录,包括技术选型逻辑、部署步骤、踩坑经历和可以直接抄作业的配置。适合正在为“系统烟囱化、数据没人录、对账靠人工”头疼的团队,尤其是没有专职算法工程师的中小型公司。
1. 项目整体设计:先别急着上模型,把问题拆到“能自动化”为止
说实话,很多团队一听“AI中台”就想去上K8s、搞Flink、搭一堆组件,最后运维成本比业务收益还高。我这次刻意把方案压得很轻,核心思路只有一句话:不解决所有问题,只解决“重复录入”和“对账困难”这两个具体的痛。但即便是这两个问题,如果不拆清楚,模型再强也接不住。
1.1 业务流程里的“痛点雷达”:问题到底出在哪个环节
我花了大概两天把实际业务走了一遍,把重复录入的链路画了出来。这里有一个很重要的经验:不要直接看系统间有没有接口,而是要看数据从“原始凭证”到“业务系统”之间要经过几双手。以我这边的场景为例,梳理出的问题非常典型。
- 客户资料录入:销售在微信/邮件里收到客户填写的报价申请表,手动复制到CRM,同一个客户被不同销售重复建了至少三四个档案。
- 销售订单生成:渠道订单通过Excel发过来,业务员要逐条核对商品编码、价格,再手工录入ERP订单模块,一不当心就录错行。
- 仓储核销:仓库发货后,要在系统里逐条勾选发货状态,这个动作和订单录入是分开的,单据一多必然对不上。
- 对账环节:财务从电商平台后台导出结算单,再从ERP导出已发货明细,两边在Excel里用VLOOKUP匹配订单号,结果因为订单号前后带空格、长度不一致、退换货拆分单等各种原因,匹配不上的一大堆。
围绕这四件事,我确定了AI中台必须提供的三种能力:解析(把邮件、Excel、PDF里的数据读出来)、理解(识别字段含义、补全缺失值、判断有没有重复)、执行(调用各系统的API写入数据并把结果反馈给人工)。这就是“轻型”中台的边界——不碰核心交易逻辑,只做数据搬运和判断。
1.2 “轻型AI中台”的定位:不是数据中台,是流程机器人
很多人问,为什么叫“轻型”?因为传统中台是“数据集中做治理,再对外提供统一服务”,而我要的其实是一层流程智能代理。它不需要把所有数据同步过来,只需要在合理的时机、以合理的粒度介入原有流程。
打个比方,传统中台是修一座中央厨房,所有食材都运过去加工再配送到各个档口;轻型AI中台更像是给每个档口配了一个会看菜单、会下单、会核对食材的帮厨。它不接管全部后厨流程,但能把你天天重复的切菜、配菜动作自动化掉。
所以整个系统的架构从第一天起就定死了:业务系统保持原样,AI中台挂在旁边,通过Webhook和API来对接。数据模型也简单,左边是各业务系统的凭证数据,右边是一个轻量的任务存储,中间是模型和工作流。这样即使AI服务挂掉,核心系统还能正常跑,不会出现“中台故障、全公司瘫痪”的局面。
1.3 三个核心模块的拆分:感知、认知、执行
我把AI中台分成了三个互相独立的模块,之间只通过接口通信,方便后续替换。
感知层负责把非结构化数据转成结构化字段。比如收到的报价单可能是PDF、照片、Excel,需要先经过OCR和表格解析,转成统一的JSON。这里我没有用特别复杂的模型,而是选了PaddleOCR加MinerU的组合。MinerU对PDF版面解析很稳,尤其是带表格的扫描件。
认知层是整套系统的决策大脑。主要是各种规格的大模型,负责字段标准化、重复检测、匹配判断、异常识别。这层的模型选择直接决定效果上限,后面专门讲。
执行层则是做一些确定性的操作,比如查重、写CRM、更新ERP状态、发送待办通知。执行层尽量用普通代码和HTTP请求完成,不交给模型,因为模型不适合做幂等性要求很高的写操作。
这三个模块加起来,部署形态就是一台服务器上跑着Ollama(模型服务)加Dify(工作流和应用框架),数据量不大,不需要Kafka也不需要分布式数据库。这个设计我从开始到最后都没有动摇过。
2. 技术选型背后的逻辑:我为什么选“Ollama + Dify”这套组合
技术选型是这次项目里最容易被带偏的地方。网上铺天盖地都是模型评测和框架对比,但实际落地上,选型要考虑的无非三件事:能不能部署在内网、运维成本多高、效果是否满足业务。下面把我最终定下来的方案和理由讲清楚。
2.1 模型推理层:为什么是私有化部署而不是云API
企业数据里客户名、金额、订单号都属于敏感信息,直接传外部API,合规和商务上都有风险。而且重复录入和对账这两个场景对实时性有要求,一旦网络波动,业务等着写入,体验就很差。所以我从一开始就排除了云API,选择了内网私有化部署。
模型本身我选了Qwen系列和DeepSeek系列。做字段抽取的时候用Qwen2.5-7B,输出比较稳定,对中文表格理解力强;做匹配判断这种更需要推理的任务时,用DeepSeek-R1-Distill-Qwen-14B,效果会好一截。实际测试下来,专门做结构化抽取的小模型在这个场景足够了,没必要把几十B的大模型拉起来,推理时间反而拖后腿。
推理框架选了Ollama,这个没有太多犹豫。它安装简单、模型管理直观,一条命令就能拉模型、跑服务。16G显存上可以稳定跑7B到14B的量化模型,速度不错。如果你手头是多卡机器、要更高吞吐,也可以换vLLM,但是部署复杂度会明显上升。对于“轻型”定位,Ollama是性价比最优解。
2.2 流程编排层:Dify把“模型能力”和“业务动作”串起来
有了模型推理能力,还需要一个把这些能力组织成业务流程的地方。我选的是Dify,这一层可以有多个选择,但Dify在内置工具、可视化编排、发布成API这三件事上做得比较均衡。特别是它支持自定义工具,我可以把企业内部CRM、ERP的API封装成工具节点,然后像搭积木一样搭流程。
有个细节值得说一下:Dify里走的每一次输入输出都会自动记录,这对于排查“哪条数据被模型改错了”非常关键。以前纯代码实现流程,日志一乱,出了问题根本不知道怎么回溯。Dify的运行历史面板可以直接看到每个节点的输入输出和token消耗,这个对人工复核太重要了。
工作流只有一个场景比较复杂的时候,用Dify的Chatflow就够了;如果要做多分支、定时触发、并发审批,我建议把流程拆成多个独立应用,通过HTTP调用串联。我这个项目里就把“录入流程”和“对账流程”分成两个Dify应用,互不干扰。
2.3 数据存储与文档解析:不引入额外组件,够用就行
很多人一上来就要上向量数据库,其实这个项目里向量检索用到的地方很少。重复录入场景主要靠结构化查询判断重复,对账场景主要靠字段匹配,真正需要向量检索的只是“票据模糊搜索”这种边角功能。所以我只用了Dify自带的数据库来存流程和应用数据,向量检索这块,用了内置的Chroma插件,没有单独部署Milvus。
文档解析层用了MinerU解析PDF和扫描件,PaddleOCR负责图片和票据。这两个工具我都跑在Docker里,通过HTTP服务对外提供解析能力。如果你处理的文档比较简单,也可以直接用Dify内置的文件解析功能,但解析效果确实不如专门工具好。尤其是带合并单元格、跨页表格的Excel,内置解析很容易读乱,这个后面再说。
2.4 工具选型对比参考
我把试过的方案放在一起做个对照,方便其他人根据自己情况取舍。
| 层次 | 方案A | 方案B | 我的选择 | 选择理由 |
|---|---|---|---|---|
| 模型推理 | Ollama | vLLM | Ollama | 部署简单,运维轻,7B/14B量化模型足够 |
| 对话与流程 | Dify | n8n | Dify | 原生支持模型编排和运行日志回溯,内置工具丰富 |
| 文档解析 | MinerU | PaddleOCR | 两者配合 | MinerU读PDF版面,PaddleOCR识别照片和扫描件 |
| 向量检索 | Chroma | Milvus | Dify内置 | 向量场景占比低,不额外增加组件 |
这套组合下来,安装包不超过4个Docker镜像,内存占用在8G以内,GPU显存16G起步,一台物理机就能全部扛住。不要被“中台”两个字吓到,真正跑起来就是个单机应用。
3. 消除重复录入:从“人找系统录”到“系统追着人确认”
我觉得比起对账,重复录入更值得优先处理,因为它每天都在发生,时间成本积少成多,而且录入错误会在后续所有环节放大。这一节讲我实际把重复录入自动化掉的过程和配置,可以直接照着搭。
3.1 场景设计的起点:哪些录入可以自动化、哪些必须留人工
设计之前,我给录入动作分了个类:有标准模板的、字段来自外部文件的,这类最适合自动化;需要业务判断、涉及商务条款的,这类必须有人工节点。比如报价申请单的客户名称、联系人、电话这些都是固定字段,让模型抽取后自动填表风险很低;但订单里的折扣率、付款方式这些涉及商务谈判内容,我会让流程停在人工确认节点,由业务员在聊天卡片里确认后再写入。
于是我把自动化范围圈定为:客户资料建档、标准品订单导入、发货状态更新这三件事。每一件事都做成一个独立的Dify工作流,前端入口统一发到企业微信群里,员工只需要转发一个文件或者填写一个简单表单,后面就是AI的事。
3.2 工作流拆解:文件进来之后,机器到底做了什么
以“客户资料建档”为例,整个Dify工作流是这么设计的:
- 文件节点:接收用户上传的报价申请表(Excel或PDF)。
- 文档解析节点:调用MinerU把表格内容解析成Markdown或JSON,这一步会丢掉原始格式,只保留文本和表格结构。
- LLM抽取节点:提示词要求模型从解析结果中抽取客户名称、联系人、电话、地址、行业、需求描述等字段,并且输出为固定的JSON结构,同时把“不确定字段”标记为空,不允许编造。
- 代码节点:把模型输出的JSON交给一段Python代码,做数据清洗,比如电话去空格、统一手机号长度;再调用CRM的查询接口,按客户名称和联系电话做查重。
- 条件分支:如果查重结果有高置信度重复,直接走到“提示人工”分支,生成一张卡片让用户确认是合并还是新建;如果没有重复,走“自动创建”分支。
- HTTP请求节点:调用CRM的API创建客户档案,并把创建结果返回给前端。
- 通知节点:把“已创建客户XX,负责人XX,耗时XX秒”发回企业微信会话。
这套流程在Dify里排布起来不到一个小时,但真正调试的时间花了不少。最大的坑是模型输出JSON经常带多余的解释文字,导致代码节点解析失败。后来我在提示词里写了“只输出JSON,不要任何解释”,并且把temperature调到0.1,问题才彻底解决。
3.3 提示词模板:一份可直接改用的抽取Prompt
这里放一个我实际在用的提示词骨架,用Qwen2.5-7B就够。它的核心思想是给模型清晰的输出格式和边界,同时配合少量示例稳定格式。
你是一个客户资料录入助手。请从用户提供的表单内容中提取客户信息。 规则: 1. 只从给定文本提取,不得自行补充不存在的字段。 2. 字段值为空时,用空字符串表示。 3. 电话统一去掉空格和短横线,保留数字。 4. 输出严格遵循JSON,不要输出任何其他文字或解释。 JSON格式: { "customer_name": "", "contact_name": "", "contact_phone": "", "address": "", "industry": "", "requirement_desc": "" } 示例: 输入:“上海星云网络科技有限公司 联系人:张伟 电话:138-1234-5678 地址:上海市浦东新区张江高科技园区XX路XX号 行业:信息技术 需求:需要一套CRM系统” 输出: {"customer_name": "上海星云网络科技有限公司", "contact_name": "张伟", "contact_phone": "13812345678", "address": "上海市浦东新区张江高科技园区XX路XX号", "industry": "信息技术", "requirement_desc": "需要一套CRM系统"} 开始: 输入:{{文件解析后的文本}}这个提示词实际用下来,准确率在95%以上,偶尔出错也集中在地址字段带后缀、行业字段口语化等问题上。配合Dify里的人工复核节点,基本不会把脏数据写进CRM。
3.4 前端应用与企业微信机器人:让员工用聊天界面完成操作
这里有一个很关键的产品设计决策:不要给员工新增一个网页系统,越轻越好。我直接在Dify里创建了一个“客户录入助手”,然后发布为企业微信自建应用。员工在微信聊天框直接发文件,或者把文件转发给机器人,工作流自动触发。
企业微信这边配置并不复杂,无非是创建自建应用、配置可信域名、设置接收消息的服务器URL,然后把URL填到Dify的应用回调里。用户在聊天窗口发来文件后,Dify会收到文件URL,通过企业微信API下载文件,再进入工作流节点处理。
这一步我要特别提醒:大部分企业的服务器无法直接访问企业微信的API域名,需要在部署服务器上配置好外网出口或代理。但这里应该走公司网络正规代理通道,这属于IT基础设施范畴。实际落地时我尽量让流程走内网API网关,避免依赖外部网络。如果架构上必须和外部系统交互,务必由网络管理员统一走合规出口,不要自己临时搭通道。
3.5 实操效果:录入时间缩短了多少
上线跑了一个月之后,我统计了数据。客户建档从平均每人每单15分钟下降到了4分钟,其中一半的单子直接自动创建,不需要人工干预;另一半停在了人工确认节点,但员工只需要点一下按钮。最大的变化是档案重复率从28%降到了5%以下。这个数据验证了我一开始的判断:只要录入动作能拆出标准模板,模型的归模型,规则的归规则,效果立竿见影。
4. 消减对账困难:规则兜底、模型补漏,把月末三天缩到半天
对账比录入要难一些,因为它不是简单的“抽取和写入”,而是在两个数据源之间做匹配判断,而且两边都可能有不规范的数据。这里我的策略是混合匹配:硬规则先筛一遍,拿不准的再交给语言模型做判断。
4.1 对账困难的本质和我的拆解思路
对账单和内部单据对不上,通常离不开四类原因:
- 主键不一致:同样一笔订单,平台结算单写“JD202503120001”,ERP里存“20250312-0001-JD”。
- 金额口径不同:平台结算单按不含税金额结算,ERP按含税金额记账,凭空多出一块差额。
- 时间错位:平台按“放款时间”出账单,ERP按“发货时间”确认收入,月初月末总是跨期。
- 拆分与合并:一个订单拆成多个包裹发货,平台按包裹结算,ERP里却是一条原始订单。
过去这些差异全靠财务同事用肉眼和经验去逐条核对。我的思路是,先用规则把能精确匹配的自动排除掉,然后把剩下“看起来像但不确定”的交给模型,让模型给出匹配结果和置信度,最后只把低置信度的条目留给人工。这样既保证准确性,又把人工量降到最低。
4.2 规则匹配层:先把八成的账自动对上
规则层我用Python写了三个匹配器,放在Dify的代码节点里:
- 精确匹配器:对订单号做归一化处理后精确匹配,同时要求金额差额在允许误差内。
- 宽松匹配器:把订单号中的分隔符(
-、_、空格)全部剔除后再匹配,解决格式不一致问题;金额允许因含税不含税产生一个固定比例的偏差,但要通过参数配置。 - 时间窗口匹配器:如果主键匹配不上,尝试用“客户ID+金额+发货日期前后3天”的组合来匹配,这是为了对付时间错位和订单号完全对不上的场景。
每一条匹配结果都会打一个分数:精确匹配给100分,宽松匹配给80分,时间窗口匹配给60分。得分80以上的直接自动确认为“已对平”,其余进入模型判断。这样做的效果非常明显,平台账单大约82%的单据在规则层就自动对平了,完全不需要看剩余部分。
4.3 模型辅助层:让LLM判断“长得像但不敢认”的账
规则层解决不了的主要是那些模棱两可的单据,比如平台单显示金额1260元含税,内部单显示1100元不含税,订单号格式差异极大,光看字段机器逻辑判断容易误伤。这时候我让语言模型来做一个综合判断。
对账提示词和录入提示词风格完全不同。我要模型输出的是一个“判断+理由”,而不是一个JSON表单。我设计了一个简单直接的判断格式:
{ "match": true, "confidence": 0.92, "reason": "平台单号JD202503120001与内部单号20250312-0001-JD剔除分隔符后一致,金额差异1260含税对应内部1100不含税,税率13%可验证,判断为同一笔订单", "matched_pair": ["platform_202503120001", "erp_20250312_0001"] }给模型的上下文里我会放五到十组已经人工确认过的匹配对作为示例,让模型学习公司的对账习惯。有人会担心模型幻觉乱匹配,所以在工作流里我设置了三重保险:
- 模型输出confidence低于0.7的条目一律不进自动对平,直接进人工区。
- 模型判断“match=false”时只做标记,不做任何写操作。
- 最终写入对账结果前,还要用代码节点做一次金额比例校验,防止模型把两笔金额差一大截的单子强行配对。
实际跑下来,规则层剩下的18%单据里,模型能正确判断约七成,最终只有5%左右需要财务人工复核。对账时间从三天压缩到半天,而且财务不再需要反复打开Excel拿VLOOKUP对格式了。
4.4 对账结果页面:给财务一个能看懂的界面
对账流程最终需要一个人工交互的界面。Dify自带的Web应用可以直接用来做这个,不需要单独开发一个前端。我把“待人工复核”的单据生成一张列表,展示平台单、内部单、差异金额、匹配理由和置信度,财务在界面上点“确认”或“驳回”,确认后的结果自动同步到ERP的对账模块里。
设计这个界面时我学到一点:不要给财务塞一个AI对话框,他们会不知所措,他们需要的是一张清晰的表格和几个按钮。所以我不是用聊天窗口的形式,而是用Dify的发布功能生成一个表单型的页面,操作路径控制在三步以内:看差异、点确认、写备注。这才是“AI中台”该有的样子——把模型能力藏在后台,前端只保留最友好的交互。
4.5 你可能会犹豫的点:模型判断会不会出错
一定会出错。但关键在于出错之后能不能及时被发现、被纠正。我的做法是在每条自动确认的单据后面都保存模型原始输出和推理日志,财务月结时如果发现问题,可以一键追溯到当时模型给出的判断依据。这种可回溯性比特准率100%的虚假承诺更重要,因为有了它,财务同事才愿意把注意力放在那5%的异常单据上,而不是从头审查所有记录。
5. 从零到一的部署步骤:一台GPU服务器跑通整套系统
理论讲完,下面把实际部署过程写出来。我尽量按我自己的操作顺序来,每一步都给出命令和配置,方便直接照着搭。注意,下面的命令都基于Ubuntu 22.04和Docker,如果你用CentOS或者其他发行版,略有差异。
5.1 硬件规划:16G显存起步,预算内尽量给足内存
先说硬件。我的方案里,显存是最重要的瓶颈。一个16G显存的GPU可以稳定跑Qwen2.5-7B的量化模型,做录入抽取足够;如果要上DeepSeek-R1-Distill-Qwen-14B做对账推理,16G稍显紧张,建议用24G或32G显存的卡。如果你现阶段只有16G,也可以把对账模型换回7B,效果差一些但能用。
| 配置项 | 最低要求 | 推荐配置 |
|---|---|---|
| GPU | 16G显存(如RTX 3080及以上) | 24G或32G显存,例如RTX 3090/4090/A5000 |
| CPU | 8核 | 16核 |
| 内存 | 32G | 64G |
| 系统盘 | 100G SSD | 500G NVMe SSD |
| 数据盘 | 500G | 1TB SSD |
内存这块我建议直接一步到位上64G,因为Dify本身需要PostgreSQL和Redis,模型服务也会吃一部分内存,加上文档解析服务,32G在并发上来的时候会显得很紧张。
5.2 部署Ollama并拉取模型
Ollama的安装很简单,用官方脚本一条命令搞定。
curl -fsSL https://ollama.com/install.sh | sh安装完先启动服务,然后用命令行拉模型。我拉了两个模型,一个做抽取,一个做推理。
ollama pull qwen2.5:7b-instruct ollama pull deepseek-r1:8b如果你的显存比较充裕,拉qwen2.5:14b-instruct、deepseek-r1:14b效果会更好,但响应时间会变长。拉完之后测试一下调用是否正常:
curl http://localhost:11434/api/generate -d '{"model": "qwen2.5:7b-instruct", "prompt": "你好", "stream": false}'能返回正常JSON就说明Ollama服务没问题。需要注意,Ollama默认监听127.0.0.1,如果Dify跑在同一台服务器上那没问题,如果Dify在另一台机器,需要把Ollama服务绑定到局域网IP。修改方式是在环境变量里设置OLLAMA_HOST=0.0.0.0:11434,同时注意防火墙放行11434端口。这里要提醒,生产环境里最好再加一层简单的IP白名单,避免局域网内随便谁都能调用模型接口。
5.3 部署Dify并接入Ollama
Dify官方提供了Docker Compose的部署方式。我直接用Git拉取源码里的docker目录,然后启动。
git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d启动后访问服务器的80端口,进入Dify初始化页面,设置管理员账号。进到“设置 - 模型供应商”页面,选择Ollama,填入以下参数:
模型名称:qwen2.5:7b-instruct Base URL:http://localhost:11434 模型类型:LLM 上下文长度:默认即可保存后,Dify里就能选到这个模型了。我再补充一下:如果对账流程里需要用到向量检索功能做票据模糊查询,可以在Ollama下面继续添加嵌入模型,比如nomic-embed-text,并在Dify里配置好。这个项目里向量功能用得少,但加了也不亏,后面做“按客户名称搜相似发票”之类功能时顺手就能用上。
5.4 配置文档解析和OCR服务
文档解析我用MinerU,因为它对PDF和Office文件的表格解析能力强。MinerU也用Docker部署。
docker run -d --name mineru -p 127.0.0.1:8008:8008 mineru:latest实际部署时,我在Dify的自定义工具里封装了一个HTTP工具,把文件URL传给它,MinerU返回解析后的Markdown或JSON。这样做的好处是Dify工作流里的“文档解析节点”可以灵活对接不同解析器,哪天换更好的解析服务也不影响流程结构。
PaddleOCR主要用于图片票据识别。PaddleOCR的Docker镜像部署后,通过HTTP接口上传图片返回识别结果。这部分我把调用逻辑也封装成了Dify自定义工具,跟MinerU并列,工作流里按文件类型走不同分支:PDF走MinerU,图片走PaddleOCR。
5.5 内网访问、反向代理与Webhook回调
整套系统跑在内网,但企业微信回调、邮件监听这些入口需要服务器能和外部网络互通。我的做法是:在服务器前面加一个内网反向代理,统一管理域名、HTTPS证书和请求路由。Dify对外提供一个固定域名,比如ai.internal.example.com,所有API和回调都走这个域名。
这里给一个硬经验:一定要在早期把HTTPS证书配上。企业微信自建应用的回调URL强制要求HTTPS,如果等到要做消息入口时再补证书,会非常被动。证书申请和自动续期可以通过 acme.sh 这类工具完成,配置好后基本不用管。
Dify的部署里,Nginx是一个必选组件,我用它来反代Dify容器和企业微信回调接口。关键的nginx配置片段如下:
server { listen 443 ssl; server_name ai.internal.example.com; ssl_certificate /etc/nginx/certs/ai.internal.example.com/fullchain.cer; ssl_certificate_key /etc/nginx/certs/ai.internal.example.com/ai.internal.example.com.key; client_max_body_size 50M; location / { proxy_pass http://127.0.0.1:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /api/webhook/wecom/ { proxy_pass http://127.0.0.1:4430; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }client_max_body_size一定要调大,不然用户传一个大点的Excel或PDF会直接被Nginx拒绝。我一开始没注意,用户传超过5M的文件就一直报413,排查了好久才发现是Nginx默认限制在作怪。
5.6 备份与日常维护
轻型部署不代表不备份。Dify的数据都存在PostgreSQL和Redis里,我用最简单的方式做每日备份:把Dify目录下的数据卷用tar打包,传到另一台存储机器。模型本身不用备份,随时可以重新拉取,但要注意记录下所用的模型版本和量化精度,避免哪天拉到的模型版本变化导致效果不一致。
Ollama模型重拉的时候有一个小坑:默认拉取是最新版本,有些模型的量化方式可能更新了,行为和之前不完全一样。所以我习惯在部署文档里写清楚用到的模型tag,而不是直接写模型名,比如固定写qwen2.5:7b-instruct-q4_K_M,这样重装环境时可以完全复现。
6. 常见问题与排查技巧实录
跑了两三个月,这堆东西踩的坑不在少数。我整理了一下比较有代表性的问题,按排查难度从低到高排了个序,给即将动手的同行一个参考。
6.1 高频问题速查表
| 现象 | 可能原因 | 排查思路与解决 |
|---|---|---|
| Dify里选模型时报连接超时 | Ollama绑定只监听了127.0.0.1 | 设置OLLAMA_HOST=0.0.0.0:11434,并在Dify中填服务器实际IP |
| 上传Excel解析出来后表格乱掉 | 内置解析对复杂表格支持弱 | 改用MinerU做PDF解析,图片类用PaddleOCR兜底 |
| 模型输出JSON带多余文字 | 提示词约束不够 | 在提示词中加“只输出JSON,不要任何解释”,并把temperature调到0.1 |
| 对账匹配准确率突然下降 | 模型被人误换版本或量化精度 | 固定模型tag,检查Ollama的模型列表,回滚到记录过的版本 |
| 并发来了提示CUDA out of memory | 同时请求太多 | 在Ollama配置中限制并发数,并在Dify侧做排队,或改用更小的量化模型 |
| 企业微信用文件发不进来 | 回调URL证书无效 | 确认HTTPS证书在有效期内,并检查回调URL路径与服务器配置一致 |
| 用户上传的大文件报413 | Nginx上传大小限制 | 在nginx配置中加大client_max_body_size并重启服务 |
| 模型把完全不同的两笔记成同一笔 | 上下文里缺少对账规则示例 | 在对账Prompt中加入更多正负样本,并且把置信度阈值调到0.75以上 |
6.2 关于模型幻觉:不要试图让模型“百分百准确”
很多初次接触大模型的人会陷入一个执念,就是要让模型判断得完全准确。但我的体会是,在对账这种场景里,比起提升模型准确率,不如设计好兜底机制。所有的自动判断都留人工复核口子,所有写入操作前都做规则校验。
我实际踩过的教训是这样的:一开始对账流程让模型直接标记“是否同一笔”,模型的准确率确实有92%,但剩下8%的错误被直接写入结果后,财务发现问题时要花大把时间去反查,反而比之前纯手工还慢。后来改了设计,低置信度单据强制人工复核,虽然人工量稍微上来了,但整个流程可信度大幅提升。
6.3 并发和性能调优的一点经验
Ollama默认可以接受并发请求,但显存有限时并发拉满容易OOM。我给调用方加了一个简单的令牌桶限流,在Dify的自定义工具里通过排队来解决。具体来说就是同一时间只允许一个对账任务跑模型推理,其余任务等待。对账这种场景本身并发不高,这个办法效果很好,而且代码也就是几十行的事。
如果后续要支持更大的团队,我建议把Ollama换成vLLM,它能做Continuous Batching,对高并发支持更好。但相应的,部署和参数调优的复杂度会上一个台阶,这就偏离了“轻型”的初衷。在小团队、小数据量下,Ollama+令牌桶完全够用。
6.4 审慎对待“全自动”诱惑
最后我想特别提醒一下,别再追求把流程做到“零人工”。这次项目里,录入流程和财务对账流程我都保留了人工确认节点。这既是对业务的尊重,也是对自己的一种保护。系统一旦全自动,出错了很难解释清楚;保留了人工确认,模型和规则做得再好,也只是“辅助”,而不是“替代”。这个定位从一开始就决定了项目推进的顺畅程度,也是我推荐其他人采用的做法。
我个人最大的体会是,所谓AI中台的“轻”,不光是架构上的轻,更是模式上的轻。你把目标定在“帮人少录一次、少核一遍”上,而不是“取代所有人的工作”,项目反而更容易成功。后面如果有时间,我还打算在这套架构上扩展一个“发票智能验真”应用,把财务的发票查验也接进来,思路是完全一样的:解析、理解、执行,再加一个可靠的人工兜底。这套方法论可以复用到很多你每天都要干的重复活上面。