Skip to content

Repository files navigation

FinanceBench 财报 RAG 问答与生成质量评估

这是一个可审计、可重复运行的 FinanceBench 复现项目,覆盖:

  • 公开 150 条财报问题与 84 份配套 PDF;
  • PDF 完整性校验、逐页文本提取和按页切分;
  • BGE-small 本地向量化与 FAISS 索引;
  • 输入问题、指定财报检索、生成答案和页码引用;
  • 切分长度、重叠长度、Top K 参数对比;
  • Ragas 四项指标接口;
  • 金额、百分比、年份的抽取、答案核对和上下文支持检查;
  • CSV、JSONL、Markdown 对比报告与典型错误案例。

当前复现状态

本工作区已经完成可离线运行的全量基线:

项目 结果
公开问题 150
公司 32
所需财报 PDF 84/84
提取页数 12,013
非空页数 11,948
人工证据项 189
证据页越界/空页 0/0
全量参数记录 450
自动化测试 33 passed

主实验采用:

  • Embedding:BAAI/bge-small-en-v1.5,FastEmbed/ONNX 本地推理;
  • Vector store:FAISS IndexFlatIP,对 L2 归一化向量执行精确余弦检索;
  • Generator:离线抽取式基线 question-overlap-v1
  • LLM 生成接口:OpenAI-compatible Chat Completions,当前百炼配置使用 qwen3.7-plus
  • Ragas:Context Precision、Context Recall、Answer Relevancy、Faithfulness。

当前已接入阿里云百炼北京地域默认业务空间,并设置 API 模型硬白名单。已完成 qwen3.7-plus 生成、qwen3.7-max Ragas 评审的 30 条配对记录(每组参数 10 题),四项 Ragas 指标 30/30 完整;全量离线检索实验仍为每组 150 题、共 450 条。

本项目只允许调用以下免费额度模型;不在列表内的模型会在发送请求前被本地代码拒绝:

  • qwen3.7-flash-2026-07-15
  • qwen3.7-max-2026-05-17
  • qwen3.7-max-2026-06-08
  • qwen3.7-max-preview
  • qwen3.7-plus
  • qwen3.7-max
  • glm-5.2
  • kimi-k2.7-code
  • qwen3.7-max-2026-05-20
  • qwen3.5-ocr

1. 固定 Python 环境

所有命令均使用指定环境:

$py = 'D:\anaconda3\envs\GL\python.exe'
& $py -m pip --use-deprecated=legacy-certs install --no-build-isolation -e '.[all]'
& $py -m pytest -q

API 凭据可以只在当前 PowerShell 会话设置,也可以由你手动写入项目根目录的 .env(该文件已被 .gitignore 排除,项目不会创建或提交它):

OPENAI_API_KEY=替换为你的密钥
# 仅 OpenAI-compatible 第三方服务需要下一行
OPENAI_BASE_URL=https://服务商地址/v1
# 服务商文档要求额外请求头时使用;没有要求则删除
OPENAI_EXTRA_HEADERS_JSON={"x-foo":"true"}
# 百炼 Qwen3.7 等混合思考模型用于普通 RAG 时建议关闭思考
OPENAI_CHAT_EXTRA_BODY_JSON={"enable_thinking":false}

CLI 和网页启动时都会读取 .env;如果当前进程已经显式设置同名环境变量,则进程变量优先,便于启动脚本临时切换监听模式。不要把真实 key 写入 YAML、源码或命令历史。

阿里云百炼导出的 API CSV 可用以下命令安全转换为 .env;脚本只输出地址和密钥长度,不回显密钥:

& $py scripts/configure_bailian_from_csv.py `
  'D:\edge下载\默认业务空间-apiKey-6292544.csv'

当前 .env 还设置了 FINANCEBENCH_ALLOWED_API_MODELS。任何不在免费额度清单内的模型都会在发送 API 请求前被拒绝,防止误用付费模型。

后续免费模型清单发生变化时,手动修改项目根目录 .env 中这一行即可;多个模型使用英文逗号分隔,不要加入引号:

FINANCEBENCH_ALLOWED_API_MODELS=qwen3.7-flash-2026-07-15,qwen3.7-plus,qwen3.7-max

网页下拉框会读取该白名单。若还希望控制模型在下拉框中的显示顺序,可同步修改 src/financebench_web/service.py 中的 preferred_order 列表。修改后需要重启 Flask 服务。

本机 Windows 证书存储在 pip 安装时出现过 ASN.1 读取异常,因此使用 --use-deprecated=legacy-certs。这只改变 pip 的证书加载方式。

Flask 网页版

网页版使用 Flask + 原生 HTML/CSS/JavaScript,直接复用现有 BGE、FAISS、生成器、模型白名单和实验结果。运行:

Set-Location 'D:\user-19185\financebench'
& 'D:\anaconda3\envs\GL\python.exe' -m pip --use-deprecated=legacy-certs install --no-build-isolation -e .
& 'D:\anaconda3\envs\GL\python.exe' app.py

推荐直接运行启动脚本。脚本默认使用 Waitress 监听全部 IPv4 网卡,并自动打印本机和局域网访问地址:

powershell -ExecutionPolicy Bypass -File .\start_web.ps1

例如脚本显示 LAN URL: http://192.168.1.20:5000 后,同一局域网中的设备可以使用该地址访问。只允许本机访问时运行:

powershell -ExecutionPolicy Bypass -File .\start_web.ps1 -Mode local

端口和 Waitress 工作线程也可以调整:

powershell -ExecutionPolicy Bypass -File .\start_web.ps1 `
  -Mode lan -Port 8080 -Threads 4

也可以复制 .env.example.env,手动设置:

FINANCEBENCH_WEB_HOST=0.0.0.0
FINANCEBENCH_WEB_PORT=5000
FINANCEBENCH_WEB_THREADS=4

其中 0.0.0.0 表示监听所有 IPv4 网卡,但它不是浏览器访问地址;浏览器应使用启动脚本打印的实际局域网 IP。Windows 首次监听时如出现防火墙提示,只应允许可信的专用网络。

页面包含:

  • 84 份财报选择与 FinanceBench 示例问题;
  • 三组切分/重叠/Top K 检索配置和可调 Top K;
  • 百炼白名单模型生成与离线抽取模式;
  • 生成答案、token 用量、响应时间和可点击 PDF 页码;
  • 检索段落、相似度、FinanceBench 标准答案和金融数值核对;
  • 全量检索结果与 Ragas 子集结果切换。

网页问答默认使用增强检索:在原始 BGE/FAISS 相似度之外,对财务行项目执行词法重排,识别经营现金流、流动负债等概念,并拼接命中页的表头与相邻块。这样可以避免只检索到财务报表页首、却漏掉同页合计行。原有全量实验仍保留纯向量检索口径,确保历史结果可复现。

金融数字评测额外支持 0.661.25x 等无单位比率,也可以把回答中的带币种金额与财报表格中的无币种数字核对。标准答案没有可识别数字时,网页显示 N/A,不再误显示为 100% 召回。

接口包括 GET /healthGET /api/bootstrapGET /api/questionsPOST /api/ask 和受文档白名单保护的 PDF 路由。启动脚本默认使用 Waitress 开启局域网模式,API key 不会下发到浏览器;-Mode local 可恢复仅本机访问。局域网模式不等于公网部署,公网使用时仍需反向代理、HTTPS、身份认证和限流。

首次问答会载入本地 BGE 模型和索引,通常比后续请求稍慢。

2. 数据下载与审计

仓库已包含官方公开问题与文档元数据:

  • data/financebench_open_source.jsonl
  • data/financebench_document_information.jsonl

执行:

$py = 'D:\anaconda3\envs\GL\python.exe'
& $py -m financebench_rag.cli audit
& $py -m financebench_rag.cli download --workers 2
& $py -m financebench_rag.cli extract
& $py -m financebench_rag.cli audit-extraction

下载器会:

  1. 依次尝试 GitHub Raw、jsDelivr 和文档元数据中的原始财报链接;
  2. 使用 2 MiB HTTP Range 分段,断流时只重试当前分段;
  3. 核对远端长度、%PDF- 文件头和 %%EOF
  4. 完整下载后原子替换目标文件;
  5. artifacts/dataset_manifest.json 保存字节数、来源 URL 和 SHA-256。

文本提取使用 PyMuPDF sort=True。缓存元数据绑定 PDF SHA-256 和提取器版本,PDF 改变后会自动重新提取,避免复用截断文件生成的旧文本。

3. 构建索引

构建推荐的 1000/100 配置:

& $py -m financebench_rag.cli build-index `
  --output-dir artifacts/indices/chunk1000_overlap100_top5 `
  --chunk-size 1000 `
  --chunk-overlap 100

索引同时包含:

  • 全局 FAISS 索引,供未知文档时检索;
  • 84 个财报分片,供 FinanceBench 已知 doc_name 的严格文档内检索;
  • chunks.jsonlvectors.npyindex_meta.json 和分片映射。

如果目标目录存在不同配置,命令会拒绝覆盖。确认需要重建时添加 --force

4. 单题问答与引用

完全离线:

& $py -m financebench_rag.cli ask `
  --index-dir artifacts/indices/chunk1000_overlap100_top5 `
  --doc-name 3M_2018_10K `
  --question 'What was 3M revenue in 2018?' `
  --top-k 5 `
  --generator-provider extractive

百炼 OpenAI-compatible Chat Completions 生成:

& $py -m financebench_rag.cli ask `
  --index-dir artifacts/indices/chunk1000_overlap100_top5 `
  --doc-name 3M_2018_10K `
  --question 'What was 3M revenue in 2018?' `
  --top-k 5 `
  --generator-provider openai_chat `
  --generator-model qwen3.7-plus

当前实验固定使用百炼兼容接口与上述白名单,不调用其他服务或模型。openai_chat 使用 Chat Completions API。

返回结果包含 answersources。内部证据页码使用 FinanceBench 的零基编号,对用户显示的引用为一基页码,例如 [3M_2018_10K p.60]

5. 参数网格实验

configs/experiment_grid.yaml 定义三组实验:

配置 切分长度(字符) 重叠(字符) Top K 块数
chunk500_overlap50_top3 500 50 3 104,410
chunk1000_overlap100_top5 1000 100 5 51,290
chunk1500_overlap200_top8 1500 200 8 35,993

冒烟测试:

& $py -m financebench_rag.cli experiment `
  --question-limit 5 `
  --generator-provider extractive `
  --output-dir artifacts/experiments/smoke

全量离线基线:

& $py -m financebench_rag.cli experiment `
  --generator-provider extractive `
  --output-dir artifacts/experiments/main

API 生成实验建议写入新目录,避免与抽取式基线混淆:

& $py -m financebench_rag.cli experiment `
  --question-limit 10 `
  --generator-provider openai_chat `
  --generator-model qwen3.7-plus `
  --output-dir artifacts/experiments/bailian_qwen3_7_plus_n10

实验按题写入 results.partial.jsonl,支持断点续跑;全部完成后自动生成:

  • results.jsonl / results.csv:450 条逐题检索、回答、引用和指标;
  • summary.json / summary.csv:三组参数均值;
  • error_cases.jsonl / error_cases.csv:每组最多 8 条典型错误;
  • experiment_report.md:中文汇总与错误分析。

不要在完整索引已存在时随意添加 --force-indices,否则会重新执行耗时的全量 BGE 编码。

6. 当前参数对比结果

配置 证据页命中率 证据页 MRR 证据词项召回 金融数值 F1 数值上下文支持率
500/50/Top-3 0.4400 0.3500 0.3839 0.0934 0.9305
1000/100/Top-5 0.5667 0.4157 0.6253 0.1067 0.9855
1500/200/Top-8 0.5933 0.3640 0.7529 0.0970 0.9937

结论:

  • 1500/200/Top-8 的证据覆盖最好,但 MRR 低于 1000/100/Top-5,说明增加 Top K 能找回更多证据,却不保证正确证据排得更靠前;
  • 1000/100/Top-5 在证据页 MRR 与离线答案数值 F1 上最好,是当前较均衡的默认配置;
  • 抽取式基线的数值上下文支持率很高,但数值 F1 很低。它经常“忠实地引用错误段落”,所以支持率不能替代答案正确性。

7. Ragas 评测

当前已完成的配对样本评测:

& $py -m financebench_rag.cli ragas-eval `
  --results artifacts/experiments/bailian_qwen3_7_plus_n10/results.jsonl `
  --output-dir artifacts/experiments/bailian_qwen3_7_plus_n10_ragas_final `
  --evaluator-model qwen3.7-max `
  --embedding-provider fastembed `
  --embedding-model BAAI/bge-small-en-v1.5 `
  --limit 30 `
  --concurrency 1 `
  --evaluator-max-tokens 8192

Ragas 支持断点续评:已存在的指标不会再次请求,只补齐值为 null 的指标。--limit 30 会在三组配置间轮询抽取,而不是只评第一组。

API 子集结果如下;每组仅 10 题,不应外推成 150 题全量生成结论:

配置 证据页命中 Context Precision Context Recall Answer Relevancy Faithfulness 金融数值 F1
500/50/Top-3 0.2000 0.1000 0.1000 0.0994 1.0000 0.1000
1000/100/Top-5 0.3000 0.1000 0.1500 0.1816 1.0000 0.1500
1500/200/Top-8 0.4000 0.1079 0.4167 0.5067 0.7479 0.0525

这里由 qwen3.7-max 完成 LLM-as-a-judge,本地 BGE 只为 Answer Relevancy 提供向量,不运行本地生成模型,也不要求百炼提供 embeddings 接口。评测器逐指标保存错误;错误文本会在写盘前移除 API key 和 Bearer token。API key 只从被 Git 忽略的 .env 读取,源码和报告不保存凭据。

8. 金融数字准确性

financial_metrics.py 分别抽取:

  • 金额:支持 $US$USD 以及 thousand/million/billion/trillion;
  • 百分比:支持 %percentpercentage point(s)
  • 年份:支持 1900–2099。

金额统一换算到基础货币单位,括号金额视为负数;金额容差为 max(1 美元, 0.01%),百分比容差为 0.01 个百分点,年份要求精确一致。

主要指标:

  • financial_numeric_precision/recall/f1:生成答案相对标准答案的数字匹配;
  • financial_amount_f1financial_percentage_f1financial_year_f1:分类型结果;
  • financial_context_support_rate:生成数字能否在检索上下文中找到;
  • unsupported_response_facts:上下文不支持的生成数字;
  • missing_reference_facts:标准答案中漏答的数字。

9. 已知限制

  • 字符切分确保跨模型可复现,但不是 tokenizer 感知切分;
  • 财报复杂表格可能出现列顺序变化,证据页词项平均覆盖率为 97.73%,最低个案为 58.77%;
  • 当前向量检索不含 BM25、reranker 或表格专用解析器;
  • 当前全量答案来自抽取式基线,不代表 API 大模型生成质量;
  • Ragas 属于 LLM-as-a-judge,结果受评审模型版本影响,正式报告应记录模型名和评测日期。

10. 数据与工具来源

使用 FinanceBench 数据发表结果时,请按其官方仓库 README 引用原论文并遵守数据许可。

11. 许可证

  • 本项目自行编写的源代码采用 MIT License
  • data/ 下的 FinanceBench 公开样本不属于本项目原创内容,适用 CC BY-NC 4.0 及原始数据集要求;
  • 财报 PDF、模型缓存、向量索引、运行日志和 API 凭据均不会提交到仓库。

About

FinanceBench financial-report RAG with FAISS, Flask, Ragas, and financial numeric accuracy evaluation

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages