📋 题目描述
题目描述
NS-2026-02 图书馆问答员:带引用的 RAG 知识库问答
赛题任务
本题编号为 NS-2026-02。
题目定位
本题定位为 探索型 / benchmark 型 RAG 题。
不承诺赛前公开边界下存在 exact 800 / 800 的标准满分路线。榜单高分代表方案在当前隐藏参考集上的综合质量更高,而不是证明已经找到唯一标准解。赛后获奖审核会结合自动分数、方案复现、引用可解释性、AI 使用边界和 Writeup 证据进行确认。
任务介绍
你是一名图书馆问答员,需要根据本地知识库回答问题,并给出支撑答案的文档片段编号。知识库包含校园制度、实验室安全手册、社团章程、课程说明、设备借用规则等改写或合成文档。
你的任务是:
- 从本地知识库中检索与问题相关的片段。
- 输出简短、准确、可归一化的答案。
- 同时返回支持答案的
chunk_id列表。 - 对知识库无法回答的问题输出规定拒答文本。
本题高分来自检索命中、引用可验证、多跳拆解和拒答,不鼓励模型脱离知识库自由编答案。为避免题目退化为闭源 API 调用比赛,本题要求最终方案基于本地可运行的开源模型、传统检索算法或规则系统实现,并对可使用的开源模型规模设置上限。
最终提交不得由闭源 API、商业 Agent、远程托管 embedding/rerank 服务或人工标注平台生成。选手可以完全使用 BM25、TF-IDF、规则抽取和轻量 rerank 完成,也可以使用参数量受限的开源本地模型辅助生成。获奖候选队伍必须提交可复现证据,证明最终答案由符合规则的本地流程产生。
赛题背景
RAG 系统的核心不是单纯生成流畅回答,而是将回答约束在可验证知识来源之内。真实知识库问答需要处理多跳查询、否定条件、冲突条款、无法回答问题和文档中的干扰指令。
本题考察混合检索、rerank、引用校验、拒答阈值、JSON 输出修复和受限开源模型条件下的工程取舍。一个可行方案可以完全不使用生成式大模型,例如 BM25/TF-IDF 检索、关键词规则、轻量 cross-encoder rerank、模板化答案抽取和拒答阈值;也可以使用符合参数限制的开源本地模型辅助生成,但必须保证答案能被引用片段支撑。
本题是探索型 benchmark,参赛目标是尽可能提升受限开源本地流程的稳定性和可解释性。
赛题数据
在本页下方“相关资源”处下载数据包,或在 https://modelscope.cn/datasets/SteamedFresh/NS-2026-A-data 处获取。
NS-2026-02/├── corpus.jsonl├── train_qa.jsonl├── test_questions.jsonl├── schema.json├── example_submission/│ └── results.json└── tools/ ├── check_format.py └── eval_public.py数据说明
corpus.jsonl 每行字段:
| 字段 | 类型 | 含义 |
|---|---|---|
doc_id | string | 文档 ID |
chunk_id | string | 片段 ID,唯一 |
title | string | 文档标题 |
text | string | 片段正文 |
train_qa.jsonl 每行字段:
| 字段 | 类型 | 含义 |
|---|---|---|
id | string | 问题 ID |
question | string | 问题 |
answer | string | 标准答案 |
citations | list[string] | 支撑片段 ID |
answerable | bool | 是否可回答 |
test_questions.jsonl 不含答案和引用。测试问题包含事实查询、条件查询、多跳组合、否定条件、冲突条款、无法回答和文档中 prompt injection 干扰。
正式数据规模
| 文件 | 规模 |
|---|---|
corpus.jsonl | 90 个知识片段 |
train_qa.jsonl | 468 个带答案训练问题 |
test_questions.jsonl | 332 个测试问题 |
测试问题不提供答案。题型包括普通事实题、条件题、否定题、多跳题、冲突版本题、列表题和无法回答题。其中无法回答题必须输出 无法根据给定知识库回答,且引用列表应为空。
本题要求选手基于公开 corpus.jsonl 进行检索、组合和抽取。训练问答可用于理解答案格式和验证方法,但不应假设测试问题都能通过复用训练问答答案或固定字段模板解决。
推荐解题方式
本题不保证公开数据中已经直接包含每个隐藏问题的同问法训练样例。探索型 benchmark 的重点是利用公开语料和训练问答归纳检索、抽取、拒答和引用校验策略。
模型规模限制
最终生成提交所用模型必须满足以下限制:
| 模型类型 | 允许范围 |
|---|---|
| 稀疏检索、规则系统、字符串匹配 | 不限制 |
| embedding 模型 | 必须为开源权重,单模型参数量不超过 1B |
| reranker / cross-encoder | 必须为开源权重,单模型参数量不超过 1B |
| 生成式语言模型 | 必须为开源权重,单模型标称参数量不超过 4B |
| LoRA / adapter / finetune | 允许,但 base model 必须满足对应参数上限 |
量化不会改变参数量认定。MoE 模型按总参数量认定,不按 active parameters 认定。最终推理流程不得调用超过上述限制的教师模型、闭源模型或远程托管模型来生成测试答案、引用或拒答判断。
如果最终流程包含多个模型,总体要求如下:
- 最多使用 1 个生成式语言模型参与最终测试集答案生成。
- 最多使用 1 个 embedding 模型和 1 个 reranker / cross-encoder 参与最终检索排序。
- 不允许通过多个大模型投票、链式自洽、多模型辩论或大规模 ensemble 扩大有效算力。
- 允许使用不含可学习参数的规则、词典、BM25、TF-IDF、正则表达式、字符串匹配、数值归一化和 JSON 修复器。
注意事项
- 所有答案必须来自本地知识库。
- 禁止使用知识库之外的外部答案源回填。
- 引用必须与答案相关,伪造引用会被扣分。
- 获奖候选队伍必须能够在断网环境或只允许下载已声明开源权重的环境中复现最终
results.json。
评测说明
提交说明
提交文件必须压缩为:
NS-2026-02-answer.zip压缩包内必须只包含:
results.json提交格式
[ { "id": "q001", "answer": "需要提前三天提交申请。", "citations": ["doc12_003", "doc12_004"] }]格式要求:
- 顶层必须为数组。
- 每个测试问题必须出现一次。
answer必须为字符串,不得为空。citations必须为字符串数组,最多保留前 5 个。
得分计算
隐藏评测输出 raw score,总分 800:
| 项目 | 分值 |
|---|---|
| 答案准确性 | 400 |
| 引用命中率 | 250 |
| 无法回答识别 | 100 |
| 格式合法性 | 50 |
答案准确性使用归一化精确匹配和字符级 F1,并对少量等价答案设置别名。引用命中率按 gold chunk 的 Recall@K 计算,多引用题最多按前 2 个关键引用归一化。无法回答题建议统一输出 无法根据给定知识库回答,并保持 citations 为空。
分数含义
本题是探索型 / benchmark 型题目。800 是隐藏参考集和评分器定义出的 raw score 上限,用于校验评分器自洽和比较方案质量;组委会不承诺赛前公开边界下存在 exact 800 / 800 或 exact full score 路线。
自动榜分数主要反映以下能力:
- 能否从本地
corpus.jsonl检索到正确支撑片段。 - 能否输出简短、可归一化、由引用支撑的答案。
- 能否处理多跳、条件、冲突、否定和数值问题。
- 能否在知识库无法回答时稳定拒答。
- 能否在受限开源本地模型或规则流程下保持可复现。
无效提交情况
JSON 无法解析、ID 缺失或重复、字段类型错误、引用字段不是数组时,将判为 0 分。
条款
AI 协助规则
本题 AI 协助等级为 A1-Open,即“开源可复现 RAG”。本题允许使用 AI 工具学习概念、辅助写代码和分析报错,但最终测试集答案必须由本地可运行、可复现、参数量受限的开源流程生成。
本题不允许使用闭源 API、商业 Agent 或远程托管模型生成最终答案、引用或拒答判断。
模型规模认定
参数量按模型公开标称参数量或权重实际结构认定。量化、剪枝、低比特推理不会降低参数量认定。MoE 模型按总参数量认定,不按 active parameters 认定。
最终流程最多允许:
- 1 个生成式语言模型。
- 1 个 embedding 模型。
- 1 个 reranker / cross-encoder。
不含可学习参数的规则、BM25、TF-IDF、字符串匹配、JSON 修复和后处理脚本不计入模型数量。
可复现要求
获奖候选队伍必须提交复现实验包。复现实验包至少包含:
README.md:从公开数据生成最终results.json的完整步骤。requirements.txt、environment.yml或容器说明。- 推理脚本、配置文件、随机种子和命令行参数。
- 使用的模型名称、版本、许可证、下载地址、参数量、权重 hash 和本地路径说明。
- 关键运行日志,包括索引构建、检索、rerank、生成或抽取、拒答判断和格式校验输出。
- 若使用微调或 LoRA,必须提供训练数据来源、训练命令、checkpoint hash 和推理加载方式。
组委会可要求获奖候选队伍在断网环境中复跑部分或全部测试问题。若复跑结果无法解释地偏离最终提交,或无法提供符合规则的本地流程,组委会可取消获奖资格。
Writeup 补充要求
Writeup 必须包含 RAG pipeline 图,说明 chunk、检索、rerank、生成或抽取、引用校验、拒答策略和 JSON 修复流程。
必须披露:
- 所有模型和库的名称、版本、参数量、许可证和用途。
- 是否使用生成式模型;如果使用,说明 prompt 摘要、输入字段、输出约束和失败处理。
- 本地验证集划分方式、主要指标和与线上分数差异。
- 至少 5 个案例分析:正确引用、多跳、拒答、检索失败、模型幻觉或规则误判。
- schema 校验截图或日志、AI 工具使用声明和资源环境说明。
Writeup需包含最终提交压缩包文件 SHA256,指平台上传的 NS-2026-02-answer.zip 的 SHA256。
基本信息
-
队长用户名:Ayin
-
队伍名:L.Corp
-
题号:NS-2026-00
-
最终官网提交记录:
- 提交时间:2026-05-23 17:05:30
- 最终有效得分:745.66分

1. 解题概述
本题是一道受限开源本地流程 RAG 任务。任务的核心目标是针对校园制度、安全手册等本地知识库进行问答,不仅要求给出简短、准确、高度可归一化的答案,还必须提供可验证的 chunk_id 引用来源,并在知识库无法支撑回答时进行稳定的拒答。
本方案严格遵守 A1-Open 的模型参数量限制规则,设计并实现了一套双路混合检索 + 拒答阈值拦截 + 提示词约束生成 + 引用后校验的 RAG 工作流:
- 检索阶段:使用
jieba分词配合BM25Okapi构建稀疏检索索引,同时利用Qwen3-Embedding-0.6B提取“标题+正文”的稠密向量。通过对两路得分进行最大最小归一化后加权融合(5:5)。 - 拒答与生成阶段:在检索首位得分低于预设阈值0.35时直接触发硬拒答。对于通过的样本,结合 Top-5 召回片段构建上下文,利用
Qwen3.5-4B进行严格的 JSON 约束生成。 - 后处理阶段:通过正则表达式和严格的格式校验,确保所有
citations均在本次召回的范围内,从而最大化了答案的准确性与引用的可解释性。
2. 关键改进
1. 标题与正文文本融合嵌入
- 改进内容:在构建 Dense Embedding 索引时,将原有的仅对
chunk["text"]进行向量化,改为将文档标题与正文进行拼接格式化:"标题: {title} \n正文: {text}"后再输入嵌入模型。 - 验证依据:解决了测试集中大量“针对某项具体制度名称提问,但片段正文中未重复提及该制度名称”导致语义断层的问题。改进后,本地验证集上的引用召回率有所提升。
2. 双路检索分数归一化加权融合
- 改进内容:传统 BM25 的原始得分范围与 Cosine 相似度分值区间不一致,无法直接相加。本方案对 Dense 分数进行 Min-Max 归一化,对 BM25 分数除以 Max 分数归一化,再按
0.5:0.5进行混合打分。 - 验证依据:有效结合了关键字绝对匹配(如具体的设备型号、房间号)与语义匹配(如制度条款的同义改写)。
3. 验证与复现
运行环境
| 项目 | 信息 |
|---|---|
| 操作系统 | Ubuntu 24.04 LTS |
| Python 版本 | 3.12.11 |
| jieba 版本 | 0.42.1 |
| rank_bm25 版本 | 0.2.2 |
| numpy 版本 | 2.3.5 |
| openai 版本 | 2.9.0 |
| vllm 版本 | nightly |
| CPU 型号 | AMD Ryzen 7 9800X3D 8-Core Processor |
| GPU 型号 | NVIDIA RTX 5090 |
| 内存 (RAM) | 48 GB |
| CUDA 版本 | 13.2 |
复现步骤
# 1. 安装依赖pip install -r requirements.txt
# 下载模型文件,可使用modelscope或者hf,也可以直接下载到本地后放在指定目录# vllm部署,在src运行./deploy.sh
# 2. 执行主程序python main.py- 预计运行时间:大约 5 - 10 分钟。
- 随机种子与参数:temperature设为 0.1,拒答阈值设为 0.35。
4. AI 使用声明
全局说明
- 本队使用的AI工具:Gemini,Claude
- 主要用途:资料查询/代码辅助
逐题声明
NS-2026-02
- 官方等级:A1-Open
- 实际使用:代码辅助 / 资料查询
- AI是否接触完整题面:否
- AI是否接触测试输入:否
- AI是否接触提交反馈或排行榜反馈:否
- AI是否生成或修改最终提交:否
- 是否使用商业API、闭源远程模型或托管式Agent:是
- 详细说明:在本地部署了符合要求参数量限制的模型 Qwen/Qwen3.5-4B,Qwen/Qwen3-embedding-0.6B,并通过本地接口进行 RAG 推理问答。使用了Gemini和Claude两个闭源远程模型,主要用于资料查询和代码辅助
Writeup 写作辅助声明
- 是否使用 AI 辅助撰写或润色:是
- 使用工具:Gemini
- 使用范围:Markdown 排版格式优化与部分语句润色
- AI 接触材料:草稿,部分代码,运行日志,分数
- AI 是否生成新的实验结果、验证分数或复现命令:否
- 人工核对方式:由队伍成员仔细核对事实、代码、日志、分数和复现命令。
5. 最终提交与 SHA256
- 平台提交文件名称:NS-2026-02-answer.zip
- 平台提交时间:2026-05-23 17:05:30
- 最终有效得分:745.66
- 答案 ZIP SHA256(提交文件 SHA256):
c2cd8d7143e7b7c076bf8783fd2ce3d123af257733515cb361115e3364546733 - 内部关键文件 SHA256(提交包内部 SHA256):
results.json:b8319b03f372cf13035ea53fc7d331859d092238360aed27ca2e9e1447be9ba4
6. 证据材料
必交截图列表
| 序号 | 截图内容 | 关联图片文件 | 说明 |
|---|---|---|---|
| 1 | 平台最终提交记录 | ![]() | 显示队伍名 L.Corp、题号 NS-2026-02、提交时间、最终得分 745.66 |
| 2 | 运行环境或规格 | evidence/ubuntu.png | 包含 GPU (RTX 5090) 规格与操作系统版本 Ubuntu 24.04 运行环境 |
| 3 | 训练/推理关键日志 | ![]() | 生成最终提交文件时的本地终端运行输出日志 |
| 4 | 最终提交文件 hash | ![]() | 计算 results.json 文件的 SHA256 校验哈希结果 |
7. 补充说明 (代码包与算法配置)
7.1 代码包说明
文件都在 src 目录下,因为 vLLM 配置较多,故没有完全写入 requirements.txt。复现环境可参考前述依赖库及版本。
7.2 开源模型清单
本方案在最终测试集生成流程中,仅使用 1 个生成式大模型与 1 个 Embedding模型:
| 模型名称 | 官方标称参数量 | 开源许可证 | 本地用途 | 下载地址 | 本地路径 |
|---|---|---|---|---|---|
| Qwen/Qwen3-Embedding-0.6B | 0.6B | Apache-2.0 | 提取知识库标题与正文的语义稠密向量 | https://huggingface.co/Qwen/Qwen3-Embedding-0.6B | 本地部署 vLLM |
| Qwen/Qwen3.5-4B | 4B | Apache-2.0 | 根据检索上下文进行答案抽取与 JSON 响应 | https://huggingface.co/Qwen/Qwen3.5-4B | 本地部署 vLLM |
7.3 依赖库清单
| 库名称 | 采用版本 | 许可证 | 核心用途说明 |
|---|---|---|---|
| vllm | nightly | Apache-2.0 | 本地单端口多模型常驻大模型推理引擎后端 |
| openai | 2.9.0 | MIT | 作为调用本地 vLLM 接口的通用通用标准客户端 |
| jieba | 0.42.1 | MIT | 用于本地文档片段与用户提问的中文分词预处理 |
| rank_bm25 | 0.2.2 | GPL-3.0 | 传统稀疏检索算法,作为两路检索的关键召回支柱 |
| numpy | 2.3.5 | BSD-3-Clause | 向量点积与 Min-Max 打分归一化矩阵运算 |
7.4 生成式大模型(LLM)配置与防御披露
本方案使用生成式大模型 Qwen3.5-4B 辅助答案生成。为了防止小模型在面对负样本、恶意注入时发生幻觉,设计了严格的约束策略:
- Prompt 摘要:
- 输入字段:
【本地知识库片段】:格式化传入混合检索出的 Top-5chunk_id、title和text。【用户问题】:原始测试集提问。
- 输出约束:
- 你的回答必须简短、准确、事实完全基于给定的片段。不得发挥,不得包含外部常识。
- 如果给定的片段中没有任何一句话能够回答该问题,或者给定的信息与问题冲突、不完整,你必须直接输出: 无法根据给定知识库回答。
- 你的输出格式必须是严格的 JSON 对象,不能包含任何 markdown 格式标记 (如 ```json) 或其他文字。
- 输入字段:
- 失败处理与防御:
- JSON 修复:使用
re.sub(r"```json|```", "", llm_output)强制剥离可能生成的 markdown 标签; - 解析防御:将清洗后的文本使用
json.loads解析。一旦捕获到任何Exception(包含非标准 JSON、字段残缺等),catch块立即介入,抛弃错误结果,强制返回标准拒答。 - 引用幻觉防御(后验校验):遍历模型生成的
citations数组。通过valid_chunk_ids = {c["chunk_id"] for c, _ in search_results}建立白名单。任何企图伪造、幻觉或无中生有的 chunk_id 都会被就地剔除。
- JSON 修复:使用
7.5 本地验证集划分与线上对比
- 划分方式:从公开的 468 个
train_qa.jsonl中,将可回答题与无法回答题按8:2比例切分,构建出包含 94 个QA的本地验证集。 - 核心指标定义:查询召回准确率 + 拒答准确率。文本生成没有准备评测指标,主要检验检索与拒答的稳定性。
- 评测对比表现:
| 数据集 | 引用命中率 | 无法回答识别 | 格式合法性 |
|---|---|---|---|
| 本地验证集 | 250.0 | 100.0 | 50.0 |
| 线上隐藏集 | 249.6234939759036 | 100.0 | 50.0 |
7.6 典型案例分析
案例 1:正确引用与直接事实抽取(正样本)
- 用户问题:
按照给定知识库,科研临时存储空间办理前材料和服务对象分别是什么?不要使用外部常识。 - 系统行为:提取得到两个高置信度的片段(详见附件src/results_rag.json,id
段)。 - 模型输出:
{"answer": "材料:数据管理计划和项目编号;服务对象:承担数据密集型科研项目的团队。", "citations": ["COMPUTE-STORAGE-CHECK-001","COMPUTE-STORAGE-ACCESS-001"]} - 分析:能够实现准确的事实抽取,并且引用的
chunk_id均在本次检索结果中,说明模型能够正确理解并利用提供的上下文信息进行回答。
案例 2:正确引用与直接事实抽取(正样本)
- 用户问题:
请回答:月影多材料实验台如果目标时段还有60小时才开始,现在补交风险清单来得及吗?需要同时上传什么?请同时给出依据。 - 系统行为:提取得到一个完全相信的片段(详见附件src/results_rag.json,id
段)。 - 模型输出:
{"answer": "来得及。需要同时上传材料批号。依据:项目组必须在目标时段开始前至少72小时上传风险清单和材料批号。","citations": ["MOON-MAKER-001" ]} - 分析:能够实现准确的事实抽取,并且引用的
chunk_id均在本次检索结果中,说明模型能够正确理解并利用提供的上下文信息进行回答。
案例 3:无法回答题(LLM主动拒答)
- 用户问题:
今年毕业典礼主讲嘉宾是谁? - 系统行为:查询到了多个很高相关性的内容,但是这些内容都无法直接回答用户的问题,LLM模型足够稳定,拒绝了回答。
- 系统决策:LLM在回复时拒答。
- 最终输出:
{"answer": "无法根据给定知识库回答", "citations": []} - 分析:Prompt设计有效,能够引导模型在面对无法回答的问题时做出正确的拒答决策。
案例 4:无法回答题(LLM主动拒答)
- 用户问题:
校园卡丢失后公交余额如何转移? - 系统行为:查询到了一个很高相关性的内容,但是这些内容都无法直接回答用户的问题,LLM模型足够稳定,拒绝了回答。
- 系统决策:LLM在回复时拒答。
- 最终输出:
{"answer": "无法根据给定知识库回答", "citations": []} - 分析:Prompt设计有效,能够引导模型在面对无法回答的问题时做出正确的拒答决策。
案例 5:模型幻觉及引用伪造(后置拦截成功)
- 本地评测时未遇到过,可能是Prompt质量较好,或者是模型本身的稳定性较好。但是在线上测试时有极小部分召回失败,0.152%的测试未通过。
案例 6:多跳关联题(组合推理)
- 我没有实现多跳推理,因为测试集和训练集都比较简单,如需多跳,列举两种可能的且普遍应用的方案:
- 链式提示:给LLM自主决定是否还需要进一步查询内容(tool call),循环调用LLM,不断补充全面的知识,并加入阈值截断循环。
- Graph RAG:将相关性信息构建成图结构,利用Graph RAG进行检索,进阶手段可以给边加上权重,并且可以淡化剪枝,节省计算资源。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时




















