这是由Imagen 3生成的
在这个新的大型语言模型(LLM)时代,银行和金融机构处于一定的劣势,因为这些前沿模型由于硬件需求几乎无法在本地部署。然而,银行数据的敏感性引发了严重的隐私担忧,尤其是在它们只作为云服务存在时。为了解决这些挑战,组织可以转向本地部署或小型语言模型(SLM)方案,以将数据保留在内部,避免敏感信息的潜在外泄。这样可以利用先进的LLM(本地或仅通过少量外部请求),同时确保严格遵守如GDPR、HIPAA或各种金融法规等规定。
本文将展示如何通过结合以下几点,构建一个完全本地部署的文档智能解决方案:
- ExtractThinker — 一个开源框架,用于协调OCR、分类和数据提取管道,供LLMs使用
- Ollama — 一个本地部署语言模型(如Phi-4或Llama 3.x)的解决方案
- Docling 或 MarkItDown — 灵活的库,用于处理文档加载、OCR和布局解析
无论你是在严格的保密规定下操作,处理扫描PDF或需要从PDF中提取信息,还是想要高级的视觉提取,这个端到端的栈提供了一个安全且高性能的管道,完全在你自己的基础设施中。
1 挑选正确的模型(文本 vs. 视觉)这张图片是作者自己做的
当你构建文档智能栈时,首先需要决定是否需要一个文本模型或一个 视觉模型。文本模型通常更适用于本地解决方案,因为它们更容易获得且使用限制较少。然而,视觉模型对于复杂的分割任务非常关键,特别是当文档依赖于视觉线索,例如布局、颜色方案或特定格式时。
在某些情况下,您可以为不同阶段搭配不同的模型。例如,一个更小的moondream模型(0.5B 参数)可以处理拆分,而 Phi-4 14B 模型则负责分类和提取任务。许多大型机构更倾向于部署一个单一且更强大的模型(例如,70B 参数范围内的 Llama 3.3 或 Qwen 2.5),以涵盖所有使用场景。如果您只需要英文为中心的 IDP 系统,您可以主要使用 Phi4 来完成大部分任务,并让 moondream 模型作为特殊情况下的备用拆分工具。这一切都取决于您的具体需求和可用的基础设施情况。
2. 处理文档的过程:MarkItDown (保留原名) vs. Docling (保留原名)在文档解析方面,有两个特别突出的库。
MarkItDown(一个特定的术语或名称,此处保持原样)注:为了帮助理解,“MarkItDown”在此处保持原文,具体含义请参考上下文。
- 更简单,更直接,由微软广泛支持
- 非常适合直接处理文本任务,不需要使用多个OCR引擎
- 安装和集成都非常简单
- 更高级,支持多种OCR(比如Tesseract、AWS Textract、Google Document AI等)
- 非常适合用于扫描工作流程或从图像PDF中稳健提取信息
- 提供详细的文档,非常适合处理复杂布局
ExtractThinker 让你根据需要选择 DocumentLoaderMarkItDown
或 DocumentLoaderDocling
—— 简单的数字 PDF 文件或多引擎 OCR 技术。
- 运行本地模型程序
尽管 Ollama 是一个流行的本地托管 LLM 工具,现在也有一些可以与 ExtractThinker 无缝集成的本地部署方案。
- LocalAI — 一个开源平台,可以在本地模仿OpenAI的API。它可以在消费级设备(甚至仅CPU)上运行语言模型(如Llama 2或Mistral),并提供一个简单的端点以进行对接。
- OpenLLM — 由BentoML开发的项目,通过一个与OpenAI兼容的API来暴露语言模型。它优化了吞吐量和低延迟,以提供高效的响应速度,适合在本地和云环境中使用,并支持广泛的开源语言模型。
- Llama.cpp — 运行Llama模型的底层实现,支持高级的自定义配置。非常适合需要细致控制或HPC环境,但管理起来相对复杂。
4: 应对小范围上下文Ollama 因为易于设置和简单的CLI而成为首选。然而,在企业或HPC场景下部署Llama.cpp服务器、使用OpenLLM解决方案,或使用LocalAI这样的解决方案可能更为合适。所有这些都可以通过将本地LLM端点指向代码中的环境变量或基础URL,轻松地与ExtractThinker集成。
策略流:原创作者
当处理具有有限的上下文窗口(例如不超过大约8K令牌)的本地的模型时,管理以下几点变得非常重要:
文档拆分为了避免模型输入容量超限,惰性分段 更为理想。而是选择分批次处理文档。
- 你逐页比较页面(例如,第1至第2页,然后是第2至第3页),判断它们是否属于同一个子文档。
- 如果属于同一个子文档,你将它们进入下一步。如果不属于同一个子文档,你将开始一个新的部分。
- 这种方法节省内存,并且通过每次只加载和分析少数几页即可扩展到非常大的PDF文档。
当您有更多的标记限制时,使用 Concatenate 更适合;当窗口大小受限时,更推荐使用 Paginate。注意哦,这是根据您的具体情况进行的建议。
应对部分回复对于较小的本地模型来说,如果提示较大,每个响应也可能被截断。PaginationHandler 优雅地解决了这个问题。
- 将文档的每一页分别作为单独的请求(每页一个请求)。
- 最后合并结果,如有必要,解决页面之间在某些字段上的分歧。
注意: 当您有更多可用的 token 时,建议使用 Concatenate;如果 token 数量有限,建议使用 Paginate。
快速示例- 懒惰拆分 PDF,确保每一页都保持在你模型的限制之下。
- 跨页处理:每个部分的结果分别返回。
- 合并每个部分的页面结果以形成最终的结构化结果。
这种方法确保你不会超出模型的上下文窗口——无论是处理 PDF 还是多页响应的方式。
5. ExtractThinker:构建我们的栈以下是一个展示如何将这些组件集成在一起的代码片段。首先,安装 ExtractThinker :
pip install extract-thinker
文档加载器(Document Loader)
正如上面提到的,我们可以用MarkitDown或Docling。
from extract_thinker import DocumentLoaderMarkItDown, DocumentLoaderDocling
# 文档加载器可以选择 DocumentLoaderDocling 或 DocumentLoaderMarkItDown 中的一种
document_loader = DocumentLoaderDocling()
关于定义合同
我们使用基于Pydantic的合约模型来指定数据结构。例如,发票和驾驶证:
from extract_thinker.models.contract import Contract
from pydantic import Field
class InvoiceContract(Contract):
invoice_number: str = Field(description="唯一的发票编号")
invoice_date: str = Field(description="发票日期")
total_amount: float = Field(description="总金额")
class DriverLicense(Contract):
name: str = Field(description="持照人全名")
age: int = Field(description="持照人年龄")
license_number: str = Field(description="驾照号码")
分类 (fēn lèi)
如果你有多种文件类型,定义分类项。你可以指定具体的分类标准。
- 每个分类的名称,例如“发票”。
- 描述内容。
- 对应的合同。
from extract_thinker import Classification
TEST_CLASSIFICATIONS = [
Classification(
name="发票",
description="这是一张发票单据",
contract=InvoiceContract
),
Classification(
name="驾驶证",
description="这是一张驾驶证单据",
contract=驾驶证
)
]
整合一切:本地提取流程
以下,我们创建一个Extractor,它使用我们选择的document_loader
工具和一个本地模型(如Ollama、LocalAI等)。接着我们构建一个Process,用于加载、分类、分割和提取内容,形成一个单一的流程。
import os
from dotenv import load_dotenv
from extract_thinker import (
Extractor,
Process,
Classification,
SplittingStrategy,
ImageSplitter,
TextSplitter
)
# 加载环境变量(如果你在 .env 文件中存储了 LLM 端点/API_BASE 等)
load_dotenv()
# 示例多页文档路径
MULTI_PAGE_DOC_PATH = "path/to/your/multi_page_doc.pdf"
def setup_local_process():
"""
辅助函数,用于使用本地 LLM 端点(例如 Ollama、LocalAI、OnPrem.LLM 等)设置 ExtractThinker 过程
"""
# 1) 创建一个 Extractor
extractor = Extractor()
# 2) 连接我们选择的 DocumentLoader(Docling 或 MarkItDown)
extractor.load_document_loader(document_loader)
# 3) 配置你的本地 LLM
# 对于 Ollama,你可以这样做:
os.environ["API_BASE"] = "http://localhost:11434" # 请替换为你的本地端点
extractor.load_llm("ollama/phi4") # 或 "ollama/llama3.3" 或你本地的模型
# 4) 将 Extractor 连接到每个分类
TEST_CLASSIFICATIONS[0].extractor = extractor
TEST_CLASSIFICATIONS[1].extractor = extractor
# 5) 构建 Process
process = Process()
process.load_document_loader(document_loader)
return process
def run_local_idp_workflow():
"""
使用本地 LLM 加载、分类、拆分和提取多页文档的示例
"""
# 初始化过程
process = setup_local_process()
# (可选) 你可以使用 ImageSplitter(model="ollama/moondream:v2") 进行拆分
process.load_splitter(TextSplitter(model="ollama/phi4"))
# 1) 加载文件
# 2) 使用 EAGER 策略拆分成子文档
# 3) 使用我们的 TEST_CLASSIFICATIONS 对每个子文档进行分类
# 4) 根据匹配的合同(发票或驾驶执照)提取字段
result = (
process
.load_file(MULTI_PAGE_DOC_PATH)
.split(TEST_CLASSIFICATIONS, strategy=SplittingStrategy.LAZY)
.extract(vision=False, completion_strategy=CompletionStrategy.PAGINATE)
)
# 'result' 是一个包含提取对象(InvoiceContract 或 DriverLicense)的列表
for item in result:
# 打印或存储每个提取的数据模型
if isinstance(item, InvoiceContract):
print("[提取的发票]")
print(f"编号: {item.invoice_number}")
print(f"日期: {item.invoice_date}")
print(f"总计: {item.total_amount}")
elif isinstance(item, DriverLicense):
print("[提取的驾驶执照]")
print(f"姓名: {item.name}, 年龄: {item.age}")
print(f"执照编号: {item.license_number}")
# 快速测试时,只需调用 run_local_idp_workflow() 函数即可
if __name__ == "__main__":
run_local_idp_workflow()
6. 隐私和PII:云中的大模型(LLM)
注:PII通常指的是个人可识别信息(Personally Identifiable Information,简称PII),在中文语境中,我们通常直接使用“个人可识别信息(PII)”来指代这一概念。
并不是每个组织都愿意或能够运行本地硬件。有些人更喜欢使用基于云的高级LLM。请记住:如果这样的话。
- 数据隐私风险:将敏感数据发送到云端可能会引发合规风险。
- GDPR/HIPAA:法规可能完全禁止数据离开您的公司。
- VPC + 防火墙:您可以在专用网络中隔离云端资源,但这会增加一些复杂性。
注意 : 许多大型语言模型的 API(例如 OpenAI)确实符合 GDPR 要求。但是,如果您受到严格监管或希望轻松更换提供商,您可以考虑使用本地或本地化云的方法。
PII 掩码
一个可靠的方法是构建一个 PII 掩码管道。工具如 Presidio 可以自动检测并遮蔽个人标识符,然后再发送给语言模型。这样,你可以保持模型的灵活性,同时确保符合法规。
图片由作者提供。
7. 最后。 结论。通过将ExtractThinker与本地LLM(如Ollama、LocalAI或OnPrem.LLM)和灵活的文档加载器(Docling或MarkItDown)结合使用,您可以从头开始构建一个安全、本地化的文档智能流程。如果监管要求需要完全隐私或尽量减少对外部的依赖,这样可以确保您的数据保留在内部,同时不损失现代LLM的强大功能。
共同学习,写下你的评论
评论加载中...
作者其他优质文章