编码智能体的上下文工程:ContextBench 到底测了什么,以及为何「过度检索」必然失败

·阅读约10分钟·Evergreen Tools Team

ContextBench 由南京大学与伦敦大学学院的研究者于 2026 年 2 月 11 日提交,它问了一个多数智能体团队靠「碰运气」回答的问题:智能体到底用没用上它检索到的上下文?该基准覆盖 66 个仓库上的 1,136 个任务,结论并不好看:顶尖模型追逐召回率而牺牲精度,检索得越多,噪声越多;智能体常常检视了正确的代码,却没能把它用进最终修改,因为「检索到」不等于「用上了」;而更均衡的检索策略反而以更低成本取得更强的 Pass@1。如果你在做编码智能体,这是今年最实用的一篇论文。

注意力是有限预算

注意力是有限预算

一、ContextBench 究竟测了什么

多数编码基准只评结果:测试过没过。ContextBench 评的是流水线中段。它把「智能体是否检索到相关代码」与「它是否在最终修改中用到这些代码」分开评估,而这正是在一次失败运行里最容易丢失的区分。基准覆盖 66 个仓库、1,136 个任务,因此结论不是某个代码库或某种语言的偶然产物。

# retrieve.py - over-retrieve wide, then buy precision with a re-ranker
RETRIEVE_K = 40        # cheap recall
FINAL_K    = 8         # expensive precision

def build_context(query, repo_index, reranker):
    candidates = repo_index.search(query, k=RETRIEVE_K)   # recall stage
    ranked = reranker.score(query, candidates)            # precision stage
    return ranked[:FINAL_K]

二、召回便宜,精度昂贵

第一个发现是行为层面的:模型偏爱召回而非精度。面对不确定性,智能体会检索更多文件、更多符号、更多历史。多出来的每一段内容单看都很安全,累积起来却有腐蚀性——模型的注意力预算有限,每一个无关 token 都在与相关 token 竞争。检索得越多,引入的噪声就越多,而正是这些噪声把一次自信的修改变成一次看起来合理的错误。

# budget.py - the context window is a budget with a ceiling
TOKEN_BUDGET = {
    "system":    800,
    "task":      600,
    "code":      6000,   # the part that actually fixes the bug
    "examples":  1200,
    "reserve":   800,    # room for the model to reason
}

def fits(section_tokens):
    return sum(section_tokens.values()) <= 9000

def enforce(chunks, cap):
    kept, used = [], 0
    for c in chunks:                 # already sorted by relevance
        if used + c.tokens > cap:
            break
        kept.append(c); used += c.tokens
    return kept

三、检索到 ≠ 用得上

第二个发现最容易被团队低估:智能体常常检视了正确的代码,却没能把它用上。一个文件可以读进上下文窗口,却依然被最终 diff 忽略,因为模型从未把它和正在做的修改关联起来。这也是为什么通过率基准看起来还行、底层检索却已悄悄坏掉:检索失败与利用失败这两类不同的失败,被扔进了同一个桶里。

# filter.py - drop chunks that fail a relevance floor
MIN_RELEVANCE = 0.35

def relevance_filter(chunks, floor=MIN_RELEVANCE):
    return [c for c in chunks if c.score >= floor]

# ContextBench lesson: retrieved is not utilised.
# A chunk that scores below the floor is not context, it is noise,
# and it will compete for attention with the chunk that matters.
检索到,不等于用得上

检索到,不等于用得上

四、上下文预算是设计约束

实用结论是:把上下文窗口当成有硬顶的预算,而不是随便填的桶。一个常见的生产模式照着论文的教训来:先用较宽的 k 过度检索,再重排收敛到一个很小的最终集合。代码示例 1 用 k=40 生成候选,再重排到前 8 条——把廉价的召回收益收下,同时让重排器而不是模型来支付精度的代价。

# rerank.py - a small model that decides what the big model sees
def rerank(query, candidates, cross_encoder, top_k=8):
    pairs = [(query, c.text) for c in candidates]
    scores = cross_encoder.predict(pairs)          # one forward pass per pair
    ordered = sorted(zip(candidates, scores),
                     key=lambda pair: pair[1], reverse=True)
    return [c for c, s in ordered[:top_k]]

五、一条可落地的上下文流水线

把它拆成五个显式阶段:先规划任务需要哪些信息,再宽口径检索,然后按与本次修改的相关性重排,接着在 token 预算内组装,最后校验你留下的内容是否真的被改动引用。代码示例 2 让预算保持诚实;代码示例 3 丢弃未过相关性门槛的片段;代码示例 4 展示重排步骤;代码示例 5 把整条链路变成可度量的评估,而不是凭感觉。

# eval.py - does the context pipeline actually help?
def context_eval(runs):
    retrieved, used, cost = 0, 0, 0
    for r in runs:
        retrieved += r["chunks_retrieved"]
        used      += r["chunks_in_final_diff"]
        cost      += r["prompt_tokens"]
    return {
        "utilisation_rate": used / max(retrieved, 1),   # the number to track
        "avg_prompt_tokens": cost / max(len(runs), 1),
        "pass_at_1": sum(r["tests_pass"] for r in runs) / max(len(runs), 1),
    }

六、度量你自己的上下文

别迷信基准,复制它的方法。为每次智能体运行记录:检索了多少片段、过了重排还剩多少、最终 diff 里出现了多少、花了多少 token。被使用的片段与检索到的片段之比,才是预测质量的数字,也几乎没人跟踪它。一旦看见它,上下文工程就不再是提示词小把戏,而变成普通的系统工程。

七、窗口再大也修不好

百万 token 的上下文窗口会诱出这门手艺里最贵的错误:把整个仓库倒进去,指望注意力自己理出头绪。它不会。注意力是有限且近似零和的资源,你加进去的每个 token 都在和真正要紧的那个 token 抢位置;而模型「找到相关文本」的能力,明显强于「忽略无关文本」的能力。正是这种不对称,让均衡的检索策略在容量充裕时依然在基准中取胜。窗口是天花板,不是策略。把容量当成「可以检索得更好」的许可,而不是「可以全都检索」的借口。

八、上线前清单

编码智能体上线前有五项检查。一:每一段被检索的内容都有存在的理由,还是只是习惯?二:检索窗口是按度量定的,还是按模型上限定的?三:你有没有记录多少片段过了重排、多少出现在最终 diff 里?四:你的评估量的是利用率,还是只看通过率?五:当一次运行失败时,你能分辨是检索失败还是利用失败吗?这五问答上了,你拥有的是一条上下文流水线,而不是一段偶尔管用的提示词;答不上,你拥有的是一个连失败都解释不清的系统。

先重排,再为 token 买单

先重排,再为 token 买单

📌 常见问题 FAQ

ContextBench 是什么?

一个面向编码智能体上下文检索的基准,由南京大学与伦敦大学学院于 2026 年 2 月 11 日提交,覆盖 66 个仓库上的 1,136 个任务。

它的核心结论是什么?

模型重召回轻精度;检索到的上下文常常没被用上;更均衡的检索策略以更低成本取得更强的 Pass@1。

「检索到 ≠ 用得上」是什么意思?

智能体常常在检索时找到了正确代码,却没把它并入最终修改,因此单看检索准确率并不能预测成功。

检索窗口该开多大?

常见生产做法是先用 20 到 40 的 k 过度检索,再重排收敛到前 8 条左右,收下召回收益、控制精度代价。

上下文工程就是提示词工程吗?

不是。提示词工程雕琢指令;上下文工程决定模型每次调用看到哪些信息,这是系统问题,而不是措辞问题。