让AI替我读文档

在我做过的每一份工作中,总会有文件。我想找到一种方法将软件引入到我生活中这个枯燥的领域中,以创建一个更好的文档管理系统。

让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

汇智网翻译整理,转载请标明出处