> 只活在 prompt 里的规则,会在模型状态不好的那一周失效——而那正是它最该生效的一周

Systems & Infrastructure Intermediate 2026-10-12 04:23 2026-10-12
#llm #prompt-engineering #validation #guardrails #tooling #reporting

一个把每周工作汇总印成一页纸的工具,整页里只有一节是模型写的。 围着那一节有四层约束,每一层都在代码里,不在 prompt 里:

结论先行

一个把每周工作汇总印成一页纸的工具,整页里只有一节是模型写的。 围着那一节有四层约束,每一层都在代码里,不在 prompt 里:

① 配额在代码里强制执行,不只是在 prompt 里要求。

BRIEF_QUOTA = {"+": 2, "-": 1, "!": 1}
...
# The quota is enforced here as well as asked for in the prompt. A rule
# that only lives in a prompt is a rule that holds until the week the
# model is having an off day, which is exactly the week it matters.
if used[kind] >= BRIEF_QUOTA[kind] or len(lines) >= max_lines:
    over_quota.append(f"{kind}{name}")
    continue

配额是语义的,不是总数的:最多 2 条"有进展"、1 条"被推翻"、1 条"该停"。 不是要求凑满,是防止顺风周四行全是"项目 X 有进展", 把"某个假设被证伪"挤出去。

② 名字必须出现在确定性扫描里,否则整行丢弃。

known = {p["dir_name"] for p in evidence["projects"]}
if name not in known:
    dropped.append(name or "<unnamed>")
    continue

③ 模型看不到原始材料。 采集脚本完全不调用模型,只输出 commit hash、 文件路径+字节数、脏文件计数;摘要脚本只能看见采集脚本的输出 —— 不能读仓库、不能跑 git。

④ 模型不可用(配额、网络、超时)时这一节消失,其余照印。

一句话:模型负责压缩,不负责观察。

为什么

prompt 里的约束和代码里的约束,在"一切正常时"行为相同, 在模型状态不好时正好相反:

prompt 里的规则 代码里的规则
模型表现好 生效 生效
模型表现差 失效 生效
模型不可达 无意义 生效(整节消失)

而你需要约束的,正是第二行。一个只写在 prompt 里的"最多四条", 在模型想输出八条的那一周会输出八条 —— 那一周恰好也是输出最不可信、 最该被裁剪的一周。约束的价值全部集中在它被违反的那些场合, 而 prompt 在那些场合的执行力最弱。

第 ③ 层比前两层更根本。它改的不是输出检查,是模型能看见什么。 让摘要脚本无法读仓库、无法跑 git,意味着它说出的任何项目名 都只能来自采集结果;第 ② 层的白名单检查因此能真的判死 —— 如果模型能自己去读目录,"名字不在扫描里"就只是"扫描漏了"的同义词, 白名单会退化成噪声过滤器。

这套结构防的是一个很具体的风险:

如果小票上印的是模型编的话,它比没有日志更糟 —— 它是会被信任的假记忆。

所以硬约束是每一条印出来的句子旁边必须有可核验的锚点。 顺带还有一条排版上的决定:模型被告知表头已经印了哪些数 (提交数、focus%、空转数、了结数),不许复述 —— 它只该说表格说不出来的:学到了什么、什么被推翻了、什么该停。

怎么用

凡是 prompt 里的"必须/最多/只能",在代码里再写一遍。 不是冗余,是把规则从"请求"升级成"不变量"。 写完之后,故意喂一个违反规则的模型输出,看代码那一层是否拦住。 拦不住就说明规则仍然只活在 prompt 里。

配额要按类别分,不要只限总数。 max_lines=4 和 {"+": 2, "-": 1, "!": 1} 在正常周完全一样,在顺风周完全不同 —— 后者保证坏消息有位置。任何"取 top-k"的汇总都适用: k 个名额按来源分配,比按分数排序更能保住少数类。

在代码里统计"被丢掉的",并打到 stderr。 丢弃是静默的, 而丢弃率上升是模型变差的早期信号。这个项目丢弃时记 dropped / over_quota 两个列表。只拦不报,等于把一个可观测量扔了。

降级要让整节消失,不要让它变模糊。 模型不可用时印出 "本周结论:(不可用)",比直接不印这一节更糟 —— 读者会以为没有结论。 整节消失加上其余照印,是一个在产物上可见的降级 (见 优雅降级设计好了,却没人被告知——退化必须在产物上留痕)。

不要为了第五行牺牲一条确定的行。 超页裁剪时先裁模型那一节: 截止数据是确定的、可操作的、时间敏感的,第五条模型摘要按定义 是第五重要的事。排序上也一样:结论 → 建议 → 支撑数据, 命令在上,证据在下。

这一层和"审自己的判分器"是一套。 模型做观察者时它的错误无法被检出;做压缩器时它的每句话都有一个 可核验的锚点 —— 同 把失败归因给模型之前,先审 verifier——41% 的"模型错误"其实是判分 bug、 随机占位决策器读起来像一个很弱的系统,不像"模型根本没接上"。

出处

~/Engineering/worklog-printer:analyze.py:438-439(BRIEF_QUOTA 与 KIND_ORDER)、:629-644(配额在代码里强制,含那段注释)、 digest.py:125-138(_validate,"Drop anything the scan did not actually see. The core safety property.")、digest.py:11-14(降级非致命)、 README.md §1「唯一的真风险,以及它是怎么被堵住的」与 §2 「第二轮:删掉一个指标,给建议装上依据」。