Vibe Coding 是当前 AI 编程领域里被讨论最多的工作方式之一。吴恩达(Andrew Ng)在 DeepLearning.AI 开设的 Vibe Coding 系列课程,把这种方法整理得比较系统,也附带了一组可以直接运行的示例代码。很多学习者把这套课程当作从“看 AI 生成代码”过渡到“和 AI 一起写代码”的入门材料。课程配有中英字幕,示例代码也会在视频里逐段解释,对国内开发者来说跟练门槛并不高。下面不会去复述每一节课,而是围绕“Vibe Coding 是什么、课程推荐的思路是什么、如何用示例代码跑通一个最小项目、常见坑怎么避”来展开。如果你正准备用 AI 编程工具写小工具、自动化脚本或者 Web 原型,这篇文章可以作为开课前后的操作笔记。
1. Vibe Coding 到底在解决什么问题
1.1 从“逐行手写”到“描述 + 迭代”
Vibe Coding 这一概念由 AI 领域研究者 Andrej Karpathy 提出,最早描述的是一种高度沉浸式的编程状态:人把主要精力放在表达意图上,AI 根据自然语言生成大段代码,人再通过运行结果和错误信息给出反馈。这里的“Vibe”并不意味着随便,而是指一种节奏,一段描述、一次生成、一次运行、一次修正,循环往复。
技术层面看,Vibe Coding 依赖的是大语言模型对代码的生成能力。模型并不是在“背答案”,而是根据你提供的上下文,预测下一段最可能的代码。正因为模型有概率性,同一个需求在不同提示词下会得到完全不同的结果。因此提示词质量、上下文完整度、失败后的反馈,都会直接影响输出质量。
在传统开发流程里,编码是一个“人写代码—人看错误—人改代码”的过程。Vibe Coding 把这个过程变成“人描述—AI 写代码—人跑起来—人反馈错误或新需求—AI 再改”。这个变化听起来简单,实际会改变工具链、项目结构和代码评审方式。课程里大量时间不是在讲语法,而是在讲如何把模糊想法拆成 AI 能理解的指令。
1.2 为什么吴恩达会单独开设这样一门课
吴恩达在 DeepLearning.AI 的课程体系里一直强调“AI 是放大器”。Vibe Coding 系列课程想回答的问题很直接:当代码生成能力足够好时,开发者的核心工作会从“写每一行代码”转向“定义清楚需求、拆解任务、评审代码、保证质量”。这门课因此受到程序员、产品经理和数据分析师的共同关注。
从课程内容安排看,它并不要求你先掌握复杂算法,而是重点训练这几件事:
- 把模糊想法变成具体需求。
- 用自然语言让 AI 生成完整功能。
- 阅读、测试、修复 AI 生成的代码。
- 把一个小工具逐步扩展成可维护应用。
这套能力并不只属于软件工程师。数据分析、运营、测试、产品岗位,只要需要处理数据或自动化任务,都可以用类似流程提高效率。这也是课程和普通“提示词教程”不太一样的地方:它不是教你几条万能咒语,而是带你从一个小项目开始,完整走一遍“AI 辅助开发”的流程。
1.3 Vibe Coding 不等于不写代码
需要先纠正一个常见误解:Vibe Coding 不是“完全不用写代码”,更不是“不会编程也能直接开发复杂系统”。课程里反复出现的一种状态是,人负责判断方向,AI 负责生成备选代码,人还要负责验收。如果完全看不懂代码,AI 一旦给出错误方案,你连错误日志都定位不了。
举一个典型例子:AI 生成了“把数据保存到 JSON 文件”的逻辑,本地测试没问题,但生产环境一旦有多进程同时写入,就可能丢数据。如果开发者不理解文件写入的竞争问题,就不会想到去换数据库。这个例子说明,Vibe Coding 适合作为编程学习的新入口,但不能替代基础能力训练。
真正的 Vibe Coding 能力,不在“让 AI 生成了多少行代码”,而在“你能不能判断它生成的代码对不对,能不能在出错时快速指出问题”。课程里的示例代码,就是为了训练这种判断力。
2. 学习这套课程前,先把环境准备到“可运行”状态
2.1 两条路线:云端 IDE 与本地 IDE
跟随课程练习时,第一步不是背提示词,而是准备一个能立即运行代码的环境。根据你的使用场景,可以选两条路线中的一条。
| 路线 | 代表工具 | 适合场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 云端 IDE | Replit、CodeSandbox 等 | 课程跟练、快速原型 | 不需要本地安装,打开浏览器就能运行 | 依赖网络,环境定制能力受限 |
| 本地 IDE | VS Code + AI 编程插件 | 长期项目、生产调试 | 可控性强,方便结合 git 和本地服务 | 需要自己安装环境,排错成本更高 |
课程视频里通常会在云端环境演示,因为观众不用花时间装依赖。但实际工程里,我更推荐本地路线。原因很简单:本地环境能让你看到虚拟环境、依赖安装、路径配置这些真实工程问题;云端环境把这些都隐藏了,你不太容易理解“为什么换一台电脑就跑不起来”。
2.2 用 VS Code + AI 编程插件搭建本地环境
本地路线的核心是:VS Code + Python 解释器 + 一个能读取代码上下文的 AI 编程插件。AI 编程插件可以选择 Continue、GitHub Copilot、通义灵码等。选择原则不是看谁名气大,而是看它是否支持把当前文件或选中代码作为上下文发送给模型。
安装完 VS Code 后,先创建项目目录和虚拟环境。
mkdir vibe-todo cd vibe-todo python -m venv .venvWindows PowerShell 激活方式:
.venv\Scripts\Activate.ps1macOS 或 Linux 激活方式:
source .venv/bin/activate激活后执行下面的命令,确认 Python 和 pip 已经指向虚拟环境:
python --version pip --version虚拟环境的作用是把项目依赖和系统 Python 隔离。实际项目中,不同项目可能依赖不同版本的 Flask、Django 或 requests。如果全部装到系统 Python 里,版本冲突只是时间问题。这一步看似多余,却能避免大量“我这能跑、你那报错”的问题。
2.3 依赖和项目结构
为了后面的示例能直接运行,先准备一个requirements.txt。这里以 Flask 3.x 为例,实际课程如果使用其他模板,以模板里的版本为准。
flask==3.0.3项目目录建议这样组织:
vibe-todo/ ├── app.py ├── requirements.txt ├── templates/ │ └── index.html └── data/ └── todos.jsonapp.py是 Flask 应用入口,templates/index.html是页面模板,data/todos.json用来保存待办事项数据。data目录可以先不创建,代码在运行时可以通过Path.mkdir自动建立。这样做的目的是保持项目结构简洁,同时让 AI 生成的代码具备“自动初始化”能力,减少手工建目录的步骤。
在课程学习阶段,用 JSON 文件存数据完全够用,也方便观察数据变化。生产环境再换成数据库,逻辑不会变,只是数据层实现不同。
3. 一个最小 Vibe Coding 示例:让 AI 从零生成一个待办事项工具
3.1 明确需求,像写产品需求一样写提示词
课程的核心理念之一是:AI 只能基于你提供的信息做决定。如果你只说“帮我写一个待办事项应用”,AI 可能会给你 React 前端、Vue 前端、也可能是命令行版本,完全因人而异。正确做法是把提示词写得像一份小需求说明书。
下面是一个可以直接发给 AI 编程插件的提示词:
你是一个 Python Web 开发工程师。 请用 Flask 写一个单文件待办事项应用 app.py: - 支持新增待办事项 - 支持勾选完成/取消完成 - 支持删除待办事项 - 数据保存到 data/todos.json,如果文件或目录不存在则自动创建 - 每个待办事项包含 id、text、done 三个字段 - id 使用 uuid,不要用自增数字 - 页面使用 templates/index.html 渲染 - 路由包括: GET / POST /add POST /toggle/<todo_id> POST /delete/<todo_id> - 新增时如果内容为空,直接返回首页,不写入数据 - 代码中包含必要的异常处理为什么要写得这么具体?因为“单文件”决定了项目结构复杂度,“JSON 存储”决定了数据层实现,“uuid”决定了 id 生成方式,“接口路径”决定了前端表单和路由的对应关系。这些信息越清楚,AI 第一次生成的结果就越接近可运行状态。
3.2 第一轮:让 AI 生成可运行版本
把上面的提示词发给 AI 后,通常第一次生成的代码就能跑。下面是参考实现,实际项目可以按课程中的代码为准。
app.py:
import json import uuid from pathlib import Path from flask import Flask, render_template, request, redirect, url_for app = Flask(__name__) DATA_FILE = Path("data") / "todos.json" def load_todos() -> list: if not DATA_FILE.exists(): return [] with DATA_FILE.open("r", encoding="utf-8") as f: return json.load(f) def save_todos(todos: list) -> None: DATA_FILE.parent.mkdir(parents=True, exist_ok=True) with DATA_FILE.open("w", encoding="utf-8") as f: json.dump(todos, f, ensure_ascii=False, indent=2) @app.route("/") def index(): todos = load_todos() return render_template("index.html", todos=todos) @app.route("/add", methods=["POST"]) def add(): text = request.form.get("text", "").strip() if not text: return redirect(url_for("index")) todos = load_todos() todos.append( { "id": str(uuid.uuid4()), "text": text, "done": False, } ) save_todos(todos) return redirect(url_for("index")) @app.route("/toggle/<todo_id>", methods=["POST"]) def toggle(todo_id): todos = load_todos() for todo in todos: if todo["id"] == todo_id: todo["done"] = not todo["done"] save_todos(todos) return redirect(url_for("index")) @app.route("/delete/<todo_id>", methods=["POST"]) def delete(todo_id): todos = [todo for todo in load_todos() if todo["id"] != todo_id] save_todos(todos) return redirect(url_for("index")) if __name__ == "__main__": app.run(debug=True)templates/index.html:
<!doctype html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>Vibe Todo</title> </head> <body> <h1>待办事项</h1> <form method="post" action="/add"> <input type="text" name="text" placeholder="输入待办事项" required> <button type="submit">添加</button> </form> <ul> {% for todo in todos %} <li> <form method="post" action="/toggle/{{ todo.id }}" style="display:inline"> <input type="checkbox" {% if todo.done %}checked{% endif %} onchange="this.form.submit()"> </form> <span>{{ todo.text }}</span> <form method="post" action="/delete/{{ todo.id }}" style="display:inline"> <button type="submit">删除</button> </form> </li> {% endfor %} </ul> </body> </html>这份代码里有两个关键点。第一,load_todos和save_todos把数据读写逻辑抽出来了,后续如果要改存储方式,只需要动这两个函数。第二,id使用uuid,避免删除某个元素后,后续新增元素因为自增 id 冲突导致页面状态错乱。学习课程时,不要只是把代码复制走,要体会这些设计为什么能减少问题。
3.3 第二轮:迭代修复和增强功能
Vibe Coding 真正的体验在第二轮。第一轮生成的是“能跑”的版本,但你很快会发现功能不够:没有编辑功能、没有创建时间、没有筛选。这时不要重新写完整需求,而是只描述增量变化。
第二轮回合提示词:
请修改现有的 app.py 和 templates/index.html: - 新增编辑功能 - 页面中每个待办事项旁边添加“编辑”按钮 - 点击编辑后,把该事项的文本替换成输入框和“保存”按钮 - 新增路由 POST /edit/<todo_id>,用于保存修改后的文本 - 如果没有改动,不要修改现有数据格式 - 旧的 todos.json 数据要能继续使用这里的关键是“如果没改动,不要修改现有数据格式”和“旧数据要能继续使用”。它给 AI 设定了一个边界:允许你扩展功能,但不要破坏兼容性。很多 AI 生成的代码在迭代后会出现数据迁移问题,就是因为在第一轮生成时没有约定稳定数据结构。课程里相当多篇幅也在训练这种“增量式开发”的沟通方式。
4. 理解示例代码:AI 生成的代码也要能读懂
4.1 核心文件与职责
Vibe Coding 最容易出现的误区是“只生成,不阅读”。但实际项目中,你很可能需要解释代码、排查错误、扩展功能,所有操作都建立在理解代码结构的基础上。
| 文件 | 职责 | 关键点 |
|---|---|---|
app.py | Flask 路由、数据处理逻辑 | 数据读写被封装成load_todos和save_todos |
templates/index.html | 页面展示和表单交互 | 使用 Jinja2 模板语法遍历待办事项 |
data/todos.json | 数据持久化文件 | 运行前不存在,首次保存时自动创建 |
requirements.txt | Python 依赖清单 | 固定 Flask 版本,避免环境漂移 |
这个结构很小,但已经体现了 MVC 的基本思想:路由负责请求分发,模板负责展示,JSON 文件负责存储。AI 生成代码时,会自动选择这种常见结构。如果生成的代码把所有东西都写在一个文件里,可以继续发一句“请把样式和逻辑拆分到单独文件”,让代码更接近工程化。
4.2 关键逻辑说明
load_todos里使用Path.exists()判断文件是否存在。如果不存在,返回空列表。这样应用第一次启动时,不会因为缺少数据文件而崩溃。
save_todos里有两个细节:
DATA_FILE.parent.mkdir(parents=True, exist_ok=True)这一行会递归创建data目录。如果目录已经存在,exist_ok=True不会报错。这是 AI 生成代码时常见的“防御性写法”,保证新环境也能自动初始化。
json.dump(todos, f, ensure_ascii=False, indent=2)ensure_ascii=False表示不把中文转换成\uXXXX形式,让 JSON 文件直接可读;indent=2让数据格式更清晰,方便手工检查。
uuid.uuid4()生成随机 id,避免使用自增数字。自增数字在删除操作时会遇到一个问题:删除第 3 条后,新加的第 4 条可能仍旧是 4,但页面顺序和 id 的对应关系会变得不容易理解。使用 uuid 后,每次新增都是全新 id,前端路由、勾选、删除都不会混淆。
路由使用 POST 而不是 GET,也是有意设计。新增、删除、修改都会改变服务端数据,属于副作用操作。如果使用 GET,浏览器刷新或预加载可能会重复提交。POST 更符合 Web 语义,也方便后续加入 CSRF 防护。
4.3 如何给 AI 补充上下文
在 VS Code 的 AI 编程插件里,通常有两种方式补充上下文。方式一是在对话窗口直接粘贴app.py的代码;方式二是在代码中选中某个函数,让插件基于选中内容回答。第二种方式更推荐,因为上下文更聚焦,模型不会被无关代码干扰。
一个实用的对话示例:
请只解释 app.py 中 toggle 函数的作用。 如果前端复选框发出 POST /toggle/<todo_id>, 但数据没有更新,可能是什么原因? 请按这个顺序排查: 1. 路由是否匹配 2. 请求方式是否 POST 3. load_todos 是否读取正确文件 4. save_todos 是否被调用这样问,AI 会给出一个排查思路,而不是直接丢一段重写后的代码。把 Vibe Coding 从“让 AI 写代码”变成“让 AI 陪我读代码”,是课程最值得借鉴的学习方法。
5. 运行与验证:从“生成成功”到“真正可用”
5.1 启动应用并访问页面
安装依赖并启动:
pip install -r requirements.txt python app.py正常情况下,终端会显示类似下面的输出:
* Running on http://127.0.0.1:5000浏览器访问http://127.0.0.1:5000,应该能看到“待办事项”页面。添加一条文本后,条目会出现在列表中。勾选复选框后,文字对应的任务应该变成完成状态;点击删除后,条目应该消失。
如果页面提示template not found,通常是templates目录没有和app.py放在同一级。Flask 默认会从app.py所在目录下的templates目录查找模板,路径不对就会报错。
除了浏览器操作,还可以用curl直接验证接口逻辑:
curl -X POST -d "text=学习 Vibe Coding" http://127.0.0.1:5000/add curl http://127.0.0.1:5000/第一条命令新增一条待办,第二条命令返回首页 HTML。如果返回的 HTML 中包含“学习 Vibe Coding”,说明接口和模板渲染都正常。
5.2 验证数据文件
功能验证通过后,打开data/todos.json,预期会看到一条 JSON 记录:
[ { "id": "b2871e75-64c7-44db-9d5b-8a6d5dfbdab6", "text": "学习 Vibe Coding", "done": false } ]数据文件的作用有两个:一是确认写盘成功,二是方便排查问题。如果页面显示和文件内容不一致,问题大概率出在load_todos或save_todos的路径上。检查路径时直接看Path("data") / "todos.json"是相对路径还是绝对路径,当前工作目录是否正确。
5.3 常见运行异常排查表
| 问题现象 | 常见原因 | 检查方式 | 解决建议 |
|---|---|---|---|
ModuleNotFoundError: No module named 'flask' | 未安装依赖或激活了错误的虚拟环境 | 执行pip list查看 Flask 是否在列表 | 执行pip install -r requirements.txt |
jinja2.exceptions.TemplateNotFound | templates目录位置不对 | 检查app.py同级目录 | 把templates和app.py放在同一目录 |
| 访问后一直转圈或端口冲突 | 5000 端口被其他进程占用 | 执行lsof -i:5000或netstat -ano | 修改app.run(port=5001)或结束占用进程 |
| 页面显示中文乱码 | HTML 或 JSON 编码不一致 | 检查meta charset和文件保存编码 | HTML 使用utf-8,读取 JSON 时指定encoding="utf-8" |
| 新增后刷新页面出现重复提交 | 浏览器重复提交 POST 表单 | 查看终端请求日志 | 提交后使用redirect跳转,不要直接返回渲染后的 HTML |
这里最关键的是理解“现象对应入口”。很多新手遇到问题第一反应是重新生成整个应用,但在课程里,更好的做法是把错误日志原样复制给 AI,让它基于当前代码修复。错误日志比“为什么我的程序报错”这种模糊问题更有价值。
6. Vibe Coding 实战中的常见坑
6.1 提示词太宽泛,AI 返回“正确的废话”
典型错误提示词是“帮我写一个网站”。这个需求范围太大,AI 只能靠猜:猜前端框架、猜后端语言、猜页面数量。生成结果可能很完整,但和你想象完全不同。
| 提示词级别 | 示例 | 结果 |
|---|---|---|
| 宽泛 | 帮我写一个网站 | 生成一个空白 React 模板,或一个 Django 项目,无法直接使用 |
| 具体 | 用 Flask 写一个单文件待办应用,JSON 存储,包含新增、勾选、删除 | 生成后可立即运行,并符合数据格式要求 |
实际项目中,可以把一个完整需求拆成多个小需求。比如先写“读取 CSV 并统计数据”,验证通过后再写“生成可视化页面”,最后再写“部署到服务器”。每一轮都保持提示词具体到“技术栈 + 文件 + 接口 + 数据格式”四个维度。
6.2 连续迭代却没有版本管理
Vibe Coding 最大的诱惑是“改需求只要一句话”。AI 连续修改几轮后,可能功能已经偏离目标,或者某次修改引入了一个新 bug。如果项目没有版本管理,你就只能靠记忆恢复。
一开始就把项目纳入 git:
git init git add . git commit -m "init: AI 生成待办事项应用"每完成一轮迭代,都提交一次:
git add . git commit -m "feat: 增加编辑功能"这样出现问题时,可以随时回到上一个可用版本。课程虽然不会花太多时间讲 git,但实际跟练时,git 是 Vibe Coding 的安全网。没有这个安全网,迭代越快,风险越大。
6.3 过度信任生成结果,不做安全校验
AI 生成的代码擅长实现功能,但不会默认考虑安全。课程里的待办事项示例只是学习项目,如果直接部署到公网,会面临几个问题:没有登录鉴权、输入长度没有限制、JSON 数据可能被并发写坏、表单接口没有 CSRF 防护。
生产环境至少要做这些补充:
- 输入内容使用
strip()去空格,并限制最大长度。 - 页面渲染时不要随意关闭模板转义,避免 XSS。
- 不要在代码里硬编码数据库密码或 API Key。
- 数据存储使用数据库,而不是直接用 JSON 文件。
- 部署到公网前增加认证和审计日志。
Vibe Coding 适合快速搭建原型,但“能跑”和“能上线”是两个完全不同的标准。课程里很多代码都是演示性质,生产环境需要额外做安全加固,这一点要在学习时形成明确认识。
6.4 不知道如何让 AI 修改局部逻辑
很多人会让 AI “修复 bug”或“加一个功能”,然后 AI 对整个文件大改。更可控的做法是给修改范围划定边界。
例如只修改toggle函数的对话:
请修改 app.py 中的 toggle 函数: 1. 只处理当前 todo_id 对应的记录 2. 如果记录不存在,返回 404 3. 不要改动其他路由 4. 修改后给出一段简要说明这个提示词明确告诉 AI:“改哪里、不要碰哪里、怎么验证”。实际效果会好很多。Vibe Coding 中的“沟通能力”不是指说废话,而是学会给 AI 设置边界和验收标准。
7. 从课程到生产:一份可复用的 Vibe Coding 工作流
7.1 学习环境的快速工作流
跟着课程练习时,可以固定一套流程,减少重复思考:
- 先激活虚拟环境,确保依赖已经安装。
- 在 AI 对话里描述需求,遵守“角色 + 功能 + 接口 + 数据格式 + 约束”的结构。
- 让 AI 生成初始版本,先不追求完美,只求能运行。
- 运行程序,记录错误信息或功能缺失。
- 把错误信息和当前文件路径发给 AI,要求它做增量修改。
- 看 diff,理解 AI 改了哪些地方。
- git 提交一个可用版本。
这个流程既是学习课程的步骤,也是日常开发的最小循环。它把“生成代码”和“确认代码”分开,每一步都有明确目标,不会陷入无限聊天。
7.2 生产环境需要补上哪些环节
课程示例是学习环境,生产环境还需要补上多个工程环节。
| 环节 | 学习示例 | 生产要求 |
|---|---|---|
| 数据存储 | todos.json文件 | PostgreSQL 或 MySQL,考虑并发和备份 |
| 服务启动 | python app.py | gunicorn、systemd 或容器编排 |
| 配置管理 | 硬编码在代码中 | 环境变量、配置中心 |
| 日志监控 | print或 Flask 默认输出 | 结构化日志、错误告警 |
| 安全性 | 无登录、无防护 | 登录、权限、HTTPS、CSRF、输入校验 |
| 发布流程 | 手动运行 | CI/CD、灰度发布、回滚方案 |
| 测试 | 手动点击页面 | 单元测试、接口测试、回归测试 |
其中最重要的一条是数据存储。JSON 文件适合单进程、低并发场景,一旦部署到生产环境,多个进程同时写同一个文件,容易出现数据丢失或文件锁问题。所以课程里的save_todos只是一个示意实现,不是生产方案。
生产环境建议把数据层抽象成接口,比如TodoRepository,然后分别实现JsonTodoRepository和DatabaseTodoRepository。这样从学习项目迁移到生产项目时,只需要替换实现,路由和页面逻辑不用大改。
7.3 推荐练习路径
如果刚学完课程,不建议立刻写大系统,而是按这个顺序练习:
- 把课程里的待办事项示例完整跑一遍,包括修改、删除、数据持久化。
- 让 AI 生成一个自己真正会用的小脚本,比如批量重命名文件、统计 CSV 数据、把 Markdown 转换成 HTML。
- 给脚本加上命令行参数、日志和错误处理,再让 AI 写出对应的单元测试。
- 把一个脚本扩展成 Web 应用,加入用户登录和数据存储。
- 最后尝试让 AI 对现有代码做代码审查,找出潜在 bug 和安全问题。
这套路径从“单文件脚本”到“可部署应用”一步步增加复杂度,每步都能使用 Vibe Coding,但每步也都会逼你理解更多基础概念。越往后,你会越清楚 AI 擅长什么、不擅长什么,也就越能把注意力放在真正需要人来判断的地方。
Vibe Coding 最值得学习的不是某一条提示词,而是“快速尝试、小步迭代、持续验证”的开发节奏。它不会取代程序员,但会改变程序员的工作方式。刚开始练习时,不必追求一次生成完整系统,先把“AI 生成、人验证、git 提交”这一圈流程跑顺。等你习惯了这种节奏,再回头看课程里的示例代码,会发现每一段代码背后都是在教你如何与 AI 协作。