AI代理驱动的财务文档处理管线
ztj100 2025-01-02 20:33 16 浏览 0 评论
SEC 10-K 报告等财务文件通常处理起来复杂而繁琐,但有了正确的工作流程,整个流程就可以改变。
我开发了一个集成 Phidata、n8n 和 Qdrant 的简化解决方案,以自动执行财务文件分析。此工作流程无缝处理报告,提取精确且结构化的见解,并将其存储在强大的矢量数据库 Qdrant 中,从而实现高级搜索和检索功能。结果是一种更快、更有效地处理财务数据的方式,使决策者可以访问和采取行动。
通过这种方法,管理大规模财务运营不仅变得更简单,而且更智能,利用人工智能和自动化来推动有影响力的结果。
1、架构
该架构集成了各种组件,以创建高效且简化的流程来处理 SEC 10-K 财务文件。它从本地文件触发器开始,该触发器监视本地系统上的指定目录以查找新的财务文件。一旦检测到文件,它就会启动工作流程。系统的核心是使用 phidata 设计的 Sec10k 代理,phidata 是一个定制的财务分析代理,由 Claude 3.5 Sonnet 模型提供支持。该代理专门用于分析财务文件并生成结构化的 JSON 输出,使用 PDF 分析工具和精确指令集的组合。该代理还配置了调试和流式传输功能,以确保可靠且动态的分析过程。
然后,处理后的数据流入 Qdrant Vector Store,这是一个强大的矢量数据库,用于存储和管理嵌入。这些嵌入由 Embedding Ollama 模块生成,该模块将提取的内容转换为适合高级搜索和检索的矢量化表示。为了确保文档得到有效处理,默认数据加载器负责文档的准备工作,确保它们满足后续操作的必要要求。内容通过递归字符文本分割器进一步细化,它将文本分解为可管理的块,同时保留其语义完整性。
2、测试文档
为了撰写本文,我考虑了一份 sec 10-Q 文档 ,你可以下载 pdf 进行实验。导入以下 JSON 文件以创建 n8n 工作流。
{
"name": "filechange2qdrant",
"nodes": [
{
"parameters": {
"mode": "insert",
"qdrantCollection": {
"__rl": true,
"value": "multi_document_agent",
"mode": "list",
"cachedResultName": "multi_document_agent"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreQdrant",
"typeVersion": 1,
"position": [
60,
-100
],
"id": "988b5468-8483-49db-832f-15d77333f391",
"name": "Qdrant Vector Store",
"credentials": {
"qdrantApi": {
"id": "jbqGna16O2L9iR8V",
"name": "QdrantApi account"
}
}
},
{
"parameters": {
"method": "POST",
"url": "https://f309-2401-4900-889d-f100-6539-35f9-5e06-1638.ngrok-free.app/api/v1/analyze",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "query",
"value": "analyse the financial statement and provide the final response as a structured JSON"
},
{
"name": "file_path",
"value": "={{ $json.path }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-160,
-100
],
"id": "1657cd1d-246f-4b28-975b-fcc5b1a6edfc",
"name": "sec10k agent"
},
{
"parameters": {
"triggerOn": "folder",
"path": "YOUR_DATA_PATH",
"events": [
"add"
],
"options": {
"usePolling": true
}
},
"type": "n8n-nodes-base.localFileTrigger",
"typeVersion": 1,
"position": [
-440,
-100
],
"id": "bd57a74a-4d96-4d86-97f2-b376505da7ad",
"name": "Local File Trigger"
},
{
"parameters": {
"jsonMode": "expressionData",
"jsonData": "={{ $('sec10k agent').item.json }}",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"typeVersion": 1,
"position": [
240,
100
],
"id": "e4e22dd9-cac9-4bcc-a893-d5339f99a49c",
"name": "Default Data Loader"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"typeVersion": 1,
"position": [
340,
260
],
"id": "bcbfa95e-a1c2-4144-8525-c7e43b231b3c",
"name": "Recursive Character Text Splitter"
},
{
"parameters": {
"model": "nomic-embed-text:latest"
},
"type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
"typeVersion": 1,
"position": [
100,
100
],
"id": "e634d2e6-c6ca-4e31-9dfd-f63d182731c5",
"name": "Embeddings Ollama",
"credentials": {
"ollamaApi": {
"id": "3fAFU0fFchwovvbD",
"name": "Ollama account"
}
}
}
],
"pinData": {},
"connections": {
"sec10k agent": {
"main": [
[
{
"node": "Qdrant Vector Store",
"type": "main",
"index": 0
}
]
]
},
"Local File Trigger": {
"main": [
[
{
"node": "sec10k agent",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Qdrant Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Recursive Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"Embeddings Ollama": {
"ai_embedding": [
[
{
"node": "Qdrant Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "e4f7ee4a-b657-46a5-b2ff-82b7cd6c3aad",
"meta": {
"instanceId": "e711fbe877d128d86a078d3ddcaeb0c456781dc70945c5f7c313501777f80a45"
},
"id": "FHzKIgnbgnbIcZu8",
"tags": []
}
3、代理实现
首先,项目脚手架如下:
├── api_server.py
├── data
│ └── 0001437749-24-035313.pdf
├── phidata
│ ├── __init__.py
│ ├── anthropic_utility.py
│ ├── financial_agent.py
│ └── financial_models.py
└── requirements.txt
requirements.txt 文件如下所示,该文件具有使用 fastapi 将代理公开为 API 的依赖模块。
phidata==2.7.5
anthropic==0.42.0
openai==1.58.1
python-dotenv==1.0.1
pypdf==5.0.1
fastapi==0.115.6
uvicorn==0.34.0
代理需要 Anthropic API 密钥才能与 Anthropic API 交互。在根文件夹中创建一个 .env 文件并将 API 密钥保存在那里。我的情况是,我同时尝试了 OpenAI 和 Anthropic,所以我两者都有。
OPENAI_API_KEY=sk-proj-****
ANTHROPIC_API_KEY=sk-ant-****
现在让我们从如何构建 Agentic 工具的提示开始。整个系统依赖于 2 个提示 system_prompt 和 user_prompt
def _create_user_prompt(self, file_type: str, page_count: int) -> str:
"""Create the user prompt for the financial analysis."""
return f"""I'm sending you a {file_type} document as {page_count} images. Please analyze all pages and extract the following financial metrics:
- EBIT
- EBITDA
- Net Income
- Revenue
- Currency
- Units: (Actuals | Thousands)
- Depreciation
- Amortization
- Filing Date
- Fiscal Year End
- Language
- Country
For each metric, please provide:
1. The exact value
2. Where it was found (coordinates/page numbers)
3. The relevant snippet of text
4. Your reasoning for the extraction
5. A confidence score
6. Whether the value was derived or directly extracted
7. Any calculations performed
8. Detect the language and country and populate the fields accordingly.
Please provide the output in valid JSON format matching the provided class structure. No other text is needed just the JSON is sufficient
"""
def _create_system_prompt(self) -> str:
"""Create the system prompt for the financial analysis."""
return """You are a specialized financial analyst with deep expertise in interpreting
corporate filings across multiple languages. Your strength lies in identifying, extracting, and
validating financial metrics like EBIT, EBITDA, Net Income, and other key performance indicators.
You have been trained to provide detailed documentation of your findings, including coordinate references
and contextual snippets. You are meticulous about explaining your reasoning and providing confidence scores
for each extraction. No other text is needed just the JSON is sufficient.
You MUST provide your analysis in the following JSON structure:
{
"company_name": str,
"filing_date": str,
"filing_type": str,
"currency": str,
"fiscal_year_end": str,
"language": str,
"country": str,
"unity": str
"metrics": [
{
"attribute": str,
"value": float,
"coordinates": str | null,
"snippet": str,
"reasoning": str,
"confidence_score": float,
"translation": str | null,
"is_derived": bool,
"calculation_details": {str: float} | null,
"unit": str
}
],
"confidence_summary": float
}
"""
现在,该工具将考虑上述提示,使用下面的pydantic模型制作更结构化的输出:
from pydantic import BaseModel
from typing import Optional, Dict, List
class FinancialMetric(BaseModel):
attribute: str
value: float
coordinates: Optional[str]
snippet: str
reasoning: str
confidence_score: float
translation: Optional[str]
is_derived: bool
calculation_details: Optional[Dict[str, float]]
unit: str
class FinancialAnalysis(BaseModel):
company_name: str
filing_date: str
filing_type: str
currency: str
country: str
language: str
unit: str
fiscal_year_end: str
metrics: List[FinancialMetric]
confidence_summary: float
实际调用anthropic的工具以及 pdf 上传,如下所示:
def analyze_financial_filing_pdf(self):
"""Analyze financial filings PDF file and return the financial analysis."""
try:
# Load and encode the PDF
with open(self.pdf_path, "rb") as f:
pdf_data = base64.b64encode(f.read()).decode("utf-8")
self.logger.info(f"{self.pdf_path} converted to base64")
reader = PdfReader(stream=self.pdf_path)
self.logger.info("creating the Anthropic message contract and calling API")
message = self.client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
system=self._create_system_prompt(),
messages=[
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": pdf_data
},
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": self._create_user_prompt("PDF", len(reader.pages))
}
]
}
],
)
try:
response_text = message.content[0].text
print(response_text)
response_dict = json.loads(response_text)
analysis = FinancialAnalysis(**response_dict)
self.logger.info(json.loads(analysis.model_dump_json(indent=2)))
return analysis.model_dump_json(indent=2)
except Exception as e:
self.logger.error(f"Error parsing response: {e}")
self.logger.info("Raw response:")
self.logger.info(message.content
raise
except Exception as e:
self.logger.error(f"Error analyzing PDF: {e}")
raise
现在让我们创建代理,使用上述工具正确分析财务文件(本例中为 sec-10Q)并生成指定的输出:
from phi.agent import Agent, RunResponse # noqa
from phi.model.anthropic import Claude
from phidata.anthropic_utility import FinancialAnalyzer
from phidata.financial_models import FinancialAnalysis
def init_financial_analyzer():
analyzer = FinancialAnalyzer()
return analyzer
def financial_agent(analyzer: FinancialAnalyzer):
# Agent that uses JSON mode
json_mode_agent = Agent(
model=Claude(id="claude-3-5-sonnet-20241022"),
name="financial Agent",
description="financial filings Analysis Agent",
response_model=FinancialAnalysis,
tools=[analyzer.analyze_financial_filing_pdf],
show_tool_calls=True,
tool_call_limit=5,
reasoning=False,
instructions=["Your task is to get the financial analysis in a specified json format"],
stream=True,
debug_mode=True,
structured_outputs=False
)
return json_mode_agent
来自代理的响应
上述过程确保代理生成的整个响应被矢量化并存储在 Qdrant 中。这种方法不仅便于高级搜索和检索,而且还支持使用 RAG 流式处理相似性分析等下游任务。将生成的内容集成到 Qdrant 的矢量数据库中,简化了组织、分析和检索上下文和相关信息的过程。
4、结束语
本文介绍的架构和工作流程展示了将人工智能、自动化和矢量化相结合用于财务文档处理的变革潜力。通过无缝集成 Phidata、n8n 和 Qdrant 等工具,该系统不仅简化了复杂文件(如 SEC 10-K 报告)的分析,而且还确保提取的数据结构化、存储并准备好进行高级检索。
该工作流程是朝着更智能、更高效的财务运营迈出的一步,使组织能够精确轻松地做出数据驱动的决策。随着财务数据的复杂性和数量不断增长,这样的解决方案为未来管理此类信息变得更快、可扩展且高度可访问铺平了道路。
原文链接:财务文档的AI处理管线 - 汇智网
相关推荐
- Java网络编程(JAVA网络编程技术)
-
网络编程三要素1.IP地址:表示设备在网络中的地址,是网络中设备的唯一标识2.端口号:应用程序在设备中唯一的标识3.协议:连接和数据在网络中传输的规则。InetAddress类Java中也有一个...
- 字节Java全能手册火了!多线程/网络/性能调优/框架啥都有
-
前言在这个技术不断更新的年代,跟不上时代变化的速度就会被刷掉,特别是咱们程序员这一群体,技术不断更新的同时也要同时进步,不然长江后浪推前浪,前浪......一个程序员从一个什么都不懂的小白在学到有一定...
- 一分钟了解java网络编程(java基础网络编程)
-
一、OSI七层网络模型应用层:Http协议、电子邮件传输、文件服务器等;表示层:数据转换,解决不同系统的兼容问题(跨语言);会话层:建立与应用程序的会话连接;传输层:提供了端口号和传输协议(TPC/U...
- Java编程-高并发情况下接口性能优化实践-提升吞吐量TPS
-
记得前段时间工作中接到一个任务是优化一个下单接口的性能提高接口的吞吐量TPS,前期通过arthas工具跟踪接口的具体方法调用链路及耗时,发现了影响此接口的性能瓶颈主要是加锁的方式,后来变更了锁的方式...
- socket 断线重连和心跳机制如何实现?
-
一、socket概念1.套接字(socket)是网络通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,...
- 迅速了解-Java网络编程(java基础网络编程)
-
Java网络编程在JavaSE阶段,我们学习了I/O流,既然I/O流如此强大,那么能否跨越不同的主机进行I/O操作呢?这就要提到Java的网络编程了。...
- Java网络编程详解(java 网络编程)
-
网络编程基础知识最!最!最!重要网络编程基础概念网络编程不等于网站编程,网络编程即使用套接字(socket)来达到各进程间的通信,现在一般称为TCP/IP编程;网络编程分为服务端和客户端。服务端就相当...
- 「开源推荐」高性能网络通信框架 HP-Socket v5.7.2
-
简介HP-Socket是一套通用的高性能TCP/UDP/HTTP通信框架,包含服务端组件、客户端组件和Agent组件,广泛适用于各种不同应用场景的TCP/UDP/HTTP通信系统,提供C/...
- Java网络编程从入门到精通:打造属于你的网络世界
-
Java网络编程从入门到精通:打造属于你的网络世界在当今这个信息爆炸的时代,网络编程已经成为程序员必不可少的一项技能。而Java作为一种功能强大且广泛使用的编程语言,在网络编程领域也有着举足轻重的地位...
- 5分钟读懂C#中TcpClient、TcpListener和Socket三个类的角色
-
一、核心功能与定位1.Socket类:底层通信的基石-位于System.Net.Sockets命名空间,提供对网络协议栈的直接操作,支持TCP、UDP等多种协议。-手动管理连接细节:需...
- (三)谈谈 IO 模型(Socket 编程篇)
-
快过年啦,估计很多朋友已在摸鱼的路上。而我为了兄弟们年后的追逐,却在苦苦寻觅、规划,导致文章更新晚了些,各位猿粉谅解。上期分享,我们结合新春送祝福的场景,通过一坨坨的代码让BIO、NIO编程过程呈...
- 大数据编程入门:Java网络编程(大数据 编程)
-
如果想要编写出一个可以运行在多个设备上的程序,应该怎么做呢?答案是网络编程,今天小编将为大家带来大数据编程入门:Java网络编程。一、网络编程概念网络编程是指编写在通过网络连接的多个设备(计算机)上运...
- 基于JAVA的社交聊天室(java聊天设计与实现)
-
基于Java的社交聊天室一、前言随着互联网技术的迅速发展,实时通信和在线社交已成为人们日常生活的重要组成部分。基于Java的社交聊天室系统,凭借其跨平台、高性能和安全性等特点,为用户提供了一个集中、开...
- java-socket长连接demo体验(java socket长连接)
-
作者:DavidDing来源:https://zhuanlan.zhihu.com/p/56135195一、前言最近公司在预研设备app端与服务端的交互方案,主要方案有:服务端和app端通过阿里i...
- JAVA数据库编程(java数据库编程指南)
-
预计更新###第一节:什么是JAVA-JAVA的背景和历史-JAVA的特点和应用领域-如何安装和配置JAVA开发环境###第二节:JAVA基础语法-JAVA的基本数据类型和变量-运算符和...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)