我懒得再说第二遍的话,都写进了 AI 的常驻指令

网上那些提示词秘笈我几乎都试过,有点用,但不多。真正改变 AI 给我做事方式的是一件无聊事:AI 每个新对话都失忆重置,像一个绝顶聪明却完全不记得你怎么做事的新人。这是我给它的那份入职说明——我真在用的常驻指令和几个交任务的习惯,挑顺手的拿。

Cover Image for 我懒得再说第二遍的话,都写进了 AI 的常驻指令

我懒得再说第二遍的话,都写进了 AI 的常驻指令

网上那些「提示词秘笈」我基本都试过。让它扮演某个领域的资深专家,许诺给它两百美元小费,请它先深呼吸再作答。有点用,但不多,用久了更像一种心理安慰——仿佛口诀念对了,它今天就能超常发挥。一段时间下来,这些口诀在我的工作流里几乎没留下什么。

真正改变它给我做事方式的,是一件无聊得多的事。

我的判断是,AI 的每一个新对话(术语叫 session),都像一个当天入职的新人。这个人绝顶聪明,读过的东西比谁都多,打字比谁都快,只有一个毛病:彻底失忆。每天早上他干干净净地重置一遍,昨天你教他的做事习惯、你的偏好、上一段对话的来龙去脉,全忘光。

于是真正替你省时间的,从来不是某一句能让他超常发挥的口诀,而是把你每天最不想再讲一遍的那些话,一次写清楚,开工前直接交给他。这份东西我放在 CLAUDE.md 里(AGENTS.md 也一样——都是 AI 每次开工会自动加载的常驻指令文件),它不谈任何具体任务,只谈两件事:我要它怎么做事,和我怎么把任务交给它。

下面这些都不花哨,是我在真实的研究和编程工作里反复用、真沉淀下来的。挑你顺手的拿去用。

我要它怎么做事

把这几条常驻指令摊开,你会发现它们无聊得很。但它就该无聊——一份入职说明,越枯燥、越清楚、越没有歧义越好。每一条背后,都是一次我懒得再打第二遍的纠错。

我最看重的一条:出了问题,立刻、响亮地失败,别用兜底掩盖过去。原话大意是「尽可能快速失败,不要用各种 fallback(兜底方案)、启发式、事后补丁掩盖真实的失败;禁止伪造、双写来假装程序能跑;最优先的目标是让错误尽快暴露」。翻成日常的话,就是对那个新人说:地基要是歪的,你当场喊我,别自己闷头花八小时在上面砌一座看着笔直的歪楼。我宁可五分钟后知道地基有问题,也不要八小时后收一栋危房。
左边地基一歪就当场喊停,只砌了一层;右边在同一道歪地基上,花好几个小时砌起一堵笔直的墙

第二条,动手前先想,别把困惑藏起来。把你的假设明确讲出来;不确定就问;有多种解释,全摆出来,别默默替我选一种;有更简单的做法,说出来,该反对就反对;有不清楚的地方就停下,指明到底哪里不清楚。这是「上车前先看一眼地图」。一个在岔路口默默替我选了方向、然后一路狂奔三小时的新人,远不如一个在路口停下来问「导航让左转,可右边好像有条近路,走哪条」的新人。

第三条,能简单就简单。用能解决问题的最少代码,别投机地多写,别加我没要的功能、抽象和配置;要是写了两百行、其实五十行能解决,重写;顺手问自己一句,一个资深工程师会不会嫌它过度设计。我防的是「简历驱动开发」——为了一个五十行脚本就能了结的事,非要搭一套大而全的复杂系统,好证明自己会的东西多。

最解放我的是第四条:把任务变成一个能自己验证的目标,每一步带一个明确的验收动作。「修这个 bug」到他手里,会被改写成「先写一个刚好能复现这个 bug 的测试,看着它先失败;再改代码,直到这个测试通过」。判据一旦够硬,他就能独立运转,一直做到达标为止,我不用一步一步盯着。我从监工变成了验收员。

剩下几条不展开了,都是一个路数:更新文档时当它是全新的写,少留历史包袱,让第一次读的人最快看懂现在是什么样,而不是陪他走一遍完整的演变史;改东西先想能不能删、能不能复用,别一上来就加一堆新的。合起来,就是让这个聪明又健忘的新人,每回开工做事的姿势都还合我意。

我怎么把任务交给它

入职说明交给他了,剩下是每天怎么安排任务。这里也有几个习惯。

一个是,让他自己去读上下文,别把整个项目的材料都塞进对话框。他会读文件。要用到哪部分,我就说「去读某某目录下这三个文件,你要的都在里面」,而不是把内容复制一大段贴进去。就像让新人自己去档案室翻卷宗,而不是塞给他一摞复印件。他会读,就让他读。

再一个,先给样本,再让他动手。我几乎不说「帮我写一篇某某风格的东西」。我会先挑三五篇自己觉得写得好的同类旧作,让他读完,再说「照着这个,写一篇新的」。几篇少而精的样本,比一长串风格形容词管用得多。我甚至常驻着一条:「在我给你具体例子之前,不许泛泛而谈。」就为逼他别一上来先给一段放之四海都对、于是对谁都没用的空话。

第三,把想要的输出形态讲清楚、定下来。要评审,我就讲明「别重写,只给我关于结构、逻辑漏洞和该澄清之处的具体意见」;要洞察,就讲明「要一份综合判断,不要一张检索清单」;有时干脆让他先反问我缺哪些信息,别急着答。说白了就是当一个把话说清楚的甲方,而不是丢一句「你看着办」。

第四,「加法」和「减法」分开做,一遍只做一件事。「帮我把这段改得更好」是一句没法执行的话。我会拆成两趟:一趟只做加法,比如「把我上回讲的那个比喻加回来,再补一点亲身经历」;一趟只做减法,我给他一张具体清单——删掉所有强行的排比、所有像鸡汤金句的句子、所有可有可无的副词——然后让他照着删。一张具体的清单,永远比一句「写自然点」可控。
一趟只做加法,另一趟只做减法;出来的稿子比进去时更短也更干净

第五,给他具体的物证,别让他从一句抽象结论开始演绎。写东西时我给的原料是几件实打实的东西:一个具体数字,一句客户原话,一个当时的报错。从这些出发,出来的东西才具体、才可信;从「我们这季度表现出色」这种结论出发,只会得到一段更抽象的复述。

最后一个,追一层「凭什么」。他给了结论或方案,我习惯再问一句,你为什么这么判断,背后的机制是什么。这一问,常能分出他是真明白了,还是只按概率拼了一个看起来最像样的答案。同样地,我用它去提取一个人的想法时,要的从来不是「这人说过什么」,而是「他为什么会这么想」——没有来由的结论,我不收。

把它抄进你自己的文件

这篇讲的是怎么跟 AI 协作,工作纪律加交互习惯。它还有一篇姊妹文《你掌握多少种思维模式,AI 就有多大用》,讲的是该告诉 AI 哪些知识——把你脑子里的思维模式直接说给它,它做事才更有章法。一个管操作,一个管内容,两半都写进你的 CLAUDE.md,这套工作流才算配齐。

我现在手上不止一个编程 agent。Claude Code、Codex、OpenCode 各有一份常驻指令,因为它们的能力和角色不一样,入职说明也就不一样。下面按工具分开贴,都是我真在用的原文,你可以挑着抄进自己的 CLAUDE.md 或 AGENTS.md。

给 Claude Code 的是十条工程哲学:

## 工程哲学

1. 在更新文档时,请把它当作 greenfield来更新,尽量减少历史性的信息,目标是让任何第一次阅读的读者都能够最快地了解到最新的现状,而不需要了解无用的完整的发展过程,除非是明确的流水账型日志或进展记录型文档。
2. 在做任何兼容性设计前,和用户确认,很多情况下我们不需要兼容性设计。
3. 除非用户许可,你要始终以任务完全完成、彻底到达终态为目标,而不是处在某种中间状态、兼容状态、迁移过程中。
4. 我们尽可能 fast fail,而不是各种各样的 fallback 掩盖真实的失败。In other words, avoid degradation handling, fallback, hacks, heuristics, local stabilizations, or post-processing bandages that are not faithful general algorithms.
5. 禁止伪造、双写来假装程序能够运行。你的最优先目标是让错误尽快暴露。
6. 在做任何改造时,优先删代码和复用代码,而非新增代码。
7. 尽量追求 single source of truth。
8. 需要遵循名实相符的原则,如果语义改变,符号名字也要改变。
9. 在做测试时,需要借助合理的也可用于未来上线的前后端日志来判断问题,而不是猜测。
10. commit messages 里面需要加上对本次变更前因后果的描述,便于未来追溯。

给 Codex 的前十条基本相同,只在第 3 条多了一句「不该为了中间态下的测试通过而撰写临时代码」,后面另加了四条放权的话:允许它自己决定调 subagent,放开读代码、文档和会话历史,默认交付完整方案,以及从人能理解的角度而非工程建模的角度去设计系统:

# PRINCIPLES
## 工程哲学

1. 在更新文档时,请把它当作 greenfield来更新,尽量减少历史性的信息,目标是让任何第一次阅读的读者都能够最快地了解到最新的现状,而不需要了解无用的完整的发展过程,除非是明确的流水账型日志或进展记录型文档。
2. 在做任何兼容性设计前,和用户确认,很多情况下我们不需要兼容性设计。
3. 除非用户许可,你要始终以任务完全完成、彻底到达终态为目标,而不是处在某种中间状态、兼容状态、迁移过程中,更不该为了中间态下的测试通过而撰写临时代码。
4. 我们尽可能 fast fail,而不是各种各样的 fallback 掩盖真实的失败。In other words, avoid degradation handling, fallback, hacks, heuristics, local stabilizations, or post-processing bandages that are not faithful general algorithms.
5. 禁止伪造、双写来假装程序能够运行。你的最优先目标是让错误尽快暴露。
6. 在做任何改造时,优先删代码和复用代码,而非新增代码。
7. 尽量追求 single source of truth。
8. 需要遵循名实相符的原则,如果语义改变,符号名字也要改变。
9. 在做测试时,需要借助合理的也可用于未来上线的前后端日志来判断问题,而不是猜测。
10. commit messages 里面需要加上对本次变更前因后果的描述,便于未来追溯。
11. 你可以主动积极地决定是否调用subagents来帮助任务的完成。
12. 你可以充分阅读代码、文档、git历史、codex会话历史来更充分地了解上下文信息。
13. 请默认用户需要的是完整的方案,并且默认你需要执行完成完整的方案后才能回报用户。
14. 永远都从人类能理解、能读懂、用户体验最佳的角度出发去设计系统,而非一比一映射工程建模的角度出发去设计和实现系统,尤其是任何用户界面。

OpenCode 里跑的是开源模型,智力要弱一些,我不指望它们做复杂任务,所以这份指令一条哲学都没有,只教最基础的事:怎么把工具调用做对。

# Tool Calling Rules

When calling tools, follow these rules strictly. They override any conflicting habits from chat training.

## Argument formatting

1. **Omit optional fields you don't need.** Do not send null, "", {}, or [] as a placeholder. If a field is optional and you have no value, leave it out of the JSON entirely.

2. **Match the container type exactly.**
   - Array fields take JSON arrays: ["a", "b"], never "[\"a\",\"b\"]" (string), never {} (object), never "foo" (bare string).
   - Single-element arrays still need brackets: ["foo"], not "foo".
   - Object fields take JSON objects, not arrays or strings.

3. **Strings are raw strings.** Do not wrap values in extra quotes, code fences, or markdown.

4. **Numbers and booleans are unquoted.** 30, not "30". true, not "true".

## Paths and identifiers

5. **File paths, URLs, IDs, and similar fields go to system functions, not chat output.** Never format them as markdown links, never wrap them in backticks, never add explanatory parentheses.

   Correct:   "/Users/me/notes.md"
   Wrong:     "[notes.md](notes.md)"
   Wrong:     `"/Users/me/notes.md"`
   Wrong:     "/Users/me/notes.md (the notes file)"

6. **If a tool description says "path", treat it as input to a filesystem call.** No formatting, no decoration.

## Related parameters

7. **When a tool has paired parameters (e.g., offset + limit, start + end, from + to), provide both or neither.** Read the description — if two fields work together, half the pair often produces an error.

## Recovery

8. **If a tool returns a validation error, read the error message carefully and fix only what it complains about.** Do not rewrite the whole call. Do not retry the same arguments.

9. **If a tool returns a "Note:" with a defaulted value, that's informational, not an error.** Continue the task. If the default is wrong, retry with the correct explicit value.

## Tool selection

10. **Use the tool whose description matches your intent most specifically.** Don't reach for shellCommand if a dedicated tool exists. Don't reach for execute_code for things a single tool call can handle.

最后

这些都是我在自己的工作里长出来的习惯,不担保对你也全对。但那个「失忆的天才新人」的比喻,也许对你有点用。真正省事的,其实不是那句灵验的口诀,是把你反复要讲的话,一次性、清清楚楚地写下来。往后每天开工,你无非是把它再交给一个新人。

挑你顺手的,拿去用。