4. 系统架构设计

金融研报与财报的RAG问答系统,难点不在“能不能调用大模型”,而在于如何把一份几十页、含大量表格与脚注的PDF,稳定地变成可检索、可追溯、可复现的知识资产。因此架构设计的核心思路是:把整条链路拆成职责单一的模块,每个模块有明确的输入输出契约,并允许独立替换与评测。下面按端到端数据流展开。

一、核心原理:分层解耦与契约驱动

整条链路可划分为六层:采集层、解析层、索引层、检索层、重排层、生成层。层与层之间只通过结构化数据交互,例如解析层输出统一的Document对象,索引层只认这个对象,不关心PDF来自哪里。这样做的好处是:更换PDF解析器不影响检索逻辑,更换向量模型不影响采集逻辑。

关键契约包括:解析层必须保留页码、章节标题、表格结构、来源文件四类元数据;检索层必须返回chunk_id与score;生成层必须能引用chunk_id回溯原文。没有元数据的RAG,在金融场景中几乎不可用,因为合规与投研都要求“答案可溯源”。

金融RAG端到端数据流与模块契约 采集层 PDF/HTML/公告 解析层 文本+表格+元数据 索引层 切分+向量化 检索层 向量+关键词召回 重排层 Cross-Encoder 生成层 LLM + 引用chunk_id 反馈与评测回流

二、方法流程:六个模块的输入输出

  1. 采集层:从交易所、公司IR页面、研报平台拉取PDF/HTML,记录source_url、publish_date、doc_type。建议用增量哈希去重,避免同一份财报重复入库。
  2. 解析层:将PDF转为结构化文本。表格必须单独抽取为Markdown或HTML,脚注与正文分离。输出统一Document对象。
  3. 索引层:按语义边界切分,金融文档建议按章节+表格行切分,而非固定512字符。切分后调用Embedding模型生成向量,写入向量库。
  4. 检索层:采用混合检索,向量召回负责语义相似,BM25负责财务术语与数字精确匹配。
  5. 重排层:用Cross-Encoder对Top-K结果精排,解决“向量召回把相似但不相关的段落排前”的问题。
  6. 生成层:将重排后的上下文注入Prompt,要求模型输出答案并标注引用编号。

关键参数建议:向量召回Top-20,重排后保留Top-5;chunk大小300~600中文字符,表格chunk可放宽到800;重叠窗口50~80字符,防止跨段语义断裂。

三、案例场景:一份年报的问答链路

用户提问:“宁德时代2023年研发费用同比变化多少?”系统执行:采集层定位到2023年年报PDF;解析层抽取“研发费用”表格行,保留页码与表名;索引层将该行与上下文切为一个chunk并向量化;检索层同时命中“研发费用”关键词与语义向量;重排层将含具体数字的表格行排到第一;生成层输出“同比增长约X%,见第Y页研发费用表”,并附chunk_id。

模块输入输出常见失败
采集URL/文件原始PDF重复入库、版本混淆
解析PDFDocument对象表格错行、脚注混入正文
索引Document向量+元数据切分过碎、丢失表头
检索QueryTop-K候选数字召回不准
重排候选集精排Top-N延迟高、显存不足
生成上下文+Query答案+引用幻觉、引用错位

四、误区与复盘

误区一:只做向量检索。金融问答中大量问题涉及精确数字与专有名词,纯向量检索容易把“营业收入”和“营业成本”混淆。必须加入BM25或关键词过滤。

误区二:解析层偷懒。把整页PDF直接丢给切分器,表格会被切成无意义的碎片。表格必须结构化抽取,并保留表头与单位。

误区三:忽略元数据。没有页码和来源的答案无法审计,投研与合规场景直接不可用。

复盘建议:为每个模块建立独立评测集。解析层看表格还原准确率,检索层看Recall@20,重排层看NDCG@5,生成层看引用正确率与幻觉率。只有分层评测,才能定位问题到底出在“没检索到”还是“检索到了但生成错了”。

# 典型配置片段(伪代码)
retriever:
  vector_top_k: 20
  bm25_top_k: 20
  fusion: rrf
reranker:
  model: bge-reranker-large
  top_n: 5
chunker:
  size: 500
  overlap: 60
  respect_section: true
  table_as_chunk: true

综上,端到端架构的价值在于把不确定性关进模块里:采集保证来源可信,解析保证结构可信,检索与重排保证召回可信,生成保证表达可信。每一层都可替换、可评测、可回滚,这才是金融RAG系统能够长期迭代的基础。