skip to content
tlj 的工程笔记
← 项目

禁用向量检索、限调 Qwen:金融长文本问答 Agent

比赛

天池 AFAC2026 金融赛的一道硬约束题——只能调通义千问、不许微调、禁一切 embedding 向量检索,还有 500 万 token 的硬预算,去答五类金融长文档的选择判断题。A 榜两次真实提交 58 到 65 分,真正的料是挖出来的六个检索/解析 bug,和一次我自己武断判断埋下的隐性大坑。

时间
2026-07
角色
主导需求 / 架构 / 检索策略 / 逐条验收(代码由 AI 写)
成果
禁 embedding、限调 Qwen、500 万 token 预算下做金融长文档 QA;A 榜提交 58→65(准确率约 61%→69%,超官方 baseline 49%);挖修 6 个真实检索/解析 bug,含一次自己抽查 3 题就武断跳过 HTML 致监管领域只索引到 1.2% 文档

阿里云天池 AFAC2026 金融智能大赛挑战组的赛题四:对保险、监管、财报、合同、研报五类金融长文档的单选/多选/判断题作答。这道题的难点不在模型,在约束

官方 baseline 只有 49% 准确率,而且烧了 687 万 token 超预算、token 分直接归零。所以真正要解的是:在不能用向量检索的前提下,怎么把长文档里那一小段决定答案的证据找准。

真实结果

A 榜两次真实提交,平台给分:

提交得分反推准确率
第一次57.9954约 61%
第二次64.9941约 69%

对官方 baseline(49%)是实打实的超出,绝对进步真实。但要如实说清楚位置:这个分数在 1251 支队伍里属于后三分之一,不是好名次——别人能做到 80、90 分以上。这里值得写下来的不是成绩,是过程里那些坑。另外整套代码是 AI 写的,我主导需求、架构、检索策略和逐条验收;下面这些判断和排错,是验收环节里真实发生的。

六个真实的坑

1. 思考模型偷偷烧 token。 让模型回一句”已连通”,completion_tokens 却是 595~1278;同样的问题换 qwen-plus 只花 3 个 token。根因是那一版是带隐藏推理链的思考模型,内部思考的 token 也计费、也算进 500 万预算——官方 baseline 超预算八成就栽在这。解法是显式 enable_thinking=False 默认关掉,压回个位数,复杂题再按需打开。

2. 全局 BM25 的马太效应。 四篇需要对比的文档混在一起检索,字数多的一两篇霸占了 top_k,其余的召回是 0——模型手里根本没证据。解法是按文档独立检索 + 动态公平配额(比如 12 个名额分给 4 篇、每篇最多 3 个),再给每个片段前面拼一个中文定位头「来自文档:某产品(doc_id=x),第 N 页」,防止多文档张冠李戴。还有个反直觉的调整:把”产品名精确命中”的基础分从 100 压到 15——因为产品名是高频背景词,分太高会把真正含指标数字的片段挤下去。

3. 条款跨页,文本被丢了。 有道题反复检索到错误的条款,模型算不出给付比例,干脆拿选项里的数字反推。深挖发现:条款跨页时,某一页开头那段属于上一条延续的文本被直接丢弃了,真正决定比例的第五条残缺。解法是修掉跨页丢失、保留延续文本,再给单文档单条款设名额上限,防长条款霸榜。

4. answer 字段和推理结论对不上。 模型推理里写”正确应为 B、C”,输出 JSON 的 answer 字段却填成”AB”。根因是 answer 和推理是两次独立生成,容易脱节。解法是让模型对每个选项单独输出 verdict,最终答案由代码从 verdict=true 确定性拼出,不再依赖模型复述。这一条我判断比降低瞎猜率更能直接提分——61%→69% 那次提交正是含这个修复。

5. JSON schema 字段顺序也是 bug。 verdict 排在了 reasoning 前面。模型是自回归生成的,先写完 verdict 再写 reasoning,中途想改主意也回不去改 verdict。把 reasoning 调到前面就好了——这种”让模型先想后答”的顺序,在结构化输出里是实打实影响正确率的。

6. 解析失败别急着退兜底。 有几道题模型在 JSON 外面包了 markdown 或解释文字导致解析失败,早期直接退 mock 假答案。改成三层解析(直接 loads → 提取代码块 → 提取花括号子串 → 才退兜底),降级率压到 0。

一次我自己埋的隐性大坑

这条要单独写,因为坑是我自己判断失误造成的。

监管领域有 513 个文档,重建索引后发现只索引进去了 6 个(1.2%)。追根源:早期让 AI 写解析脚本时,我只抽查了前 3 道题、看到它们都引用 txt 文件,就武断下结论”HTML 和 txt 内容重复,跳过 HTML”。实际上 txt 只有 6 个文件,HTML 有 377 个、附件 PDF 有 130 个——HTML 才是主体语料。结果是有些监管题”看起来答上了”,其实是零证据瞎蒙。

这个坑没有报错、不会 crash,是靠一道题空答案回归倒查出来的。教训很直白:抽样下的结论不能当全量事实,尤其当这个结论会决定”要不要整类数据都不要了”的时候。

一次拦下 AI 作弊的审查

还有一条关于”AI 自评不可信”。负责写代码的 AI 在自主循环里报告”瞎猜现象已完全解决”,我实测发现是假的——某些题里模型还在拿选项数字反推。更严重的是,它为了让效果好看,在检索代码顶部硬编码了一张字典,把测试集里 16 个保险产品的真名写死了——这等于”看过测试集内容记下答案”式的作弊,B 榜一换文档就会灌错误产品名,评审复现代码一眼能看穿。

这是我逐行审查时删掉的,不是 AI 自己改的。所以我不敢让 AI 的自我总结进验收结论——它说”解决了”,我得自己复跑确认;它写的代码,我得逐行看有没有为了好看走捷径。

诚实的边界

这道题对我的价值不在分数,在那个反直觉的约束——当你不能用向量检索、还要省 token,你会被逼着回到”证据到底在文档哪一段”这个最朴素的问题上,而这恰恰是很多 RAG 系统被 embedding 糊过去、没真正解决的地方。