尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Docker+Ollama搭建轻量AI中台,解决重复录入与对账难题

Docker+Ollama搭建轻量AI中台,解决重复录入与对账难题 去年下半年我被财务和采购两个部门轮番找过核心问题就两个一笔订单在三个系统里录了四遍月底对账永远对不平。一开始我想上正规的商业中台报价和周期直接劝退。后来换了个思路用Docker加Ollama部署一套轻量级的AI中台把重复录入和对账这两个最头疼的环节用本地大模型服务接了起来。这套方案跑了有大半年实测效果超出预期。写这篇东西主要是给那些想在内部搞自动化、又不想一上来就买几十万软件的朋友做个参考。我说明白一点这套东西不是那种动辄十几个微服务的重型中台它就是用一台16G显存的工作站跑一个本地大模型套一层API服务再接上内部系统的数据库和表单流程。但就是这看起来不起眼的一套把两个部门每月加班的时间砍掉了大半。下面我把整个思路、选型、部署和踩坑过程都展开讲。1. 项目为什么这么定重复录入和对账到底痛在哪1.1 两个高频业务场景的现场还原先说重复录入。采购部每天要处理几十张供应商发来的送货单这些单据有PDF、有照片、有传真件内容五花八门。传统做法是人工看一眼然后往ERP里录一遍订单号、品名、数量、单价、到货日期录完还得在Excel里再登记一遍方便月底对账。一个单据全流程走下来至少录入三次采购系统一次、ERP一次、财务对账表一次。对账困难就更典型。月底财务要把采购系统的订单、ERP的入库记录、供应商发来的对账单、银行的付款流水四份数据放一起核对。问题在于同一家供应商在不同系统里的名称可能差一个字订单号格式不统一日期有的是下单日有的是到货日金额有的含税有的不含税。人工对账全靠眼睛和Excel的VLOOKUP稍有变化就对不上最后只能一笔一笔翻原始单据。这两个场景的共同点是什么高重复、强规则、大量非结构化输入。高重复适合用自动化解决强规则适合用程序约束而非结构化输入正好是大模型和OCR的强项。所以这个项目的切入点本质上不是做一个什么创新技术而是把人肉做的重复劳动转成模型推理规则校验的标准流程。1.2 为什么选轻型AI中台而不是传统中台我之前也认真研究过传统的数据中台或业务中台方案。几万到几十万的软件授权费先不说光是实施周期就是三到六个月还得专门养一个团队去运维。对一个几十人的公司来说这种投入注定不可持续。轻型AI中台的优势在于四个字够用、可控。我可以完全掌控硬件、模型和代码不需要依赖外部厂商的售后响应。数据不出内网敏感单据不用交给第三方API这在财务场景里特别重要。而且从部署形态上看它就是一个Docker Compose编排的服务组任何能跑Linux的机器都能搬。有人可能会问这和直接写个Python脚本有什么区别区别在于模型能力。传统脚本处理规则固定的文本还行但遇到单据排版不同、字段叫法不同、供应商简称不同的时候脚本就崩了。大模型把理解这一步扛了下来规则脚本只需要处理模型输出的结构化结果。这种分工让整个系统有了很强的泛化能力。1.3 方案边界与目标做这个项目之前我和业务部门对齐了三个边界条件。第一不追求百分百无人化目标是把90%的标准单据自动处理掉剩下10%的异常单据转人工复核。第二不替换现有业务系统中台只在现有系统之间做数据流转和智能补全避免动核心系统的风险。第三模型只用本地部署保证财务数据和供应商信息不出内网。围绕这三个边界我定义了两个核心目标单据录入的人工操作量降低80%月底对账的时长从2天压缩到半天以内。后面的所有技术选型和部署动作都是为这两个数字服务的。2. 选型与架构轻量、可维护、能落地的设计2.1 硬件基线16G显存起步模型部署第一件事是定硬件。我查了很多16G显存本地部署AI的案例结合自己的预算最后定的基线是一张16G显存的N卡32G内存1TB SSDCPU随便找个八核以上的就行。为什么16G是起步线因为当前主流开源大模型的量化版本基本都能塞进这个显存范围。7B模型用Q4量化大概需要5到6G显存14B模型用Q4量化大概需要10到12G显存16G显存可以跑14B级别推理速度和效果之间能取得一个不错的平衡。如果显存只有8G那基本只能跑7B模型复杂单据的字段提取准确率会明显下降。内存方面建议32G起步因为Ollama加载模型的时候会把权重映射到内存内存太小容易触发交换分区直接把推理速度拖垮。硬盘用NVMe固态主要是模型文件动不动就4到7G加载速度对首次请求延迟影响很大。如果你手头只有一台Windows工作站也没关系这套方案可以跑在WSL2里或者在Windows上直接用Docker Desktop跑容器。我最初就是在Windows上验证的后来才迁移到Linux服务器。2.2 组件选型Docker Ollama 量化大模型组件选型我遵循一个原则每个组件只干一件事能容器化就容器化。模型服务这一层我选了Ollama而不是直接裸跑llama.cpp或vLLM。Ollama对模型的管理非常方便一条命令就能拉模型、跑模型自带OpenAI兼容的API对外提供标准接口。对于不想花时间折腾底层推理代码的团队来说这是性价比最高的选择。vLLM当然也优秀它的吞吐量在并发高的时候明显更好但配置相对复杂更适合服务几十个并发请求的场景。我这边内部工具最多同时五六个人用Ollama的并发能力完全够而且Ollama支持模型按需加载不用的时候可以释放显存对一台机器多任务跑很有帮助。模型本体选的是DeepSeek系列。原因有三中文理解能力强对单据里那些口语化、简称化的字段名识别得准开源模型可以本地部署不依赖外部API量化版本对硬件要求低16G显存跑14B量化模型体感和效果都很好。容器运行时用Docker Compose统一编排。Ollama容器、中台API服务容器、数据库容器、Redis容器全部写在一个compose文件里。好处是环境一致换机器一条命令拉起来不用重新配环境。数据库我选了PostgreSQL用来存识别记录、对账结果和操作日志Redis用来做任务队列和接口限流。2.3 中台数据流与模块划分整个中台的数据流我画在脑子里其实就是一条线业务源数据进入中台AI服务识别提取规则引擎校验补全结果写入目标系统全程留痕可追溯。具体分四个模块。接入层负责对接上游系统可以是ERP的数据库只读账号也可以是API回调还可以是手工上传的Excel和PDF文件。处理层是核心包含OCR识别服务、大模型提取服务、字段映射服务。OCR负责把图片和PDF转成文本大模型负责从文本里抽结构化字段字段映射负责把模型输出的字段名对齐到下游系统的字段名。流转层负责把处理结果写入目标系统同时生成记录。展示层是一个简单的Web界面用来人工复核异常单据和查看对账差异报告。模块之间的通信我用的是HTTP接口加JSON格式。模型服务由Ollama提供OpenAI兼容接口中台API服务作为编排中心调用Ollama的接口完成推理。数据量不大没必要引入消息队列Redis做简单的任务串联就够了。3. 核心部署实操从裸机到服务可用3.1 主机基础配置与容器运行时我先说Linux主机的情况。操作系统我选的Ubuntu 22.04 LTS主要看中它的软件源新、内核版本高对N卡驱动和Docker的支持好。装好系统之后第一件事是安装NVIDIA驱动然后装NVIDIA Container Toolkit这一步很关键它能让容器里直接调用GPU资源。驱动安装不建议用Ubuntu自带的附加驱动工具我直接去NVIDIA官网下载对应型号的runfile关闭图形界面后静默安装。跑大模型的机器讲究的就是稳定驱动别追求最新版选官方长期维护分支就可以。装完用nvidia-smi验证能看到显卡型号和显存就说明驱动OK。接着装Docker和Docker Compose插件C代码参考按Ubuntu环境常见做法curl -fsSL https://get.docker.com | bash sudo systemctl enable --now docker sudo apt-get install -y docker-compose-plugin docker compose version然后安装NVIDIA Container Toolkitdistribution$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo systemctl restart docker装完之后可以用一条命令验证容器能不能调用GPUdocker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi能正常输出显卡信息就说明容器GPU通道打通了。这一步做完后面的Ollama容器才会用上GPU推理。3.2 Ollama部署DeepSeek模型Ollama的部署非常直接。我直接拉官方镜像docker run -d --gpus all -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama这里我把模型数据目录挂载到了名为ollama的卷里这样即使容器删了重建模型也不用重新下载。端口11434是Ollama默认API端口后面中台服务就通过这个端口调用推理接口。然后进容器拉模型。我需要的是支持结构化输出且中文能力强的模型选的是deepseek-r1系列的量化版。14B的Q4量化版本显存占用大概10到12G16G显存跑起来余量充足。命令是这样docker exec -it ollama ollama pull deepseek-r1:14b如果想跑得更轻快也可以拉7B版本占用大概5到6G显存响应延迟低不少但字段提取的准确率会略降。我建议先拉7B做功能验证确认流程没问题后再换成14B。拉完模型可以立刻测一下curl http://localhost:11434/v1/chat/completions \ -H Content-Type: application/json \ -d {model:deepseek-r1:14b,messages:[{role:user,content:提取这段话中的订单号、品名、数量}]}能正常返回内容说明模型已经就绪。这里有个小技巧Ollama支持在环境变量里配置OLLAMA_KEEP_ALIVE控制模型在显存里的驻留时间。如果业务是白天集中处理可以把驻留时间设长一点避免频繁加载如果晚上没有任务驻留时间设短一点把显存释放给其他服务。3.3 中台API服务的Docker编排中台API服务我用的Python FastAPI写的功能很简单接收单据图片或文本调用OCR服务转成文字再调用Ollama提取结构化字段最后根据规则模板写入下游系统的接口。整个服务打包成一个镜像和其他中间件一起用Docker Compose编排。Compose文件的核心结构大概是这样的services: ollama: image: ollama/ollama container_name: ollama volumes: - ollama_data:/root/.ollama ports: - 11434:11434 deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] api: build: ./ai-mid-platform container_name: ai-mid-platform ports: - 8080:8080 environment: OLLAMA_BASE_URL: http://ollama:11434 DB_URL: postgresql://user:passdb:5432/midplatform REDIS_URL: redis://redis:6379/0 depends_on: - ollama - db - redis db: image: postgres:16 container_name: mid-db environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: midplatform volumes: - db_data:/var/lib/postgresql/data redis: image: redis:7-alpine container_name: mid-redis这段配置里最需要注意的是API服务连接Ollama时不要用localhost要用容器服务名ollama。因为每个容器是独立的网络命名空间只有通过Compose内部网络才能互相访问。我第一次就是踩了这个坑API容器里一直连不上模型服务日志报连接拒绝换成服务名之后一次通过。前端展示层我单独起了一个Nginx容器托管一个Vue写的单页应用用来做人工复核和对账展示。为了减少维护成本这层没有打包进compose主文件而是独立部署方便前端单独发布。3.4 接入业务系统的打通方式中台服务建好之后最难的反而不是AI部分而是怎么跟现有ERP和财务系统对接。我总结出三种接入方式按优先级排序。第一种是数据库只读视图适用于允许中台直接查询业务库的场景比如采购系统的订单表只需要给它开一个只读账号中台就能定时拉取新数据。第二种是开放API适用于有标准接口的系统中台把处理结果通过API写回比如ERP的出库单新增接口。第三种是文件摆渡适用于老旧系统导出Excel放到指定目录中台定时扫描处理处理完再生成导入文件。实际项目里我三种都用了。采购系统用数据库视图拉单据ERP用API写回入库单财务对账表用文件摆渡方式处理。每种方式各有优缺点数据库视图最简单但耦合度高API最规范但需要对方系统配合开发文件摆渡最笨但对老旧系统最友好。我建议凡是能走API的尽量走API因为每一步操作都有留痕出问题时方便回溯。文件摆渡方式一定要在文件名或内容里加处理状态标记避免同一个文件被重复处理。4. 业务落地两个目标的实现细节4.1 消除重复录入单据识别与自动填单消除重复录入关键是要把识别和写入两个环节做成可靠的流水线。识别环节我用了两步走。第一步是OCR把PDF和图片里的文字转成可编辑文本。开源方案里PaddleOCR做得比较成熟对中文、表格、模糊单据的识别效果都不错。我用Docker单独跑了一个PaddleOCR服务PDF每页转成图片后调用它识别返回带坐标的文本块。这样做的目的是拿到文字的同时也知道每个字段在单据上的大概位置后续可以做版面分析。第二步是大模型字段提取。OCR给出的文本是线性的还需要把品名数量单价金额这些字段从里面挑出来。我设计了一套提示词模板把OCR文本和已知的供应商、单据类型传进DeepSeek要求它输出严格JSON{ bill_no: PO-2025-0317, vendor: 华东金属材料, items: [ {name: 8.8级高强度螺栓, qty: 500, unit_price: 0.85, amount: 425.0} ], total_amount: 425.0, delivery_date: 2025-03-20 }为了让模型输出稳定的JSON我在提示词里明确要求只输出JSON不要任何解释文字同时在代码里加了JSON解析失败重试机制。第一次跑的时候模型偶尔会在JSON前后加来回车或者代码块标记重试一次基本就正常了。写入环节中台API服务拿到结构化字段后先查重再去重。查重规则是订单号加品名加数量三者都一致就判定为重复单据自动标记跳过不写入ERP。去重之后才调用ERP的接口创建入库单。每一条识别记录都会落库原始单据、OCR文本、模型输出、最终写入结果都关联存储方便事后审计。这一套跑下来原来需要人工录入三遍的单据现在处理员只需要在Web界面上看一眼自动提取的字段有没有错点确认即可。确认后的数据自动同步到ERP和对账表三处录入变成了一次人工确认加两次自动同步。4.2 消减对账困难多源数据自动匹配与差异预警对账模块是另一个大头。四份数据来源、字段格式都可能不一致我的方案是把所有数据先统一成标准结构再用大模型做模糊匹配最后用规则引擎输出差异报告。统一结构这步很关键。采购系统导出的订单、ERP的入库记录、供应商对账单、银行流水我先分别写好四个解析器把它们都转成统一字段对账编号、业务日期、往来单位、金额、币种、来源系统。转完之后全部落到一张对账明细表里。然后是匹配环节。同一笔业务在四个系统里的字段值可能不一样最典型的就是往来单位名称华东金属材料有限公司华东金属华东金属材料其实都是同一家。用传统SQL的等值匹配肯定对不上我用DeepSeek做实体归一化把每一个往来单位名称标准化成统一的规范名称同时还让它识别订单号和金额的等价关系比如含税价和未税价的转换。匹配的具体做法是以供应商对账单为主线先生成候选匹配集规则是同一供应商名称、业务日期前后三天之内、金额差额在5%以内然后让模型判断候选集里哪些记录是同一笔业务。模型会给每对记录返回一个置信度高于95%的直接合并60%到95%的进入人工确认列表低于60%的标记为待排查。差异预警就简单了匹配完成之后对账明细里凡是有一方缺少记录、金额有差异、日期差超过三天的自动生成预警条目。财务打开Web界面看到的是一个按供应商分组、按风险等级排序的差异清单点击每条差异能看到四个系统的原始记录和模型给出的匹配依据。这套逻辑上线后最直观的变化是原来财务月底要花整整两天做的匹配动作现在系统运行十来分钟就能给出结果剩下的人力只需要处理那些置信度不高的边缘单据。4.3 上线后的实测效果项目上线三个月后我拉了一组数据做复盘。单据录入方面采购部每天四十多张送货单自动识别加自动写入的比例稳定在86%左右剩下的14%大多是单据破损、印章盖住了数字、手写笔迹潦草这类极端情况靠人工复核兜底。录入时间从原来的每单三分钟缩短到半分钟而且因为数据是从单次识别结果同步过去的三个系统里的数据一致性明显好了很少再出现这边录了那边漏录的情况。对账方面月度对账时长从两整天压缩到半天以内。四源数据自动匹配的准确率在92%上下剩余的8%进入人工复核池。财务同事最满意的是差异预警功能以前要自己翻原始单据才能发现的问题现在系统直接把矛盾点摆出来了。这里我要说明一点这些数字不是一下子到位的。第一个月的自动识别准确率只有六成多对账匹配率不到八成是后来我调整了OCR参数、优化了提示词模板、加入了实体归一化规则之后才慢慢提升上去的。所以如果你部署后效果不理想别急着否定方案先去看是哪个环节拖了后腿。5. 常见问题与排查技巧实录5.1 模型加载慢、首字延迟高Ollama的机制是按需加载模型第一次请求进来的时候模型要从磁盘读入显存16G显存加载14B量化模型大概要二三十秒这段时间内第一个请求就会迟迟没有响应。我原来的做法是业务高峰期之前手动预热一次但容易忘。后来直接在Ollama容器环境变量里加了OLLAMA_KEEP_ALIVE30m让模型在显存里常驻半小时。又写了一个简单的健康检查每隔五分钟调一次模型接口保证模型一直是加载状态。这两个改动之后日常使用时基本上是零感知。如果并发请求多导致响应变慢可以在API前面加一层请求队列用Redis做简单的先进先出控制同时进入推理的最大请求数。我这边设的最大并发是2实测14B模型在16G显存下两个并发已经比较吃力了一个请求最稳。5.2 OCR漏字、字段漂移OCR是最容易出问题的环节。我踩过的坑主要是三个扫描件分辨率太低、表格线干扰、印章压字。分辨率这块PaddleOCR对300DPI以上的图片识别效果好很多我加了一步预处理把过小的图片先放大到宽2000像素再进OCR。表格线干扰可以通过OCR参数里的表格识别选项解决但如果表格过于复杂我建议直接把表格线检测关掉用纯文本模式因为大模型提取字段时并不依赖表格结构。最头疼的是印章压字。供应商的送货单上经常有红色公章正好盖在品名或金额上OCR会识别出乱码。我的处理办法是多角度裁剪把图片旋转几个小角度分别识别再用投票方式取出现频率最高的字段值。虽然会增加一点处理时间但对准确率的提升非常明显。5.3 对账匹配准确率不足对账模块刚开始的时候自动匹配准确率只有七成多问题主要集中在两个地方供应商名称归一化不过关日期差判断太死板。自从引入DeepSeek做实体归一化之后名称问题大幅缓解但模型偶尔还是会把广东华南钢铁集团和华北钢铁集团误判为同一家。后来我加了一个规则层模型给出的标准化名称必须经过编辑距离校验相似的走模糊匹配差异太大的一律拒绝。日期差问题也做了优化。原来规定前后三天内才算匹配但有些供应商的对账单是按月汇总的业务日期和付款日期可能差将近一个月。我改成对日期类型做分类入库日期紧凑匹配付款日期宽松匹配匹配准确率慢慢提到了九成以上。5.4 容器资源限制与OOMDocker跑容器时如果不做资源限制模型服务可能会把内存吃满导致整机卡死。我在Compose配置里给每个服务都加了mem_limit和cpus参数Ollama服务的内存限制设为28GCPU限制为4核API服务和其他中间件也按需分配。显存也需要关注。虽然Ollama会动态管理模型显存但如果同一个GPU上还有其他任务就容易出现显存溢出。我建议Ollama独占显卡不要把其他容器也用gpus all的方式共享同一块卡。如果条件允许直接一张卡跑模型一张卡跑其他AI任务最省心。5.5 备份、升级与安全这套系统跑在生产业务上容不得半点马虎。我每周日凌晨做一次全量备份备份内容包含PostgreSQL数据库、Ollama模型目录和API服务的配置文件。备份脚本很朴素就是tar打包加rsync到另外一台机器。升级方面Ollama和模型都可以平滑升级。先拉新镜像再重启容器模型文件不会丢失因为数据在卷里。API服务升级更简单重新build镜像再up就行。升级前一定先在一个测试环境跑一遍别直接在生产上动手。安全方面的几个基本配置还是不能省API接口加了Token认证Nginx上配了IP白名单数据库账号用了最小权限只开放中台需要访问的表。因为模型是本地部署不存在数据外泄的问题这一点在财务场景里特别加分。6. 我的一点体会这套轻型AI中台做完我最大的感受是不要一开始就想着做平台先找准一两个要命的应用场景把价值做出来再考虑扩展。如果你问我要不要把这个方案推广到更多部门我的建议是分两步走。先把现有两个场景做深做透让业务部门形成依赖然后才是往合同识别、客服工单分类、库存预测这些方向扩展。每个新场景本质上都是在复用同一套中台底座只是换个模型、换套提示词、换个业务流程而已。最后分享一个小技巧模型提示词模板一定要用版本管理。我最初图省事直接把模板写在代码里后来发现调来调去很容易乱套。现在我把所有模板抽成了独立的配置文件每次调整都记变更说明。这套流程帮我在后续扩展场景时省了大量时间。如果你也要做类似的东西这一步千万别省。
返回列表