ccRAG:美国信用卡问答

覆盖 Chase、美国运通、美国银行共 54 张信用卡的中英双语问答系统。用中文或英文提问,得到一个简短的回答,回答里每个数字都标注出处:银行官网的产品页、持卡人协议、权益说明,或者带日期的博客文章。检索基于 LlamaIndex 和 Qdrant,回答由本地 9B 大模型生成,整个系统用家里的一块显卡对外提供服务。每个设计选择都由对比实验决定:比较规则在跑实验之前就定好,评测集逐题人工审核。

在线体验

私有仓库。如想了解代码,欢迎联系。


亮点

  • 检索是关键: 采用”小块检索、大块返回”(512 token 小块,2,048 token 大块),再加上按卡名过滤,测试集 Recall@5 从 0.62 提升到 0.93。卡名过滤靠一张人工审核的别名表,收录了中文俗称和 CSP、BCE 这类缩写。中文提问、但事实只在英文官网上的题目,Recall@5 从 0.34 提升到 0.97。
  • 不检索,模型基本没法用: 不给任何资料直接问,本地 Qwen3.5-9B 在 61 道测试题里答错 57 道(评委打分 0.10 / 2)。有了检索后得分 1.69 / 2,和 Claude Sonnet 相差不到 0.2,而且每次查询零成本。
  • 严谨的评测:
    • 122 道评测题,每题都有标准答案和逐字摘录的证据原文,逐题人工审核。
    • 所有选择都在开发集上做,测试集只在最后跑一次。
    • 比较规则在跑实验之前就定好,每组比较都给出配对 bootstrap 95% 置信区间。
  • 如实保留负面结果: 混合检索、交叉编码重排、官方资料优先排序、思考模式都试过,没有一个带来显著提升。重排让耗时增加 7–20 倍;思考模式下有 11/61 题回答为空。
  • 大模型评委与人工评分校准: Claude Opus 按 0–2 分标准盲评,和我本人的盲评一致性为二次加权 κ 0.63,分歧从不超过一档。
  • 真正对外运行: 经 Cloudflare Tunnel 对外提供服务,并做了加固:
    • 请求排队,并显示排在第几位
    • 按 IP 限流
    • 提示词注入防护,在 122 道评测题上零误拒
    • 访客和反馈日志,以及只有我能打开的统计页

工作原理

  1. 抓取与解析: 用无界面 Firefox 渲染银行产品页,包括隐藏的标签页和读屏文字;协议和权益说明 PDF 原样保存;再加上中英文博客文章。共 237 份文档,统一转为 Markdown。
  2. 建立索引: 按”小块检索、大块返回”切块,用多语言 BGE-M3 向量化后存入 Qdrant,共 2,961 个段落。
  3. 识别卡片: 别名表把”CSP”“蓝宝石”这类叫法对应到具体的卡,只在这些卡的资料里检索。名字有歧义时反问”你说的是哪一张”,不去猜。
  4. 带引用地作答: 最相关的 5 段资料连同标签(官方或博客、日期、语言)交给模型,提示词要求以官方数字为准。引用按出现顺序重新编号,只显示真正被引用的来源。

结果

测试集(61 题),所有选择在开发集上定好之后只跑一次
生成模型 评委打分(0–2) 闭卷(不检索) 每次查询成本
Claude Sonnet 5.5(API) 1.87 1.08 约 $0.03–0.04
Claude Haiku 4.5(API) 1.79 — 约 $0.01
Qwen3.5-9B(本地,上线) 1.69 0.10 $0
Gemma 4 12B(本地) 1.67 — $0
Granite 4.2 8B(本地) 1.34 — $0

本地模型主要输在”该信哪条资料”。遇到博客宣传其他渠道更高优惠的陷阱题,Qwen 得 0.6 / 2,Sonnet 得 2.0 / 2。


截图

卡包:把卡拖进提问栏(或双击卡面),只检索这张卡的资料
对比题回答,引用按出现顺序编号,下方只显示被引用的来源
"蓝宝石"对应两张卡,系统会反问,不去猜
英文界面:鼠标悬停在引用上,可以看到原文段落,对应数字会高亮

对外运行

  • 和开发版分开: 公开站只读发布出去的快照,包括网页、卡面和自己的一份索引副本。开发中的改动不会直接上线,也不会和实验抢向量库的锁。
  • 设置固定,处处有上限:
    • 只用一个模型,设置固定,浏览器传来的参数一律忽略
    • 问题最多 500 字,回答最多 800 token
    • 一次只回答一个问题,最多 6 人排队
    • 每个 IP 每分钟最多 6 题、每小时 60 题
    • 出错时浏览器只收到错误代码
  • 防提示词注入:
    • 公开站的提示词会拒绝和信用卡无关的请求,并忽略问题里夹带的指令。
    • 9 种攻击(扮演角色、索要系统提示词、写长文、重复灌水、违规请求)中 8 种直接被拒。
    • 第 9 种让模型在回答末尾加一个链接;现在服务器会删掉含有资料里没提到的网址的句子。
  • 不用登录也能统计访客:
    • 用浏览器匿名标识统计独立访客。
    • 访问、提问、回答和 👍/👎 写进本地日志。
    • 统计页只有我能打开。
  • 开机自启: 用 systemd 服务开机启动网站、隧道和统计页。不用在路由器上开端口,家里 IP 也不会暴露。

技术概览

   
检索 LlamaIndex、Qdrant、BGE-M3(稠密向量)、小块检索大块返回、基于别名表的按卡过滤
生成 Qwen3.5-9B(Ollama 本地运行);对比了 Gemma 4、Granite 4.2、Claude
评测 122 道人工审核题、配对 bootstrap、大模型盲评(κ 0.63)
后端 Python 3.12,服务器推送事件(SSE)流式输出
前端 React 19、TypeScript、Vite、Tailwind、shadcn/ui、Motion、dnd-kit
部署 Cloudflare Tunnel、systemd、一块 RTX 5070 Ti(16 GB)
语言 问题、界面和回答均支持中英文