Appearance
Part 4: 正确使用 AI 编程 (25-30 min)
核心思路:从「怎么做」出发,通过现场演示展示 Best Practice
4.1 Context Engineering 实操要点
Part 2 讲了 Context Engineering 是什么,这里讲怎么做。
text
┌─────────────────────────────────────────────────────────────────────┐
│ Context Engineering 的核心思维 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 错误思维:「我要把所有信息都告诉 AI」 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 项目文档 + 所有代码 + 历史对话 + 各种规范 + ... │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ Context 爆炸 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 准确率下降 (Context Rot) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ✅ 正确思维:「最小化高信号 Token」 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 只给当前任务需要的信息 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ System Prompt │ ← CLAUDE.md (精简) │ │
│ │ │ + 相关文件 │ ← 按需读取 │ │
│ │ │ + 当前任务描述 │ ← 具体、明确 │ │
│ │ └─────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 高质量输出 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘三条核心原则(来自 Anthropic 官方指南):
| 原则 | 说明 | 实操建议 |
|---|---|---|
| Context 是有限资源 | 准确率随 token 数增加而下降 | 定期 /clear,不要让对话无限累积 |
| 工具集要精简 | 每个工具占用 Context,功能重叠会让 AI 困惑 | MCP 不要装太多,保持功能不重叠 |
| 具体胜过模糊 | 「写测试」不如「为 foo.py 的登出边界情况写测试,不要用 mock」 | 花时间写好 prompt,比反复纠正划算 |
4.1.1 好 Context vs 坏 Context
这是同一个需求的两种写法,效果天差地别:
text
┌─────────────────────────────────────────────────────────────────────┐
│ ❌ 坏 Context │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 「帮我写一个时钟」 │
│ │
│ 问题: │
│ · 什么样的时钟?数字?模拟? │
│ · 什么技术栈?React?Vue?原生 JS? │
│ · 什么风格?简约?华丽? │
│ · 要什么功能?只显示时间?还是要闹钟? │
│ │
│ 结果:AI 自己猜,猜错了再改,浪费 Context │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ ✅ 好 Context │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 「用原生 HTML/CSS/JS 写一个数字时钟: │
│ │
│ 功能要求: │
│ - 显示当前时间(时:分:秒) │
│ - 每秒自动更新 │
│ - 24 小时制 │
│ │
│ 样式要求: │
│ - 深色背景 (#1a1a2e) │
│ - 白色数字,使用等宽字体 │
│ - 居中显示,字号要大 │
│ │
│ 文件结构:单个 index.html 文件,CSS 和 JS 内联」 │
│ │
│ 结果:AI 一次性给出符合预期的代码 │
│ │
└─────────────────────────────────────────────────────────────────────┘写好 Context 的检查清单:
- [ ] 技术栈明确了吗?
- [ ] 功能边界清晰吗?
- [ ] 有没有可能被误解的地方?
- [ ] 输出格式/文件结构说清楚了吗?
4.1.2 提问心智:模拟器而非实体
专家观点 — Andrej Karpathy
背景:前 Tesla AI 总监、OpenAI 联合创始人、斯坦福 CS231n 课程讲师 来源:2025 年 12 月 X 推文 [1]
「不要把 LLM 当作实体(Entity),要当作模拟器(Simulator)。」
这是什么意思?
text
┌─────────────────────────────────────────────────────────────────────┐
│ LLM 是模拟器,不是实体 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 把 LLM 当「实体」 │
│ │
│ 你: 「关于 XXX,你怎么看?」 │
│ │
│ 问题:根本不存在「你」。 │
│ │
│ LLM 会怎么做? │
│ → 采用一个「人格嵌入向量」(personality embedding vector) │
│ → 这个向量来自微调数据的统计规律 │
│ → 模拟一个「大众脸」来回答你 │
│ │
│ 结果:你得到的是一个「平均意见」,不是深思熟虑的观点 │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ✅ 把 LLM 当「模拟器」 │
│ │
│ 你: 「如果要探讨 XXX 这个话题,最合适的专家是谁?他们会怎么说?」 │
│ │
│ LLM 会怎么做? │
│ → 模拟特定领域专家的视角 │
│ → 调用训练数据中该领域的知识 │
│ → 给出更专业、更有针对性的回答 │
│ │
│ 结果:你得到的是「专家视角的模拟」,质量更高 │
│ │
└─────────────────────────────────────────────────────────────────────┘专家观点 — Andrej Karpathy [^65]
(2023 年 State of GPT 演讲)
「这些 Transformer 就是 token 模拟器。它们不知道自己不知道什么,只是尽力模拟下一个 token。」
这和 Context Engineering 有什么关系?
其实这也是一种「高信号 Context」—— 告诉模型要模拟谁。
| 提问方式 | 模型行为 | 结果质量 |
|---|---|---|
| 「你觉得这段代码怎么样?」 | 模拟「平均程序员」 | 泛泛而谈 |
| 「假设你是 Google 的 Staff Engineer,审查这段代码会关注什么?」 | 模拟「资深工程师」 | 更专业的审查意见 |
| 「这个架构设计有什么问题?」 | 模拟「平均意见」 | 可能漏掉关键点 |
| 「如果 Martin Fowler 看这个架构,他会怎么评价?」 | 模拟「架构大师视角」 | 更深入的分析 |
实操建议:
- 问观点性问题时,指定一个「角色」或「专家群体」
- 不是说「你是 XXX 专家」这种 roleplay,而是问「XXX 领域的专家会怎么看」
- 这样做的本质是:帮模型选择一个更高质量的「模拟目标」
4.1.3 Course Correct:早期纠偏
AI 走偏是正常的,关键是早发现、早纠正。
text
┌─────────────────────────────────────────────────────────────────────┐
│ Course Correct 时机 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 太晚纠正 │
│ │
│ 你: 写一个时钟 │
│ AI: [写了 500 行 React 代码] │
│ 你: 不对,我要原生 JS │
│ AI: [重写 500 行] │
│ │
│ → 浪费了大量 Context 和时间 │
│ │
│ ✅ 早期纠正 │
│ │
│ 你: 写一个时钟 │
│ AI: 我打算用 React 来实现,首先... │
│ 你: 停,用原生 JS,不要框架 │
│ AI: 好的,那我用原生 JS... │
│ │
│ → 在 AI 动手之前就纠正方向 │
│ │
└─────────────────────────────────────────────────────────────────────┘纠偏技巧:
| 场景 | 做法 |
|---|---|
| AI 选错技术栈 | 立刻打断:「停,用 XXX 而不是 YYY」 |
| AI 过度设计 | 「简化,不需要 XXX 功能」 |
| AI 理解错需求 | 「不是这个意思,我要的是...」 |
| 对话太长开始混乱 | /clear 清空上下文,重新开始 |
4.2 CLAUDE.md:项目的 AI 说明书
CLAUDE.md 是 Claude Code 的核心配置文件——AI 每次启动都会自动读取它。
text
┌─────────────────────────────────────────────────────────────────────┐
│ CLAUDE.md 的作用 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 没有 CLAUDE.md 有 CLAUDE.md │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Claude Code │ │ Claude Code │ │
│ │ │ │ │ │
│ │ 「这是什么项目? │ │ 「我知道: │ │
│ │ 用什么语言? │ │ - 这是 Python 项目│ │
│ │ 怎么跑测试? │ │ - 用 pytest 测试 │ │
│ │ 有什么规范?」 │ │ - 代码风格是... │ │
│ │ │ │ - 提交规范是...」│ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ 每次都要重新解释 直接开始工作,风格一致 │
│ │
└─────────────────────────────────────────────────────────────────────┘4.2.1 CLAUDE.md 写什么?
遵循 WHAT / WHY / HOW 结构(来自 HumanLayer 指南):
| 部分 | 内容 | 示例 |
|---|---|---|
| WHAT | 项目是什么、技术栈 | 「这是一个 Python 3.11 的 Home Assistant 集成」 |
| WHY | 项目目标、各模块作用 | 「用于接入公司物联网网关」 |
| HOW | 开发流程、测试方法、提交规范 | 「用 pytest 跑测试,commit 遵循 Conventional Commits」 |
关键原则:
| 原则 | 说明 |
|---|---|
| 保持精简 | 研究表明 LLM 可靠遵循 150-200 条指令,Claude Code 自带 ~50 条,留给你的不多 |
| 控制长度 | 300 行以内,理想情况 60 行以内 |
| 只写通用规则 | 不要写「某个具体功能怎么实现」,那是任务描述不是项目规范 |
| 不要当 Linter | 代码风格用 ESLint/Prettier/Ruff 等工具,不要写在 CLAUDE.md 里 |
| 手动编写 | 不要用 /init 自动生成,那个效果很差 |
4.2.2 我的实践:OpenSpec
作者实践
以下是我个人采用的工作流,不一定适合所有人。供参考。
我现在用的是 OpenSpec——一个 spec-driven 的开发流程。
text
┌─────────────────────────────────────────────────────────────────────┐
│ OpenSpec 目录结构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ project/ │
│ ├── CLAUDE.md ← 项目入口,引用 OpenSpec │
│ └── openspec/ │
│ ├── AGENTS.md ← AI 的详细指南 │
│ ├── project.md ← 项目规范 │
│ ├── specs/ ← 当前状态(已实现的功能) │
│ │ └── [capability]/ │
│ │ └── spec.md │
│ └── changes/ ← 变更提案(待实现的功能) │
│ └── [change-name]/ │
│ ├── proposal.md │
│ ├── tasks.md │
│ └── specs/ │
│ │
└─────────────────────────────────────────────────────────────────────┘OpenSpec 的核心思想:
「Specs 是真相(已构建),Changes 是提案(待构建),保持它们同步。」
三阶段工作流:
| 阶段 | 触发条件 | 产出 |
|---|---|---|
| 1. 创建提案 | 新功能、Breaking Change、架构变更 | proposal.md + tasks.md + spec deltas |
| 2. 实现提案 | 提案被批准 | 代码实现,按 tasks.md 逐项完成 |
| 3. 归档提案 | 部署完成 | 移动到 archive/,更新 specs/ |
这样做的好处是:AI 在写代码之前,先帮你把需求和方案理清楚。避免了 Vibe Coding 那种「边写边想」的混乱。
4.3 现场演示:从零到部署
演示任务:用 Claude Code 从零开始,创建并部署一个时钟应用到 GitHub Pages
阶段一:好 Context vs 坏 Context
第一步:展示「坏 Context」的效果
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 1(坏 Context) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 帮我写一个时钟 │
│ │
│ [等待 AI 响应,观察它会怎么理解这个模糊需求] │
│ │
│ 预期问题: │
│ - AI 可能选择你不想要的技术栈 │
│ - AI 可能添加你不需要的功能 │
│ - AI 可能问一堆澄清问题(浪费时间) │
│ │
└─────────────────────────────────────────────────────────────────────┘第二步:展示「好 Context」的效果
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 2(好 Context) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 用原生 HTML/CSS/JS 写一个数字时钟。 │
│ │
│ 功能: │
│ - 显示当前时间(时:分:秒),24 小时制 │
│ - 每秒自动更新 │
│ │
│ 样式: │
│ - 深色背景,白色等宽字体 │
│ - 数字要大,居中显示 │
│ │
│ 输出:单个 index.html 文件,CSS/JS 内联 │
│ │
│ [观察 AI 直接给出符合预期的代码] │
│ │
└─────────────────────────────────────────────────────────────────────┘第三步:迭代添加功能
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 3(增量开发) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 在数字时钟下方加一个模拟时钟(圆形表盘 + 时针分针秒针)。 │
│ 保持同样的配色风格。 │
│ │
│ [观察 AI 如何在现有代码基础上增量修改] │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 4(主题切换) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 加一个主题切换按钮,可以在深色/浅色主题之间切换。 │
│ 记住用户的选择(用 localStorage)。 │
│ │
└─────────────────────────────────────────────────────────────────────┘阶段二:Course Correct 演示
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 5(故意制造纠偏场景) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 加一个闹钟功能 │
│ │
│ AI: 好的,我来添加闹钟功能。我打算: │
│ 1. 添加一个设置闹钟时间的输入框 │
│ 2. 添加多个闹钟的支持... │
│ 3. 添加重复闹钟(每天/每周)... │
│ │
│ 你: 停。简化一下,只要: │
│ - 一个闹钟就够 │
│ - 用 prompt() 输入时间 │
│ - 到时间 alert 一下就行 │
│ │
│ [展示早期纠偏如何节省 Context] │
│ │
└─────────────────────────────────────────────────────────────────────┘阶段三:部署上线
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 6(GitHub 部署) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 你: 帮我把这个时钟部署到 GitHub Pages: │
│ │
│ 1. 用 gh 命令创建一个新的 public 仓库,名字叫 clock-demo │
│ 2. 初始化 git 并推送代码 │
│ 3. 配置 GitHub Actions 自动部署到 GitHub Pages │
│ 4. 告诉我最终的访问地址 │
│ │
│ [观察 AI 如何: │
│ - 调用 gh repo create │
│ - 创建 .github/workflows/deploy.yml │
│ - 执行 git 命令 │
│ - 一次性完成整个部署流程] │
│ │
└─────────────────────────────────────────────────────────────────────┘阶段四:Skill 实战
text
┌─────────────────────────────────────────────────────────────────────┐
│ 演示 Prompt 7(使用 Git Workflow Skill) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [先对时钟做一个小修改,比如改个颜色] │
│ │
│ 你: /git-workflow 帮我提交这个修改 │
│ │
│ [Skill 自动加载,按照预定义的流程: │
│ - 检查 git status / git diff │
│ - 生成符合 Conventional Commits 格式的 message │
│ 格式: type(scope): concise summary │
│ 类型: feat / fix / refactor / docs / test / chore │
│ - 不带 AI 生成标记(无 🤖 签名) │
│ - 执行 commit 和 push] │
│ │
│ 示例输出: │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ feat(ui): add theme toggle button │ │
│ │ │ │
│ │ - Support dark/light theme switching │ │
│ │ - Persist user preference in localStorage │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ 对比:没有 Skill 时,你需要每次都告诉 AI: │
│ 「帮我 commit,用 Conventional Commits 格式,不要加 AI 签名...」 │
│ │
└─────────────────────────────────────────────────────────────────────┘Git Workflow Skill 的三个工作流(可独立或组合使用):
| 工作流 | 触发方式 | 作用 |
|---|---|---|
| Commit | /git-workflow 帮我提交 | 生成规范的 commit message |
| Pull Request | /git-workflow 帮我创建 PR | 创建分支 → commit → 开 PR |
| Release | /git-workflow 帮我发布 | 更新版本号 → 改 CHANGELOG → 打 tag → 发布 |
演示要点总结:
| 阶段 | 展示的概念 | 对应 Part 2 的知识点 |
|---|---|---|
| 阶段一 | Context 质量决定输出质量 | Context Engineering |
| 阶段二 | 早期纠偏节省 Context | Agent 的 ReAct 循环 |
| 阶段三 | AI 直接操作外部工具 | Function Call / Tool Use |
| 阶段四 | Skill 封装重复工作流 | Skills 渐进式加载 |
[!TODO] 演示准备
- [ ] 准备干净的演示环境(新文件夹、gh CLI 已登录)
- [ ] 测试完整流程(确保 GitHub Pages 能正常部署)
- [ ] 准备 Git Workflow Skill
- [ ] 录制备用视频(防止现场网络问题)
- [ ] 准备「坏 Context」的反面例子
4.4 什么时候 AI 帮助最大?
不是所有任务都适合用 AI。引用 软件工程的「纯」与「不纯」:
text
┌─────────────────────────────────────────────────────────────────────┐
│ 纯粹工程 vs 不纯粹工程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 纯粹工程 不纯粹工程 │
│ (Pure Engineering) (Impure Engineering) │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ · 你非常了解的问题 │ │ · 你只有粗浅理解 │ │
│ │ · 社区不熟知 │ │ · 问题不新颖 │ │
│ │ (值得研究) │ │ 只是对你新 │ │
│ │ · 在专长极限边缘 │ │ · 很少处理透彻 │ │
│ │ · 有无限时间 │ │ 理解的问题 │ │
│ │ │ │ · 紧迫的截止日期 │ │
│ └──────────┬──────────┘ └──────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ AI 帮不上忙 │ │ AI 可能比你更聪明 │ │
│ │ (需要深度思考) │ │ (快速出活) │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘物联网开发的例子:
| 场景 | 类型 | AI 的作用 |
|---|---|---|
| 写 Home Assistant 集成的样板代码 | 不纯粹 | 很有帮助,快速生成 |
| 调试特定硬件的通信协议问题 | 纯粹 | 帮助有限,需要你深入理解 |
| 把现有代码移植到新平台 | 不纯粹 | 很有帮助,机械性工作 |
| 设计系统架构 | 纯粹 | 可以讨论,但决策得你做 |
| 写单元测试 | 不纯粹 | 很有帮助,重复性工作 |
| 排查生产环境的诡异 bug | 纯粹 | 帮助有限,需要经验判断 |
作者观点
AI 最擅长的是「不纯粹工程」——那些你知道怎么做、但做起来很繁琐的事情。而「纯粹工程」——需要深度思考和创造性的部分——还是得靠你自己。
4.5 工具链总结
text
┌─────────────────────────────────────────────────────────────────────┐
│ Claude Code 工具链全景 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ CLAUDE.md │ │
│ │ (项目入口配置) │ │
│ │ │ │
│ │ · WHAT: 项目是什么、技术栈 │ │
│ │ · WHY: 项目目标 │ │
│ │ · HOW: 开发流程、测试方法 │ │
│ └──────────────────────────┬──────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Skills │ │ MCP │ │ Slash │ │
│ │ │ │ Servers │ │ Commands │ │
│ │ 可复用 │ │ │ │ │ │
│ │ 能力包 │ │ 连接外部 │ │ 快捷命令 │ │
│ │ │ │ 服务 │ │ │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │writing- │ │ GitHub │ │/openspec │ │
│ │assistant │ │ Slack │ │:proposal │ │
│ │git- │ │ Database │ │/git- │ │
│ │workflow │ │ ... │ │workflow │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘| 工具 | 作用 | 我的使用场景 |
|---|---|---|
| CLAUDE.md | 项目配置入口 | 每个项目都有,定义基本规范 |
| OpenSpec | Spec-driven 开发流程 | 大功能开发前先写 proposal |
| Skills | 可复用的能力模块 | writing-assistant 写文章、git-workflow 提交代码 |
| MCP | 连接外部服务 | GitHub、文件系统 |
| Slash Commands | 快捷命令 | /openspec:proposal 创建提案 |
实际例子:这篇分享稿就是这样写出来的:
- 起手
/writing-assistant启动写作 Skill - Skill 引导我按启发问题逐步写
- 写完后用审校模式检查结构、语言
- 最后用
/git-workflow提交
注意事项:
- MCP 不能装太多——每个 MCP Server 的工具定义都占用 Context
- Skills 按需加载——只有用到的时候才会消耗 Token
- 定期
/clear——不要让对话历史无限累积
[!TODO] 素材准备
- [ ] 展示你的 MCP 配置
- [ ] 展示 writing-assistant Skill 的效果
- [ ] 展示 OpenSpec 的工作流程
参考资料
💬 L4 | Don't think of LLMs as entities but as simulators | Andrej Karpathy - 2025 年 12 月 7 日推文,提出「LLM 是模拟器而非实体」的心智模型,解释 personality embedding vector 概念。 ↩︎