十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

稀疏+语义+LLM重排序:构建ADHD症状句检索流水线

稀疏+语义+LLM重排序:构建ADHD症状句检索流水线 “DSGT-ARC at eRisk 2026 Task 3: Sparse, Semantic, and LLM Reranking for ADHD Symptom Sentences”——第一次看到这个标题很容易把它理解成一个医疗 NLP 分类任务模型把句子分成“有 ADHD 症状”和“没有 ADHD 症状”。但如果真按这个思路去做大概率会在评测里吃亏。因为这个任务设计的核心不是“分类”而是“排序”。系统要做的不是给每个句子贴标签而是在给定文本中找出一批与 ADHD 症状相关的句子并按相关性从高到低排好。如果让我给这类任务下一个判断我会说能不能在 eRisk 这样的评测中拿到稳定成绩不取决于某个单模型有多强而取决于你有没有把稀疏检索、语义检索和大模型重排序组合成一条完整、可控、可复现的流水线。1. 先想清楚任务本身它给的是一堆文本要的是一串排序1.1 这是一个“给句子排队”的任务不是一个“打标签”的任务从标题里的“Symptom Sentences”和“Reranking”来看这个任务的核心对象是句子。系统输入通常是用户生成文本可能是一篇帖子也可能是一整段讨论输出则应该是若干与 ADHD 症状相关的句子并且按相关性排序。很多人会把这种任务下意识当成文本分类模型读一个句子输出 0 或 1。但在评测任务里这样做有风险。原因在于分类模型天然只关心“是不是”不关心“哪句更重要”。如果一段文本里有 5 个相关句子分类模型可能把 5 句都标出来但评测指标可能更关心前几名是否排得准。比如 nDCG、MAP、Recallk 这类排序指标都对位置的敏感程度远高于普通分类准确率。你给出的顺序不对哪怕句子选对了分数也会受影响。所以接到这类任务的第一步是把心态从“做分类”切换到“做排序”。后面所有方案选择都要围绕排序目标来设计。1.2 为什么常见做法是“先召回再精排”在信息检索领域有一个几乎固定的两段式流程先召回再排序。召回阶段用高效但略粗糙的方法从大量句子里捞回一批可能相关的候选排序阶段再用更准但更慢的方法给这些候选重新打分排序。这种流程不是怕模型不够强而是成本和效果之间的平衡。直接让一个大模型读完整篇文章然后输出所有相关句子看起来很美但实际会遇到几个问题长文本可能超过模型上下文窗口结果就是开头结尾能记住中间被截断。一次性让模型做“找句子 排序”两件事输出格式容易乱质量也难保证。如果语料里每一篇都很长全量跑一遍 LLM 的时间成本和调用成本会迅速失控。更稳的做法是先用低成本方法把候选句从上千甚至上万句压缩到几十句再用高成本方法只对这几十句做精细排序。这样既不会漏掉关键词上的强信号又能把昂贵的判断花在真正值得判断的地方。这也是这个标题里“Sparse, Semantic, and LLM Reranking”的含义三种信号分工各管一段。2. 稀疏、语义、LLM 三种信号为什么要一起用2.1 稀疏检索负责“不会漏掉关键词”稀疏检索的代表是 BM25。它的核心逻辑很简单看一个句子和查询里有多少关键词重合词频越高、句子越短、关键词越罕见得分越高。这种方法在 ADHD 症状句场景里有天然优势。比如查询里出现“注意力不集中”一个句子里恰好出现这个短语BM25 会给高分。它不依赖模型训练速度很快还很容易解释为什么这个句子排前面因为关键词命中了。但它的短板也很明显对“换一种说法”无能为力。“我很难集中注意力”和“我总是走神”意思几乎一样但字面上没有任何共同词。BM25 对这种情况容易漏判。还有一类更隐蔽的问题有些句子包含关键词但语义上并不是在描述确诊者本人的症状。比如“我在查 ADHD 的症状听说注意力不集中很常见”这句话里有“注意力不集中”但它更像背景知识不是候选系统应该优先输出的症状描述句。所以稀疏检索不能单独用但它一定不能缺席。它可以保证那些有明显关键词的句子优先进入候选池为后续精排兜底。2.2 语义检索负责“换一种说法也能匹配”语义检索用向量表示句子把语言变成高维向量相近含义的句子在向量空间里距离更近。它解决的最大问题就是同义改写和隐式表达。同样那句“我总是走神”如果 embedding 模型训练得够好它和“注意力不集中”的向量距离会比较近从而被召回。不过语义检索也有自己的问题。它不是真正理解句子而是学习到了向量空间距离。如果训练数据偏向通用领域遇到心理健康文本里的一些特殊表达效果可能打折扣。而且它不像 BM25 那样可解释也不像规则那样可控。更关键的是纯语义检索对“关键症状词”不够敏感。一个句子如果整体意思和 ADHD 相关但缺少具体症状词向量可能仍然会给它较高分数但在评测里这种模糊句子未必是真正被需要的正样本。反之一句非常具体、证据充分的症状句可能因为表达方式比较冷静、措辞不太情绪化反而向量得分不高。所以语义检索适合当“召回的第二条腿”而不是唯一答案。2.3 LLM 重排序负责“最后一公里的判断”重排序是流水线的最后一段。它已经不是“找可能相关”而是“判断哪句更相关”。LLM 在这里能做几件稀疏和语义都做不好的事理解任务规则知道这里要找的是“ADHD 症状描述”而不是所有关于 ADHD 的讨论。结合上下文判断一个句子说的是使用者自身的感受还是朋友转述还是资料引用LLM 可以区分。对多个候选句做相对比较不是孤立打分而是“这句和那句哪个证据更直接”。输出可解释结果让模型解释为什么把某句排前面便于人工检查。但 LLM 的问题也很大成本高、延迟高、输出不稳定。同样一句话不同 prompt、不同温度、不同运行批次给出的分数可能不一样。这会在评测里造成不可复现的问题。因此LLM 重排序只能放在候选集比较小的时候用不能直接对整个语料库跑。这就是为什么它叫“重排序”而不是“首轮召回”。2.4 三种信号各自的角色可以用一张表说清信号代表方法优势短板建议位置稀疏检索BM25、Elasticsearch 等精确词匹配、速度快、可解释对同义改写不敏感、语境理解弱候选召回语义检索dense embedding、向量检索能匹配“换一种说法”的表达对关键词证据不够敏感、可解释性弱候选召回、粗排LLM 重排序prompt-based reranking综合语义、任务规则和上下文判断成本高、延迟高、输出不稳定最终精排这三者不是三个并列选项而是一条流水线里的三个功能模块。决定系统上限的是流水线设计而不是其中某一个模块。3. 一个可复现的三段式重排序流程3.1 阶段一候选召回先保证“该出现的句子都出现”在具体实现里我会先把语料拆成句子而不是对整篇文档做检索。整篇文档过长后续的排序和精排都难处理。分句之后还要做基础清洗去掉过短句子、重复句子、明显的引用模板等。然后并行跑两路召回稀疏路用 BM25 对每个查询或症状词做检索得到候选句集合。语义路用 embedding 模型把所有句子转成向量再对同一个查询转成向量做相似度检索。两路结果怎么合并最简单的办法是 RRFReciprocal Rank Fusion不需要训练权重公式也非常简单对每个句子把它在两路结果里的排名的倒数相加得到一个融合分。常见参数是 k60。# 伪代码RRF 融合候选 def rrf_fuse(sparse_hits, dense_hits, k60): scores {} for rank, doc_id in enumerate(sparse_hits, start1): scores[doc_id] scores.get(doc_id, 0) 1 / (k rank) for rank, doc_id in enumerate(dense_hits, start1): scores[doc_id] scores.get(doc_id, 0) 1 / (k rank) return sorted(scores.items(), keylambda x: x[1], reverseTrue)候选数量建议设置为最终需要数量的 5 到 10 倍。如果评测要求输出每篇文档前若干句候选召回先取 100 到 200 句是比较稳妥的起点。这里有一个最容易被忽略的原则召回阶段的目标不是“召回的每句都对”而是“不要把真正相关的句子丢掉”。漏掉一句后面再强的重排序也救不回来。宁可召回一堆模糊候选也不要让召回列表太干净。不要一开始就把候选数设得太小。先保持较大的候选池观察重排序结果稳定之后再尝试压缩候选数以节省 LLM 调用成本。3.2 阶段二语义粗排缩小 LLM 要看的范围候选池如果仍然有 100 句以上直接全部丢给 LLM 是不划算的。可以先用一个更便宜的模型做一次粗排把最像正例的句子挑出来。粗排可以有两种选择使用 cross-encoder 模型。把查询和句子拼成一段文本输入模型输出相关性分数。这种方法比纯向量相似度准但也比向量检索慢适合对 100 个句子做打分。如果连 cross-encoder 都不方便部署可以退回到语义相似度取 top 50。粗排的输入是查询和句子输出是一个分数。排序后通常取前 50 句进入下一阶段。这个阶段的“准”是相对召回而言的不需要追求完美。它的主要目的是挡住明显不相关的句子让后面真正昂贵的 LLM 判断集中在高价值候选上。3.3 阶段三LLM 重排序做最后的判断LLM 重排序的输入不能只是孤零零的句子。更合理的做法是把查询、候选句、任务说明一起给模型必要时还要带上句子所在的原文段落。比如 prompt 可以这样组织你是一个信息检索精排助手。 任务从下面候选句子中找出最符合“ADHD 症状描述”的句子并按相关性从高到低排序。 判断时注意只考虑与 ADHD 症状直接相关的描述不要选背景介绍、医学定义、一般性议论。 候选句子 1. ... 2. ... 请输出排序后的句子编号例如[3, 1, 2]。如果希望模型输出分数可以要求它输出 JSON[ {id: 3, score: 0.9, reason: 直接描述注意力难以维持}, {id: 1, score: 0.7, reason: 描述经常被外界干扰} ]这里要注意几个参数temperature 调到 0或者尽可能小减少随机性。max_tokens 不要设置过小否则输出可能被截断。候选句数量建议不超过 50 句超过之后LLM 输出的稳定性会明显下降。如果使用 API要考虑超时和失败重试。LLM 输出后要把结果解析成标准格式再映射回原始句子 ID。解析失败时要有备选方案比如直接保留粗排顺序而不是返回空结果。3.4 阶段四输出规范化评测通常不是看你打印了什么而是看你提交的文件是否符合格式。因此在生成最终结果前要做几件事去重同一个句子如果既在后候选里出现又在另一个候选里出现只保留一次。保序如果最终要按原文档中的位置展示要把排序结果和原文位置一起保存。阈值如果是真实场景可能需要只输出分数超过阈值的句子但阈值不要拍脑袋定要在验证集上画 P/R 曲线。在比赛场景里如果评测指标是排序类指标不要轻易丢弃低分候选。系统输出 30 句和输出 50 句最终得分可能完全不同。先看评测指标对 False Positive 的惩罚程度再决定是否设置阈值。4. 四个最容易丢分的细节4.1 召回漏了重排序再强也救不回来我在类似任务里吃过比较大的亏是花大量时间调 LLM 的 prompt最后发现问题出在候选召回。当时系统只用了 BM25结果大量“换一种说法”的症状句根本没进候选池。LLM 再怎么精排看到的都是同一批句子自然不可能找到真正漏掉的内容。所以排查的时候不要一上来就调重排序。先看召回率测试集里如果已知有 100 句正例你的候选召回池里覆盖了多少如果覆盖率低于 70%不要先去优化 LLM 的排序能力先解决召回。检查到底是稀疏路漏得多还是语义路漏得多。一个实用的方法是分别统计“只被 BM25 召回”“只被向量召回”“两者都召回”的句子数量。如果两路结果的重合率极高说明融合没有带来增益如果两路结果几乎不重合说明其中一个信号可能在做无用功。4.2 评估口径不统一导致调参方向错误排序任务不能只看“第一个句子是不是对的”。很多团队的实验日志里只记了 top1 的准确率结果发现 top1 很不错nDCG 却不高。原因是评测指标可能特别看重前 10 个位置的综合排序质量。一个排序结果是 [对错对错对]另一个是 [对对对错错]可能在 top1 上一样但在 nDCG 上差很多。建议每一轮实验都至少记录这些指标指标作用Recall50 / Recall100候选召回覆盖了多少正例nDCG10前 10 名排序质量P5前 5 名中有多少是正确句子MRR第一个正确答案出现的位置如果只盯着一个指标很容易把系统调成“前三句很漂亮整体一塌糊涂”。4.3 LLM 打出的“分”不是概率LLM 给出的 0 到 1 分数或者“相关/不相关”的判断本质上不是经过校准的概率。它只能说“模型用训练时形成的能力给这个句子一个主观判断”。所以不要把一个 0.85 分和一个 0.82 分过度解读也不要把 0.9 分当成有 90% 概率正确。在比赛里最好的方式是让 LLM 只负责排序不负责分类在真实场景里如果一定要阈值先用一个独立验证集做校准不要把训练集上的分布直接当作真实分布。4.4 输出不稳定同一句话两次结果不同LLM 重排序最大的工程隐患是“随机性”。同样输入低温度下也可能出现细微差异如果用了采样差异会更明显。缓解方法固定 temperature0或允许的最小值。固定 prompt 模板不要频繁改措辞。多做几次预测用投票或平均分融合。把模型的输出格式限制为 JSON并做 schema 校验。对最终结果做日志记录出现异常时能回滚到上一版本。如果同一批候选句在两次运行中排序变化超过一定比例说明 prompt 或参数还不够稳定。先别急着报结果把稳定性问题解决掉。4.5 一套排查链路遇到实验结果不理想我一般按这个顺序排查先看候选召回覆盖率。如果覆盖不够问题在召回不在精排。再看粗排是否把正确句子提前。粗排结果可以用 nDCG 单独评测。再看 LLM 重排序的稳定性。同一批输入跑两次结果是否一致。最后看评测脚本和提交格式。很多分数异常其实是字段名写错、句子 ID 分错、输出顺序反转造成的。日志和模型版本要能对上。否则出了问题根本没法回溯。这个顺序可以避免把时间浪费在错误的模块上。5. 从比赛到真实落地还要补哪些拼图比赛系统只需要在固定数据集上产生一个提交文件。真实系统面对的是长尾文本、实时请求、隐私约束和不可控的模型服务。两者之间还差不少工程化能力。5.1 标注症状句的边界本来就模糊ADHD 症状句的标注比想象中难。一个句子究竟是“描述症状”还是“表达情绪”还是“治疗效果反馈”不同人会给出不同判断。比如“我今天根本没法开始写作业”算不算 ADHD 症状句它可能只是普通拖延。又比如“我刚刚又在房间里转了三圈才想起要拿什么”算不算冲动/注意力相关表现这需要非常明确的标注标准。在真实项目里我会建议至少双人标注标注不一致时由第三人裁决。把“症状句”的定义写清楚包括是否包含主诉、行为描述、自我感知、环境影响。定期做标注一致性检查不要一次标完就结束。如果标注标准不稳定后面所有模型训练和评估都有可能是空中楼阁。5.2 隐私和合规这不是一句“公开数据”就能带过的事用户生成文本非常敏感。帖子内容可能包含个人经历、情绪状况、用药信息、人际关系等。即使比赛数据是公开的真实部署也必须考虑脱敏、权限控制、数据保留期限等问题。更重要的边界是这个系统不构成医疗诊断。它可以作为一个信息检索工具帮研究者或专业人员从大量文本里快速定位可能和 ADHD 症状相关的句子但最终判断必须由人完成。系统输出不能直接作为诊断依据也不能用于任何形式的自动化医疗决策。技术实现上可以做得很漂亮但部署之前一定要想清楚谁会看这个输出他们拿这个输出做什么如果输出被误用后果是什么5.3 工程化没有日志和版本就没有可复现性LLM 应用最大的工程风险是结果不可复现。你很难向同事说清“上次跑出来的结果这次为什么变了”。为了减少这种问题需要把几个版本都记录下来稀疏检索用的索引版本和 BM25 参数。embedding 模型版本、向量索引版本。LLM 模型名称、版本、temperature、max_tokens、prompt 模板。候选召回数量、粗排数量、重排序数量。这些信息听起来很琐碎但等你要连续调一周参数或者系统上线后突然效果下滑时它们就是救命日志。另外要考虑降级策略。如果 LLM 服务突然不可用系统应该能自动退回“语义重排序”或“RRF 融合结果”而不是直接报错。这个降级链路要在上线前测好。5.4 明确适用边界这套“稀疏 语义 LLM”重排序方案适合这些场景从大量文本中筛选潜在相关句子供人工复核。需要综合关键词证据和语义相似度的检索场景。可接受一定延迟、但需要较高排序质量的精排场景。研究型评测、内容整理、辅助标注。不适合这些场景实时性要求极高的在线搜索LLM 精排往往太慢。需要绝对可解释输出的场合LLM 推理过程不稳定。资源受限环境无法稳定调用大模型。已经有人工规则且效果良好的场景引入 LLM 未必值得。这里没有“万能方案”。判断要不要用这套流程取决于你的数据规模、成本预算、延迟容忍度和对结果稳定性的要求。6. 比排名更值钱的是这套流程eRisk 2026 的结果最终会过去但这个任务背后代表的问题会一直存在如何在大量非结构化文本里把最相关、最有证据、最需要被看到的内容挑出来并且按正确顺序展示给使用者。这个问题的答案不是某一个模型打天下而是“先召回、再粗排、最后精排”的流程设计。你可以把这套流程复用到很多场景简历筛选先按关键词召回再按语义匹配最后由 LLM 判断是否满足岗位核心要求。客服工单分类先找候选历史工单再排序最相似的解决方案。法律条款检索先用关键词加向量召回候选条款再让 LLM 做最终匹配。评论内容整理从海量评论中找出与某个主题相关的句子按证据强度排序。这套流程真正沉淀下来的是一个可复用的五步法明确任务类型是分类是检索还是排序这会决定你选择什么指标。列出可用信号关键词、向量、模型推理各有各的强项和弱项。搭流水线先召回再粗排最后精排每个阶段控制候选规模。定义评估指标不只盯一个数字至少覆盖召回、排序、稳定性三个维度。固化版本模型版本、prompt 版本、参数配置、日志全部留底。回到文章开头那个判断真正稳定有效的不是某一个模型而是流程设计。你在评测里学到如何把稀疏、语义和 LLM 重排序组合起来就已经比“哪个模型更好”这个问题的答案更有价值了。
返回列表