金融业的AI替代,最近一直是热议焦点。身边不少做信贷审批、财报复核、合同整理的朋友开始失眠,担心自己每天干的活儿哪天被机器从流程里摘出去。作为一个在金融数据自动化方向摸爬滚打多年的开发者,我反而觉得,AI替代的从来不是“工作”本身,而是工作里那些重复、机械、可以被规则描述的部分。这半年,我带一个小团队做了个“金融文档智能提取与复核系统”,把客户经理交上来的尽调报告、借款合同、财务摘要,从人工逐条读取录入压缩到了三分钟出结构化结果,准确率达到业务可接受范围。下面不吹概念,只讲落地:为什么这么设计,关键技术点在哪,代码怎么组织,实践中踩了哪些坑,以及我对金融业AI替代潮的一些真实看法。
1. 这个项目到底在解决什么问题
1.1 需求从哪里来:非结构化文档是金融流程里的隐形黑洞
金融行业每天产生大量文档,尽调报告、授信合同、股东决议、审计意见、抵押登记证明,每一份都是信息孤岛。过去这些文档的处理方式非常原始:人工打开PDF,用眼睛找关键字段,手敲进信贷系统,再让复核员逐项比对。一份二十页的尽调报告,熟练员工也要花二十分钟到半小时,而且没人能保证一辈子不漏看一个数字。
更麻烦的是,这些文档不是统一模板生成的。有的合同用扫描件,有的报告是多家机构拼出来的,字号混乱、页眉页脚还带公司广告。业务口径更是千奇百怪,同样一个期限,有人写“自提款之日起36个月”,有人写“3年期”,还有人写“至2027年12月31日止”。信息抽取不只是“读取”,还要做归一化,否则下游风控系统根本没法比较。
我和团队接到的任务,就是做一个内部工具,把这些文档变成标准化的JSON字段,输出字段包括客户名称、贷款金额、期限、利率、担保方式、批复日期等。一开始业务部门提需求时,语气很谦虚:“能做到人工效率一半就行,不要求百分百准。”但我知道,这类项目真正的难点从来不是算法,而是边界定义——哪些字段必须要求高置信度,哪些字段允许模糊,错误出现时怎么溯源。
1.2 为什么不直接买一套现成系统
刚立项时有人提议去买商业智能OCR产品,我们做过调研,最终否了。原因有三个:
一是字段口径对不上。商业产品擅长识别发票、身份证、营业执照这类标准化证照,但金融机构内部文档的格式私有化程度高,而且每隔半年伴随监管要求调整,字段就会变。定制开发费用先放一边,单是每次调整的商务流程就够拖垮项目节奏。
二是数据合规问题。这些文档包含客户财务数据、抵押物信息、关联方情况,不能随便上传到外部服务。公司要求所有处理能力必须内网部署,而很多商业方案核心引擎在云端,私有化版本价格和技术支持都不理想。
三是我们需要的不只是识别,还有复核和审计追踪。业务方要能清楚看到每个字段的原文位置,要能一键定位“这笔利率为什么被识别成4.35%”,而不是看到一个孤零零的输出结果。这个诉求在市面产品里选择很少,基本等于要二次开发。
所以最后决定自研,成本可控,逻辑透明,也能沉淀成团队的内部技术资产。
1.3 整体方案:LLM抽取加规则引擎兜底,拒绝“大模型万能论”
这里先给结论:我的方案不是“端到端大模型识别一切”,而是三层架构——解析层负责把PDF变成可处理的结构化文本,抽取层由大模型完成语义理解与字段提取,校验层用规则引擎处理格式归一化和非法值拦截。
为什么不用纯大模型?因为大模型擅长理解自然语言,但不擅长稳定输出格式,更不擅长处理“同一字段多种写法”的归一化。它今天可能把“利率:LPR上浮50BP”解读成“5.5%”,明天心情不好就给你输出“50BP”。相比之下,规则引擎是确定性的,只要正则写好,一万次运行结果都一样。两者配合起来,就像让实习生先读一遍文档写批注,再由老员工拿着流程清单逐项复核签字。实习生负责理解不常见的表述,老员工负责挡掉明显不合理的值。这样系统既有大模型的灵活,又有规则系统的稳定。
这个架构还有一个好处:任何一层出问题,都可以独立修复。如果发现是解析层漏了表格,只需要改解析代码;如果发现某类字段大模型总搞错,就加一条规则拦截,不需要重新训练模型。对于金融机构来说,这种“可拆解、可回退、可观测”的特性,比单点模型的漂亮指标重要得多。
2. 核心细节解析:解析、抽取、校验三层各有各的坑
2.1 解析层:PDF转文本,最难的不是OCR而是空间关系
第一个想的太简单的点,是PDF解析。我最初天真地以为,用现成解析库把文字提取出来就行,结果第一轮测试就翻车。
PDF里的文字分两种:一种是原生文本层,直接复制就能取出;另一种是扫描图片,必须先做OCR。前者优先用解析库处理,后者上OCR服务。真正的麻烦在于表格。PDF解析库提取文字时通常是按行流式输出,表格里的单元格会被拆得七零八落。比如“担保方式”这一列,表头在第二页,数据在第三页,提取出来的文本根本不知道哪行属于担保方式列。
我采用的方案是“段落化”:读取每一页时,先把页面上的表格单独提取出来,把每个单元格拼成带行号列号的标记文本,再把剩余普通文本按阅读顺序切块。这样传给大模型的输入不是一段糊成一团的文字,而是“第5页、第2节、表格第3行”这种带结构的信息。
实操里还有一个容易被忽略的点:页眉页脚。很多PDF每一页都带公司LOGO、联系电话、“机密文件”字样,这些内容如果不清理,大模型容易被干扰,尤其是遇到“电话”“传真”字样时可能误判成客户联系方式。我会在做版面分析前先做一次“页眉页脚掩码”,按页面高度比例裁掉顶部和底部固定区域,有效降低噪声。
2.2 抽取层:提示词工程怎么设计,才能让大模型稳定输出JSON
抽取层是整个系统的大脑。我们要的不是聊天式问答,而是“输入一份文本,输出严格JSON”的批量任务。所有经验浓缩成一句话:别考验大模型,把一切能约束的都约束死。
我的提示词模板固定包含四个部分:身份设定、字段Schema、few-shot示例、输出规则。字段Schema用JSON描述,每个字段要写清楚中文含义、允许的取值范围、单位要求。例如:
{ "customer_name": {"type": "string", "description": "客户全称,企业需带公司全称或统一社会信用代码,自然人为姓名"}, "loan_amount": {"type": "string", "description": "贷款金额,保留数字、单位与币种,如人民币5000万元"}, "loan_term": {"type": "string", "description": "贷款期限,统一为数字加单位,如12个月"}, "interest_rate": {"type": "string", "description": "利率,百分比数值,不含LPR说明"}, "collateral": {"type": "string", "description": "担保方式,取值保证/抵押/质押/信用"}, "approval_date": {"type": "string", "description": "批复日期,格式YYYY-MM-DD"} }每个字段后面还要求模型输出confidence字段和snippet字段。confidence是模型自评分,snippet是从原文摘录的一句依据。这两个字段看起来增加了很多token开销,但实际价值巨大。它让校验层有了“判断材料”,也让后续审计追踪成为可能。业务人员点击“客户名称”时,可以直接看到原文切片,而不是干瞪眼。
few-shot示例也很关键。第一个示例用一份模拟合同,输入两句话,输出完整JSON;第二个示例用一份有歧义表述的文档,比如“利率4.35%上浮10%”,要求模型输出原值并给出说明。这样比纯Schema描述更能约束模型的输出风格。
2.3 校验层:用确定性规则兜底概率性输出
大模型输出的字段,我并不直接接收。所有字段先过一遍规则校验器。这层干三件事:
第一,格式归一化。金额字段去掉“人民币”“万元”前后的杂字,统一转成大写数字加单位的规范格式;日期字段把“二零二四年十二月三十一日”“2024.12.31”“2024/12/31”统一成ISO格式;百分比浮点误差统一保留两位小数。
第二,非法值拦截。如果贷款期限抽出来是“3个工作日”,而文档里实际写的是“36个月”,说明模型抽错了上下文。规则里会做“关键词相关性检查”,比如期限字段出现“工作日”,就要触发复核标记。
第三,字段间逻辑校验。这个最实用。比如借款金额是5000万元,担保方式是“信用”,但文档里有一句话写着“抵押物评估价值为2000万元”,模型有时会把2000万误抽到金额字段。规则会做交叉验证:金额字段与文本中“抵押物评估价值”这个标签的匹配关系,一旦发现字段来源标签不匹配,自动驳回。
校验层不是要追求拦截率百分之百,而是要把“显而易见的错误”在前端挡掉。剩下的模棱两可情况,交给低置信度复核队列。
3. 实操过程与核心环节实现:一套可以直接参考的落地方案
3.1 环境准备与依赖清单
我们是在内网GPU服务器上部署的大模型服务,Python环境为3.10。依赖库用得比较克制:
- PDF解析:pdfplumber 和 pypdf
- 数据处理:pandas、openpyxl
- 大模型调用:通过本地HTTP服务封装,返回标准JSON
- 校验与格式化:re、json、dateutil
实际开发中,我不建议一上来就接大模型,而是先把解析层和校验层跑通,用一份人工标注好的测试集反复验证。大模型那种“看起来能跑”的错觉会掩盖很多工程问题,先把外围稳住再接入模型,排查起来会轻松很多。
3.2 主流程代码示例
下面给出一段简化但结构完整的主流程代码,重点体现Pipeline的骨架。实际生产版本比这个复杂一些,但核心逻辑差不多。
import pdfplumber import json import re class FinanceDocExtractor: def __init__(self, schema, llm_client, rule_validator): self.schema = schema self.llm_client = llm_client self.rule_validator = rule_validator def read_pdf(self, pdf_path): """把PDF拆成带页码的结构化文本块""" blocks = [] with pdfplumber.open(pdf_path) as pdf: for pno, page in enumerate(pdf.pages, start=1): # 提取普通文本 text = page.extract_text() or "" # 提取表格,转成管道分隔形式 table_text = "" tables = page.extract_tables() for table in tables: for row in table: cells = [c if c else "" for c in row] table_text += "|".join(cells) + "\n" blocks.append({ "page": pno, "text": text, "table_text": table_text }) return blocks def build_prompt(self, blocks): schema_desc = json.dumps(self.schema, ensure_ascii=False, indent=2) content = "" for block in blocks: content += f"\n[第{block['page']}页内容]\n" content += block["text"] + "\n" if block["table_text"]: content += "[表格]\n" + block["table_text"] + "\n" prompt = f""" 你是一名金融授信文档要素抽取助手。 请阅读以下文档内容,按给定Schema抽取字段。 字段不再是聊天回答,只需输出JSON,不要输出额外文字。 Schema: {schema_desc} 要求: 1. 每个字段都必须包含 value、confidence、snippet。 2. snippet 是你在原文中看到的依据片段,保留原句。 3. 如果某字段在文中找不到,value 输出null,confidence为0,snippet为“未找到”。 4. 金额、期限、日期必须做基本归一化。 文档内容: {content} """ return prompt def extract(self, pdf_path): blocks = self.read_pdf(pdf_path) prompt = self.build_prompt(blocks) response = self.llm_client(prompt) raw = self._safe_parse(response) return self.rule_validator.validate(raw) def _safe_parse(self, response): """容错处理:清理代码块标记,防止JSON解析失败""" try: return json.loads(response) except json.JSONDecodeError: cleaned = re.sub(r"```json|```", "", response).strip() return json.loads(cleaned)这段代码里,llm_client是内网大模型服务的调用函数,rule_validator是规则校验器。实际生产中,build_prompt里还会加入few-shot示例和业务词表,内容会很长,我这里保留最小可运行版本。
3.3 关键参数与调优清单
如果你要在自己的场景复现,这几个参数很值得先调:
第一,模型推理温度设置为0.1,top_p设置为0.2。抽取任务需要稳定,不需要创造力。温度太高会把“差不多”的表述放大,出现奇怪的输出。
第二,max_tokens要估算够。一份二十页文档的正文可能有两万字,如果全部塞进上下文,可能超出长度限制。我的做法是“滑动窗口+分块抽取”:按章节或页码切块,每块分别抽取,最后合并去重。合并时如果同一字段在不同块出现不同值,以置信度高者为主,并把冲突信息写入日志。
第三,大模型输出格式强制JSON,避免自然语言回答。如果LLM服务支持JSON Mode,一定要开启;如果不支持,必须在提示词里强调“只输出JSON,不要输出任何说明文字”,并在_safe_parse里做容错。
第四,每次调用加入业务词表。比如把常见的担保方式枚举值写进提示词里,让模型在受限范围内选择,而不是自由发挥。
3.4 实测结果与耗时统计
我们在内部测试集上跑了40份文档,覆盖授信批复、借款合同、财务简表三类。人工基准由两名业务骨干手工标注,每个字段取双人一致的取值作为标准答案。
| 文档类型 | 平均页数 | 人工耗时 | 系统耗时 | 字段级准确率 |
|---|---|---|---|---|
| 授信批复 | 25页 | 22分钟 | 1分40秒 | 98.1% |
| 借款合同 | 18页 | 11分钟 | 48秒 | 99.0% |
| 财务简表 | 12页 | 15分钟 | 1分10秒 | 95.6% |
财务简表准确率略低,主要问题出在表格跨页后表头与数据对不上。后来加了跨页表头关联逻辑,准确率提升到97.2%。即便如此,这个速度已经足够让业务流程从“当天提交、次日反馈”变成“实时反馈”。业务部门对准确率没有过分苛求,因为他们真正想要的是把人力从重复劳动中释放出来,而不是完全无人化。
4. 常见问题与排查技巧实录
4.1 问题速查表
把项目里踩过的坑整理成一张表,方便你直接对照排查:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 金额字段抽成了抵押物评估价 | 模型对上下文标签不敏感 | 增加字段来源标签校验规则,禁止“抵押物评估”上下文映射到借款金额 |
| 日期输出成“2024-0-0” | 大模型对不完整日期做了臆测 | 增加日期格式正则,非法日期强制置为null并进入复核队列 |
| 表格跨页后数据错位 | PDF解析库按页拆分导致表头丢失 | 合并相邻页的表格表头,以第一页表头为准重建列关系 |
| 长文档漏掉末尾关键条款 | 上下文窗口截断 | 采用分块抽取+汇总合并,末尾块单独处理 |
| 同字段不同页出现两个值 | 合同正文和附件表述不一致 | 保留两个候选,按置信度和业务优先级取舍,写入冲突日志 |
| 大模型把正文里的“假设”当成真值 | 提示词缺少“事实性约束” | 在提示词里明确“只抽取明确陈述的事实,禁止推测” |
4.2 三个印象最深的坑
第一个坑在解析层。某类扫描件PDF,表面看是图片,但混着少量文字层。最初我用文本提取方式处理,结果漏掉了大量手写批注。后来改成“文本层优先,同时做OCR兜底”的双通道方案,再按OCR置信度合并文本,才解决。
第二个坑是金额单位的归一化。文档写着“5,000万元”,模型输出“50000000元”,本身没错,但业务系统要求统一为“5000万元”。规则引擎里需要把阿拉伯数字每四位一组,去掉后面多余的零,还原成中国财务习惯。这个规则听起来容易,写起来全是边界条件。
第三个坑是复核界面设计。最初我们只给人工复核员展示抽取结果,不给原文位置,导致复核员必须打开PDF自己找,效率很低。后来改成“点字段、看切片、跳原文”,并记录复核动作日志。这个改动比优化模型阈值带来的体验提升还大,说明工具交付不能只优化后端指标。
4.3 低置信度复核机制:不是所有字段都一视同仁
不要把置信度阈值设成一个固定值。不同字段的风险等级完全不同。借款金额、利率、日期这些强监管字段,置信度阈值设到0.8以上;客户名称这类稳定性字段,阈值可以放到0.7;担保方式这种枚举型字段,因为取值有限,模型输出可信度天然高,阈值甚至可以放到0.9。
对于低于阈值的字段,系统不会直接丢弃,而是把它们导入人工复核队列。复核界面按照“风险等级从高到低”排序,确保复核员先处理金额和利率,再处理其他低风险字段。这有点像一个漏斗:规则引擎拦掉明显错误,大模型释放大部分效率,人工只处理最不确定的少数案例。
这套机制跑通后,人工复核量从最初的每份文档平均7.3个字段,下降到1.6个字段。业务部门终于觉得“AI不是来抢饭碗的,是来帮我擦桌子的”。
5. “AI替代潮”的技术真相:哪些会被替代,哪些不会
5.1 可被替代的,往往是流程的中间层
我的观察是,金融机构里最容易先被AI替代的岗位,不是写报告的客户经理,也不是做决策的风险总监,而是那些处于流程中间层、主要负责“搬运信息”的人。他们把A系统的数据搬到B系统,把PDF里的字段抄进Excel,把邮件里的数字整理成台账。这些工作的本质是“信息转换”,规则越明确,越容易被替代。
反过来,真正难替代的是两类:一类是“信息判断”型工作,比如这笔业务的风险到底可不可控,客户经理的话术里有没有隐藏的还款风险;另一类是“责任承担”型工作,AI可以给出风险评估,但最终签字的还是人。技术越成熟,责任链条上的那个人反而越重要。
5.2 AI替代的边界在于“责任”
很多非技术朋友担心AI会完全取代人,但从工程角度看,AI系统的输出必须有人兜底。我们内部有一条原则:任何AI抽取结果都必须保留可溯源证据,任何阈值之外的案例必须进入人工确认,任何业务决策必须由有权限的人类完成。这不是技术限制,而是责任归属问题。
AI可以做到“看到”所有信息,但“认定”某个事实仍然需要人来背书。在金融行业,一旦出错,需要的不是一句“模型猜的”,而是一个可解释、可追溯、可复盘的证据链。所以,我认为未来不是人和AI竞争,而是“掌握了AI工具的人”和“不会使用AI工具的人”之间产生差距。
5.3 技术人怎么利用这次浪潮
对技术从业者来说,这轮金融业AI替代潮更像一次大范围基础设施升级。早年做文档处理要写死规则,遇到新模板就得改代码;现在有了大模型,语义理解能力大大增强,我们更有余裕去打磨数据规范、复核体验和业务流程。
我的建议是,别把精力全押在“调模型”上,多关注三件事:一是业务口径,真正懂行业的人比懂模型参数的人稀缺得多;二是数据管线,高质量标注集和清洗过程决定了系统上限;三是人机协作流程,怎么让业务人员愿意用、敢用、信任系统。这三件事做好了,就算底层模型换了三代,系统依然有价值。
最后分享一个小技巧:不管用哪种模型,抽取结果里一定要保留原文切片和页码。不要只存一个值,要把“值从哪来”一起存下来。我见过太多项目,准确率刷得很高,可一旦业务方对某个字段提出质疑,开发人员只能翻日志大海捞针。做金融AI落地,信任比准确性更重要。而信任从来不是靠模型评分刷出来的,是靠每一次出错之后的定位、解释、修正积累出来的。