☰
Ollama+DeepSeek+Dify打造轻型AI中台:财务单据自动录入与对账实践
2026/10/5 8:56:03 网站建设 项目流程

去年底帮一家做B端耗材贸易的老客户做信息化改造,对方财务最头疼的不是系统少,而是系统太多——订单走一套、发票走一套、银行回单再来一套,同一笔业务每天要在不同系统里敲三遍。我当时的方案,是给他们在内网部署一个轻型AI中台,用本地大模型把重复录入和对账这两个痛点先打掉。

所谓轻型AI中台,我理解下来不是大厂那种重资产平台,而是一个能把本地大语言模型、流程编排、数据集成串起来的小系统,专门解决具体业务场景的自动化和智能化问题。这套方案的核心组件是Ollama + DeepSeek本地部署 + Dify + Docker,重点落地两件事:一是单据自动录入,二是流水自动对账。整体做下来三周左右就能从零跑到上线,非常适合中小企业IT人员、财务数字化负责人参考,也适合刚接触企业大模型私有化部署的同学拿来练手。下面完整拆一下设计思路、部署步骤和踩坑记录。

1. 整体设计与架构:先想清楚边界再选组件

1.1 从业务痛点倒推中台边界

做企业内部AI项目,最忌讳上来就搭一个“什么都能干”的中台。我以前也犯过这毛病,平台搭完发现业务部门根本用不起来。这次我反过来做,先盯着财务那边最痛的两件事:

  • 重复录入:订单在业务系统录一遍,到财务系统又录一遍,部分对公回单还要手工补录到Excel台账。每天平均花掉一个财务专员两个小时。
  • 对账困难:银行流水、订单流水、发票流水三套数据口径不一致,同一笔交易可能因为跨日到账、手续费拆分、部分退款等原因对不上。月末靠人眼比对Excel,几千行数据经常对出几十条差异。

所以这个AI中台不需要做算法训练,也不追求通用对话,它的边界就是一条“智能业务管道”:接收不标准的数据,经过理解、抽取、匹配,变成标准结构化数据,再写进业务系统或推送给人确认。模型能力只是管道里的一个环节,真正的核心是编排和集成。

1.2 分层架构与选型理由

我把整个中台拆成四层:

第一层是模型推理层。负责所有文本理解、字段抽取、匹配判断。部署在本地GPU服务器上,不走公网API,满足企业私有化要求。选型上短期内不追求大参数,7B到14B量级的中文模型量化后完全够用。

第二层是应用编排层。负责把模型能力串成业务流程,包括工作流、定时任务、结构化输出、知识库、工具调用。我选了Dify社区版,理由后面单说。

第三层是数据集成层。负责接收Excel、PDF、图片、数据库流水,也负责把结果写入ERP、财务系统、消息通知平台。轻型方案下用Python脚本加Dify自带的HTTP请求节点就够了,不需要单独搞数据中台。

第四层是任务调度与监控层。定时触发对账工作流、推送日报、记录异常日志。初期用Dify的定时触发器配合企业微信机器人,不需要再引入独立的调度平台。

从物理部署拓扑看,一台带GPU的Linux服务器负责模型推理和Dify编排,一台普通应用服务器放业务对接脚本和数据库。如果数据量特别大,对账流水可以放到ClickHouse或Doris里做存储分析,但轻型场景先把MySQL用明白更实在。

1.3 组件对比与选择依据

很多朋友问为什么选Ollama和Dify,这里直接给一个对比表,方便大家结合自己情况做判断:

功能需求可选组件我的推荐推荐理由
模型推理服务Ollama、vLLM、llama.cppOllama安装简单、Docker化、显存管理直观;高并发需求再换vLLM
工作流编排Dify、FastGPT、Coze开源版Dify社区版功能完整,工作流节点丰富,支持定时任务和API调用
流水存储分析MySQL、ClickHouse、Doris先用MySQL数据量在百万级以内时没必要上OLAP引擎
自动抽取解析Unstructured、PyMuPDF、PaddleOCRPyMuPDF + 自写解析对账单和发票以PDF、Excel为主,规则解析比什么都交给模型更可控

这套组合的好处是组件之间分工明确,每一层都能独立替换。比如今天觉得Ollama并发不够,可以随时换成vLLM,因为API形式上都是标准接口;明天觉得Dify流程不够灵活,可以在自己业务服务里直接调用模型API。不会出现“牵一发动全身”的情况。

2. 模型推理层:本地大模型私有化部署实操

2.1 模型选型:7B还是14B,量化怎么选

对账和录单场景里,模型要干的活主要是三类:从非结构化文本里抽取字段、把不同格式的表头统一、对“疑似匹配”做人工判断。这些任务对推理深度要求不高,但对中文实体识别和JSON输出稳定性要求高。

我的建议是:字段抽取任务用7B量化模型就够了,例如Qwen2.5-7B-Instruct的Q4_K_M版本;涉及复杂业务规则判断和长文本分析,再考虑14B。DeepSeek-R1-Distill-Qwen-7B也很适合做这种逻辑判断,因为它的推理风格会把“怎么判断出来的”讲清楚,方便我们排查。

显存估算有一个不算严谨但好用的公式:模型显存大约等于参数量乘以量化位宽再除以8,再加上上下文长度带来的KV Cache开销。以7B模型Q4量化为例:7B × 4bit ÷ 8约等于3.5GB,加上KV Cache和运行开销,实际占用5到6GB显存。一张24GB显存的显卡可以并行跑两个7B模型,或者跑一个14B模型。

我常用的一批模型和显存参考如下:

模型量化格式显存需求参考适用任务
qwen2.5:7b-instructQ4_K_M约6GB字段抽取、JSON生成
deepseek-r1:7bQ4_K_M约6GB逻辑判断、疑似记录判定
qwen2.5:14b-instructQ4_K_M约11GB长文本总结、复杂对账解释
glm4:9b-chatQ4_K_M约8GB中文结构化抽取

2.2 用Docker快速拉起Ollama和DeepSeek

在服务器上部署Ollama非常简单,整体就几步。先建模型目录:

# 创建模型存储目录,建议放到数据盘 mkdir -p /data/ollama/models

然后用Docker启动Ollama服务,我这里把GPU和模型目录都挂进去:

docker run -d \ --name ollama \ --restart=unless-stopped \ --gpus all \ -v /data/ollama/models:/root/.ollama \ -e OLLAMA_HOST=0.0.0.0:11434 \ -e OLLAMA_NUM_PARALLEL=2 \ -p 11434:11434 \ ollama/ollama:latest

这里有几个细节值得注意。OLLAMA_HOST=0.0.0.0:11434是为了让同内网的其他容器和应用能访问,单独跑本机回环就用127.0.0.1;OLLAMA_NUM_PARALLEL=2表示允许两个请求并行处理,如果显存紧张就不要加,默认串行更稳妥;模型目录必须挂到宿主机,否则容器一重建模型全没了。

启动后拉取模型:

docker exec -it ollama ollama pull qwen2.5:7b-instruct docker exec -it ollama ollama pull deepseek-r1:7b

拉取完成后,用一条标准接口调用验证:

curl http://127.0.0.1:11434/api/generate \ -H "Content-Type: application/json" \ -d '{"model":"qwen2.5:7b-instruct","prompt":"把这句话转换成JSON:客户A于2025年1月15日支付订单20250115001共计1200元","stream":false}'

返回的JSON里response字段就是模型输出。这一步通了,说明模型推理层已经就位。

2.3 并发、显存与上下文调优

部署时最容易踩的坑是“模型能跑但一压就崩”。Ollama本身不是高并发服务,如果业务方在Dify那边同一时间触发多个工作流,模型推理层很容易成为瓶颈。我调优时主要盯四个变量:

  • OLLAMA_NUM_PARALLEL:并行请求数。24GB显存跑7B模型设2到3比较合适,设太高会触发显存溢出。
  • OLLAMA_NUM_THREADS:CPU线程数。纯CPU推理时设为核心数的一半,避免系统卡死。
  • OLLAMA_MAX_LOADED_MODELS:可同时加载的模型数量。我限制为1,防止多个模型抢显存。
  • 上下文长度:默认2048通常不够用。遇到长对账单时,建议拉取模型时指定更大上下文,比如Ollama从0.5版之后支持num_ctx参数;Dify里也可以给模型节点单独设置。

如果并发量实在上不去,可以把推理服务从Ollama换成vLLM。vLLM部署DeepSeek量化模型后并发能力更强,但需要把模型转成兼容格式,运维成本也更高。轻型AI中台先不要一开始就上vLLM,我在客户那边跑了两个月,两个财务同时用基本没有任何压力。

2.4 内网访问与接口安全

本地大模型服务本身没有完善的账号体系,直接裸奔在局域网里是不行的。尤其财务数据敏感,内网也不是绝对安全。我做了两层保护:

第一层,Ollama只绑定内网IP的端口,不暴露到公网,防火墙层面只允许Dify所在容器IP访问11434端口。

第二层,在Dify的模型配置里接入“Ollama”类型时,填入内网地址和模型名。Dify通过自有API Key做用户侧鉴权,前端用户根本不会直接触达模型服务。这样一来所有调用都经过Dify统一管理和审计,谁调用了大模型、调了多少次,后台都有日志。

3. 应用编排层:Dify搭建“自动录入+对账”工作流

3.1 为什么用Dify而不是自己写服务

市面上工作流编排工具不少,我最终选Dify是因为它把“面向企业的Agent落地”需要的基础能力都做齐了:可视化工作流、定时任务、数据集/知识库、自定义工具、外部API调用、发布成独立应用。这意味着大部分代码不用自己写,业务人员甚至能看明白流程图。

对中小企业来说,这比从零写一套调度服务划算得多。我自己最早用Python写过一个版本,后来发现每加一个业务节点就要改造代码,最后彻底放弃了。Dify这种“低代码编排+底层可编程”的模式,才是轻型AI中台该有的样子。

部署Dify官方推荐Docker Compose方式:

git clone https://github.com/langgenius/dify.git cd dify/docker # 按实际环境修改.env里的端口和密钥 cp .env.example .env docker compose up -d

首次登录Dify控制台,设置管理员账号,然后去“设置-模型供应商”里添加Ollama,填入http://宿主机IP:11434和刚才拉好的模型名,类型选“Ollama”。这一步做完,Dify就能调用本地大模型了。

3.2 单据自动录入工作流拆解

消除重复录入的核心思路是:让AI从原始单据里抽字段,然后把结构化数据直接推到下游系统,人只做确认和异常处理。

我在Dify里建的工作流叫“单据自动录入Agent”,节点顺序如下:

  1. 开始节点:接收上传的PDF或Excel文件,也支持直接把邮件内容粘贴进来。
  2. 文档解析节点:用自定义工具调PyMuPDF或Pandas解析文件,输出纯文本和表格。
  3. LLM节点1-字段抽取:把解析后的内容丢给Qwen2.5-7B,输出固定JSON结构。
  4. 代码节点-校验:检查JSON里订单号、金额、日期是否完整,不完整则进入异常分支。
  5. HTTP请求节点:把校验通过的JSON按ERP接口格式提交。
  6. 通知节点:提交成功推企业微信,失败也推一条,方便财务第一时间知道。

这个流程里,LLM节点是核心。提示词我建议这样写:

你是财务单据信息抽取助手。请从单据内容中抽取以下字段: - order_id: 订单号,字符串 - order_amount: 订单金额,数字(保留两位小数) - order_date: 订单日期,格式 YYYY-MM-DD - customer_name: 客户名称 - remark: 备注,没有就填空字符串 只输出JSON,不要输出额外解释。

注意要求模型“只输出JSON”,这是减少解析报错的关键。Dify里还可以开启“结构化输出”功能,配合JSON Schema做校验,能挡住八成格式问题。

3.3 对账工作流:从流水上传到差异报告

对账工作流比录入复杂得多,它的核心是“匹配”。我在Dify里设计了两个版本,第一版全部让模型判断,效果不理想,因为模型对几千行数据做匹配既慢又不稳定。最终我把工作流改成“规则先行、模型兜底”:

  1. 开始节点:接收两个文件,一个是银行流水Excel,一个是业务订单流水Excel。
  2. 代码节点-解析归一化:用脚本把两个文件的表头统一成内部标准字段:交易日期、金额、对手方、流水号、业务单号。
  3. 代码节点-规则匹配:先按流水号精确匹配,再按金额+日期窗口缩放匹配,输出匹配结果和未匹配列表。
  4. LLM节点-差异判断:把未匹配的候选记录成对地丢给DeepSeek-R1模型,让它判断是否为同一笔业务。
  5. 代码节点-生成报告:汇总匹配成功、匹配失败、模型判定结果、可能的差异原因。
  6. 通知节点:推送给财务并附上报告链接。

这个流程跑通后,财务每天只需要看未匹配清单,不用再逐行翻流水。原来一天的对账工作压缩到半小时左右。

3.4 与ERP、企业微信的集成方式

Dify的HTTP请求节点可以对接绝大多数系统。对接ERP时要注意字段映射,不要指望对方接口设计得“刚刚好”。我通常先让模型输出标准字段,再用代码节点做一层转换,转成目标系统能认的格式。

消息推送我用了企业微信群机器人,Dify里通过自定义工具把Webhook地址包一层即可。也可以对接钉钉、邮件。一个实用经验是:对账结果不要直接发到全员大群,单独拉一个财务处理群,每天固定时间推送,避免刷屏。

Dify还支持定时触发,我在“自动化”里建了一个每日9点的定时任务,自动跑前一天的流水对账,结果直接推送到群里。这一步让“月结前突击对账”变成“每天顺手处理”,对账困难自然就消减了。

4. AI对账后台的实现细节

4.1 数据口径统一和标准表设计

对账之所以难,表面上是对不上,本质是两套数据描述的不是同一件事。银行流水里只有日期、金额、摘要、对方户名;业务订单里有订单号、客户名、商品明细、含税金额、实付金额。要AI帮忙,先得让数据口径一致。

我设计了一张标准流水表,字段如下:

字段名类型说明
trade_datedate交易日期
amountdecimal(14,2)实际金额,正数为收款,负数为退款
counterpartystring对手方名称,清洗过空格和别名
source_refstring原始流水号或业务单号
source_typestringbank/order/invoice,标识来源
txn_descstring原始摘要或备注,用于模型兜底判断

数据进表之前先做清洗:全角转半角、去掉空格和人民币符号、统一日期格式。这一步看起来机械,但能消除因表头差异产生的虚假差异,在“AI介入”之前先“数据治理”,之后模型判断准确率会高一大截。

4.2 三种匹配策略:精确、模糊、模型兜底

我的对账匹配分三层:

第一层是精确匹配。两张表的流水号或业务单号如果相同,直接认定为一笔。这个逻辑对订单号、回单号都能对上,能快速消掉六到七成记录。

第二层是模糊匹配。没有单号时,按金额相同且日期相差3天内来匹配。这里要注意金额单位可能差一分钱,所以比较时用±0.01的容差。我还会识别“手续费拆分”“合并支付”这种特殊情况——例如银行流水里一笔1000元拆成两笔的,规则就复杂了,需要靠第三层模型判断。

第三层是模型兜底。把确实匹配不上的候选记录成对交给DeepSeek-R1,提示词让它基于金额、日期、摘要判断“是否是同一笔业务,并说明理由”。这一步能处理掉大部分“银企两方摘要表述不同但实际是同一笔”的情况。

我用一个Python伪代码表达核心匹配逻辑:

def match_pair(bank_row, biz_row): if bank_row.source_ref == biz_row.source_ref: return "exact" if abs(bank_row.amount - biz_row.amount) < 0.01: date_gap = abs((bank_row.trade_date - biz_row.trade_date).days) if date_gap <= 3: return "fuzzy_date" return "pending_llm"

4.3 差异处理与生成调节表

匹配完成之后,工作流会自动生成一张“待确认差异表”,每一行包含:来源记录、金额、日期、匹配状态、模型判断理由、建议处理动作。财务不需要动手找差异,只需要逐条确认“调账/忽略/待补充”。

模型在处理退款和手续费时容易犯迷糊,所以我在代码节点里加了规则:金额为负数的记录优先跟负数记录匹配;银行手续费通常只出现在银行流水里,业务订单没有对应记录,这种情况直接标记为“手续费”,不再进入模型判断。

生成调节表时,工作流会输出一个Excel附件,包含已匹配、未匹配、差异原因汇总三个Sheet。这个表既给财务内部用,也能作为审计留底。上线一个月后,客户的未匹配率从原来的5%左右降到1%以内,剩下的基本是真正的异常交易。

4.4 人工复核与审计要求

AI自动化录入最大的争议就是“出错了谁负责”。所以我在设计里坚持一个原则:AI永远不直接改账,只提供结果和建议,任何写操作都要过人工确认。

具体落地是两件事。第一,Dify工作流推送到ERP的字段只包含“确定无误”的部分;有疑义的自动进入“人工复核队列”。第二,所有模型判断日志、工作流执行记录都保留在Dify后台,至少留存六个月。财务复核时能看到是哪个环节把这条数据标记为异常,也方便审计追溯。

这个原则在向客户和领导汇报时非常重要。一旦出了差错,能查到链路,比嘴上说“AI很聪明”有用得多。

5. 上线排障实录与安全注意事项

5.1 模型显存溢出

现象:Dify里跑工作流时日志报out of memory或CUDA OOM。
排查:先看显存占用:

nvidia-smi

如果是多个模型同时加载导致OLLAMA_MAX_LOADED_MODELS过高,就调成1;如果是单次请求上下文太长,就把模型的num_ctx从4096改回2048,或换更小量化格式。还有一个容易忽略的点:Ollama容器里虽然加了--gpus all,但宿主机没有安装NVIDIA Container Toolkit,容器实际用的是CPU,一张卡也没跑起来。CUDA OOM反而说明GPU被识别到了。

5.2 容器之间访问不通

现象:Dify容器调用Ollama超时,curl宿主机IP的11434端口却正常。
排查:Dify用docker-compose起的时候,默认网络是dify_default,和Ollama不在同一个网络里。两个容器要通了才能互访。我常用的解决方式有两种:一种是把Ollama容器加到Dify的默认网络里:

docker network connect dify_default ollama

另一种是在Ollama启动时不加--name ollama的网络隔离,直接用宿主机IP访问。注意防火墙也要放行内网网段到11434的访问权限。

5.3 中文抽取效果差

现象:模型把客户名称抽错、金额多一位,或者JSON里多了中文注释。
排查:先检查提示词是不是明确要求“只输出JSON”。如果还是不稳定,建议在LLM节点前加一个“预处理清洗节点”,把PDF解析产生的乱码和多余空格清掉。还可以在提示词里给两个Few-shot示例,效果提升非常明显。示例最好用真实业务单据脱敏后的内容。

5.4 定时任务不触发

现象:Dify定时任务没到点触发,或者到点了没跑。
排查:Dify默认时区是UTC,中国用户经常因此错过时间。检查.env里的TZ=Asia/Shanghai是否配置。另外定时任务不能手动勾选“仅一次”然后不管,要确认任务状态是启用的。设置完先手动运行一次,确认各节点没问题再等定时触发。

5.5 内网部署的安全规范

企业大模型私有化部署最忌讳“以为在内网就安全”。我的基本安全清单如下:

  • 模型服务不绑定0.0.0.0成外部可达地址,只在内网网段监听;如必须对外,要走统一入口服务做鉴权转发。
  • 涉及客户名称、金额的数据,日志脚本里禁止明文打印;调试时用样例数据替代生产数据。
  • 上传到Dify知识库和文件里的数据,设置好访问权限,不能让所有普通员工都能查看。
  • 定时任务推送的报表里不要带银行卡号、身份证号这类敏感信息,推送前用代码节点做脱敏。
  • Ollama和Dify都放在独立的Docker网络里,数据库端口不要直接映射到宿主机外。

还有一点容易被忽略:不要把模型文件直接放在系统盘,业务量大了文件体积会涨到几十GB,长期跑会把系统盘塞满。我习惯把模型、Dify数据、数据库文件都挂载到独立数据盘,并且配置自动清理日志。

最后说几句实际体会

这套AI中台跑起来之后,给我最大的感受不是大模型多厉害,而是“边界”比“能力”更重要。把AI限定在重复录入和辅助对账这两个具体场景里,它就像一个踏实的助理;非要让它什么都干反而出乱子。我现在给客户做类似的改造,都坚持一条铁律:先找一个30天内能看到收益的场景落地,跑通之后再考虑扩展。你不需要上一整套GPU集群,也不需要招算法工程师,一台像样的服务器加几个开源组件,就能把很多过去靠人堆的活儿接过去。

如果你也想在内部搞这样的东西,我的建议是从财务单据识别做起,因为它数据规范、价值明显、反馈周期短。项目推进时不要只跟技术聊,多跟财务坐在一起看几天她们怎么录单、怎么对账,你会发现难题往往不在算法,而在那些没人写进文档的业务习惯里。把那些习惯拆清楚了,AI中台自然就落地了。

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

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

立即咨询