SKILL 31 / SAFETY · DEEP DIVE

「诚实优先」类 Skill

逼它说「不知道」,逼它跑完再说「好了」——而这类 skill 自己是 fail-open 的

2026-10-02 · BigCat

先说件扫兴的事:主角 truth-first 在 Agensi 上确有条目,但搜索引擎把它归到 Addy Osmani 的 agent-skills 名下,而那仓库 25 个 skill 目录里没有它。这正是本期要治的病。下面点名 9 个真实可装 / 可读的条目,给安装命令与第一条能跑的用法,以及最该记住的判据:没有「不知道」这一档的,都是二值,不合格。

同系列 → Skill 21 来源接地与引用可信度 · Skill 7 给 Skill 写 Eval · Skill 27 Hooks 与确定性自动化

// WHY THIS MATTERS

模型有两种谎:编事实(引文、版本号、URL)与编完成(「测试应该过了」)。Skill 21 已把前者交给工具接地,本期专攻后者,外加一件更难的事——把「不知道」变成输出契约里的合法取值。这类 skill 的手艺全在此:不改模型的知识,只改它发言的前置条件。

// 01

它替你干掉什么:把「我觉得好了」变成「闸门没开不许说好了」

论断:这类里真正有用的四个,装法都在一屏之内。先给命令,判据放后半程。
# ① 主角:truth-first(Agensi marketplace 的条目)
npx agensi install truth-first

# ② 官方 marketplace 里最硬的完成门禁(Superpowers 的其中一个 skill)
/plugin install superpowers@claude-plugins-official

# ③ 「先查官方文档再写」与「先找人反驳再做」
npx skills add addyosmani/agent-skills --list   # 先看 25 个目录名
npx skills add addyosmani/agent-skills

# ④ 往 CLAUDE.md 里塞「允许说不知道」那一派
/plugin marketplace add instantX-research/anthropic-anti-hallucinate-skills
/plugin install anti-hallucinate@anthropic-anti-hallucinate-skills

第一条立刻能跑的用法

不用等它自动触发。下次它说出「应该」,把这句贴回去:

你刚说「测试应该过了」。按 verification-before-completion 走:
这句要哪条命令证明?在这一条消息里完整跑一遍,
贴出 exit code 与失败计数,再说结论。

四个分别替你干掉什么、什么时候别装

SEO 站把 truth-first 挂在 Addy Osmani 名下——这就是反例本身。 真去查 addyosmani/agent-skills 的目录,25 个 skill 里没有 truth-first。所以本系列那条规矩在这一期格外要紧:聚合站只能用来发现候选,名字一律以 GitHub 仓库目录或官方 marketplace 页面为准。
// 02

机制:三个设计,没一个是「讲道理」

论断:有效的「诚实优先」skill 都不写「请谨慎」,它们写的是闸门、三态、和一张预先驳回借口的表。

① 闸门函数:声称必须过闸

要说「好了」之前,必须走完: 1 IDENTIFY 哪条命令能证明这句话? 2 RUN 完整跑一遍(新鲜的,不是上次的) 3 READ 读全量输出 · 看 exit code · 数失败条数 4 VERIFY 输出真的支持这句话吗? └ 否 → 带证据说出真实状态 └ 是 → 带证据再说结论 5 ONLY THEN 才允许发言 跳过任一步 = 撒谎,不是验证

这比「请先验证」强在:「发言」本身成了受管动作,于是「太好了!」这类表态也落进门禁——那份 SKILL.md 把表达满意列进了红旗清单。

② 三态分级:二值会把「不知道」挤进「知道」

这是本期最可复用的一条。输出只有「对 / 错」两格时,不确定的东西必须被塞进一格,而模型的默认偏置是「对」。所以认真做的都设了第三格:truth-first 的 Verified / Inferred / Unknown、verify-claim 的 Verified / Refuted / Inconclusive、source-driven-development 的 UNVERIFIED。官方那侧更直白:Reduce hallucinations 第一条基本策略就叫 Allow Claude to say「I don't know」,并给了可直接抄的句子——「If you're unsure about any aspect or if the report lacks necessary information, say『I don't have enough information to confidently assess this.』」(据该页,2026-10)。

③ 借口预防表:预先写下它会说的每句借口

上面两个 skill 都带一张两列表:左列借口,右列驳回。「应该能跑了」→ 去跑。「我很有信心」→ 信心不是证据。「就这一次」→ 没有例外。「换个说法规则就不适用」→ 精神高于字面。「抓文档浪费 token」→ 编错 API 浪费得更多。

为什么非要这么写?因为这类规则最常见的失效不是模型不懂,而是绕过:换措辞、只验一半、「这次特殊」。把绕法写进 skill 等于提前堵住出口——这也是判断它认真与否的最快信号。
// 03

用法与边界:另外五个条目,以及怎么验收

论断:这类不能装三个同款——触发时机与作用面都不同,装重了互相打架。先分清谁管哪段。

五个里只有 anti-hallucinate 给了命令;其余四个是单目录 skill——把仓库里那个目录拷进 ~/.claude/skills/ 或项目 .claude/skills/。

四条判据(用来在上面九个之间取舍)

  1. 反向 eval 才算验收:正向场景谁都能过。要造的是三个证据根本不存在的场景——不存在的文件里的函数、查不到的版本号、在跑不起来的环境里确认测试通过。合格线只有一条:它说「不知道」。按 Skill 7 先跑不装 skill 的 baseline,否则量不出它带来了什么。
  2. 有没有第三格:输出规格里必须有 Unknown / Inconclusive / UNVERIFIED 这一档。只有「已核实」没有「核不了」的是二值,直接淘汰。
  3. 有没有借口预防表与红旗清单:认真做的硬标志(见上节)。只写原则不堵绕法的,第二天就被绕过去。
  4. 触发时机写在哪一侧:读它 frontmatter 的 description:写「在声称完成 / 提交 / 建 PR 之前」的管编完成,写「用户问事实时」的管编事实。别指望一个 skill 全包——该叠的是不同段,不是同款。
一个真实的踩法:truth-first 与 verification-before-completion 一起装,然后抱怨「每句话都要跑命令」。两者都要证据,但一个要的是系统状态(读配置、看日志),一个要的是命令退出码。不在排障就该关掉前者。
// 04

代价与替代品:这类 skill 是 fail-open 的,真门禁不在它这儿

论断:Skill 29 那条「安全类必须 fail-closed」在这里是被违反的——这类 skill 全是提示词,模型可以不听,而不听时没有任何东西会报错。

两笔要先认的账

替代品阶梯:越往下越硬,也越贵

一句 prompt 官方那句「不确定就说不知道」,零成本,只管这一轮 ↓ CLAUDE.md 常驻全项目,代价是永久占 context ↓ skill 可触发、能写长规格;fail-open(本期九个都在这层) ↓ hook Stop 事件 exit 2 / {"decision":"block"},绕不过 ↓ CI 唯一能挡住已经 push 出去的那层

往下一层怎么做:Claude Code 的 Stop hook 是「它想收工时」触发的,退出码 2 会阻止它停下并让对话继续,JSON 形式是 {"decision":"block","reason":"..."},也可用 hookSpecificOutput.additionalContext 把「还有 3 个测试在失败,继续」喂回去(据官方 hooks 文档,2026-10)。换句话说:「跑没跑过测试」该交给 hook,不该交给 skill。

把不确定性写进输出契约

如果是在你自己的程序里而不是 CLI 里聊,别靠提示词,靠 schema:Structured Outputs 用 output_config.format(type: "json_schema")把输出钉在 schema 上,于是 status: "verified" | "inferred" | "unknown" 与 evidence 可以设成必填字段——模型没法再用一段自信的散文绕开「不知道」这一格。限制:不支持递归 schema 与 minimum/maxLength 这类约束、additionalProperties 必须 false、拒答或撞到 max_tokens 时输出可能不符合 schema(据该页,2026-10)。

// 一页行动卡

今天就做这三件:① /plugin install superpowers@claude-plugins-official,然后只在它要说「好了」之前手工点 verification-before-completion——九个里收益最直接。② 把官方那句原文抄进 CLAUDE.md:「If you're unsure … say『I don't have enough information to confidently assess this.』」,零成本、全项目生效。③ 写三个证据不存在的反向 eval 场景,先跑不装任何 skill 的 baseline。

按需再加:source-driven-development(写框架代码)· doubt-driven-development(不可逆或跨模块的决定)· truth-first(排障与系统状态问答,装前自读 SKILL.md)· discernment-nudge(答案给非技术读者)· fact-checker(核稿子里的数字与引文)· 一条 Stop hook(「测试没跑过不许收工」钉死在这儿)。

明确别做:同时装两个「要证据」的同款 · 把这类 skill 当 CI 门禁(它 fail-open) · 抄聚合站写的 skill 名与作者 · 只用正向场景验收 · 在探索性脚本上开完成门禁 · 以为「我声明了可能过时」等于核过。

// 术语表

编完成(false completion)
没跑验证就声称「测试过了 / 修好了」。与编事实并列的另一种谎。
三态分级
Verified / Inferred / Unknown 这样的输出分档。关键在第三格——二值会把不确定归进「确定」。
fail-open / fail-closed
失效时放行 / 失效时拦住。skill 属前者(被忽略无人报错),hook 与 CI 属后者。
借口预防表
SKILL.md 里那张「借口 → 驳回」两列表,预先堵住换词、半验、「就这一次」。
Structured Outputs
Claude API 的 output_config.format(json_schema),把输出钉在 schema 上,可把「不知道」做成必填字段。

// 三个想不通的地方

既然模型可以不听,这类 skill 到底还有没有意义?
有,但意义不在「保证」,在改默认值:模型无外部约束时默认给出一个听起来完整的答案,这类 skill 把默认值挪到「先找证据」。它的正确定位是随叫随到的检查表,不是一道门。于是有个反直觉的结论:手工点它比等它自动触发更有效——你读到「应该」两字时主动调用,命中率远高于指望它自己在那一刻触发。真要门,往下走 Stop hook。
装了「诚实优先」,会不会得到一个什么都标 Unknown 的废物?
会,这是这类最常见的真实失败,不是理论风险:你奖励了「说不知道」,它就把它当安全出口。对策两条——只在高风险场景开(verify-claim 明写低风险不用);别只验「它会不会说不知道」,反向 eval 要双向:另造三个证据完全充分的场景,看它是否仍敢给结论。单向验收必然养出一个把问题全退回给你的助手,那不是诚实,是推责。
为什么「逼它说不知道」比「逼它去查」难验收得多?
因为「去查」有痕迹,「不知道」没有。查过就有工具调用、抓过的 URL、命令输出,能在 transcript 里数出来;而「它本该说不知道却没说」,只有你已知正确答案才发现得了——那恰恰是你用它的场合里不具备的条件。所以验收必须人工构造证据缺口:你亲手挖掉那份证据,于是你成了唯一知道标准答案的人。这也解释了为什么这类口碑分歧最大——大多数人没法验,只能凭感觉。

// 延伸阅读