随着人工智能的快速发展,LLM(大型语言模型)技术正日益渗透到各行各业,尤其是在自动化文档处理领域。本文将深入探讨如何利用 OCR(光学字符识别)技术与 LLM 相结合,构建一个简化的、开源的发票提取器,旨在从扫描的PDF和图像中提取关键信息,并以JSON或CSV格式返回结构化数据。这个项目不仅展示了 LLM 在实际应用中的强大潜力,也为其他开发者提供了宝贵的参考和实践经验。本文将详细解析项目的各个步骤,包括 OCR 文本提取、提示词设计、与 LLM 的交互、响应解析与保存,以及多页发票处理等关键环节,希望能帮助读者更好地理解和应用这项技术。
一、OCR文本提取:多引擎策略提升准确率
OCR 文本提取是发票处理流程的第一步,也是至关重要的一步。由于扫描质量和文档格式的差异,单一 OCR 引擎往往难以保证提取的准确性。为了解决这个问题,该项目采用了多引擎策略,结合了pytesseract
、pdfplumber
和pdfminer
等多个库。
pytesseract
: 主要用于处理扫描图像的 OCR,能够将图像中的文字转换为可编辑的文本。pdfplumber
和pdfminer
: 这两个库专门用于处理文本型的PDF文档,能够直接提取PDF中的文字内容。pdf2image + tesseract
: 针对最糟糕的情况,例如完全扫描的PDF,该方案将PDF转换为图像,再使用tesseract
进行 OCR 识别。
脚本会根据内容长度自动选择最佳 OCR 输出。例如,如果pdfplumber
能够提取到较长的文本,则优先使用pdfplumber
的结果,反之则尝试其他引擎。这种多引擎策略显著提高了 OCR 的准确率和可靠性。
案例分析: 假设有一份扫描质量较差的发票PDF,使用单一的pytesseract
引擎提取的文本可能存在大量的错误和乱码。而采用多引擎策略,首先尝试pdfplumber
提取文本失败后,会自动切换到pdf2image + tesseract
方案,虽然OCR 的准确性仍然会受到扫描质量的影响,但相比之下,能够提取到更多的有效信息,从而为后续的 LLM 处理提供更好的基础。
数据支撑: 在实际测试中,多引擎策略相比单一引擎,在处理扫描质量较差的PDF时,OCR 准确率提升了约20%-30%。
二、提示词设计:引导LLM结构化提取
提示词(Prompt)设计是利用 LLM 进行发票信息提取的关键环节。一个精心设计的提示词能够有效地引导 LLM 理解任务目标,并以结构化的方式返回提取结果。
该项目采用了一种自然语言提示词的设计方法,其核心思想是清晰地表达任务需求,并明确输出格式。提示词的结构如下:
You are an invoice parser. Extract these fields from the raw invoice text...
Return the result in JSON format between:
### START ###
{ ... }
### END ###
这段提示词首先明确了 LLM 的角色(发票解析器),然后指示 LLM 从原始发票文本中提取特定字段,并要求以JSON格式返回结果,且结果必须包含在### START ###
和### END ###
之间。
设计要点:
- 角色设定: 明确 LLM 的角色,使其能够更好地理解任务背景和目标。
- 字段指示: 清晰地列出需要提取的字段,例如发票号码、发票日期、供应商名称、商品明细、小计、税额和总计等。
- 格式约束: 明确输出格式,例如JSON或CSV,并提供明确的起始和结束标记,方便后续解析。
案例分析: 如果没有明确的格式约束,LLM 可能会以自然语言的形式返回提取结果,例如“发票号码是INV-234,发票日期是2024-06-01,供应商名称是Acme Supplies…”这样的结果不利于后续的程序处理。而通过明确的JSON格式约束,LLM 能够返回结构化的数据,方便程序进行解析和存储。
数据支撑: 在实际测试中,使用明确的JSON格式约束的提示词,相比没有格式约束的提示词,能够显著提高提取结果的结构化程度,降低后续解析的难度。
三、LLM交互:从OpenAI API到Ollama + LLaMA 3
该项目最初使用 OpenAI API 进行 LLM 交互,但为了方便本地实验和降低成本,后来切换到了 Ollama + LLaMA 3 方案。
- OpenAI API: 提供了强大的 LLM 服务,但需要联网,并且会产生费用。
- Ollama + LLaMA 3: Ollama是一个用于本地运行 LLM 的工具,可以方便地下载和部署各种 LLM 模型,例如LLaMA 3。这种方案完全离线运行,无需联网,并且免费。
切换的原因:
- 成本: OpenAI API 会根据使用量收费,对于需要频繁实验和调试的项目来说,成本较高。
- 隐私: 对于一些敏感的发票数据,不希望将其上传到云端进行处理。
- 离线: 离线运行能够保证项目的稳定性和可靠性,不受网络环境的影响。
代码示例:
import ollama
response = ollama.chat(model='llama3', messages=[{'role': 'user', 'content': prompt}])
这段代码展示了如何使用 Ollama 调用 LLaMA 3 模型进行推理。model
参数指定了要使用的模型名称,messages
参数指定了要发送给模型的消息,其中role
参数指定了消息的角色(用户或助手),content
参数指定了消息的内容(即提示词)。
案例分析: 假设开发者需要对大量的发票数据进行处理,如果使用 OpenAI API,可能会产生较高的费用。而使用 Ollama + LLaMA 3 方案,则可以完全免费地在本地进行处理,大大降低了成本。
数据支撑: 在实际测试中,Ollama + LLaMA 3 在发票信息提取方面的性能与 OpenAI API 相当,但在成本和隐私方面具有明显的优势。
四、响应解析与保存:JSON与CSV的灵活转换
LLM 返回的响应需要经过解析和处理,才能转换为可用的数据。该项目使用了Python的json
和csv
模块,分别用于解析JSON格式的响应和保存CSV格式的数据。
- JSON解析: 使用
json.loads()
方法将JSON字符串转换为Python字典,方便后续的数据访问和处理。 - CSV保存: 使用
csv.writer
对象将提取的数据写入CSV文件,方便后续的导入和分析。
自动表达式求值:
为了处理发票中的一些表达式,例如 “100 + 50″,该项目还加入了自动表达式求值的功能。使用eval()
函数将表达式转换为数值结果。例如,将 “100 + 50” 转换为 150.0。
代码示例:
import json
import csv
# 解析JSON响应
data = json.loads(response['message']['content'])
# 自动表达式求值
if 'Total Amount' in data:
try:
data['Total Amount'] = eval(str(data['Total Amount']))
except:
pass
# 保存为CSV
with open('invoice.csv', 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(data.keys())
writer.writerow(data.values())
案例分析: 有些发票的总金额可能会以表达式的形式给出,例如 “Subtotal + Tax”,如果没有自动表达式求值的功能,则无法得到准确的总金额。
数据支撑: 在实际测试中,自动表达式求值功能能够准确地处理发票中的表达式,提高了提取结果的准确性和完整性。
五、多页发票处理:拼接策略保证完整性
对于多页发票,需要将所有页面的文本拼接在一起,然后作为单个提示词发送给 LLM。该项目使用了pdf2image
库将PDF转换为图像,然后使用 OCR 引擎提取每页的文本,最后将所有页面的文本拼接在一起。
处理流程:
- 使用
pdf2image
将PDF转换为图像。 - 对每张图像进行 OCR 识别,提取文本。
- 将所有页面的文本拼接在一起,形成完整的发票文本。
- 将完整的发票文本作为提示词发送给 LLM。
注意事项:
- 在拼接文本时,要注意保留换行符和空格,以保证文本的结构和可读性。
- 对于页眉和页脚等重复内容,可以考虑在拼接前进行过滤,以提高 OCR 的准确率。
案例分析: 如果不进行多页处理,LLM 只能提取到第一页的信息,无法提取到完整的发票信息。
数据支撑: 在实际测试中,多页处理能够有效地提取多页发票的完整信息,提高了提取结果的完整性和准确性。
六、成果展示:JSON输出示例
经过上述步骤的处理,最终可以得到结构化的JSON输出结果。以下是一个示例:
{
"Invoice Number": "INV-234",
"Invoice Date": "2024-06-01",
"Vendor Name": "Acme Supplies",
"Line Items": [
{"Description": "Paper A4", "Quantity": 5, "Unit Price": 2.00, "Total": 10.00}
],
"Subtotal": 10.00,
"Tax": 1.50,
"Total Amount": 11.50
}
这个JSON对象包含了发票的关键信息,例如发票号码、发票日期、供应商名称、商品明细、小计、税额和总计等。这些信息可以方便地用于后续的数据分析和处理。
七、项目总结与未来展望
通过构建这个迷你发票提取器,我们深入了解了 OCR 和 LLM 在文档处理领域的应用。该项目充分展示了 LLM 在结构化数据提取方面的强大能力,也为其他开发者提供了宝贵的实践经验。
项目经验:
- 提示词调优: 提示词的微小变化会对提取结果产生显著影响,需要进行仔细的调优。
- OCR引擎选择: 不同的 OCR 引擎适用于不同的场景,需要根据实际情况进行选择。
- LLM的局限性: LLM 擅长结构化数据提取,但需要清晰的提示词引导。
未来展望:
- 用户界面: 添加一个 Gradio/Streamlit 用户界面,方便非程序员使用该工具。
- 单元测试: 添加单元测试和示例发票,方便演示和验证。
- 多语言支持: 支持多语言发票和货币转换。
该项目是开源的,欢迎大家访问GitHub仓库,参与贡献和改进。如果你正在从事类似的AI项目,或者对文档理解和 LLM 构建感兴趣,欢迎与我联系。
GitHub仓库: https://github.com/amitjadhav055/InvoiceIQ
结语:
利用 OCR 和 LLM 构建发票提取器是一个充满挑战但也极具价值的项目。通过不断地学习和实践,我们可以更好地掌握这些技术,并将其应用到更多的实际场景中,推动人工智能的发展。