让AI替我读文档
在我做过的每一份工作中,总会有文件。在第一次做数学家教的工作时,我们需要批改试卷。在第一次实习做软件工程师时,我们有保险文件。而现在,我看到了涵盖税收、保险和个人财务等数百个领域的文件。所有这些文件都有几十个字段,有些正确填写了,很多没有。我想找到一种方法将软件引入到我生活中这个枯燥的领域中,以创建一个更好的文档管理系统。
在过去的一年里,我相信很多人都使用过ChatGPT或Google来分析一张图片、一个文档或其他文本框以外的媒介。OpenAI和Google都拥有视觉工具,这些工具实现了某种形式的OCR并理解上传的内容。我希望通过精心设计的提示和自主实现来利用这一点,将这一过程提升到更高的水平。
在这个整个实现过程中,我将使用Python、Google Cloud Vision进行OCR、Cloud Firestore作为数据库,并使用OpenAI的Agents API。
这就是我想要从上传到提取再到存储或检索的流程:
用户上传 → OCR代理 → 概要代理
↓
元数据代理
↓
Firestore存储代理
↓
检索代理
与程序化流程或微服务不同,这种代理架构允许每个组件成为一个智能系统,可以推理、使用工具并返回结构化的输出,所有这些都由单个高级代理使用OpenAI的Agents API进行协调。
1、提取文件上传
首先,让我们创建一个分析文档本身的代理。该代理需要一个函数工具,使用Google Cloud Vision从上传中提取文本并获取内容。这是我的函数工具和代理实现:
function_tool
def extract_text_from_pdf_gcp(file_path: str):
client = vision.ImageAnnotatorClient()
with open(file_path, 'rb') as image_file:
content = image_file.read()
image = vision.Image(content=content)
response = client.document_text_detection(image=image)
return response.full_text_annotation.text
extract_text_agent = Agent(
name="OCR提取代理",
instructions="""
使用Google Cloud Vision OCR从PDF或基于图像的文件中提取原始文本。您将收到一个文件路径。
返回提取的原始文本。
""",
model="gpt-4o-mini",
tools=[extract_text_from_pdf_gcp]
)
由于指令的通用性和对Google Cloud Vision的使用,这两段代码能够处理我们给定的任何类型的上传。我们可以使它更具体到某种类型的文档,比如IRS文件、公司财报等财务文件等。但目前这样编写的话,我现在能够动态处理任何类型的上传,这给我们带来了灵活性。
2、将文档信息存储在Cloud Firestore中
我们已经从上一个代理中提取了内容,现在我们需要将其存储在某个地方。在这个实现中,我决定使用Cloud Firestore,因为它是一个简单且现成可用的NoSQL数据库,但我们也可以使用Amazon S3、Oracle或其他任何形式的存储。我们的代理应该获取完整的提取内容,并使用一个连接和存储/检索数据到Firestore的函数工具。这是我的实现:
@function_tool
def store_to_firestore(doc_id: str, summary: str, metadata: dict, full_text: str):
doc_ref = firestore_client.collection("documents").document(doc_id)
doc_ref.set({
"summary": summary,
"metadata": metadata,
"full_text": full_text
})
return {"status": "stored", "doc_id": doc_id}
storage_agent = Agent(
name="Firestore存储代理",
instructions="""
使用文档ID将摘要、元数据和完整文本存储到Firestore中。
""",
model="gpt-4o-mini",
tools=[store_to_firestore]
)
3、概要文档内容
对于许多情况,文档的概要是足够的,可以继续进行初步工作。因此,在上传后获得文档的概要将使我能够知道文档是什么、其中包含的关键信息以及如何在下游路由应用程序。为此,我们可以将完整的提取内容传递给代理,并允许其为我总结信息(见下文)。
summarization_agent = Agent(
name="概要代理",
instructions="""
接收长文档文本并清晰简洁地对其进行总结,以便一般理解。
包括关键部分、涉及的各方和文档的目的。
""",
model="gpt-4o-mini"
)
现在我们将知道文档的主要信息,这使我们能够创建规则引擎和基于键的逻辑。
4、从提取内容中获取关键元数据
大多数文档包含其他类型的文本,如说明、免责声明等,当我们分析文档内容时,我们并不一定关心或需要看到这些内容。为了避免这个问题,我们可以提取文档的元数据,这样我们就可以看到关键信息。大多数软件已经这样做,它们会提取PDF或CSV中的信息以匹配SQL列或某些关键词。我们的代理也可以选择元数据,并给我们所需的信息。
metadata_agent = Agent(
name="元数据提取代理",
instructions="""
分析法律或商业文档的文本并返回元数据,例如:
- 生效日期
- 涉及的各方
- 管辖范围(如果适用)
- 文档类型
- 关键词或标签
以结构化的JSON格式返回。
""",
model="gpt-4o-mini"
)
我可以根据需要更改指令以匹配文档中的任何内容。如果是税务文件,那么我可能需要额外的收入或基于位置的信息。如果是健康文件,也许我需要疫苗类型和结果。对于我们的用例,上述指令将为我们提供所需的一般信息,并清楚地描绘出它可以如何使用。
5、在Cloud Firestore中存储和检索文档信息
我们已经提取了内容、概要和元数据,现在我们需要将其存储在某个地方。在这个实现中,我决定使用Cloud Firestore,因为它是一个简单且现成可用的NoSQL数据库,但我们也可以使用Amazon S3、Oracle或其他任何形式的存储。我们的代理应该获取完整的提取内容,并使用一个连接和存储/检索数据到Firestore的函数工具。这是我的实现:
@function_tool
def store_to_firestore(doc_id: str, summary: str, metadata: dict, full_text: str):
doc_ref = firestore_client.collection("documents").document(doc_id)
doc_ref.set({
"summary": summary,
"metadata": metadata,
"full_text": full_text
})
return {"status": "stored", "doc_id": doc_id}
storage_agent = Agent(
name="Firestore存储代理",
instructions="""
使用文档ID将摘要、元数据和完整文本存储到Firestore中。
""",
model="gpt-4o-mini",
tools=[store_to_firestore]
)
@function_tool
def retrieve_documents_by_query(query: str):
docs = firestore_client.collection("documents").stream()
results = []
for doc in docs:
data = doc.to_dict()
combined_text = f"{data.get('summary', '')}\n{data.get('metadata', {})}\n{data.get('full_text', '')}"
if query.lower() in combined_text.lower():
results.append({
"doc_id": doc.id,
"summary": data.get("summary"),
"metadata": data.get("metadata")
})
return results
retrieval_agent = Agent(
name="文档检索代理",
instructions="""
您将收到自然语言查询,例如:
- “显示Acme Corp的NDA。”
- “我们上次供应商合同的有效日期是什么?”
在Firestore集合中搜索与意图匹配或包含相关信息的文档。
使用retrieve_documents_by_query函数检索匹配项,然后为用户提供总结的发现。
""",
model="gpt-4o-mini",
tools=[retrieve_documents_by_query]
)
当每个文档通过管道处理时,它会被保存到Firestore中,主要包含三个部分:完整的提取文本、概要和结构化的元数据。以下是一个典型的文档在Firestore文档集合中可能看起来的样子:
{
"doc_id": "contract_2023_09_01",
"summary": "这是Acme Corp和Beta LLC之间关于网络托管的服务协议,生效日期为2023年9月1日。",
"metadata": {
"effective_date": "2023-09-01",
"parties": ["Acme Corp", "Beta LLC"],
"document_type": "服务协议",
"keywords": ["网络托管", "SLA", "合同"]
},
"full_text": "本协议自2023年9月1日起由Acme Corp和Beta LLC签署……"
}
检索代理使用一个名为retrieve_documents_by_query的函数工具,该工具接受用户的自然语言查询并在摘要、元数据和全文字段中进行基本文本匹配。目前,它是作为一个简单的子字符串搜索实现的,所以询问“Acme NDA”将在文档内容中检查是否出现“acme nda”。
我们现在可以根据需要存储和检索文档摘要和元数据,而无需再次引用完整文档。
6、创建调度代理
所以现在,我们只需要用一个调度代理来包装这一切,该代理可以根据需要动态路由和流向不同的代理。我们的调度代理只需要有关其行为的说明、代理定义,其余的它会处理。
orchestrator_agent = Agent(
name="文档处理调度器",
instructions="""
您负责协调文档摄取流程:
1. 使用OCR提取文本。
2. 总结整个文档。
3. 提取元数据字段。
4. 在唯一的文档ID下将所有值存储到Firestore中。
确保保存:
- full_text
- summary
- metadata
每个工具必须按正确的顺序调用。
文档ID应从文件名或时间戳生成。
在所有步骤完成后返回最终的Firestore状态。
""",
model="gpt-4o-mini",
tools=[
extract_text_agent.as_tool("extract_text"),
summarization_agent.as_tool("summarize_doc"),
metadata_agent.as_tool("extract_metadata"),
storage_agent.as_tool("store_to_firestore")
]
)
调度代理消除了像Camunda这样的规则引擎或基于关键字的代码路由的需求。其他代理将返回其信息,调度代理将根据内容及其指令知道如何调用不同的代理。这使我能够有一个干净的代码库,使更新代码以满足未来业务需求变得更加容易。
在这个实现中,OpenAI的Agents API被用来协调多个专门的代理——每个代理都有特定领域的工具——形成一个连贯的文档摄取和检索管道。这种设计提供了可扩展性、模块化,并简化了跨行业(如保险、金融和医疗保健)文档密集型工作流的下游集成。
这个系统展示了代理工作流如何为文档密集型流程带来结构和智能。无论你处理的是合同、收据还是医疗表格,这种架构都能使摄取、分析和检索变得无缝,减少代码量,增加清晰度。我不再需要“快速查看PDF”。我只是让代理处理它。
原文链接:I Let AI Read My Documents, So I Don’t Have To
汇智网翻译整理,转载请标明出处