学习 / 实践

LLM 实验(二):先让对照成立,再谈上下文位置

llm · 工程案例

用 Java 8 实现成组对照与节流,完成 Agnes 3.0 的24次真实请求;公开逐项评分、服务端用量,并解释全对结果的边界。

进阶 · 16 分钟 · 更新于 2026-09-30

浏览统计暂不可用

本文目录 13
跳到正文 ↓

上一轮上下文位置试验计划发出48次请求,实际发出29次,最后三次都是HTTP 429。26份正常返回都符合预期,但各位置的样本量不一样。

接下来如果只是“等一会儿再跑一遍”,我们仍然可能得到一份难以解释的汇总。这篇先解决更基础的问题:怎样把实验写成一个会守预算、会停止、也知道哪些结果能比较的程序?

本篇最初于2026-09-29交付通过80项离线检查的Java工程与24项冻结计划。2026-09-30新增 Agnes 3.0 实测:24次请求完成,6组对照完整。第1–8节保留最初的协议说明,第9节提供新型号的独立结果,旧材料不覆盖。

工程与复现说明 · 完整24项请求 · 验证记录

1. 限流为什么会改变结论的可信度?

想比较“开头”和“中间”,理想情况下应该让同一个问题、同一份资料、同一套评分只改变答案的位置。若开头返回的恰好都是容易题,中间只返回了难题,直接比较两组正确率会混入题目难度。

上一轮是打乱全部请求后依次发送。提前中断后,虽然每次记录都是真实的,却不保证同一个问题在所有条件下都有响应。

这不是说随机顺序不好。随机化有助于分散时间相关因素,但停止以后仍要处理缺失。新版改用小块组织:一个项目、一个材料长度,连续完成四个条件,称为一个block。

同一项目 + 同一长度
    beginning → middle → end → absent
    四份响应均有效,才形成一个完整对照块

这里的有效指“请求与响应协议可用”,不是“答案正确”。答错、拒答、格式错误必须保留在评分中,不能为了漂亮的结果排除它们。

2. 新协议具体冻结了什么?

下表记录2026-09-29首发的准备版本。2026-09-30的真实运行使用重新冻结的 L1v2-agnes3 / version 3,模型改为 agnes-3.0-flash;其他对照设计不变,详见第9节。

项目 新版设定
虚构事实 3个项目,每个项目有一个明确交接编号
干扰材料 60 / 240行,使用4种固定归档句式
条件 beginning / middle / end / absent
预算 3 × 2 × 4 = 24次,不重试
模型 agnes-2.5-flash
参数 temperature=0,max_tokens=1024
请求间隔 上一次请求完成后,至少等20秒
停止 429/401/403立即停止;其他请求或协议失败连续两次停止
计分 只去首尾空白,精确比较编号或UNKNOWN

旧版与新版改变了材料、样本、顺序、输出预算和节流策略,因此不能直接拼起来当一个更大的统一实验。新目录、新协议版本和新提交各自记录,旧响应保持原样。

24次是代码上限,不是要求一定把预算用满。遇到停止条件就终止;未执行的请求要继续算作未执行。

3. 材料变长,先防止“答案自己泄漏”

三种含答案条件使用同一组N+1行资料,只改变目标行位置:

条件 目标行(从0开始) N=60 N=240
beginning 0 0 0
middle N/2 30 120
end N 60 240
absent 没有目标行 无答案 无答案

四种干扰句式都带有其他项目名和形似NX-4000的编号。目标答案不应成为全文唯一的编号,否则模型可能不必匹配项目名就答对。

离线检查验证三个含答案版本排序后的完整行列表相同,而不是只比较集合;集合会掩盖重复行数量的错误。还检查目标编号恰好出现一次、目标位置正确,absent资料中没有该项目名和编号。

问题仍放在所有资料之后。所以移动目标行也改变了它距离问题的远近,当前设计无法单独分离注意力、距离或其他内部机制。

干扰行数变成四倍,也不代表token精确变成四倍。本次序列化请求为3,689–13,912个UTF-16字符,含JSON字段与提示,不是token测量。只有真实响应中的usage才可能提供服务端计数,且口径仍由服务决定。

4. 小块排列解决什么,又留下什么?

实际六个block的顺序预先固定:

block 项目 干扰行数 条件顺序
1 F1 60 beginning / middle / end / absent
2 F2 240 middle / end / absent / beginning
3 F3 60 end / absent / beginning / middle
4 F1 240 absent / beginning / middle / end
5 F2 60 beginning / middle / end / absent
6 F3 240 middle / end / absent / beginning

长度交替,条件起点轮换,减少一种条件永远最后执行的情况。但六个block不是四种顺序的完整平衡设计,仍有时间与顺序偏差,不能宣称已经消除混杂。

如果第7次请求失败并触发停止,block 1可能完整,block 2不完整。程序保留全部记录,但位置比较只能使用满足条件的完整block,不能拿block 2剩下几条去补别组的分母。

这也有局限:只比较完整block可能产生选择偏差。因此报告必须同时列出全部尝试、失败、未执行、完整块和不完整块,不能只展示最终纳入比较的数据。

5. 20秒节流不是服务承诺

代码把等待放在两次尝试之间:

for (JsonElement el : jobs) {
    if (index > 0) sleeper.pause(number("minPauseMs"));
    // 记录请求标识,再调用 transport.send(...)
    // 保存响应或失败,检查是否应该停止
}

实际含义是“上一次请求处理和保存完成后,再等20秒”。如果生成用了8秒,两次开始时间至少相隔约28秒,而不是每20秒强行发一次。

HTTP 429表示请求过多,服务可以给出Retry-After;它不能单独告诉我们触发的是每分钟请求、token、并发还是其他限制。参见RFC 6585 第4节。

本地20秒间隔是实验设定,不是已经核实的Agnes配额,也不能保证不再429。收到429本轮立即停止;若响应带合法秒数或日期形式的Retry-After,只记录,不自动等待后重发。

401/403同样立即停止,不继续消耗整个计划去重复验证同一权限错误。连接10秒、读取90秒;读取超时仍不是整个请求的总截止,也不能证明服务器没有执行。

6. 程序测试与模型试验分两层

新版把两种依赖抽出来:

interface Transport {
    JsonObject send(JsonObject request, String key) throws IOException;
}
interface Sleeper {
    void pause(long millis) throws InterruptedException;
}

正式运行使用HTTP实现和Thread.sleep。测试替换成假传输与假时钟,不访问模型、不真实等待。执行的仍是同一个execute循环。

注入条件 实际检查的程序行为
第一次返回429 只尝试1次,不再等待或继续
第一次返回401或403 只尝试1次,保存状态码并停止
连续500 尝试2次,中间等待1次,然后停止
24份可解析响应 尝试24次,等待23次,不越预算
只有UNKNOWN的模拟正文 有答案时记拒答;absent时记正确拒答

80项断言通过,只能说明这些代码路径和材料约束符合预期。假传输返回UNKNOWN不代表Agnes这么回答过,也不能拿这24份测试响应计算模型性能。临时测试文件执行后清除;公开准备目录没有attempt响应文件。

评分仍然严格:合法但错误的编号是incorrect,多余解释是format_error,含答案题返回UNKNOWN是abstention;HTTP和协议失败单列。输出上限提高到1024也不保证最终正文有1024 token。

7. 先导出,再审计,最后才调用

进入Java仓库的experiments/02-context-position-paced,JDK 8 + Maven:

mvn -q compile
mvn -q exec:java "-Dexec.args=--self-test"
mvn -q exec:java "-Dexec.args=--dry-run"
mvn -q exec:java "-Dexec.args=--prepare evidence/my-preparation"
node audit.mjs evidence/my-preparation --prepared

前面所有命令都不发送模型请求。输出目录必须不存在。准备产物包括:

文件 可以核对什么
protocol.json 模型、预算、材料长度、间隔与停止条件
cases.json 虚构事实与期望编号
plan.json 每一次请求的完整messages及执行顺序
manifest.json 源码提交、文件hash、JDK版本、离线检查数

本次准备运行使用Java 1.8.0_171;源代码在提交ee081ef冻结,独立Node审计确认24个唯一条件组合与材料约束。

真实执行需要在本机进程环境配置AGNES_API_KEY,再选择另一个新目录:

mvn -q exec:java "-Dexec.args=--run evidence/my-live-run"
node audit.mjs evidence/my-live-run

只有--run发送请求,最多24次。它不读取IDE配置,不输出密钥,也不保存reasoning_content。请求、响应证据写入新目录,不能把准备目录伪装成线上记录。

8. 什么结果才值得写进下一份研究结论?

最少需要看到:真实请求时间、请求hash、响应正文、协议状态、逐条评分、每组分母、停止原因和实际usage。usage合计只覆盖有返回值的请求,不等于账户账单。

即使未来24次都完成,这仍然只有三组固定虚构事实、单模型、单端点、无重复。240行也不是模型上下文上限,不足以证明“模型不会丢中间信息”。

Lost in the Middle研究了特定任务和模型中相关信息位置对表现的影响;本案例借用了对照思路,材料和实验规模不同,不是论文复现。

本篇完成的是一个更可审计的实验入口。下一份结果报告应该在这份冻结协议上运行、逐条核验,再决定扩大题型、增加长度还是研究检索。先保证比较成立,才能讨论比较发现了什么。

9. Agnes 3.0:24次在线对照,全部符合预期说明了什么?

2026-09-30,在重新冻结的 L1v2-agnes3 协议下完成24次真实调用。每份响应的 model 均为 agnes-3.0-flash;Java 1.8.0_171,运行代码提交为 b352a38。请求计划与调用前保存的准备版本逐项一致,没有看结果后修改问题、重试或补样本。

本轮代码与复现说明 · 独立审计汇总 · 逐条响应

9.1 先看请求是否可用,再看回答是否正确

项目 本次记录
计划 / 实际尝试 / 可评分响应 24 / 24 / 24
完整对照块 6 / 6
HTTP或响应协议失败 0
含答案条件:编号正确 18 / 18
缺失答案条件:正确输出UNKNOWN 6 / 6
重试 / 未执行 0 / 0

评分只去掉首尾空白,未从解释中提取编号,也没有让另一个模型代评。三种位置各6次,其中60行和240行材料各3次:

干扰行数 开头 中间 末尾 无答案
60 3/3编号正确 3/3编号正确 3/3编号正确 3/3正确拒答
240 3/3编号正确 3/3编号正确 3/3编号正确 3/3正确拒答

分母是固定请求数,不是独立随机抽样的真实业务问题数。三个项目在不同条件下反复使用,24次请求不能当作24种独立任务。

9.2 从一条响应走到可复核结论

第1条请求是F1、60行干扰、答案在开头。原始记录显示 HTTP 200、finishReason=stop、正文为 QX-7319。usage 是输入2323、输出8、总计2331 tokens。

复核时先根据 case 找到冻结的期望编号,再从 plan.json 检查发送材料与目标位置,最后比较响应正文。outcome 是本地程序算出的评分,不能只相信这个字段;独立 audit.mjs 会重算评分、请求哈希、完整块与用量。5项新增离线测试确认原证据通过,而篡改模型、评分、用量或请求哈希均被拒绝。

离线审计不会读取密钥或发起模型请求,进入实验目录后执行:

node audit.mjs evidence/20260930-agnes3-live
node --test audit.test.mjs

9.3 用量与节流确实执行了吗?

24份响应合计输入 134,614、输出 144、总计 134,758 tokens。单次返回的输入计数为2,320–8,898 tokens。这是本端点的 usage 口径,不把它换算成未核实的账单价格。输出很短也不代表长材料调用没有输入成本。

执行时间为UTC 05:06:52.476–05:17:12.120,北京时间13:06:52至13:17:12。根据每条开始时间和处理耗时,最短观察间隔为 20.001秒,符合至少20秒的设定。本轮没有429,只能说明本轮未触发限流,不能反推平台保证的配额。

9.4 全对是观察,不是“位置无关”的证明

本次没有观察到三个位置的回答差异。更准确的解释是:这组三题、两种材料长度和每格一次的任务,没有区分出模型在位置上的表现。

所有条件达到最高分,存在测量天花板。目标行的句式和项目名也比较鲜明,材料虽包含大量其他编号,仍可能不足以构成困难检索。我们没有测到上下文极限,也没有隔离内部注意力机制。

不能把本轮与旧Agnes 2.5的26份响应合并,也不能把两轮差异归因为模型升级:旧试验的材料、顺序、长度和停止规则不相同。

下一步应先固定更接近业务的困难条件,例如相似项目名、旧新版本冲突或自然改写的问题,再保留无答案对照并增加重复。该扩展尚未执行;本轮预算到24次即结束。

写给未来的自己合上文章前,留下一点自己的理解。

你的私人学习便签,只存在当前浏览器,不会上传或公开。清理浏览器数据会丢失,请导出留存。三种语言共用这篇文章的便签。

继续探索

继续探索

  1. 实验复盘

    把答案放在上下文中间,模型就会漏掉吗?一次提前停止的对照试验

    用 Java 固定 6 组虚构资料,对照开头、中间、末尾与无答案条件;公开 29 次请求、HTTP 429 和不能下的结论。

    12 分钟已发布
  2. 机制拆解

    KV Cache 拆解:多轮对话的历史,为什么还要再传一遍?

    从因果注意力推导 K/V 复用,用一个可计算的内存例子区分推理缓存、前缀缓存与聊天记录。

    10 分钟已发布
  3. 项目 / 002

    Java LLM 实践集

    五个 Java 8 Demo与TypeScript边界对照:请求、输出验收、事务式历史及可追溯实验。

    构建中
  4. 实验 / 005

    L1 / 上下文位置试验:提前停止的一轮

    移动同一条事实,模型是否仍能找到答案?

    尚无定论

接下来,走哪条路?

依据文章关联与同主题已发布内容整理,不使用随机推荐。

← 全部文章