最近,利用大模型进行财务报表分析正逐渐成为垂直领域的一个热门应用。大模型能够比人类更准确地理解复杂的财务规则,并在基于专业知识的基础上输出合理的分析结果。然而,财务报表信息庞大且复杂,对数据分析的准确性要求极高,通用的RAG和Agent的解决方案往往难以满足这些需求。
以某公司的2022年财务报表为例,传统方法在处理类似“2022年XXX子公司的第三季度的营业净利润是多少?”的查询时,通常通过知识向量相似检索和匹配来召回最相关的文本块进行总结和问答。然而,财务年报中包含多处相关信息,如不同季度的利润表、现金流量表等,这些信息可能会引发误判。如果不能准确召回并理解正确部分,就容易生成错误答案。如果涉及到财务指标的计算,分析过程可能会变得更加复杂。例如,计算毛利率、净利率等指标需要对收入和成本等多方面的数据进行综合分析。
为了克服大模型应用中的这些挑战,我们需要结合财务领域的知识背景,添加专门的外部模块来增强其功能。本文将以DB-GPT的AWEL编排模式为例,借助DB-GPT-Hub的几个关键原子,详细阐述如何利用大模型进行有效的财报数据分析,希望能为在垂直领域的进行数据AI赋能的朋友提供一些思考。
目前我们的实现方式是通过上传公司年报,利用大模型作为知识驱动引擎,调用向量数据库、关系型数据库、OCR服务以及相关模型等组件,通过AWEL(agent流式编排)构建一个财报分析的问答助手,能够直接回答用户这几类问题:

这里的架构设计主要是通过意图分类解决财报分析中可能出现的问题。针对每类意图执行单独的处理链路,每条处理链路基于不同场景精心设计。同时为了保证数据分析的正确性,我们还会通过解析和抽取用户查询中的相关参数,调用工具或执行 SQL 查询,为分析结果提供更准确的数据支持。因此整个架构围绕 3 部分进行实现,金融知识构建,查询意图识别,以及金融知识检索。


在A股上市公司发布的财务报告中,通常会包含一些重要的文本描述、财务表格和其他附注信息。每个财务报表都提供了不同方面的财务数据,用来展示公司的财务状况、经营成果和现金流情况:

这些表格数据结构化程度高,需要提取出完整有用的数据信息进行加工处理。而财报文本部分则包含大量公司简介、业务描述、风险分析和管理层讨论等重要信息。我们希望大模型能够通过深入理解文本内容,提取对投资决策有帮助的信息,如公司未来的战略规划、市场风险和机遇等。
数据预处理,让杂乱数据结构化
针对财报pdf这样的非结构化数据处理,考虑到针对财报文档的一些特性,表格数据密集,专业术语繁多等情况,需要在信息抽取之前对pdf这样的非结构化数据进行预处理,主要的思路是将非结构化数据 —> 结构化数据,因此首先在数据读取和数据预处理模块,利用pdfplumber按页读取并转换为json格式,并且识别出哪些是需要的文本数据,哪些是表格数据,哪些是不需要的数据,比如页眉,页脚等等。

知识抽取,精准提炼文本和表格信息
数据预处理后,我们得到了标准的结构化的json数据,基于处理后的json数据,我们将内容划分为文本和表格两大块,针对这两块数据分别进行文本信息抽取和表格抽取。
文本抽取包括知识切片,元数据信息抽取,embedding等一系列子任务组成。
1.保持语义相关性,也就是上下文相关性,这直接关乎回复准确率。
2.保持在大模型的上下文限制内,分块保证输入到LLMs的文本不会超过其token limitations。这里有很多种分片策略进行选择:按照文本大小切分,按照页切分,按照标题进行切分。
本次案例为了保持语义的相关性,推荐采取按照页切分和按照标题级别进行切分:
1.按照页切分:

2.按照标题级别切分:
这里需要识别财报里面的标题信息,以标题层级构建chunk的树形节点,形成一个多叉树结构,每一层级节点只需要存储文档标题,叶子节点存储具体的文本内容。这样利用树的遍历算法,如果用户问题命中相关非叶子标题节点,就可以将相关的子节点数据进行召回。


●表格抽取:
我们的目标是对金融财报指标进行计算和分析,这里有两个难点:

1.合并成一张大宽表,由于不同公司的主要财报数据的表格定义都是相似的,因此可以针对财报数据的表格进行分类:

根据分类情况单独提取每一类别的表格信息进行合并,最后再将 3 类表格汇总成一张大宽表,生成最终的 DataFrame。
优点:
- 
由于都汇总成了一张表,避免了数据计算分析环节 nl2sql 过程中表召回困难,表召回错误的情况。 
- 
不同的公司的表格数据都汇总到了一起,可以对不同公司的数据进行比较分析。 
缺点:在表格提取和数据合并的过程中,存在一部分数据的丢失,导致有些信息的缺失。

2.合并成多张表数据,包括基本信息表,员工信息表,资产负债表,现金流表,其他信息表等等。

一、问题分类
目前我们提供了几种不同的意图识别方案,每种方案各有优缺,大家可以根据自己的资源和精度要求进行选择实现:
方案一、基于embedding(Bert)的识别
- 
利用BGE-v1.5对用户query和意图label进行向量化,使用逻辑回归等简单的机器学习模型进行学习分类就能获得很好效果。这种方案训练时间短、准确率高,但需要根据实际业务制作query意图数据集。 
- 
这个方案最重要的其实是选择一个高质量的embedding模型,文本数据的多样性和复杂性很高,直接处理原始文本往往效果不佳。大多数embedding模型是在大规模语料库上预训练的,它们已经捕捉了广泛的语言特征,embedding模型能够适应和理解不同的文本语义,将输入文本转化为标准化的稠密向量表示,提供了丰富的语言特征,从而使得逻辑回归等简单的分类器也能进行精确分类。 

方案二、大模型prompt的ICL能力
- 
通过在prompt中加入意图识别的样例和规则,引导大模型理解用户意图,生成期望输出。这种方案无需大量数据集和训练,但可能产生大量token消耗,且意图数量增加时准确率下降。 
- 
Prompt一般包含意图列表和相关示例,输出一般为具体的意图名称或对应的序号 
方案三、大模型SFT
- 
构建意图识别的指令微调数据集,输入为用户查询语句,输出为意图标签文本或json。这种方法是通过微调的方式,让大模型具备理解和学习意图的能力 
- 
开源大模型微调可以试试llama-factory或者DB-GPT-Hub 
方案四、在大模型上sequence标签监督微调
- 
针对特定意图识别任务,对大模型进行类似bert的序列分类微调。通过lora微调方式在小规模模型(如1.5b、7b)上实现最佳效果,同时可以切换adapter实现下游任务切换,提升推理速度和准确率,降低资源消耗。(DB-GPT-Hub/src/dbgpt-hub-nlu/dbgpt_hub_nlu/intent.py at nlu · eosphoros-ai/DB-GPT-Hub · GitHub) 
- 
在分类任务中,标签通常由高度集中的单词或短语组成,某些标签含义比较专业或模糊,在一些模棱两可的情况下会导致LLMs难以从字面上有效理解标签的语义。虽然Meta自LLaMA-1以来就提供了序列分类接口,但其实很少有用LLM直接用于标签分类的工作,因为从直觉上来看decoder的因果掩码避免了前向信息泄露,无法关注全局信息。但是大模型毕竟在参数量和学习的知识信息量级上要远超过往的BERT簇模型,神经网络的黑盒可能会带给我们意外的惊喜。 
- 
所以我们尝试用标签监督微调LLMs的方式去实现相关分类任务。在DB-GPT-hub中,我们用lora微调qwen-2-1.5B模型,我们直接从大模型输出的最后一层中提取潜在向量,本来这层最初是为自回归下一个token预测而设计的。现在我们将这些向量通过前馈层映射到标签空间中,产生用于判别标签分类的逻辑。从实验结果来看,模型输出的准确率和稳定性是最高的。 
还有的工作是在微调到时候将因果掩码去除了,因为因果掩码的存在会导致token级别表示的致命信息丢失,会限制双向信息流的交互,模型难以理解关键信息
(https://arxiv.org/pdf/2310.01208)
当标注数据语料匮乏时,可以应用大模型+sft+prompt工程模式辅助冷启动,积累一定标注语料后切BERT式微调方式,以提升任务精度。
二、槽位提取
处理用户查询时,需要识别query中的关键槽位(slot),并根据这些槽位在数据库中进行精准匹配。例如,用户查询“2023年Q1的净利润”时,系统需要识别时间(2023年Q1)和指标(净利润),据此查询数据库获取结果。我们具体也做了以下实现:
- 
大模型few-shot:通过few-shot学习,利用少量标注数据对大模型进行训练,使其能够在低资源条件下进行高效的信息抽取。 
- 
大模型SFT:需要构建槽位抽取的指令微调数据集,输入为用户查询语句,输出为json化的槽位标签及实体。这种方法是通过微调的方式,让大模型理解并输出格式化的槽位抽取结果 
- 
在大模型上进行token标签监督微调:针对具体的信息抽取任务,对大模型进行类似bert的token分类微调,使其能够准确识别出query中的各个槽位,并进行相应的数据库匹配。但是你需要创建或收集BIO标注格式的槽位分类数据集 
sentence = "请问你知道《Harry Potter and the Philosopher's Stone》的作者是谁吗?"[{'entity_group': 'book', 'score': 0.8257975, 'word': "Harry Potter and the Philosopher's Stone", 'start': 6, 'end': 47}]sentence = "近日,北京市市场监管局召集美团等互联网企业负责人,召开落实“长江禁捕打非断链”工作电商平台行政约谈会。"[{'entity_group': '约谈机构', 'score': 0.8824913, 'word': '北京市市场监管局', 'start': 3, 'end': 11}, {'entity_group': '公司名称', 'score': 0.9569145, 'word': '美团', 'start': 13, 'end': 15}]
- 
DB-GPT-Hub/src/dbgpt-hub-nlu/dbgpt_hub_nlu/ner.py at nlu · eosphoros-ai/DB-GPT-Hub · GitHub 
Text2SQL

- 
构建一个元数据字典,用来描述数据库的结构,包括表名、字段名及其类型、表之间的关系等,将其插入数据查询 prompt 
- 
将实体-关系(ER)图抽象成文本表示,例如 

- 
优化本地数据库结构,尽量减少复杂查询,将关键信息或常用数据放入一张大宽表中进行处理 
Query 查询预处理:
- 
对查询语句进行信息抽取,将关键实体与关系与 schema 信息匹配,然后链接映射到具体的数据库表中 
- 
可构建 query-sql_template 对进行分类训练,按照不同难度配比生成不同模板下的 SQL 语料集,用户输入 query,应输出对应的 sql 模板或相应集合,再尝试填充或直接放入 prompt 中。 
- 
针对复杂查询可以将其分解为几个简单查询逐步生成 SQL 语句 
SQL 优化
- 
在 prompt 中告诉模型使用索引和适当的查询优化策略,提升 SQL 查询性能,避免全表扫描等低效操作。 
- 
将生成的 SQL 查询在数据库上执行,并验证结果是否符合预期,不符合预期应反馈给用户或执行专门的复杂查询链路 
1.基础信息查询

2.财务指标计算
"毛利率": {"公式": "毛利率=(CAST(营业收入)-CAST(营业成本))/CAST(营业收入)", "数值": ["营业收入", "营业成本"]},"营业利润率": {"公式": "营业利润率=CAST(营业利润)/CAST(营业收入)", "数值": ["营业利润", "营业收入"]},"流动比率": {"公式": "流动比率=CAST(流动资产合计)/CAST(流动负债合计)", "数值": ["流动资产合计", "流动负债合计"]},"速动比率": {"公式": "速动比率=(CAST(流动资产合计)-CAST(存货))/CAST(流动负债合计)", "数值": ["流动资产合计", "存货", "流动负债合计"]},"资产负债比率": {"公式": "资产负债比率=CAST(负债合计)/CAST(资产总计)", "数值": ["负债合计", "资产总计"]},"现金比率": {"公式": "现金比率=CAST(货币资金)/CAST(流动负债合计)", "数值": ["货币资金", "流动负债合计"]},"非流动负债合计比率": {"公式": "非流动负债合计比率=CAST(非流动负债合计)/CAST(负债合计)", "数值": ["非流动负债合计", "负债合计"]},"流动负债合计比率": {"公式": "流动负债合计比率=流动负债合计/负债合计", "数值": ["流动负债合计", "负债合计"]},"净利润率": {"公式": "净利润率=CAST(净利润)/CAST(营业收入)", "数值": ["净利润", "营业收入"]}

3.信息统计分析
统计分析类别中,常常需要涉及分组(GROUP BY)和排序(ORDER BY), 因此,除了前面讲到的需要召回到具体查询的数据列以后,还需要召回统计维度和规则,是需要分组还是需要排序等等。

金融知识检索
通过对查询进行意图识别后,通过知识检索模块,根据用户的query精准的找到相关性比较高、有一定时效性、比较丰富的内容。目前分为四个阶段,query的改写,元数据过滤,多级召回以及相关性重排序。

查询改写
有了意图识别后,查询改写目的是将用户的query改写成语义更清晰、含义更丰富的一个可检索的Query。比如用户问贵州公司资产负债率是多少,但是实际数据库存的公司名称是贵州航天电器股份有限公司,因此需要对查询的主体进行补全改写,当然常用的改写手段还有查询纠错,使用大模型来进行改写等等。通过这一系列的处理,最终目的是把用户的Query从一个主体缺失,语义不明确、不完整、有歧义、有错的改写成一个正确的、语义表达清晰的,可召回的Query。

元数据过滤

多级召回

相关性重排序
与 Embedding 模型不同,重排序模型以查询和上下文作为输入,直接输出相似度分数,而不是 Embeddings。重要的是要注意,重新排序模型是使用交叉熵损失函数进行优化的,允许不限于特定范围的相关性分数,甚至可以是负的。目前,没有很多可用的重排模型。一种选择是 Cohere 提供的在线模型,可以通过 API 访问。还有一些开源模型,如 bge-reranker-base 和 bge-reranker-large 等。
应用实践
本章节会介绍怎么通过AWEL表达式语言实现金融财报答疑机器人应用。安装金融财报分析应用相关教程:
- 
v0.5.10 版本更新 · 语雀:https://www.yuque.com/eosphoros/dbgpt-docs/lyqq2r20wyvxu69g 
- 
相关代码:https://github.com/eosphoros-ai/dbgpts Agentic Workflow Expression Language(AWEL)是一套专为大型模型应用开发而设计的智能代理工作流表达语言。它提供了强大的功能和灵活性。通过AWEL,我们可以自定义财务分析的各个环节,从数据收集、清洗、解析到最终的报告生成,形成一个完整的自动化分析链路。在财务分析系统中,不同任务可由不同的AWEL workflow协同完成。例如,一个workflow负责财务报告的知识加工,另一个workflow负责投资评级。通过AWEL编排,让不同的agent可以协同工作,实现更复杂和全面的财务分析任务。 


财报智能问答 workflow





