
最近好几个做项目对接的老朋友都在讨论一门新课讲的是用大模型直接提取文档信息。我平时做自动化流程设计最烦的就是从各种合同、报告、简历里抠关键字段眼睛看花了容易漏。这门课的核心思路其实说穿了不值钱让大语言模型读文档按你指定的结构把信息吐出来把“人肉整理”变成“机器整理”。它不是死板的规则匹配而是让模型理解内容之后再抽取。我把这门课里的思路、代码和实战经验重新梳理了一遍重点放在“为什么这么做”和“实际会遇到什么问题”上应该能帮有同样需求的朋友少走点弯路。1. 先想清楚手动整理文档到底痛在哪1.1 文档格式的“万国博览会”手动整理文档信息听起来很Low但真正做过的都知道这活儿比想象中复杂得多。我平时要处理的文档包括PDF合同、扫描版营业执照、Excel台账、Word需求说明还有网页导出的超长报告。这些文档格式五花八门有的带目录有的不带有的表格套表格有的扫描件模糊得像马赛克。传统做法是安排一个人专门复制粘贴把关键字段填到系统里。但问题是当一个月要处理几百份文件时纯粹靠手工会让人崩溃。更麻烦的是文档里还夹杂着图片和扫描页你得先做OCR转成文字。可很多OCR工具转出来的文字段落错乱不仅没省时间反而要花更多精力去修正。1.2 传统自动化方案的三个老毛病我以前试过不少看起来能自动化的方案比如用正则表达式匹配合同号用模板表单解析固定格式的报表甚至试过老式的文档识别软件。这些方案在格式特别规整的场景下确实能用但一旦文档有一点变化就崩格式一变正则就废。同一个字段可能叫“甲方”也可能叫“委托方”正则只能认死字别的写法一概识别不出来。表格变形模板就废。有些模板要求单元格名称完全一致实际文件里多一行少一列就解析失败了。维护成本特别高。规则越多代码越难维护改了这条影响那条最后只能守着老代码过活。这套“规则驱动”的思路本质上是让计算机死记硬背版面位置做不到语义理解。所以一碰到非标准文档系统就彻底歇菜。1.3 为什么大模型能解决这个问题大模型跟传统规则不一样的地方在于它不是靠固定关键词去匹配而是靠理解整段文字后把你要的信息找出来。模型会根据上下文判断“甲方”指的是哪个主体识别出“合同编号”这个字段在文档里出现在什么位置然后按你要求的格式填到输出里。这意味着哪怕文档格式千差万别只要文档里写了“这是合同编号”“这是签约日期”模型就能提取出来。就算字段名变了比如“委托方”换成“客户”它也能靠语义关联推断出来。这个泛化能力是传统方案完全没法比的。课程里反复强调一个观点与其写十条规则不如写一段好的提示词。投资回报也很直观。规则系统需要持续维护提示词系统只需要迭代。模型升级一次你之前写的提示词大概率还能用而规则系统的代码很可能需要重写。这个账算得过来。2. 课程核心思路拆解从文档到结构化信息的完整链条2.1 整条处理链路不止“调一次模型”那么简单很多第一次接触这个概念的人以为“用AI提取文档信息”就是调一个API、传一段文字、拿回一段JSON。实际操作会复杂不少。课程里的链路大致分五步第一步文档解析。把PDF、Word、图片变成纯文本。这一步决定后面所有环节的上限解析做得不好模型再聪明也没用。第二步文本预处理。把很长的文档切分成合理片段避免超出模型的上下文长度同时保留足够的信息上下文让模型能看懂前后关系。第三步构造提示词。告诉模型要提取哪些字段输出的格式是什么。这是整个流程里最讲究的部分。第四步调用模型并解析输出。拿到结果后要处理模型偶尔输出格式不稳定的情况比如在JSON外面包了一层说明文字。第五步结果校验和兜底。对输出做基本校验比如日期格式、金额范围发现异常就标记人工介入。这五步环环相扣每一步都有细节。课程里对前两步强调得比较多因为大部分常见失败案例都出在文档解析和文本切分上很多人一开始就把力气全花在提示词上方向就跑偏了。2.2 文档解析PDF、Word、扫描件要区别对待PDF是最常遇到的格式但PDF有两种完全不同的底子。一种是文本型PDF可以直接复制文字另一种是扫描图片型PDF本质上是图片必须先做OCR否则你拿到的是一堆图像不是文字。文本型PDF直接用解析库按页码提取文本就行扫描型PDF就得先过一道图像识别。Word文档稍微好一点但要注意里面可能嵌了表格、图片、文本框。如果直接提取纯文本版式信息会丢掉。比如合同里有一个多行表格你只按段落提取表格内容可能全挤在一坨模型就分不清哪一行对应哪一列。扫描件的处理更需要谨慎。OCR工具识别率很难做到100%尤其是中文手写体、艺术字、模糊印章经常会把“壹”认成“一”把“0”认成“O”。这个环节质量不过关后面模型提取的准确率会断崖式下跌。课程里提到一个很实用的做法不要一上来就指望一次OCR完美先通过页面内容判断是不是扫描页再决定是否需要OCR。判断规则很简单看这一页能不能提取到足够多的文本提取不到就当作图片处理。2.3 文本切分长度和语义要平衡大语言模型对输入长度有限制不同模型有不同上限。一个超长文档你直接拿几十页内容去请求大概率会报错或者漏掉后面部分。所以需要把文档切成小段再逐步处理。但切分不能硬按字符数切那样会把一句话拦腰截断影响模型理解。更好的做法是按段落、按标题、按章节边界切分尽量保持语义完整。课程里给了一个很实用的策略如果文档超过模型上下文长度的一半以上就先切块处理每一块只提取当前块内涉及的字段最后把各块结果合并去重。比如一份合同有30页你可以每10页切一块分别提取“合同编号、签约日期、金额”最后合并。这里有个小技巧切块粒度不是越小越好。切得太细模型看不到跨页的背景信息切得太粗又可能超长。我自己试下来单块文本量控制在模型允许长度的70%以内比较稳妥给输出留出余地。因为模型还要生成返回值如果把输入塞到满输出很容易被截断。2.4 提示词设计让模型按固定结构“填表”提示词是从规则世界进入大模型世界的门槛。同一份文档提示词写得好不好抽出来的结果天差地别。课程里展示了一个标准提示词模板我整理成了自己的版本你是一个文档信息提取助手。请阅读下面的文档片段提取以下字段 - 合同编号 - 甲方名称 - 乙方名称 - 合同签订日期 - 合同总金额单位人民币元 要求 1. 只能从文档中提取信息不要编造。 2. 如果某个字段不存在输出null。 3. 金额请提取数字如12345.67不要带货币符号。 4. 以JSON格式输出字段名为contract_id, party_a, party_b, sign_date, total_amount。 5. JSON中不要输出其他任何内容。 文档内容如下 ...这个提示词看起来简单但几个细节非常关键。第一明确告诉模型“只能从文档中提取信息”这是防止模型编造内容的关键。第二规定“字段不存在输出null”而不是让模型自己决定格式。第三给输出指定了JSON字段名让后续代码解析更方便。我自己把提示词扩展了一下加了一个“来源引用”字段让模型把每个字段对应的原文片段也返回。这样如果结果不对我能直接定位是模型理解错了还是文档本身就缺失这个信息不用一条条去翻原文档核对。3. 实战搭一套能用的文档信息提取流水线3.1 环境准备最小可用配置先说环境。我用的是Python因为文档处理和模型调用的生态最全。你不需要装很多包一个PDF解析库、一个HTTP请求库加一个JSON处理库就够了。你要是处理Word或图片再按需补对应的解析库。模型方面你可以用大模型平台的API也可以本地部署开源模型。我自己建议初学者先用API跑通流程再考虑本地化。本地模型的坑太多了尤其是一上来就搞显卡部署环境问题能让人崩溃。API虽然按量付费但省心效果也稳定。安装命令不用搞得多华丽缺什么装什么pip install pdf-parser-lib requests这里要提醒一句别盲目复制网上的“全家桶”安装命令。很多库你根本用不到装了反而造成版本冲突。我一开始图省事把所有号称能用的库全装了一遍结果光排冲突就花了半天。3.2 读取PDF文档文本型与扫描型分开处理文本型PDF处理起来很简单用解析库按页提取文本就行。下面这段代码把PDF每一页的文字打印出来方便你检查解析质量from pdf_parser import open_pdf, extract_text doc open_pdf(contract.pdf) for page_index in range(doc.page_count): page doc.get_page(page_index) text extract_text(page) print(f--- Page {page_index 1} ---) print(text)跑完这段程序你就能看到PDF每一页的文字内容。如果发现某页提取出来的文字是空的只有一堆乱码那这一页大概率是扫描图片需要走OCR流程。判断是否走OCR不需要太智能的算法。课程里教了一个简单规则如果某一页提取到的文本数量少于20个字就认为这页是图片进入OCR流程。def process_page(page): text extract_text(page) if len(text.strip()) 20: return ocr_page(page) return text这个启发式规则虽然简单粗暴但非常实用。它能大幅减少OCR调用次数节省时间也节省费用。别小看这个判断我曾经为了省事把所有PDF页面全部强制OCR结果既慢又贵文本识别出来还不如直接用文本提取准确。3.3 构造输入文本保留标题和段落结构解析出文本后不要直接把杂乱文字丢给模型。原始PDF解析出来经常有断行、重排的问题你最好先把文本按段落重新组织保留标题层级。我做了一个简单处理把连续的换行替换成空格把空行保留为段落分隔再给每个段落标注大致归属的标题。比如合同编号HT-2024-001 甲方某科技有限公司 一、合同标的 ...这样处理后模型更容易理解文档结构。我试验下来提取准确率比直接丢原始文本高出不少。具体高多少不好量化但同一批测试文档出错率大概降低了一半。这个环节比较琐碎但性价比很高。别嫌麻烦花十分钟把文本规整好后面可能省两小时。3.4 调用模型把提示词和文档内容发出去接下来就是把提示词和整理好的文档拼接起来发给模型。下面这段代码用HTTP请求调用大模型接口import requests import json def extract_info(document_text): prompt f 你是一个文档信息提取助手。请阅读下面的文档片段提取以下字段 - 合同编号 - 甲方名称 - 乙方名称 - 合同签订日期 - 合同总金额单位人民币元 要求 1. 只能从文档中提取信息不要编造。 2. 如果某个字段不存在输出null。 3. 金额请提取数字不要带货币符号。 4. 以JSON格式输出字段名为contract_id, party_a, party_b, sign_date, total_amount。 5. 不要输出其他任何内容。 文档内容 {document_text} response requests.post( https://api.example.com/v1/chat/completions, headers{Authorization: Bearer YOUR_API_KEY}, json{ model: current-model, messages: [{role: user, content: prompt}], temperature: 0.0 }, timeout60 ) data response.json() content data[choices][0][message][content] # 清理可能夹杂的 json 标签 content content.strip().replace(json, ).replace(, ) return json.loads(content)temperature设为0这个细节容易被忽略。temperature控制模型输出的随机性信息提取是确定性任务不需要模型发挥创意。所以必须设成0否则同一份文档跑两次结果可能都有差异。别小看这个参数我见过有人跑了好几遍每次金额都不一样最后才发现是temperature默认值太高。还要注意模型输出有时候会带json标记或者在JSON前后加说明文字。代码里做个简单清理不然json.loads会直接报错。3.5 批量处理加上错误处理和重试单条处理跑通后批量就顺理成章了。我的做法是写一个循环遍历文件夹里所有PDF逐个调用提取函数把结果写入JSON文件。import os import json from tqdm import tqdm results [] for file_name in tqdm(os.listdir(contracts)): if not file_name.endswith(.pdf): continue try: text read_pdf(os.path.join(contracts, file_name)) info extract_info(text) info[file] file_name results.append(info) except Exception as e: print(f处理失败: {file_name}, 错误: {e}) results.append({file: file_name, error: str(e)}) with open(results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2)这里故意加了异常捕获因为API调用时可能出现超时、限流、输出解析失败。一个合同处理失败不应该让整个批任务崩溃把错误信息记录下来事后统一检查更高效。实际批量跑下来一百份文件的目录几分钟能处理完具体速度取决于模型接口的响应时间和文档大小。相比人工复制粘贴效率能提升几十倍。这个效率提升不是夸张我拿一份二十页的合同做过对比人工整理一份大概要十分钟用这个流程跑一份不到一分钟。4. 常见问题与排查技巧4.1 输出经常不是合法JSON怎么治这个问题我遇到最多。明明在提示词里写了“只输出JSON”模型还是会在前面加一句“根据文档提取结果如下”或者在JSON后面补一截解释文字导致json.loads直接报错。我的排查方法是不要一上来就改提示词先看看原始输出长什么样。很多时候只是前后多了几个字符清理一下就完事。如果输出总是被截断可能是输出长度限制太小需要在API参数里调大max_tokens。如果模型总是忘记JSON格式最有效的办法是在提示词里给一个示例输出示例 {contract_id: HT-2024-001, party_a: 某科技有限公司, party_b: 某商贸公司, sign_date: 2024-03-12, total_amount: 128000.00}给模型一个“标准答案”比抽象描述“一定要JSON格式”有用得多。大模型在示例引导下的表现会好很多这也是课程里重点提到的“少样本提示”思路。4.2 文档太长模型直接超限当你处理一份五十页的合同时模型可能会报请求过大或者把后面内容截断。解决办法就是前面说的切块。但切块会带来一个新问题同一个字段可能在多个块里重复出现合并结果时要考虑去重和冲突。我的策略是每块提取相同字段如果各块结果一致直接取如果冲突按出现次数来选出现最多的那个优先实在不行就标记该字段为“待人工确认”。不要自作主张随便选一个因为这种冲突往往意味着文档里存在歧义。切块时还有一个容易忽略的问题块与块之间要留一些重叠。比如每十页切一块第1块是1到10页第2块是9到18页这样能避免跨页关键字段被切断。这个技巧课程里没讲透我是踩了坑才发现的。有一次合同编号刚好落在第10页和第11页交界处不重叠的话直接就漏掉了。4.3 提取的信息不对怎么判断是文本解析问题还是模型问题信息提取错误时很多人第一反应是改提示词但其实问题可能出在更早的环节。我总结了一套快速定位方法第一步打印解析出来的纯文本人眼看一遍确认文字是否完整、顺序是否正确。如果这里就乱了那说明解析环节出了问题别急着改提示词。第二步检查文本里有没有OCR错误。比如“壹”被识别成“一”数字“1”被识别成“l”。这些都会导致模型提取出错。处理OCR错误最有效的方法是提高OCR质量或者在识别后做一轮字段级校验。第三步拿一段干净、规范、简短的样例文档测试提示词。如果样例文本上提取正确那说明提示词没问题问题还是在文档解析或原始文本质量上如果样例文本上提取都不对那才需要改提示词。这套排查流程能帮你避免做无用功。我后来一遇到问题就先看解析文本再拿样例测试基本上十分钟就能定位问题不用火急火燎去改提示词。4.4 表格信息提取需要拆成行列再交给模型合同里经常有表格比如付款计划表、物料清单。直接把表格转成纯文本模型很难分清一行有几列。最好的做法是把表格用分隔符转成类似CSV的文本。我在代码里加了这么一段处理解析到表格时把每行单元格用竖线分隔行与行之间用换行分隔付款批次 | 付款比例 | 预计付款日期 第一批 | 30% | 2024-04-01 第二批 | 40% | 2024-07-01 第三批 | 30% | 2024-10-01模型看到这种结构理解能力会好很多。注意不要用Tab做分隔符因为模型和解析工具对Tab的处理经常有歧义用竖线或逗号会更稳妥。这里还要说一个坑有些表格的单元格里本身就带了竖线比如地址里写“北京市|朝阳区”这样用竖线分隔就会产生歧义。遇到这种情况可以换个分隔符比如用“||”这种不常见的组合或者在提示词里明确说明分隔符的含义。4.5 中文编码和乱码问题处理中文文档时乱码是最容易遇到的坑。PDF解析库在识别特殊字体的嵌入时经常会出现乱码表现是提取出来的文本全是方框或者问号。扫描件遇到手写体OCR识别出来也经常是错字。这种情况下先换一个PDF解析库试试。如果还是不行就得考虑用OCR方案。另外在读写文件时一定记得用utf-8编码否则写进Excel里的中文会全部变成乱码。代码里所有open函数都加上encodingutf-8以及json.dump时加上ensure_asciiFalse一个小细节能省一大把排查时间。还有一个容易忽略的点Windows终端上直接print中文可能乱码这不代表程序有问题是终端编码不对。把输出重定向到文件里再用编辑器打开就能正常看到中文了。5. 实操中最值得留意的几点经验5.1 接口调用一定要加超时和重试自动化工序最怕的就是一个环节卡死。大模型接口偶尔会慢甚至挂掉。不加超时的话程序可能一直卡在某个请求上整个批任务就废了。不加重试的话一次偶发失败就会中断全部流程。我用的重试策略是第一次失败后等两秒重试第二次等四秒第三次等八秒最多重试三次。这种指数退避的方式能有效避免把接口打到限流。课程里没详细讲这块但真实生产环境里特别重要。我一开始没做重试有一次跑批量任务某份文档刚好触发模型超时程序直接崩溃了白跑了半小时。5.2 不要迷信“一次性万事通”一套流程跑通后你一定会遇到新类型的文档比如手写扫描件、多层嵌套表格。这时候不要急着改主流程而是把异常文档单独收集起来集中测试再考虑是不是需要针对这类文档做特殊处理。我自己的做事方式是维护一个“异常样例库”每份出错的文档都存一份样本备注出错原因。等积累到一定数量再统一分析看是共性还是偶发。如果是共性比如所有扫描件的OCR效果都很差那就在OCR环节升级方案如果只是个别文档的问题那就在流程里加一个“人工复核”标记不值得为个别案例增加复杂度。5.3 字段级校验能兜底模型再强也不能保证每个字段都正确。提取完金额后我会用正则校验是不是纯数字日期是不是合法格式不符合的直接标记出来。这一步相当于给流程加了一个保险网。校验规则不用很复杂其实就是几个简单的判断金额字段必须是非负数字允许小数点后最多两位。日期字段必须是类似2024-03-12的格式且月、日是合法范围。编号字段不能包含空格和换行。这些规则写在代码里跑一遍也就几秒钟。能把明显不合常理的错误提前拦下来避免污染下游数据。抽查还是有必要的但比例不用太高一百份里抽五份看看有没有系统性错误就可以。5.4 提示词也要做版本管理提示词这东西看着只是个文本但改起来影响很大。我今天改一版提示词明天又改一版到底哪一版跑出来的是哪个结果必须留档。不然某天结果不对劲你都不知道是哪次改动引起的。我用的是一个特别土的办法单独建一个文本文件每次改提示词就把旧版本复制一份标注修改时间和修改原因。别小看这个土办法关键时刻能救命。有一次我发现某批合同的提取准确率明显下降回溯提示词改动记录才发现是上周为了处理另一类文档把“只能从文档中提取信息”这句删掉了模型就开始放飞自我偶尔编造内容。5.5 先抓关键字段跑通流程再慢慢加课程里有一个观点我特别认可与其追求一次把所有字段都提取全不如先抓最重要的两三个字段跑通流程再逐步增加字段。第一次跑的时候你一定会发现意想不到的问题比如某个字段在文档里根本不存在或者模型总是把甲方和乙方搞反。这些问题只有在你真正跑起来、看到输出结果之后才会暴露光靠想是想不出来的。我自己就是从“只提取合同编号和金额”开始确认流程稳定后再加签约日期、双方名称一步一步增加到十多个字段。每加一个字段跑一批新文档验证再调整提示词。这种迭代方式虽然看起来慢但非常稳。我见过有人想一口吃个胖子第一版就要求提取二十个字段结果输出各种混乱排查了两天才发现是其中一个字段名的表述有歧义。从我自己的经验看从手动复制粘贴到全流程自动化大概花了两周时间。其中大部分时间花在文档解析和排错上真正写提示词只花了一下午。所以别觉得这种自动化很神秘肯动手把链路搭起来用AI提取文档信息这件事真没有想象中那么难。做完了之后你会发现最值钱的不只是省下的时间而是终于不需要在人肉整理文档这种重复劳动上消耗精力了。