这是一个可审计、可重复运行的 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-15qwen3.7-max-2026-05-17qwen3.7-max-2026-06-08qwen3.7-max-previewqwen3.7-plusqwen3.7-maxglm-5.2kimi-k2.7-codeqwen3.7-max-2026-05-20qwen3.5-ocr
所有命令均使用指定环境:
$py = 'D:\anaconda3\envs\GL\python.exe'
& $py -m pip --use-deprecated=legacy-certs install --no-build-isolation -e '.[all]'
& $py -m pytest -qAPI 凭据可以只在当前 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 + 原生 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.66、1.25x 等无单位比率,也可以把回答中的带币种金额与财报表格中的无币种数字核对。标准答案没有可识别数字时,网页显示 N/A,不再误显示为 100% 召回。
接口包括 GET /health、GET /api/bootstrap、GET /api/questions、POST /api/ask 和受文档白名单保护的 PDF 路由。启动脚本默认使用 Waitress 开启局域网模式,API key 不会下发到浏览器;-Mode local 可恢复仅本机访问。局域网模式不等于公网部署,公网使用时仍需反向代理、HTTPS、身份认证和限流。
首次问答会载入本地 BGE 模型和索引,通常比后续请求稍慢。
仓库已包含官方公开问题与文档元数据:
data/financebench_open_source.jsonldata/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下载器会:
- 依次尝试 GitHub Raw、jsDelivr 和文档元数据中的原始财报链接;
- 使用 2 MiB HTTP Range 分段,断流时只重试当前分段;
- 核对远端长度、
%PDF-文件头和%%EOF; - 完整下载后原子替换目标文件;
- 在
artifacts/dataset_manifest.json保存字节数、来源 URL 和 SHA-256。
文本提取使用 PyMuPDF sort=True。缓存元数据绑定 PDF SHA-256 和提取器版本,PDF 改变后会自动重新提取,避免复用截断文件生成的旧文本。
构建推荐的 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.jsonl、vectors.npy、index_meta.json和分片映射。
如果目标目录存在不同配置,命令会拒绝覆盖。确认需要重建时添加 --force。
完全离线:
& $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。
返回结果包含 answer 和 sources。内部证据页码使用 FinanceBench 的零基编号,对用户显示的引用为一基页码,例如 [3M_2018_10K p.60]。
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/mainAPI 生成实验建议写入新目录,避免与抽取式基线混淆:
& $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 编码。
| 配置 | 证据页命中率 | 证据页 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 很低。它经常“忠实地引用错误段落”,所以支持率不能替代答案正确性。
当前已完成的配对样本评测:
& $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 8192Ragas 支持断点续评:已存在的指标不会再次请求,只补齐值为 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 读取,源码和报告不保存凭据。
financial_metrics.py 分别抽取:
- 金额:支持
$、US$、USD以及 thousand/million/billion/trillion; - 百分比:支持
%、percent、percentage point(s); - 年份:支持 1900–2099。
金额统一换算到基础货币单位,括号金额视为负数;金额容差为 max(1 美元, 0.01%),百分比容差为 0.01 个百分点,年份要求精确一致。
主要指标:
financial_numeric_precision/recall/f1:生成答案相对标准答案的数字匹配;financial_amount_f1、financial_percentage_f1、financial_year_f1:分类型结果;financial_context_support_rate:生成数字能否在检索上下文中找到;unsupported_response_facts:上下文不支持的生成数字;missing_reference_facts:标准答案中漏答的数字。
- 字符切分确保跨模型可复现,但不是 tokenizer 感知切分;
- 财报复杂表格可能出现列顺序变化,证据页词项平均覆盖率为 97.73%,最低个案为 58.77%;
- 当前向量检索不含 BM25、reranker 或表格专用解析器;
- 当前全量答案来自抽取式基线,不代表 API 大模型生成质量;
- Ragas 属于 LLM-as-a-judge,结果受评审模型版本影响,正式报告应记录模型名和评测日期。
使用 FinanceBench 数据发表结果时,请按其官方仓库 README 引用原论文并遵守数据许可。
- 本项目自行编写的源代码采用 MIT License;
data/下的 FinanceBench 公开样本不属于本项目原创内容,适用 CC BY-NC 4.0 及原始数据集要求;- 财报 PDF、模型缓存、向量索引、运行日志和 API 凭据均不会提交到仓库。