更新于

LLM 长上下文 Needle-in-a-Haystack 实测方法与结果解读


厂商公布的”上下文窗口”数字(比如 100 万 token)说明模型能接收多长的输入,但不代表模型能记住并用上这么长输入里的所有信息。Needle-in-a-Haystack(大海捞针,简称 NIAH)是业界公认用来检验这件事的标准测试方法。本文讲清楚这个测试到底测什么、怎么自己动手做,以及看结果时该注意哪些坑。

一、NIAH 测试到底在测什么

测试方法很直接:

  1. 准备一段很长的”干扰文本”(haystack),通常是无关的书籍或文章拼接而成
  2. 在文本的某个位置插入一句与上下文完全无关的”针”(needle),比如”最好吃的三明治配方需要在 Dolores Park 一个晴朗的日子里准备”
  3. 把整个长文本喂给模型,然后单独提问”最好吃的三明治配方需要在哪里准备?”
  4. 检查模型能否准确从几万到几十万 token 的文本中把这句话找出来并正确回答

测试会在不同的插入深度(文本开头 / 中间 / 结尾)和不同的总长度(比如 10K、50K、200K、1M token)两个维度上做网格测试,最后画出一张热力图:横轴是上下文总长度,纵轴是插入深度,颜色代表检索准确率。

二、为什么这个测试比”上下文窗口大小”更重要

上下文窗口只是”能塞进去多少”,NIAH 测的是”塞进去之后模型能不能用”。业内观察到几个共性现象:

  • “中间丢失”(Lost in the Middle):很多模型对文本开头和结尾的信息检索准确率高,插在文本正中间的内容反而容易被忽略,这是长上下文模型的经典弱点
  • 窗口越大,衰减越明显:同一个模型在 10K token 长度下几乎 100% 准确,但拉到接近其宣称的窗口上限时,准确率会有不同程度的下滑
  • 单针 vs 多针差异巨大:只测一根针的成绩通常好看,但如果同时插入多根针(多个不相关的关键信息),要求模型同时记住并综合回答,准确率下降幅度会大很多,这个”多针”版本更接近真实的长文档问答场景

三、自己动手跑一遍测试

如果想验证自己项目里实际用的模型在长上下文场景下的真实表现,不需要复杂的框架,一个基础脚本大致思路如下:

import random

def build_haystack(base_text: str, target_length: int) -> str:
    # 通过重复拼接无关长文本凑够目标 token 长度
    repeats = target_length // len(base_text) + 1
    return (base_text * repeats)[:target_length]

def insert_needle(haystack: str, needle: str, depth_percent: float) -> str:
    insert_pos = int(len(haystack) * depth_percent)
    return haystack[:insert_pos] + needle + haystack[insert_pos:]

def run_test(model_call, haystack_text, needle, question, depths, lengths):
    results = []
    for length in lengths:
        base = build_haystack(haystack_text, length)
        for depth in depths:
            prompt_text = insert_needle(base, needle, depth)
            answer = model_call(prompt_text, question)
            correct = needle_answer_in(answer)
            results.append((length, depth, correct))
    return results

关键是选一个答案唯一、无法从常识猜出的针,比如一串随机数字或一句荒诞无意义的话,避免模型靠”蒙”答对导致测试结果失真。测完之后按长度和深度分组统计准确率,画热力图就能直观看出模型的”记忆盲区”分布在哪个区间。

四、看测试报告时容易踩的坑

  • 只看平均分:平均准确率 95% 可能掩盖了某个深度区间(比如文本 40%-60% 位置)准确率只有 60% 的问题,一定要看分区间数据
  • 不同评测机构的针不一样:有的用一句话,有的用一个 UUID,有的用数字,难度不同直接导致分数不可比,跨报告横向比较模型时要先确认测试方法是否一致
  • 只测英文语料:中文长文档的分词和语义密度和英文不同,同一模型在中文语料下的 NIAH 表现可能和英文报告不一致,如果你的实际场景是中文文档问答,最好用中文语料自测一遍
  • 没测多针场景:真实业务里的长文档问答往往需要综合多处信息,单针满分不代表多针也满分,尽量补一组多针测试再下结论

五、对实际项目选型的意义

如果你的应用场景是长文档摘要、合同审查、代码库理解这类需要模型”通读并综合”长文本的任务,NIAH 分区间的表现比单纯的上下文窗口大小更能预测真实效果。建议的选型顺序:

  1. 先明确自己的典型输入长度(比如平均 5 万 token 还是 50 万 token)
  2. 找该长度区间内、覆盖开头中间结尾三个深度的 NIAH 成绩,而不是看模型宣传页上的”最大窗口”
  3. 如果预算允许,用自己的真实语料跑一遍轻量版测试,比看第三方报告更可靠

六、相关阅读

想用多个模型跑同一份 NIAH 测试脚本做横向对比?通过 YoTradeApi 一个 Key 就能调用 Claude、GPT、Gemini 等主流模型,不用为每家单独开账号配置。