从一句话到可发布插件:R-P-C-T + Instructions + Skills 实战全记录
在前几期文章中,我们逐步搭建起了 AI 高效开发的**”三位一体”**体系:
-
1. 理论篇:R-P-C-T 全链路工作流 —— 解决”怎么想”的问题。 -
2. 配置篇:Copilot Instructions (静态外脑) —— 解决”怎么规范”的问题。 -
3. 工具篇:Agent Skills & Planning (动态外脑) —— 解决”怎么记忆”的问题。
很多读者反馈:“工具都装好了,道理也懂了,但真刀真枪干一个复杂项目时,这三者怎么配合?”
今天,我们就来一场综合实战。
我们将不再赘述基础概念,而是直接进入Hardcore Mode:综合运用上述三套武器,从零开发一个完整的 VS Code 提示词管理器插件。我们来看看,当一个懂架构、有记忆、守规矩的 AI 辅助你时,写代码能有多爽。
一、 实战目标:开发 “Prompt Manager” 插件
为了演示这个过程,我们设定一个真实且有一定复杂度的任务:
目标:开发一个 VS Code 扩展,在侧边栏提供一个 Webview 界面,用于增删改查常用的 AI 提示词(Prompt),并支持将提示词一键插入到编辑器中。
如果你直接把这一段话丢给 Copilot,它大概率会给你生成一堆零散的代码片段。但这次,我们将严格遵循 R-P-C-T 流程。
Step 0: 环境自检 (Check Environment)
本次实战依赖前两期文章中搭建的两层基础设施,请确保你的工作区已就绪:
-
1. 静态规范层 — .github/copilot-instructions.md
它是 AI 的”员工手册”,在本项目中负责定义编码元规则,例如 “使用 TypeScript strict 模式”、“Webview 样式必须使用 VS Code 内置 CSS 变量保持主题一致性,禁止硬编码颜色值”。如果尚未配置,请参考**《给 Copilot 装上”外脑”:用 .github 配置文件彻底根治 AI 的”健忘症”》**。
💡 冷启动技巧:不知道该写什么规则?两个办法:① 抄作业 — 去 GitHub 搜索同类型项目(如
vscode-extension copilot-instructions),看看开源大神怎么写的;② 让 AI 总结 — 在完成下面 Step 1 的调研后,让 Copilot 根据技术选型自动生成一版 Instructions(我们马上就会演示)。 -
2. 动态能力层 — .github/skills/planning-with-files/SKILL.md
它是 AI 的”工作方法论”,强迫 AI 在执行复杂任务时维护三个文件:task_plan.md(进度)、findings.md(决策)、progress.md(踩坑记录),并遵守”写代码前先读文件”的铁律。如果尚未配置,请参考**《Copilot 长任务总是跑偏?用 “Planning with Files” 给它装个动态外脑》**。
两层配合的逻辑是:Instructions 管”一直要遵守什么”,Skills 管”现在该做什么”。 准备好了?开干。
Step 1: 调研与启动 — 从”一句话想法”到”专业需求” (Research)
这是 R-P-C-T 中最容易被跳过、也最值钱的环节。大多数人会直接说”帮我写个插件”,然后就开始等代码。但我们要做的是:让 AI 当产品经理,反过来帮我们澄清需求。
第 1 轮:抛出原始想法
User:
@workspace 使用 planning-with-files skill。我想做一个 VS Code 插件,在侧边栏管理常用的 Prompt。请先帮我做需求调研。
Copilot:
好的,我已创建
task_plan.md、findings.md和progress.md,进入 Phase 1: Research。在开始之前,我需要澄清几个关键问题:
1. “管理”的具体含义:你需要哪些操作?增删改查?还是只要收藏和快速粘贴? 2. 数据范围:Prompt 是纯文本,还是需要支持分类/标签? 3. 持久化:数据是跟随 VS Code(跨工作区同步),还是每个项目独立存储?
看到了吗?AI 没有直接动手写代码,而是先反问。这正是 R-P-C-T 中”Research”阶段的核心——把模糊需求变成具体约束。
第 2 轮:逐步收敛
User:
1. 需要增删改查,还要支持一键插入到编辑器光标处。 2. 纯文本就行,但希望能分组(比如”代码审查类”、”文档生成类”)。 3. 跟随 VS Code,跨项目都能用。
Copilot:
明白了。基于你的需求,我建议:
• 存储方案:使用 context.globalState,它是 VS Code 内置的跨工作区持久化存储,无需额外依赖。• 数据模型: { id, title, content, group, createdAt },支持按 group 分组显示。• UI 方案: WebviewViewProvider注册侧边栏面板,使用 VS Code 内置 CSS 变量(--vscode-*)保持原生风格。还有一个问题:你是否需要导入/导出功能(比如把 Prompt 分享给团队)?
第 3 轮:确认边界
User:
暂时不需要导入导出,放到以后做。MVP 先做增删改查 + 分组 + 插入编辑器。
Copilot:
好的,我已将调研结论写入
findings.md,并将导入导出标记为 Future Scope。
此时打开 findings.md,你会看到 Copilot 工工整整地把三轮对话的结论固化了下来:
# Findings
## Product Requirements (MVP)
- CRUD operations for prompts (title + content)
- Group/category support
- One-click insert to active editor cursor position
- Cross-workspace persistence
## Future Scope (Out of MVP)
- Import/Export (team sharing)
## Technical Decisions
| Decision | Reason |
|----------|--------|
| `context.globalState` for storage | Built-in, cross-workspace, zero dependencies |
| `WebviewViewProvider` for sidebar | Official API for sidebar panels |
| VS Code CSS Variables for theming | Built-in `--vscode-*` variables, consistent with native UI |
| `postMessage` for communication | Standard Ext ↔ Webview messaging |
## Data Model
\`\`\`typescript
interface PromptItem {
id: string;
title: string;
content: string;
group: string;
createdAt: number;
}
\`\`\`
这就是”动态外脑”的威力。 三轮对话下来,一个模糊的”想做个管 Prompt 的插件”已经变成了带有数据模型、技术选型和明确边界的专业产品需求。哪怕你关掉 VS Code 明天再来,这些关键决策依然躺在磁盘里,AI 只要一读就能接上昨天的思路。
🔧 别忘了更新你的”员工手册”
调研阶段的技术决策(globalState、WebviewViewProvider、CSS 变量主题适配……)正是
copilot-instructions.md最好的素材。趁热让 AI 帮你固化:User:
请根据
findings.md中的技术决策,更新.github/copilot-instructions.md,把本项目的编码规范和技术约束补充进去。Copilot 会自动读取调研结论,在 Instructions 中追加类似这样的规则:
• 存储必须使用 context.globalState,禁止引入额外数据库依赖• Webview UI 必须使用 VS Code 内置 CSS 变量( --vscode-*)适配主题,禁止硬编码颜色值• Extension ↔ Webview 通信必须通过 postMessage,消息类型需在types.ts中定义这样一来,后续所有阶段的代码生成都会自动遵守这些约束——Research 的成果直接变成了 Instructions 的规则,形成闭环。
Step 2: 制定计划 — 让 AI 当架构师拆解任务 (Plan)
需求明确了,但还不能直接写代码。此时我们要让 AI 切换角色:从产品经理变成架构师,把需求翻译成可执行的工程计划。
第 1 轮:请求初版计划
User:
请以资深 VS Code 插件架构师的视角,根据 findings.md 制定详细的实施计划,更新到 task_plan.md。
Copilot:
我已读取
findings.md,以下是初版计划:
• Phase 1: Research ✅ • Phase 2: Project Scaffold — 使用 yo code生成项目骨架• Phase 3: Data Layer — 实现 PromptService(CRUD + globalState)• Phase 4: Webview Provider — 实现 SidebarProvider• Phase 5: UI — 编写 Webview HTML + 消息处理 • Phase 6: Testing & Polish
第 2 轮:追问架构细节
User:
等一下。Phase 4 和 Phase 5 的划分逻辑是什么?另外,Extension Host 和 Webview 之间的消息协议应该在哪个阶段定义?
Copilot:
好问题。让我解释设计决策:
Phase 4 vs Phase 5 的边界:Phase 4 只做”管道”(注册 Provider、建立通信通道),Phase 5 做”内容”(HTML 渲染、按钮事件)。这样 Phase 4 完成后就能用最简单的
<h1>Hello</h1>验证侧边栏是否正常加载,不用等 UI 全部写完才能测试。消息协议:你说得对,应该在写代码之前先约定。我建议在 Phase 3 和 Phase 4 之间插入一个 Phase 3.5: Interface & Protocol Design,把
PromptItem接口和WebviewMessage类型定义清楚,它们是 Data Layer 和 Webview 之间的”合约”。是否同意这个调整?
第 3 轮:确认并锁定计划
User:
同意。另外每个 Phase 的子任务也列出来,我需要能一项项打钩。
Copilot:
已更新
task_plan.md。
此时打开 task_plan.md,计划已经从粗粒度的 6 行变成了可执行的工程 Checklist:
# Task Plan
## Goal
VS Code 侧边栏插件:增删改查 Prompt,支持分组和一键插入编辑器
## Phases
- [x] **Phase 1: Research** (Completed)
- [ ] **Phase 2: Project Scaffold** (Current)
- [ ] Run `yo code` → TypeScript extension template
- [ ] Configure `package.json`: viewsContainers, views, activationEvents
- [ ] Verify empty sidebar panel loads in Extension Dev Host
- [ ] **Phase 3: Data Layer**
- [ ] Define `PromptItem` interface in `src/types.ts`
- [ ] Implement `PromptService` class (CRUD via globalState)
- [ ] Unit tests for PromptService
- [ ] **Phase 3.5: Interface & Protocol Design**
- [ ] Define `WebviewMessage` types (addPrompt, deletePrompt, getPrompts, insertToEditor)
- [ ] Document message flow in findings.md
- [ ] **Phase 4: Webview Provider (管道)**
- [ ] Implement `SidebarProvider.resolveWebviewView()`
- [ ] Wire up `onDidReceiveMessage` ↔ `PromptService`
- [ ] Verify with minimal HTML (`<h1>Hello</h1>`)
- [ ] **Phase 5: UI Development (内容)**
- [ ] Build HTML with VS Code CSS variables for native theming
- [ ] Implement prompt list rendering (grouped)
- [ ] Implement add/edit form
- [ ] Implement "Insert to Editor" button handler
- [ ] **Phase 6: Testing & Polish**
- [ ] End-to-end manual testing
- [ ] Error handling and edge cases
- [ ] README documentation
注意两个亮点:
-
1. Phase 3.5 是通过对话追问后新增的——AI 最初的计划并不完美,但通过一轮追问,我们让它补上了接口协议设计这个关键步骤。这正是 R-P-C-T 的价值:你不需要自己是架构师,只需要会提问。 -
2. Phase 4 的验证点明确写了”用最简 HTML 验证”——这让每个阶段都有一个可测试的里程碑,而不是等到全部写完才发现基础就是错的。
Step 3: 验收标准 — 先写”及格线”,再动手 (Criteria)
经过前两步,我们的需求和架构已经非常清晰——这正是引入 TDD(测试驱动开发) 的最佳时机。需求越明确,测试越好写;测试越先写,代码越不会跑偏。
在 R-P-C-T 中,C (Criteria) 的含义是:在写一行实现代码之前,先定义”什么算完成”。
User:
我们进入 Phase 3: Data Layer。在写实现之前,请先根据 findings.md 中的数据模型和需求,为
PromptService生成验收标准和对应的测试用例。采用 TDD — 先写失败测试。
Copilot:
好的。我已读取
findings.md中的PromptItem接口和 MVP 需求。以下是PromptService的验收标准:
1. ✅ 能添加一条 Prompt,返回带有自动生成 id 的完整对象 2. ✅ 能按 id 删除一条 Prompt 3. ✅ 能按 id 更新 Prompt 的 title、content 或 group 4. ✅ 能获取全部 Prompt 列表 5. ✅ 能按 group 过滤 Prompt 6. ✅ 数据在 VS Code 重启后仍然存在(globalState 持久化) 我先生成对应的测试文件。
Copilot 随即创建了 src/test/promptService.test.ts:
import { PromptService } from'../promptService';
// Mock globalState
constmockState: Record<string, any> = {};
const mockGlobalState = {
get: (key: string) => mockState[key],
update: (key: string, value: any) => { mockState[key] = value; returnPromise.resolve(); }
};
describe('PromptService', () => {
letservice: PromptService;
beforeEach(() => {
// 每个 Case 重置状态,确保测试隔离
Object.keys(mockState).forEach(k =>delete mockState[k]);
service = newPromptService(mockGlobalState asany);
});
test('should add a prompt and return it with generated id', async () => {
const result = await service.add({ title: 'Review', content: 'Please review...', group: 'Code Review' });
expect(result.id).toBeDefined();
expect(result.title).toBe('Review');
});
test('should delete a prompt by id', async () => {
const added = await service.add({ title: 'Test', content: '...', group: 'General' });
await service.delete(added.id);
const all = await service.getAll();
expect(all).toHaveLength(0);
});
test('should update a prompt', async () => {
const added = await service.add({ title: 'Old', content: '...', group: 'General' });
await service.update(added.id, { title: 'New' });
const all = await service.getAll();
expect(all[0].title).toBe('New');
});
test('should filter prompts by group', async () => {
await service.add({ title: 'A', content: '...', group: 'Review' });
await service.add({ title: 'B', content: '...', group: 'Docs' });
const filtered = await service.getByGroup('Review');
expect(filtered).toHaveLength(1);
expect(filtered[0].title).toBe('A');
});
test('should persist data via globalState', async () => {
await service.add({ title: 'Persist', content: 'test', group: 'General' });
// 模拟重启:用同一份 mockState 创建新实例
const newService = newPromptService(mockGlobalState asany);
const all = await newService.getAll();
expect(all).toHaveLength(1);
expect(all[0].title).toBe('Persist');
});
});
此时运行测试——全部失败 (RED)。这完全是预期的,因为 PromptService 还没写。但现在我们手里有了一份精确的”验收合同”,接下来的实现只需要把红变绿就行。
💡 为什么这一步如此关键? 想象一下,如果没有测试,AI 写的
delete()方法可能只从内存中删了数据却没调用globalState.update()同步持久化——你当时测试”看起来删掉了”,但重启 VS Code 后数据又回来了。有了最后一条持久化测试(模拟重启后数据仍在),这种 Bug 在第一时间就会被捕获。
Step 4: 红绿重构 — 让测试从红变绿 (TDD)
现在是最有确定性的阶段:我们不需要告诉 AI”大概写个什么”,而是给它一个明确的目标——让测试通过。
User:
现在请实现
PromptService,目标是让刚才的所有测试用例通过。严格遵守 findings.md 中的技术决策。
Copilot 遵循 Skill 中的 “Read Before Write” 规则,先读取 findings.md 确认存储方案和数据模型,然后生成实现代码。
运行测试——假设有 4 个通过,1 个 getByGroup 失败了。Copilot 自觉记录到 progress.md:
progress.md 更新:
## [2026-02-08] Phase 3: Data Layer
- Action: Implemented PromptService (add, delete, update, getAll, getByGroup)
- Test Result: 4/5 passed
- Error: `getByGroup('Review')` returned empty array
- Cause: Filter compared `group` with strict equality but stored value had trailing space
- Fix: Added `.trim()` to group field during `add()`
- Re-run: 5/5 passed ✅
修复后再次运行——全部通过 (GREEN)。
User:
测试全过了。请打钩 Phase 3,继续下一阶段。
Copilot 更新 task_plan.md,将 Phase 3 标记为完成,把当前指针移到 Phase 3.5。
后续的 Phase 4(Webview Provider)也遵循同样的节奏:先写”侧边栏能加载出来”的验证、再写”消息能发送和接收”的测试,然后让 AI 写实现代码去通过它们。
比如在 Phase 4 中,AI 遇到了一个经典坑——忘记在 package.json 中注册 contributes.views,导致侧边栏压根不显示。但因为我们有测试和 progress.md,这个错误会被立刻记录:
## [2026-02-08] Phase 4: Webview Provider
- Error: "No view is registered with id: promptManager.sidebarView"
- Cause: Missing `contributes.views` and `viewsContainers` in package.json
- Fix: Added sidebar container and view configuration
如果将来在 Phase 5 或其他项目中需要注册新的 View,AI 会检索这个文件,避免在同一个坑里跌倒两次。
Step 5: 成果展示 — 回顾 AI 交付了什么
经过多个 Phase 的 “Read Plan → Write Code → Run Tests → Update Status” 循环,我们从一句”想做个管 Prompt 的插件”出发,最终得到了一个可发布的 VS Code 扩展。让我们盘点一下成果,以及 AI 在每个环节到底扮演了什么角色。
交付物一览
|
|
|
|
| 数据层 | types.ts
promptService.ts |
findings.md 中的数据模型自主生成接口定义和完整 CRUD 实现,包含 globalState 持久化 |
| 通信层 | WebviewMessage
|
addPrompt、deletePrompt、getPrompts、insertToEditor 四种消息类型 |
| 视图层 | SidebarProvider.ts |
WebviewViewProvider API 实现侧边栏注册,正确处理 Webview 生命周期和消息路由 |
| UI 层 |
|
|
| 测试层 | promptService.test.ts |
|
| 配置层 | package.json
|
viewsContainers、views、activationEvents 等声明式配置 |
核心功能演示
最终的插件实现了 MVP 中规划的所有能力:
┌─────────────────────────────┐
│ PROMPT MANAGER (Sidebar) │
├─────────────────────────────┤
│ 📁 Code Review │
│ ├─ "代码审查通用" [📋] │
│ └─ "安全审查专项" [📋] │
│ 📁 Docs │
│ └─ "API 文档生成" [📋] │
│ 📁 General │
│ └─ "需求分析模板" [📋] │
├─────────────────────────────┤
│ [+ Add Prompt] │
└─────────────────────────────┘
📋 = Insert to Editor
-
• 增删改查:在侧边栏直接管理 Prompt,数据通过 globalState跨工作区持久化 -
• 分组展示:按 group 字段自动归类,一目了然 -
• 一键插入:点击 📋 按钮,Prompt 内容直接插入到当前编辑器光标位置
AI 在每个阶段扮演的角色
回顾整个过程,AI 的贡献远不止”自动补全”——它在体力、速度、知识广度、学习深度上全面碾压人类个体,而 R-P-C-T 的作用就是给这头猛兽套上缰绳,让它的能力精确释放在每个阶段:
|
|
|
|
| Research | 信息整合
|
|
| Plan | 架构经验
|
|
| Criteria | 严谨推演
|
|
| TDD | 执行速度
PromptService 实现,跑测试、定位 Bug、修复、再跑,整个 RED→GREEN 循环不到 1 分钟 |
|
换个更直白的说法:AI 在智力密度(瞬间调用全量 API 文档)、执行速度(秒级代码生成)、知识广度(同时懂 VS Code 扩展架构、TDD 方法论、TypeScript 类型系统)上,已经远超任何单个开发者。它缺的不是能力,而是方向感——而这正是 R-P-C-T + Instructions + Skills 给它的东西。
最终统计:整个项目约 800+ 行代码,人类手动输入的不超过 20 句自然语言对话。AI 负责了 99% 的执行,你负责了 100% 的决策。
二、 这套体系为什么有效?
你可能会问:搞这么多文件和流程,不是比直接聊天更麻烦吗?
恰恰相反。短期看是多了几步,长期看是省了几倍。 让我们从三个维度拆解。
1. 对抗”熵增”——从混乱对话到结构化知识
对话是线性的流,旧信息会被不断挤出上下文窗口。项目进行到第三天,AI 早就忘了第一天定下的数据模型。
而我们的三文件体系把知识固化到磁盘:
|
|
|
|
findings.md |
|
|
task_plan.md |
|
|
progress.md |
|
|
无论项目进行到哪一天,AI 只需 “Read files before coding”,就能在 3 秒内恢复满血状态。
2. 三层架构形成”飞轮效应”
本次实战最关键的洞察是:三套工具不是各自为战,而是互相增强。
┌─────────────────────────────────────────────┐
│ 你 (Tech Lead) │
│ 决策 · 审查 · 提问 · 验收 │
└──────────┬──────────────┬───────────────┬────┘
▼ ▼ ▼
┌─────────────┐ ┌────────────┐ ┌────────────┐
│ R-P-C-T │ │Instructions│ │ Skills │
│ 工作流引擎 │ │ 静态规范 │ │ 动态记忆 │
│ │ │ │ │ │
│ 告诉 AI │ │ 告诉 AI │ │ 告诉 AI │
│ "按什么顺序 │ │ "一直遵守 │ │ "现在该做 │
│ 思考" │ │ 什么规矩" │ │ 什么事" │
└──────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
└───────────────┼───────────────┘
▼
高质量代码输出
-
• R-P-C-T 确保 AI 按正确的顺序思考:先调研、再规划、定标准、最后动手 -
• Instructions 确保每一行生成的代码都符合项目规范,不会偏离技术选型 -
• Skills 确保 AI 在执行复杂任务时保持记忆,不在第五步忘了第一步的决策
更妙的是,它们之间还有反哺回路:Step 1 的调研成果写进 findings.md,同时也更新了 copilot-instructions.md——Research 喂养 Instructions,Instructions 约束后续所有 Phase 的代码生成。
3. TDD 让 AI 从”碰运气”变成”有目标”
很多人用 AI 写代码的体验是:生成一坨,跑一下,报错,再让 AI 改,改完又报新错…… 无限循环。
本次实战中,我们用 TDD 彻底终结了这个死循环:
-
• C (Criteria):先写测试 → AI 有了精确的靶子,而不是”大概写个什么” -
• T (TDD):RED → GREEN → Refactor → AI 每次修改都有即时反馈,而不是”改了不知道对不对”
结果就是:Copilot 不再是那个”写一堆你还得逐行 Review”的代码生成器,而变成了一个能自我验证、自我修复的工程师。
总结:一个人就是一支队伍
让我们回看这次实战的全貌:
从一句 “我想做个管 Prompt 的插件”,到一个可发布的 VS Code 扩展——800+ 行代码、7 个工程阶段(含 Phase 3.5)、完整的测试覆盖。而你,全程只输入了大约 20 句自然语言。
这是怎么做到的?因为你不是在”跟 AI 聊天”,而是在带领一支虚拟团队:
|
|
|
|
| 产品经理 |
|
findings.md |
| 架构师 |
|
task_plan.md |
| QA 工程师 |
|
|
| 开发工程师 |
|
progress.md |
| 规范管理员 |
|
|
| 项目记忆 |
|
|
而你,在这个体系中扮演的是 Tech Lead:
-
• 你不写代码,但你审查每一个 Phase 的产出 -
• 你不做设计,但你追问”消息协议应该在哪个阶段定义?”——一个问题逼出了 Phase 3.5 -
• 你不改 Bug,但你定下”先写测试再写实现”的铁律——让 Bug 在诞生的第一秒就被捕获
这才是 AI 时代开发者的正确姿态:你负责方向和标准,AI 负责速度和执行。
试试看吧。打开你的 VS Code,配好 Instructions 和 Skills,对 Copilot 说出你的第一句话。然后你会发现——原来一个人,真的可以是一支队伍。
下期预告
解决了”怎么想”和”怎么记”的问题,下期我们来聊聊”怎么动”。
我们将深入 VS Code 的 Slash Commands(斜杠命令),教你如何自定义 /fix-bug、/generate-test 等快捷指令,让繁琐的重复性工作变成一键直达的魔法。
关注我,不迷路,带你玩转 AI 编程!
夜雨聆风
