微信扫码
添加专属顾问
今天介绍一个项目案例,利用大语言模型打造上市公司财务报表智能问答系统。
在当今竞争激烈的市场环境中,企业和投资者对财务信息的获取与分析要求越来越高。上市公司财务报表作为评估公司财务健康和未来发展的重要依据,提供了大量关键信息。
然而,传统的财务报表分析技术不成熟、依赖很多人工解读,费时且容易出现误差,痛点如下。
随着大数据技术和人工智能的快速发展,如何高效、准确地从这些海量数据中提取有价值的信息成为了一个亟待解决的问题。
智能问答系统为解决这一问题提供了创新解决方案。通过先进的自然语言处理技术,智能问答系统可以快速解读财务报表,自动回答涉及财务、市场趋势和投资策略的问题,如下图所示。
构建一个上市公司财务报表智能问答系统,需要通过如下核心步骤:
数据收集:利用爬虫技术从财经网站上抓取上市公司的季度、半年、年度财报,这些财报通常以PDF格式存储。
数据处理:将非结构化的PDF内容转换为结构化数据。这通常是一个难点,后面会详细展开处理和分析。
RAG系统搭建:构建基于RAG(检索增强生成)的智能问答系统。首先,将处理后的数据导入向量数据库中,并利用双编码器模型进行向量化处理。然后,集成大语言模型(如GPT-4)与检索系统,通过提示工程和重排序技术优化模型的输出,以提高对财报内容的理解和回答质量。
问答系统,基于RAG实现,其流程如下图所示。
下面,就通过具体代码案例来搭建上市公司财务报表智能问答系统。
一、数据收集
通过使用爬虫技术,用selenium库来做模拟批量下载公司的财报,具体过程如下:
第一步:引入相关的包。
#包含控制浏览器的类和方法from selenium import webdriver#用于执行复杂鼠标和键盘操作的类from selenium.webdriver.common.action_chains import ActionChains#用于添加延时或暂停import time#用于等待特定条件发生后再继续执行from selenium.webdriver.support.ui import WebDriverWait#定义用于等待的条件from selenium.webdriver.support import expected_conditions as EC#定义一组用于选择元素的方法from selenium.webdriver.common.by import By
第二步:写了一个用于判断可供选择的链接是年报还是年报摘要的函数。因为研究中需要的是年报,就把后文调用函数用到的关键词定为了“摘要”。
#定义一个check_world函数def check_word(sentence, word):if word in sentence:#如果关键词word在文本中,返回true,否则返回falsereturn Trueelse:return False
第三步:接下来就是用于自动化测试的函数啦!在这里,定义了一个download_report函数,当调用函数时,输入股票代码code,函数将会执行自动测试操作并下载网页。
def download_report(code): # 启动Edge浏览器并加载选项browser = webdriver.Edge()url = 'http://www.cninfo.com.cn/new/commonUrl?url=disclosure/list/notice#sse'browser.get(url)browser.maximize_window()#输入时间#注:这段有没有都无所谓()因为我发现就算写了他也不会给我执行这段操作,但是因为网站的自动检索年报的范围就是我需要的范围,所以没差()browser.find_element_by_xpath('//*[@id="main"]/div[2]/div[1]/div[2]/div[1]/div[2]/form/div[1]/div/div/input[1]').send_keys('2022-12-31')browser.find_element_by_xpath('//*[@id="main"]/div[2]/div[1]/div[2]/div[1]/div[2]/form/div[1]/div/div/input[2]').send_keys('2022-06-15')#browser.find_element_by_xpath("//body").click()#browser.find_element_by_xpath("//body").click() #输入年报,将检索范围锁定在年报中#第一段用于点击分类按钮browser.find_element_by_xpath('//*[@id="main"]/div[2]/div[1]/div[2]/div[1]/div[2]/form/div[2]/div[3]/div/div/span/button').click()#第二段用于点击年报选项browser.find_element_by_xpath('/html/body/div[6]/div[1]/label[1]/span[1]/span').click()#输入代码#第一段用于点击输入框browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div[2]/div[1]/div[2]/form/div[2]/div[1]/div/div/div/div/input').send_keys(code)#这一段用于暂停页面操作,等待等待元素加载完成后继续执行操作(我设置的是三秒)time.sleep(3)#这一段用于点击搜索按钮,使用了更为稳健的模拟鼠标操作button_element = browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div[2]/div[1]/div[2]/div[1]/button')actions = ActionChains(browser)actions.move_to_element(button_element).click().perform()# 等待页面元素加载完成time.sleep(3) #进入公告#写了一个try,因为有时候可能对应的代码没有公司try:#调用check_word函数,判断要进入具体页面的报告是摘要还是年报word = "摘要"#获取页面中第二个xpath对应的text内容(如600000号股票就会返回“上海浦东发展银行股份有限公司2022年年度报告(全文)”)browser_text = browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div[3]/table/tbody/tr[2]/td[3]/div/span/a').text #如果是摘要,返回true,执行第一个xpath#注:有的页面可能有三个按钮,但是前两个按钮中一个有一个是年报或者年报修订版(确信)if check_word(browser_text, word):browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div[3]/table/tbody/tr[1]/td[3]/div/span/a').click() #上一步操作后会打开一个新的页面,我们要获取新页面的url用于下载,将browser变更为新页面window_handles = browser.window_handleslatest_window_handle = window_handles[-1]browser.switch_to.window(latest_window_handle) #当不含有摘要,返回false,点击第二个xpathelse:browser.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[1]/div[1]/div[2]/div/div[3]/table/tbody/tr[2]/td[3]/div/span/a').click()window_handles = browser.window_handleslatest_window_handle = window_handles[-1]browser.switch_to.window(latest_window_handle) #获取网页urlbrowser_url = browser.current_url #当所属公司code无法搜索出年报,那么这家公司可能是退市了,输出没有找到年报except Exception as e:print("没有找到",code,"的对应年报")browser.quit()#跳出方法return#这一段用于检测code有没有对应的公司,如果没有公司,那么点击搜索按钮只会停留在原来的页面上。这时执行上文获取的url就会下载错误的年报。#这里我用了暴力的解决方法,直接查看原有页面的前两个xpath具体页面的url内容,然后ban掉他们!这里在使用的时候一定要记得检查当日的前两位urlif browser_url == "http://www.cninfo.com.cn/new/disclosure/detail?stockCode=688669&announcementId=1217087254&orgId=gfbj0833817&announcementTime=2023-06-17" or browser_url == "http://www.cninfo.com.cn/new/disclosure/detail?stockCode=603825&announcementId=1217085098&orgId=9900024448&announcementTime=2023-06-17":print("没有",code,"对应的公司")browser.quit()else: browser2 = webdriver.Edge()browser2.get(browser_url)#进入url的页面,点击下载按钮,下载年报。其中,如果网不好+文件大的情况,就需要将time.sleep(10)的参数调大,不然下不完,网站就关了browser2.find_element_by_xpath('/html/body/div[1]/div/div[1]/div[3]/div[1]/button').click()time.sleep(10)print("已成功下载",code,"公司的年报") #关闭网站,防止资源浪费browser.quit()browser2.quit()第四步:调用download_report方法开始下载。
# 贵州茅台code = "600519"download_report(code)
二、数据处理
数据处理的目的是将PDF文件解析成结构化的数据,以便为后续的RAG系统做好准备。此过程包括提取和整理文本中的关键信息,如财务数据、表格和图表,从而确保数据的结构化格式能够支持高效的检索和生成操作。
一、文档解析的准确性对RAG系统的影响
在RAG的预处理阶段,文档解析的准确性至关重要,因为任何解析上的误差都会直接影响后续的检索和生成结果,进而影响整个系统的性能。以下是文档解析不准确可能带来的具体问题及其影响:
信息丢失:如果解析不准确,财务报表中的关键信息可能会丢失或被误解,这会导致模型无法正确回答用户的查询。
数据错误:解析错误可能会导致财务数据的错位或误读,从而影响生成的回答的准确性和可靠性。
检索效率降低:结构化数据的准确性直接影响到检索的效果。如果数据结构不一致或不准确,将会增加检索难度,降低检索效率。
模型性能下降:文档解析的不准确性可能导致模型在训练和推理阶段的性能下降,使得生成的答案不够精准或有偏差。
因此,对于面向消费者的文档问答RAG系统应用产品,精准的文档解析显得尤为重要。这不仅保证了数据的完整性和准确性,还能显著提高系统的整体性能和用户体验。精准解析确保了关键信息的正确提取和结构化,进而提升了检索的效率和生成的回答的质量。
二、PDF文档解析的技术路线
对于简单的文档解析,Python提供了很多PDF解析工具,如PDFplumber、pyPDF2或简单的开源的ocr工具(如:Paddleocr)等能够对多种文件类型进行解析。下图是一个标准的文档解析流程。
然而,对于更复杂的文档解析,尤其是涉及大量图表、复杂表格或非标准格式的财务报表时,单一的开源工具可能难以满足需求。
这种情况下,选择商用的高性能工具就显得尤为重要。这些工具通常具备更强的功能、更高的准确性和更好的技术支持,能够有效处理复杂的文档结构和数据格式。
在我们的项目中,使用了一款商业文档解析服务TextIn,工作台如下图所示,上传了一份贵州茅台2023年的年报。
TextIn解析PDF,具有以下优势:
高级图像处理能力:对文档进行区域划分,通过使用边界框bounding box定位其中的关键区域,如文字、标题、表格、图片等。这样能够准确识别和提取图表中的数。
复杂表格解析:支持对复杂、多层级的表格进行精确解析。
定制化支持:提供对特定格式或行业文档的定制化处理。
技术支持和维护:提供专业的技术支持和持续的维护服务,确保系统的稳定性和性能。
下图是我们通过测试得到的性能指标。通过对比发现,整体的速度、召回率、正确率都比较高,非常适合我们的业务场景。
此外,在批量解析PDF的场景中,TextIn还提供了各种编程语言的API接口,如下图所示。
在使用API调用接口的时候,需要先获取对应的app_id 和 secret_code,获取方式,在账号管理-开发者信息中,如下图所示。
这样就可以调用TextIn的API服务将PDF的年报解析成结构化的数据。
这里我提供一个Python的调用示例,帮助你快速调用。
import requestsclass CommonOcr(object):def __init__(self, img_path):# 请登录后前往 “工作台-账号设置-开发者信息” 查看 x-ti-app-id 和 x-ti-secret-codeself._app_id = '0c88509xxxx'self._secret_code = '3017d8ccxxxx'self._img_path = img_pathdef get_file_content(self):with open(self._img_path, 'rb') as fp:return fp.read()def recognize(self):# 通用文档解析url = 'https://api.textin.com/ai/service/v1/pdf_to_markdown'head = {}try:image = self.get_file_content()head['x-ti-app-id'] = self._app_idhead['x-ti-secret-code'] = self._secret_coderesult = requests.post(url, data=image, headers=head)return result.textexcept Exception as e:return eif __name__ == "__main__":file_path = r'PDF测试文档.pdf'response = CommonOcr(file_path)output = response.recognize()print(output)
三、RAG系统搭建
通过前面文章教你实现ChatPDF:从零到一的完整指南!,已经了解到构建RAG的过程。
文档上传和处理:用户首先上传PDF文档,系统将对文档进行解析和处理,包括文本抽取和结构识别。
集成语言模型:使用先进的语言模型对提取的文本进行嵌入,建立文档内容的向量表示。
嵌入模型选择标准:如何高效选择RAG的中文Embedding模型?揭秘最佳实践与关键标准!
自然语言查询:用户可以通过自然语言输入查询问题,系统将通过模型检索相关信息,并生成回答。
反馈与优化:系统根据用户的反馈不断优化文档处理和查询模型,提高回答的准确性和相关性。
下面使用 Langchain和FAISS向量数据库,快速构建一个财报问答库。
import requestsimport jsonimport timefrom langchain.vectorstores import FAISSfrom langchain_core.documents import Documentfrom langchain.text_splitter import CharacterTextSplitterfrom langchain.embeddings import HuggingFaceEmbeddingsdef get_all_docs(input):if isinstance(input, str):result = json.loads(input)result = result.get('result', {})markdown = result.get('markdown')metadata = {"source": file_path}documents = [(Document(page_content=markdown, metadata=metadata))]return documentsif __name__ == "__main__":file_path = r'2023年度贵州茅台财务报告.pdf'response = CommonOcr(file_path)output = response.recognize()documents = get_all_docs(output)# print(documents)text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=2048)texts = text_splitter.split_documents(documents)local_model_name = 'shibing624_text2vec-base-chinese'embeddings = HuggingFaceEmbeddings(model_name=local_model_name)db = FAISS.from_documents(texts, embeddings)faiss_index = "vectors_db/hln_tb_faiss_index"db.save_local(faiss_index)# db = FAISS.load_local(faiss_index, embeddings)while True:question = input("请输入问题: ").replace(" ", "")if question == "stop":breakstart_time = time.time()docs = db.similarity_search(question, k=10)print(docs)for doc in docs:print(doc)print(f"本次回答共耗时:{time.time() - start_time}")
RAG问答库的优化,包括对数据的深度处理、表格处理,以及对重新排序(rerank)优化的关注。
通过搭建该系统不仅提升了财务信息的处理效率,也显著提高了数据分析的准确性,为企业决策者和投资者提供了强有力的支持。
TextIn文档解析产品目前正火热进行内测阶段,并向用户提供海量免费额度体验。
海量额度:特别为每位用户准备了每周高达7000页的免费解析额度。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-07-01
提升 RAG 准确率全攻略 让你的 AI 知识库 真正靠谱起来!
2026-06-30
教程:如何用AutoRAG + Milvus避免RAG 与Agent 中出现串租问题
2026-06-30
知识库不是文件堆——我把RAG准确率从60%调到了92%
2026-06-30
本体论语义建设新思路,另类RAG来解决检索问题
2026-06-30
别把RAG当架构:Ontology(本体)才是Agent的业务世界
2026-06-29
PixelRAG:伯克利团队颠覆传统 RAG,用截图代替文本检索! 28 天狂揽 3000+ Star!
2026-06-29
腾讯WeKnora开源详解(三):检索引擎与生态集成
2026-06-29
腾讯开源WeKnora详解(二):知识库与对话核心能力
2026-04-06
2026-04-27
2026-04-23
2026-04-20
2026-04-09
2026-04-12
2026-04-22
2026-04-10
2026-05-14
2026-04-30
2026-06-23
2026-06-23
2026-06-15
2026-06-10
2026-06-10
2026-05-20
2026-05-18
2026-05-11
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。