Lesson 0007 · Engineering · 人和 AI 都能启动(model-invoked)· 独立工具课

research:把阅读跑腿派给后台代理

你正在和 AI 讨论一个功能怎么设计,聊到一个关键问题:「这个库的 API 在并发调用时到底什么行为?」答案不在仓库里,在官方文档和源码里。 谁去读?如果你让当前会话停下来读四十分钟文档,讨论的思路就断了。 research 就是为这一刻准备的:把「查清楚一件事」这单跑腿活 (legwork,指查资料、读文档这类花时间但不需要你做判断的工作) 派给一个后台代理(background agent:在你当前会话之外独立干活的 agent), 你继续讨论,它读完把一篇带来源引用的 Markdown 报告放进仓库。 这个 skill 的全部正文只有三条指令,但每一条都值得拆开讲。 学完这节课,你能说清楚它什么时候自动触发、报告写到哪里、写完该带去哪一步, 以及行为不对时这三条指令里该拧哪一条。

1. 它在整个系统里站在哪

0001 把 22 个 skill 分成三层:配置层(跑一次性的初始设置)、编排层(你手动启动的完整流程)、 纪律层(被反复调用的基本功)。按调用方式这根轴,research 被归进纪律层: 它是 model-invoked 的(人和 AI 都能启动),frontmatter 里没有 disable-model-invocationagents/openai.yaml 里也没有 policy.allow_implicit_invocation: false——按 .agents/invocation.md 的契约,两个条件都不设就是 model-invoked 的默认形态。 它的 description 是写给 AI 看的,带着触发短语 「Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent」,所以 AI 能在任务变质成阅读跑腿时自己把它捡起来。

但按流程位置这根轴,ask-matt 把它放在 Standalone(主流程之外的独立工具)一节, 和 prototypegrill-meteach 站一排。 两种归类不矛盾,它们说的是两件事:

看它的角度 归类 意思
调用方式(0001 的分层) 纪律层 · model-invoked AI 可以自己伸手用它,不需要你逐字打出 /research;别的 skill 也能用一句自然语言把它拉进来(0001 讲过,这叫 prose 调用)
流程位置(ask-matt 的地图) Standalone,随时可伸手 它不在「想法 → 交付」的主流水线上,不拆票、不写代码;它产出的报告是思考的材料,要带回主流程的 grill-with-docs 才发生作用

上一课的 handoff(0006)和本课是一对好对照,两者都解决「上下文装不下」, 但方向相反:handoff 把当前对话压缩成一个文件,换一个新会话接着干 (跨会话的桥);research同一个会话内分出一个后台代理去平行干活, 主线程一步不停。一个是串联的接力,一个是并联的外包。

罗盘:MISSION.md · 地图:0001 · 路由规则:ask-matt/SKILL.md 的 Standalone 一节 · 调用契约:.agents/invocation.md · 上一课:0006 handoff

2. 它是什么、什么时候用

2.1 一句话定义

SKILL.md 的 description 原文:对一个 question 做调查,依据 high-trust primary sources(高可信度的一手资料,第 5 节细讲), 把发现写成仓库里的一个 Markdown 文件。docs 页补了一句它的价值主张: 报告里保存的东西可以追溯到权威来源,「而不是一份转述的转述」 (a summary of a summary)。

一句话定性 research 回答的是「世界上已经存在的事实」:某个 API 怎么行为、 某份规格实际写了什么、某个说法站不站得住。它不替你做决定、不替你写代码、 也不替你想清楚你想要什么——它只把带出处的事实放到你桌上。 docs 页的原话是:它是「你派出去的跑腿,不是你外包出去的思考」 (legwork you delegate, not thinking you outsource)。

2.2 两种启动方式

谁启动 怎么发生 典型场景
User 你手动 直接输入 /research,后面跟要查的问题 你明确知道下一步是「查清楚一件事」,而且不想让这个会话停下来读
Model AI 自动 description 里的触发短语命中:任务变成了 reading legwork(读文档、收集 API 事实之类的阅读跑腿) 讨论中冒出一个事实问题,AI 判断「这要读不少资料」,自己把 research 拉进来,继续陪你聊
Model 被 wayfinder 调用 wayfinder 的研究票(research ticket)由 /research 子代理来解决(第 8 节) 大型模糊工程画决策地图时,「去查某个事实」的那类票

docs 页给的判断标准很朴素:当下一步是 finding something out(把某件事查出来), 而不是把某件事想出来或试出来的时候,用它。想靠对话把计划磨清楚 → 那是 grilling;想用一次性代码把设计问题试出答案 → 那是 prototype。 下一节把这条岔路讲透。

权威原文: skills/engineering/research/SKILL.md · 给人看的叙事版: docs/engineering/research.mdaihero.dev/skills-research

3. 三条岔路:research、grilling、prototype

讨论中冒出一个悬而未决的问题,先别急着喊「让 AI 去查一下」。这套技能库把 「回答问题」拆成三条路,选错了会浪费一整轮:答案的来源不同,用的工具就不同。

问题的性质 答案在哪 走哪条路 产物
「这个 API 到底怎么行为?」「规格里怎么写的?」「这个说法成立吗?」——事实已经存在,只是没人读过 在外部世界的资料里(官方文档、源码、规格) research 仓库里一篇带来源引用的 Markdown 报告
「我们到底想要什么?」「这个需求边界在哪?」——答案在你脑子里,还没被问出来 在你的判断里,需要被追问才能浮现 grilling / grill-with-docs 聊清楚的计划;有代码库时写进 CONTEXT.md 和 ADR
「这个状态机手感对吗?」「这个界面该长什么样?」——纸上谈兵定不下来,得看见真东西 要造出一次性代码跑一跑、看一看才知道 prototype 明确标记为一次性的临时代码 + 一个答案;代码本身不进交付
常见的选错 拿一个「你想要什么」的问题去跑 research——后台代理读遍全网也读不出你的意图, 那是面试(grilling)的活。反过来,拿一个纯事实问题去 grill 用户——用户又不是文档, 问他「这个库的并发语义是什么」只会得到猜测。docs 页把这条分叉写得很直白: 用面试磨计划选 grilling,用一次性代码探索要造什么选 prototype,阅读跑腿选 research。

岔路依据:docs/engineering/research.md 的 「When to reach for it」一节 · 面试课:0003 grilling · 原型课:0008 prototype

4. 正文只有三条指令:逐条拆

research 是整套技能库里最薄的 skill 之一:SKILL.md 连 frontmatter 一共 12 行,正文只有三条指令,外加一个 agents/openai.yaml(里面只有 Codex 选择器的显示名和一行简介,没有策略配置)。薄是设计出来的:它是一条 原语(primitive:被更大流程拼装使用的基本动作),作者故意不规定 「用哪个搜索工具、读几个页面、报告分几节」,把这些留给执行它的 agent 和仓库习惯。 但三条指令每条都钉死了一个不容让渡的要求,逐条看。

# 原文指令(压缩) 钉死了什么 故意没规定什么
0 Spin up a background agent to do the research, so you keep working while it reads. 阅读必须发生在后台代理里,主会话不停——这是整个 skill 的定义性动作(第 6 节) 派几个代理、代理内部怎么分工
1 Investigate against primary sources… Follow every claim back to the source that owns it. 证据等级:只用一手资料;每个论断都要追到「拥有这个答案的来源」(第 5 节) 具体读哪些站点、用什么检索手段
2 Write the findings to a single Markdown file, citing each claim's source. 产物形态:一个文件、Markdown、逐条论断带出处 文件名、章节结构、篇幅
3 Save it where the repo already keeps such notes; match the existing convention; if none, somewhere sensible and say where. 落盘位置服从仓库已有的笔记习惯;没有习惯时选个合理位置并明确说出来(第 7 节) 没有统一指定的目录——各仓库自己定

把这三条连起来就是它的完整行为模型:后台去读 → 只信一手 → 单文件带回出处 → 按仓库习惯落盘。记这一句,整个 skill 就记住了。

逐条原文:skills/engineering/research/SKILL.md (全文 12 行,值得直接读一遍)· 显示元数据:agents/openai.yaml

5. 一手资料纪律:什么算 primary source

primary source(一手资料)是「拥有这个答案的来源」本身: 官方文档、源代码、规格文本、第一方 API。secondary write-up (二手转述)是别人读过一手资料之后写下的解读:博客、教程、论坛回答、周刊摘要。 SKILL.md 的要求是:调查只用一手资料,并且 每个论断都要沿着引用链追回到拥有它的那个来源

来源 算一手还是二手 为什么
库的官方文档、官方 API 参考 一手 行为定义就在这儿,写文档的人拥有这段行为
库的源代码、测试、commit 历史 一手 文档可能过时,代码是行为最终的拥有者
RFC、W3C/ECMA 规格文本、协议草案 一手 规格是规则的原文,不是对规则的报道
服务方自己的 API 响应(第一方 API) 一手 直接问系统本人,答案没有经过转述
解读文档的博客、教程、视频 二手 是「转述的转述」链条上的一环,可能过时、可能读错
论坛/问答网站的回答 二手 回答者自己也常常没读过一手资料;可以当线索,不能当证据

这条纪律解决的是一个真实病变:AI 生成的答案经常引用「看起来像那么回事」的二手页面, 二手页面又引用别的二手页面,三层之后没人知道最初的论断出自哪里。docs 页说, research 存下的东西要能追溯到权威来源,而不是「一份转述的转述」。 二手材料不是不能看——它能当路标,告诉你一手资料在哪;但报告里每个论断的引用, 必须落在一手来源上。

为什么引用要逐条挂 「citing each claim's source」的意思是:报告里每个论断各自挂出处, 而不是文末统一列一串「参考资料」。前者让你能抽查任何一句「这个说法是从哪页文档来的」; 后者只是装饰。你以后拿报告做决策时,敢不敢信它,全看这一条执行得怎么样。

纪律原文:research/SKILL.md 指令 1、2 · 「转述的转述」:docs/engineering/research.md 的 「What it does」一节

6. 后台代理:为什么它是定义性动作

正文第一句不是「去读一手资料」,而是「派一个后台代理去读,这样你可以继续干活」。 指令顺序不是随便排的:docs 页把后台代理称为这个 skill 的 defining move(定义性动作)——没有这个动作,剩下两条不过是普通的「认真查资料」。

为什么是定义性动作?三个理由:

  1. 保护主线程的上下文。读几十页文档会把主会话的上下文窗口灌满原文, 真正重要的设计讨论反而被挤出去。后台代理有它自己的上下文,读完只把结论文件交回来。
  2. 时间并联。你继续聊设计、写代码,它同时在读;报告回来时你往往已经推进到 「正好需要这个事实」的位置。ask-matt 的描述就是「Keep working while it reads」。
  3. 交付的是文档,不是对话。docs 页说:你拿到的是「一份可以对着反应的文档, 出处都挂在上面」。论断挂在纸上,你才有得挑、有得驳;如果只是在对话里听 AI 说 「我查过了,是这样的」,你连检查的机会都没有。
「派跑腿」和「外包思考」的边界 docs 页的原话值得背下来:Research is legwork you delegate, not thinking you outsource. 后台代理负责「把事实找齐并挂好出处」;从这些事实推出「我们该怎么做」, 是你和主流程(grill-with-docs 及以后)的事。报告回来了,决策还没开始—— 这是用它时最容易搞错的心态。

定义性动作:docs/engineering/research.md 的 「Delegated legwork」一节 · 指令原文:research/SKILL.md 指令 0

7. 报告落在哪:仓库的笔记习惯

指令 3 是三条里最容易被忽视、却最影响日常体验的一条: 「存在仓库已经用来放这类笔记的地方;配合已有习惯;如果没有习惯, 放在一个合理的位置,并说明放在哪了。」

仓库情况 指令要求的行为 反例(行为跑偏时)
仓库已有放笔记的目录(比如 docs/research/notes/ 之类的既有习惯) 顺着既有习惯放进去,命名风格也向既有文件看齐 无视已有目录,新发明一个 research-output/ 顶在仓库根上
仓库没有这类习惯 选一个合理的位置,并且在交付时明确告诉你文件放在哪 悄悄丢在某个目录,会话结束后没人找得到

注意这条指令和 handoff 的落盘规则正好相反:handoff 的文件写进 操作系统的临时目录(它不是仓库资产,只是过桥的船票,0006 讲过); research 的报告写进仓库——它是要被反复引用、被 grill、 被设计讨论踩在上面的资产。0001 的全表里,research 的「跑完主要留下什么」一栏写的就是 「仓库里一篇带引用的 Markdown 研究报告」。

setup-matt-pocock-skills(0002)的关系也在这里:setup 负责把 「工单系统在哪、文档放哪」这类仓库约定写成 docs/agents/ 下的配置文件。 research 自己不读那些配置来决定落点——它的规则更简单:看仓库现状里笔记已经放哪。 如果你的仓库跑过 setup、文档有了统一住处,research 的报告自然会顺着那个住处走。

落盘规则:research/SKILL.md 指令 3 · 全表对照:0001 · 配置层:0002 setup-matt-pocock-skills

8. 谁在用 research:wayfinder 的研究票

research 自己不调用任何别的 skill(正文三条指令里没有一句 「Run the /xxx skill」,它是片叶子),但有一个 skill 会成体系地调用它: wayfinder(0016,大型模糊工程的决策地图流程)。

wayfinder 把大工程拆成一张张 Decision ticket(决策票: 挂着问题、解决后产出「决定」而不是「交付物」的 issue,全套词见 CONTEXT.md 和 0001)。 每张票带一个类型标签,其中 wayfinder:research 这一型,原文定义是: 读文档、第三方 API 或本地知识库,把某个决定等在上面的那个事实挖出来; 属于 AFK(agent 自己就能干完,不需要人在场);「当需要的知识在当前工作目录之外时用」; 解决方式就是派一个 /research 子代理

wayfinder 给 research 加了什么 原文依据
画地图阶段一次性并行派多个研究子代理,每张研究票一个 「Fire the research subagents」——chart 流程第 5 步
研究发现放在一次性的 research/<name> 分支上,票里留一个指过去的上下文指针 同一第 5 步:「capturing its findings on a throwaway research/<name> branch with a context pointer from the ticket」
「一个会话最多解决一张票」的铁律,对研究票开例外 「never resolve more than one ticket per session — with the exception of research tickets」

这个例外和第 6 节是同一个逻辑:研究票天生适合并联——它们彼此独立、都在等外部事实, 串行做纯属浪费。wayfinder 是 research 在编排层的最大用户; 反过来,research 对 wayfinder 一无所知,它只是被叫来「把这个问题查清楚」。 这正是原语该有的样子:被用的一方不需要知道用它的流程长什么样

wayfinder(编排层,人启动)
  │  chart 第 5 步:对每张 wayfinder:research 票
  ▼
派 /research 子代理(可并行,一会话一票的例外)
  │  读一手资料 → 单篇带引用 Markdown
  ▼
发现落在 research/<name> 分支 + 票上留指针
  │
  ▼
票被解决 → 决策地图上的雾散一格

研究票定义与例外:skills/engineering/wayfinder/SKILL.md 的 Ticket Types 与 Invocation 两节 · wayfinder 一课:0016 wayfinder

9. 会留下什么、用完接什么

9.1 副作用清单

动作 会写什么 不会写什么
单独跑 /research 仓库里一篇 Markdown 研究报告,论断逐条挂出处,位置服从仓库笔记习惯 不写 CONTEXT.md / ADR,不碰工单系统,不改代码,不写临时 HTML
在 wayfinder 里被当研究票解决 报告在一次性 research/<name> 分支上;票上留上下文指针;票的状态随解决推进 报告不直接进主分支;分支是一次性的(和 prototype 的「答案留下、代码丢弃」同一思路)

横向对比几个邻居,副作用的边界就更清楚了:codebase-design(0005)默认 什么都不写,只在对话里对齐词汇;handoff(0006)写文件但写到 系统临时目录research 写文件且写进仓库—— 它是这三个「轻」skill 里唯一常态产出仓库资产的。

9.2 用完之后,下一步去哪

  1. 默认路线:带进 /grill-with-docsask-matt 的原话: 报告是「可以带进主流程 grill-with-docs 的东西——research 喂饱思考,它不代替思考」。 拿着挂好出处的事实去被面试,比凭印象被面试质量高得多。 (docs 页把下游写成 to-prd;本仓库发布集里没有这个 skill, 对应位置是 to-spec,见 0009。)
  2. 在 wayfinder 里:报告解决一张研究票,票关掉,决策地图的雾散一格, Frontier(可开工的票的边缘)向前推。
  3. 只是顺手查个事实:报告留档,回到你被打断前正在做的事——这正是后台代理的意义, 主线从未离开过你。
  4. 报告引出新的模糊点:别连着再派一串 research 自问自答; 如果新问题是「我们该怎么办」,那已经不是研究问题,回到第 3 节的岔路重新选路。

9.3 它依赖谁、被谁依赖

方向 skill 关系
它依赖 (无) 正文不调用任何别的 skill,是叶子原语
被谁依赖 wayfinder 研究票的解决手段;chart 阶段并行派发;享一会话一票的例外
被谁指路 ask-matt Standalone 一节告诉用户它的存在和下游
流程邻居(分工不依赖) grilling · prototype 第 3 节的三条岔路:按「答案在哪」选路

10. 行为不对时,去改哪个文件的哪一段

这个 skill 一共就两个文件:SKILL.md(frontmatter + 三条指令)和 agents/openai.yaml(显示名和简介)。可调的地方少,但每一处对应一类症状:

症状 先查 / 改哪里 不要误改
AI 从不主动用它,明明任务已经是读文档的跑腿 SKILL.md frontmatter 里 description 的「Use when…」触发短语——model-invoked 的自动触发全靠这段措辞(契约见 .agents/invocation.md plugin.json(它本来就在发布集里);ask-matt 的路由句
它把主会话占住读资料,讨论被晾着 指令 0「Spin up a background agent」一句——后台化是定义性动作,被绕开就是这条没被执行 一手资料那段(那是证据纪律,不管谁去读)
报告里引的全是博客和论坛,出处经不起抽查 指令 1 的 primary sources 一段 + 指令 2 的「citing each claim's source」 docs/engineering/research.md(那是给人看的叙事,改它不改行为)
报告到处乱丢,每次目录都不一样 先想仓库有没有笔记习惯——没有就先立一个;再查指令 3 的表述是否被遵守 setup-matt-pocock-skills 的配置文件(research 的落盘规则不读它)
它开始替你做决定、顺手把代码改了 越界不是文本问题而是角色问题:决定归 grill-with-docs 及主流程,改代码归 implement/tdd——检查是不是用错了 skill(回第 3 节岔路) SKILL.md 加「不要改代码」的长篇禁令(保持它薄)
Codex 选择器里显示名不对 agents/openai.yamlinterface.display_name / short_description——它只管展示,不管行为 SKILL.md 正文(那里没有展示元数据)
微调前先想清楚:这是个 12 行的原语 这套技能库的设计哲学是把细则放在该放的地方:触发措辞在 description,行为在三指令, 展示在 openai.yaml。给 research 加「应该先搜哪个站、报告分几节」这类细则, 多半是加错了地方——那种偏好属于你们仓库的笔记习惯(指令 3 让它自己服从), 或者属于你们项目自己的配置层文档。

11. 检索练习

先别往回翻表,凭记忆答。选项的长度刻意对齐,不会从版式泄题。行为细节以本课和 SKILL.md 原文为准。

自测(立即反馈)

1. 单独跑一次 /research,默认会留下什么?
2. 下列哪个算 SKILL.md 意义上的一手资料?
3. 为什么正文第一句就要求派 background agent?
4. AI 在什么情况下会自己加载 research?
5. 同样在「回答问题」,research 和 prototype 怎么分工?
6. 研究报告写好后,ask-matt 建议带去哪?
7. wayfinder 里的研究票享受什么特殊待遇?
8. 报告总引用二手博客、出处经不起抽查,该改哪里?
额外提取练习(无选项) 合上本页,默写 research 的三条指令(后台代理 / 一手资料加逐条出处 / 单文件按仓库习惯落盘), 再用自己的话说出三条岔路的分工:什么问题给 research、什么给 grilling、什么给 prototype。 最后想一个你当前项目里「答案在官方文档里、还没人读」的问题——不要求真的去跑, 只要求说清楚它为什么属于 research 而不是另外两条路。

12. 下一课与一手材料

本课主一手材料(请打开原文读,不要只背本页摘要):

速查页(本课同步): reference/research.html

导航: 上一课 0006 handoff (跨会话的桥:把对话压缩带走;本课是同会话内的并联外包,正好一对)。 总览仍回 0001 系统地图; 岔路的另外两端见 0003 grilling 和下一课。

建议下一课(0008): 0008 prototype。 三条岔路的另一端:当问题纸上说不清、需要可运行的答案时,用一次性代码去换。 和本课的交接点很直接——先问「答案在哪」:在外部资料里走 research, 在要造的东西里走 prototype,在你自己脑子里走 grilling。

老师就在会话里。 对本课任何一条边界有疑问——比如二手材料到底能不能出现在报告里、 后台代理的上下文和主会话怎么衔接、wayfinder 的研究分支什么时候该删、 报告该按什么目录习惯归档——直接在对话里问。 回答会回到 SKILL.md / docs/engineering/research.md / wayfinder/SKILL.md 的原文,不会临场编造。 做完检索练习后,回复「练习结果 / 哪里卡住 / 开 0008 或先补 0006」,我们安排下一课。