2932 字
约 9 分钟
15
S24-B06 · 上下文工程入门:给模型什么、不给什么

同一个 OrderService,问"这里有什么问题",答"整体结构清晰,建议补充注释";换成"用户重复提交订单时库存被扣两次,找出原因并给出最小改动",答案直接落在 deduct 的非幂等调用上。模型、温度、代码全都没变,变的只是上下文。所谓上下文工程,就是把这种"碰运气"做成可重复的动作:决定放什么、放多少、放在哪。


1. 先从一次失败的提问看起

❌ 我的 Spring 服务下单有问题,帮我看下
(附:OrderService.java 全文 800 行 + tail -n 2000 的日志)
✅ 目标:修掉重复下单导致的重复扣库存
现象:同一 orderNo 下 stock 被扣两次,两次 deduct 间隔 12ms
约束:只能改 OrderService 与 StockClient 调用处;不改表结构;不加新依赖
相关代码:OrderService#create(第 40-95 行)、StockClient#deduct
验收:并发 20 请求同一 orderNo,库存只减 1;现有 OrderServiceTest 全绿
变量 第一次 第二次 差异来自
模型/温度 相同 相同 不是这里
代码量 800 行整文件 两个类、两个方法 相关面
目标 "有问题" "重复扣库存" 可判定性
约束 无 三条硬边界 搜索空间
验收 无 可观测断言 能否自检

答案质量的差别几乎全部由后三行决定。前两行是你最容易改、也最没用力的地方。

2. 窗口里真正占用的是什么

组成 典型占比 特点 变质速度
系统提示 / 规则 固定,常被低估 每轮都在,最稳定 慢
对话历史 随轮次线性增长 含大量已解决的问题 快
工具结果 / 日志 单次就可能上万 token 原文噪声最密 极快
文件内容 由你挑选 决定"看得见什么" 手动
当前提问 往往最少 决定"看哪里" 无

"装得下"和"看懂"是两件事:窗口是注意力预算,不是硬盘。放在第三万 token 处的一句"不要改其他文件",与贴在提问正上方的一句,生效概率差别很大。判据因此不是"塞不塞得进去",而是"这一步是否真的需要它"。

3. 该给的五类,不该给的三类

该给的 具体写什么 反例
目标 一句话说清修什么、加什么 "优化一下"
约束 不能改的、不能加的、必须保持的 只说"注意兼容"
相关代码 唯一的那条调用链与数据流 整个仓库、整个文件
错误信息 完整堆栈 + 触发输入 + 版本 截图里半行报错
验收标准 能跑出真/假的断言或命令 "看着对就行"
不该给的 为什么 替代做法
无关文件 稀释注意力,诱导跨文件乱改 只贴被调用到的类
整份日志 99% 是噪声,定位成本转给模型 先 grep 出 20 行关键行
闲聊历史 旧结论会盖住新事实 摘要成三行"已确认事实"

4. "给多少"的判据:删掉它,行为会变吗

最小化不是删到最短,而是删到行为不变。把上下文当实验变量:

1. 固定任务与问法,跑一次基线,保存输出
2. 只删掉一块(一个文件 / 一段历史 / 一条日志)
3. 用同一问法重跑,比对新旧输出
   输出不变 → 噪声,永久删掉
   输出变差 → 必要信息,保留并注明为什么
   输出变好 → 干扰项,删掉并记进"曾经害过我"清单
4. 对每块重复,最后得到最小充分集

判据只有这一条:删掉后行为是否变化。凭"这个可能有用"做加法,结果必然是越堆越多、越堆越糊。

5. 位置效应:关键约束放前面还是后面

位置 适合放什么 原因
最前(规则/开场) 角色、不可违反的硬约束 每轮复述,衰减最慢
任务描述里 目标、验收标准 与"这一步做什么"绑定
代码之后 具体到行的指认 刚看完代码,指认有落点
最后一句 输出格式、"只改这一个方法" 紧邻生成,指令权重最高

实践口诀:硬约束放最前,格式要求放最后,具体指认贴着代码。把"不要改其他文件"埋在中间段落,多半会被静默丢弃。

6. 格式的影响:结构化段落 vs 大段代码块

❌ 贴 300 行代码,末尾一句"看下哪里有问题"
→ 典型输出:一段综述,"建议加强幂等设计",指不到行

✅ 结构化字段 + 小片段
【位置】OrderService.java:78 create()
【现状】先 orderMapper.insert,再 stockClient.deduct
【问题】insert 成功后 deduct 超时重试,deduct 会再执行一次
【片段】
  orderMapper.insert(order);
  stockClient.deduct(item.getSku(), item.getQty());
【期望】同一 orderNo 只扣一次
格式 适用 成本
结构化字段(位置/现状/问题/期望) 定位类问题 写的人多花一分钟
小代码块(<40 行,带行号) 语法与逻辑细节 需要先裁剪
整文件代码块 只适合"通读并总结" 注意力被摊薄
截图 几乎不用 不可搜索、不可复制、行号错位

7. 文件怎么选:三条可执行路径

路径 做法 依据
按报错堆栈 堆栈里每个类名都是一个候选文件 at com.x.OrderService.create(OrderService.java:78)
按 import 关系 从入口类向外一跳就停 grep -rn "import .*StockClient" src/
按目录约定 controller→service→mapper 顺着走 ls src/main/java/com/x/{controller,service,mapper}
# 从一次报错反推文件清单
grep -oE '\(([A-Za-z0-9_]+\.java):[0-9]+\)' err.log \
  | sed -E 's/[()]//g; s/:[0-9]+//' | sort -u
# 输出就是该贴的文件名,通常 2-5 个

优先顺序:堆栈 > import > 目录。堆栈是运行时给的证据,目录只是人的想象。

8. 长历史怎么压缩

【已确认事实】(只写被验证过的)
- 重复扣库存发生在 deduct 重试路径,orderNo 未做幂等
- StockClient#deduct 不能改签名(下游三个服务共用)

【已排除】
- 不是唯一索引问题(orderNo 有唯一约束,但 insert 先成功)

【待办】
- deduct 前用 Redis SETNX(orderNo) 占位一次

规则是留结论、丢过程。"我试了 A 不行,又试了 B 不行"对下一步没有信息量;"B 不行,因为 X"是结论,必须留。压缩完最好换一轮新会话,把摘要当天花板重新开始。

9. 四类噪声

噪声 表现 处理
重复信息 同一段代码在历史里出现三次 只留最后一次,注明"以此为准"
过期结论 上一轮判断已被推翻 显式标"已废弃",别让模型猜
矛盾指示 前面说可改表,后面说不许改表 合并成一条并写优先级
无关背景 顺带提的业务沿革 删

矛盾指示最贵:模型不会报错,它会自己挑一个,而你不知道它挑了哪个。

10. 一次只改一个变量

调上下文和调代码一样,同时改三处就分不清是谁起的作用:

第 1 轮:只改目标("有问题" → "重复扣库存")
第 2 轮:只改范围(整文件 → 两个方法)
第 3 轮:只改格式(大段代码 → 结构化字段)
第 4 轮:只改位置(约束从中间挪到最前)
每轮固定同一问法、同一模型、同一温度,逐轮记录输出

11. 最小示例:同一个 bug,三种上下文

L1(差)我的下单接口有问题,帮我看看。
→ 输出:泛泛的"建议加分布式锁、加幂等表",没有指认位置
L2(中)这个 create 会重复扣库存,帮我看下。
(附 OrderService 整文件 300 行)
→ 输出:指到 deduct 可能重试,但建议改 StockClient 签名——违反你的约束
L3(好)目标:同一 orderNo 只扣一次库存。
约束:不改 StockClient 签名,不改表结构,不加新依赖。
代码:OrderService.java:40-95 + StockClient#deduct(共约 30 行)
错误:deduct 超时后重试,两次间隔 12ms
验收:并发 20 请求同 orderNo,库存只减 1。
只改 create 方法,输出 diff。
→ 输出:SETNX 占位 + 失败释放的 diff,范围正确

三级差别不在模型,而在四件事:目标可判定、约束显式、范围收敛、验收可跑。

12. 排错

现象 原因 处理
答案笼统,全是"建议" 目标不可判定 改写成能跑出真假的断言
改了不该改的文件 没有显式范围约束 加"只改 X,其他文件不动"
指的行号对不上 贴的是旧版本代码 贴前记 git rev-parse --short HEAD
反复推荐已排除的方案 排除结论没进上下文 写"已排除:A,因为 B"
长会话后期答非所问 关键约束被历史挤淡 压成摘要,重开一轮
贴截图后还被问"代码在哪" 图像文字不可靠 换成文本代码块
粘贴后缩进错乱 混了 tab 与空格、中文全角 统一 4 空格,先跑一次格式化

13. 边界

情况 更合适的做法
需要理解整个仓库结构 先产出目录级地图,再按图取文件
改动横跨 10 个以上文件 拆成多个单一目标的会话
需要精确行号与语法检查 用 IDE / 编译器,不用对话
判断"这段代码对不对" 写测试,让测试给结论
需求本身还没定 先定需求,上下文工程救不了模糊需求

一句话:上下文工程管的是信息的选择与摆放,管不了需求没想清楚这件事。

14. 自测

  1. 为什么"装得下"和"看得懂"是两件事?
  2. 判断某块上下文该不该删,唯一的判据是什么?
  3. 硬约束应该放在上下文的什么位置,为什么?
  4. 堆栈、import 关系、目录约定,三者优先用哪个?
  5. 长历史压缩时,什么该留、什么该丢?
  6. 同一段代码三次问答结果不同,你会先固定哪个变量?
S24-B06 · 上下文工程入门:给模型什么、不给什么
https://www.clxhxhhr.top/posts/6136/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。