
周一打开故障群,发现一个支付失败的工单上已经堆了三次重试。最初的提示词早就没了,取而代之的是午饭前同事随手敲的一行字。没人说得清第一次调用用了哪个工具 schema,也没人知道第二次调用有没有改过 system prompt。共享模型的调用记录里还挂着这笔费用,但 wiki 上根本找不到谁该为这串调用负责。
这个缺失的记录才是值得修的 bug,而且不用跟人争这周哪个模型更聪明。重试把失败的提示词覆盖掉,就把工单唯一剩下的输入证据销毁了。你需要的是一个 wiki 交接流程:冻结提示词、明确角色、在下一页存在之前阻塞下一次调用。
提示词冻结是一个小文件,在任何人被允许再次发送相同任务之前必须先写好。它存储提示词的哈希、工具 schema 的哈希、工单 id,以及重试负责人的名字。它不声明模型是否正确,也不替代对 Agent 修复方案的审查。你保存的是产生坏结果或不明确结果的那个输入,这样下一个人调试的是那个输入,而不是被重写过的记忆。
团队跳过这个文件是因为觉得第二次调用比在 wiki 里写一小段快。在共享的免费模型访问上,这个习惯会消耗公共资源池,让下一个 oncall 工程师面对一堆无法 diff 的东西。其实写好一个 wiki 页面加一个本地脚本能检查的 JSON 文件就够了。
即使在小团队里一个人兼任两个角色,你也要在页面顶部列出四个角色。提示词负责人保管冻结的文本,只有他才能通过创建新的冻结 id 来修改它。重试负责人是冻结文件存在之后唯一被允许再次发送任务的人。Schema 负责人确认工具定义与哈希文件匹配,包括参数名和必填字段。
记录员把编号的运行步骤粘贴到工单里,并链接冻结文件,让交接内容可见。这些角色在隐含不明确、每个人都以为别人还保留着原始文本的时候会失效。重试负责人不得在重发任务的同一步骤里编辑提示词。如果提示词负责人想要新指令,他生成下一个冻结 id,重试负责人等待检查通过后再行动。
保持运行步骤足够短,能粘贴到工单下方,长注释链接到底部。每个步骤都编号,当某个字段仍然未知时不要跳过。未知字段是停止重发的理由,而不是编造一个看似合理的值的理由。
prompt.txt,包括 system text 和 user text,不要改动任何一个句子。tools.json,并请 schema 负责人在工单里确认这个文件名。freeze.json,包含两个哈希、工单 id 和机器时钟的 UTC 时间戳。把缺失文件视为交接失败,而不是可以从记忆里填补的细节。不要从聊天记录里重建提示词然后把重建的文本称为有效冻结。如果日志查看器已经丢失了文本,就把页面标记为 prompt_unavailable 并拒绝重试。等有人从客户端历史或版本控制里恢复文本之后,才能创建新的冻结。
下面的脚本是一个示例,你可以复制到临时仓库在自己的机器上运行。这个示例在本文中没有实际执行过,所以在采用之前应该先用示例文件跑一遍。它不调用模型,也不是生产变更的安全边界或审批系统。
你用原始字节对提示词做哈希,因为一个空格的改动可能改变模型输入,即使文字看起来一样。你用规范化 JSON(键排序后)对 schema 做哈希,这样表面上的重排不会看起来像工具改动。在信任这个脚本之前你应该读懂每个分支,并且把这个辅助脚本放在记录员链接的 wiki 页面旁边。
#!/usr/bin/env python3
"""Example prompt freeze. Not a security boundary."""
import argparse
import hashlib
import json
import sys
from datetime import datetime, timezone
from pathlib import Path def prompt_digest(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def schema_digest(path: Path) -> str: parsed = json.loads(path.read_text(encoding="utf-8")) canonical = json.dumps( parsed, sort_keys=True, separators=(",", ":"), ensure_ascii=False ) return hashlib.sha256(canonical.encode("utf-8")).hexdigest() def write_freeze(prompt: Path, schema: Path, ticket: str, owner: str, out: Path) -> None: record = { "ticket": ticket, "retry_owner": owner, "prompt_sha256": prompt_digest(prompt), "schema_sha256": schema_digest(schema), "frozen_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), "retry_allowed": False, } out.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8") print(f"WROTE {out}") def check_freeze(prompt: Path, schema: Path, freeze: Path) -> int: record = json.loads(freeze.read_text(encoding="utf-8")) ok_prompt = record.get("prompt_sha256") == prompt_digest(prompt) ok_schema = record.get("schema_sha256") == schema_digest(schema) allowed = record.get("retry_allowed") is True if ok_prompt and ok_schema and allowed: print("MATCH") return 0 print("MISMATCH") print(f"prompt_ok={ok_prompt} schema_ok={ok_schema} retry_allowed={allowed}") return 1 def main() -> int: parser = argparse.ArgumentParser(description="Freeze or check an agent prompt.") parser.add_argument("--prompt", required=True, type=Path) parser.add_argument("--schema", required=True, type=Path) parser.add_argument("--ticket", default="unset") parser.add_argument("--retry-owner", default="unset") parser.add_argument("--out", type=Path) parser.add_argument("--check", type=Path) parser.add_argument("--allow-retry", action="store_true") args = parser.parse_args() if args.check: return check_freeze(args.prompt, args.schema, args.check) if args.out is None: print("need --out or --check", file=sys.stderr) return 2 write_freeze(args.prompt, args.schema, args.ticket, args.retry_owner, args.out) if args.allow_retry: record = json.loads(args.out.read_text(encoding="utf-8")) record["retry_allowed"] = True args.out.write_text(json.dumps(record, indent=2) + "\n", encoding="utf-8") print("RETRY_FLAG_SET") return 0 if __name__ == "__main__": raise SystemExit(main())
你先运行写入步骤,只有在 wiki 粘贴实际进入工单之后才设置重试标志。这个标志是 JSON 文件内的团队约定,不是模型客户端的访问控制门。你仍然依赖重试负责人遵守这个标志,这就是为什么页面上要写出角色名称。
python freeze_prompt.py --prompt prompt.txt --schema tools.json \ --ticket CHKT-1842 --retry-owner "sam" --out freeze.json
python freeze_prompt.py --prompt prompt.txt --schema tools.json --check freeze.json
python freeze_prompt.py --prompt prompt.txt --schema tools.json \ --ticket CHKT-1842 --retry-owner "sam" --out freeze.json --allow-retry
python freeze_prompt.py --prompt prompt.txt --schema tools.json --check freeze.json
检查命令应该打印 MISMATCH,直到你创建了包含 allow-retry 标志的新冻结。这个顺序是故意的,因为复制的命令不应该在交接完成前看起来成功。如果两个哈希都匹配且标志为真,脚本打印 MATCH,重试负责人可以发送唯一允许的那次调用。
下面的 JSON 结构是示例布局,不是从实际运行中捕获的,所以你运行脚本时要替换每个字段。你可以从这个小工具文件开始,重排它的键,确认 schema 哈希保持稳定。你不应该让这个辅助脚本指向 YAML 或带注释的 JSON,因为解析器会拒绝文件,交接就会停止。
System: You may call lookup_order only. Do not invent an order status.
User: The checkout ticket says order 1842 failed after payment. Report the tool result only.
{ "name": "lookup_order", "parameters": { "type": "object", "required": ["order_id"], "properties": { "order_id": {"type": "string"} } }
}
{ "ticket": "CHKT-1842", "retry_owner": "sam", "prompt_sha256": "", "schema_sha256": "", "frozen_at": "2026-10-13T15:04:00Z", "retry_allowed": false
}
不要因为恰好有个冻结文件躺在工作目录里就去重发任务。你从表中选一行,并在调用之前把那一行的名称记录到工单里。这个表是交接辅助工具,不是评分模型,它绝不会告诉你"直到日志变绿之前都重试"。
| 你看到的情况 | 冻结状态 | 下一步行动 |
|---|---|---|
| 相同提示词,传输错误,schema 未变 | 哈希匹配且重试标志为真 | 重试负责人发送一次,然后停下来等人工阅读 |
| 自信但调用了错误的工具 | 哈希匹配 | 提示词负责人写一个新的冻结;不要重发相同文本 |
| Schema 文件与任务加载的内容不同 | Schema 哈希不匹配 | Schema 负责人修复文件;没人重试 |
| 无法恢复提示词文本 | 没有冻结 | 记录员标记 prompt_unavailable 并停止 |
| 工单包含敏感信息或未脱敏的客户文本 | 任意 | 停止;脱敏是独立审查,不是重试 |
后来成功并不证明第一个提示词是合理的,尤其是当两次调用之间文本有改动的时候。你用冻结是为了让审查者可以 diff 失败的输入和最终运行的输入。如果这些哈希不同,你面对的是一个新实验,应该标记为新实验。
披露:本文是 MonkeyCode 产品推广的一部分。
MonkeyCode 在提供的素材中提供免费模型访问和免费服务器选项,你可以用来做这个交接。如果该选项在运行时仍然提供,重试负责人可以通过那个免费模型访问发送唯一允许的重发。当这个主机存在时,你可以把冻结脚本放在免费服务器选项上,而不是为了做个哈希去买硬件。除非当前文档明确说明,否则不要在 wiki 里写 token 配额、硬件规格、时长或持久性承诺。
运行手册里的过时数字会训练团队信任产品页面上已经不再展示的预算。你在链接之前确认实时条款,当文档没有公布配额时留空那一行。真正有用的约束是共享资源池,因为一次没有记录的的重试消耗的是其他工单仍然需要的注意力和访问权限。如果需要用的时候免费服务器选项不在,你仍然可以在任何安装了 Python 3 的地方运行脚本。
即使主机只是一台笔记本,在 wiki 页面和冻结文件都存在之前你仍然拒绝重发。产品名称对这个方法来说是可选的,而且如果你删掉所有对它的提及,这个方法仍然应该能工作。如果你想要一个下一步行动,把这个页面加到团队 wiki 并让重试负责人去看检查命令。
除非有新的冻结 id,否则在一次允许的重发之后就停下来,即使输出看起来几乎对了。第二次静默重试就是周一群里堆满三次调用但零个可恢复提示词的原因。当一个缺席的同事能看清谁可以下一步调用、哪些文件他们不能编辑时,这个页面才算完成。
当提示词在内存里构建、从未写入可以哈希的文件时,这个方法会失败。当两个任务共享一个提示词文件,而你在冻结和检查之间覆盖了那个文件时,也会失败。你不应该用哈希作为合规存档、秘密扫描器,或者作为 Agent 修复方案安全合并的证明。已经在其编排器里存储不可变提示词版本的团队可以跳过这个额外仪式,除非重试会丢失那些文本。
当工单包含敏感信息、支付数据或你的政策禁止你发送的文本时,应该跳过任何托管模型路径。冻结脚本仍然可以在脱敏后的本地 fixture 上运行,但重发必须等到有一条你的政策允许的路由。哈希匹配不是把原始客户日志粘贴到模型的许可,不管那个模型是免费还是付费的。你也不应该期望这个页面能抓到一个对有缺陷前提过于快速认同的模型。
冻结只是让那个前提稳定足够长的时间,让人在下一次调用之前读一下那些字。判断权在提示词负责人和检查工具调用的审查者手里,不在哈希本身。如果你的团队抽不出一个命名的重试负责人,就不要假装脚本会替你强制执行交接。