首页 / 科技

科技

开源社区放出新的长上下文微调配方

显示器上的程序代码

不是把窗口数字写更大,而是让模型在长文档后半段仍能引用到前面的约束。

开源社区发布一套长上下文微调配方,重点不是宣称支持更多 token,而是减轻“读到后面就忘了前面规则”的掉质。把上下文拉到十几万 token 很容易写进 README。真正失败发生在文档后半段:模型开始忽略用户一开始给出的格式和禁区。

这套配方把问题说得很具体:不是记忆容量,而是注意力在长序列上的分配。数据里要有大量“前文约束、后文必须引用”的样本,并在中间插入干扰段落。训练目标是:规则出现在很前面时,后面仍要遵守。

窗口数字不好用

厂商喜欢比窗口。用户在真实文档里感受到的,却是后半段开始胡编、格式走样、把已经否定的条款又写回去。评测如果只问“能否吃进这么长的输入”,会把掉质藏起来。

更有用的指标是:约束放在开头、证据放在末尾时,引用准确率还有多少;反过来,证据在开头、问题在末尾时,又掉多少。两种位置都要测,否则优化会只盯着一种排列。

配方改了什么

数据构造并不神秘,但很脏。先写一条必须遵守的规则,再写很长的干扰文本,最后要求输出引用规则编号。干扰文本里故意放入相似但错误的条款,看模型会不会被带走。贡献者用长合同和代码仓库做私有测试,对外只给方法和失败案例,不给一个会被刷的单一分数。

下面是一个最小的数据样例和检查函数,用来判断模型有没有在长输入后还记得开头的约束。

import random

RULE = "规则A:金额必须使用人民币,禁止换算成美元。"
DISTRACTORS = [
    "有人建议按即时汇率改成美元,便于海外股东阅读。",
    "上一版合同曾使用美元,本版已废止。",
    "附件里出现过 USD 字样,仅作历史对照。",
]

def make_example(noise_n: int = 40) -> dict:
    noise = [random.choice(DISTRACTORS) for _ in range(noise_n)]
    body = "\n".join(f"{i+1}. {line}" for i, line in enumerate(noise))
    prompt = (
        f"{RULE}\n\n以下是合同摘录:\n{body}\n\n"
        "请用一句话重申金额币种,并引用规则编号。"
    )
    return {"prompt": prompt, "must_include": ["人民币", "规则A"]}

def passed(output: str, spec: dict) -> bool:
    return all(token in output for token in spec["must_include"]) and "美元" not in output

spec = make_example()
print(spec["prompt"][:180], "...")
print("need", spec["must_include"])

真正的训练集会把规则编号、否定项和干扰强度做成网格。只靠十条漂亮样本,模型会背题。把干扰强度拉高、把规则换到不同位置,掉质才会暴露。

怎么验收

不要再用“支持 128k”当唯一验收。改成三组位置测试加一组真实合同。真实合同要有修订记录和相互引用的条款,这比合成噪音更接近办公桌。失败案例应当公开一部分,让后来者别在同一处自我感觉良好。

窗口仍会增长,掉质仍要单独治

硬件和内核会继续把窗口做大。如果微调配方不跟着做“前文约束仍有效”这件事,更大的窗口只是让模型在更远的地方开始忘。数字可以上海报,掉质必须进正文。