32 · 入门实战:从零到上线
用 Cursor 的四大 AI 层,从空白文件夹到生产部署,完整走一遍。
01 · 为什么要走这一遍
学 Cursor 最快的方式不是读文档,而是跟着一条完整的线走一遍。从零到上线——从 mkdir 到网站能被公开访问——这中间每一步都有 AI 介入,但每一步介入的方式不同。
本文用一个 Markdown 笔记应用作为练习项目。你不需要任何前端基础也能跟下来:它功能简单(新建笔记、编辑、保存、删除、预览),但覆盖了一个真实项目的所有环节——脚手架、编码、配置 AI 上下文、版本控制、部署。
先决条件: 本地已安装 Cursor(0.45+ 版本)、Node.js 18+、Git。注册好 Vercel 或 Railway 账号用于部署。
02 · 项目概览与最终效果
在开始之前,先知道我们要做出什么:
markdown-notes/
├── index.html # 主页面
├── style.css # 样式
├── app.js # 前端逻辑
├── server.js # Express 服务端
├── package.json
├── .cursorrules # AI 上下文文件(CLAUDE.md 的 Cursor 版本)
└── notes/ # 笔记存储目录(JSON 文件)功能清单:
- 新建 Markdown 笔记(标题 + 正文)
- 实时预览渲染后的 HTML
- 编辑、删除已有笔记
- 列表展示所有笔记
- 部署到线上
听起来简单,但足够展示 AI 的四层能力如何加速每个环节。
03 · 第一层:Tab 补全 —— 自动续写
打开 Cursor,新建文件夹 markdown-notes,创建 package.json。
在 Cursor 里输入以下内容:
{
"name": "markdown-notes",
"version": "1.0.0",光标停在这里。**不要继续打字。**按一下 Tab。
Cursor 会预测你接下来的意图,自动补全剩余字段:
{
"name": "markdown-notes",
"version": "1.0.0",
"description": "A simple markdown notes app",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2",
"marked": "^12.0.0"
}
}**这就是第一层:Tab 补全。**它像高级版的自动完成,但不只是补变量名——它能根据上下文预测整块代码。
| 场景 | 手动输入 | Tab 补全 |
|---|---|---|
| 写 package.json | 敲完所有字段 | 写一半,Tab 补另一半 |
| 写 import 语句 | 手动拼完整路径 | 输 import 后 Tab 出建议 |
| 写 HTML 结构 | 从头敲标签 | <div 按 Tab 展开 div>... |
| 写重复模式 | 复制粘贴改参数 | 光标移到下一行,Tab 猜出下一段 |
心智模型: 把 Tab 想象成一个「永远在猜你下一句要说什么的队友」。猜对了,接下去;猜错了,继续打字,它重新猜。不需要你切换模式、不需要你写注释——你正常编码,它在你身边 silently assist。
实际效果是:写一个 Express 路由时,你只需要写出 app.get('/api/notes',,按 Tab 往往就能得到完整的处理函数骨架。
04 · 第二层:Cmd+K —— 选中,告诉它改什么
现在创建 server.js。你可以让 Tab 帮你起个头,但我们试试内联编辑。
选中一个空文件(或者选中某几行代码),按下 Cmd+K(Mac)/ Ctrl+K(Windows)。
在弹出的输入框中写:
Create an Express server that:
- Serves static files from the current directory
- Has REST API endpoints for notes (CRUD)
- Stores notes as JSON files in a /notes directory
- Uses the 'marked' library to render Markdown to HTMLCursor 会直接在当前文件内重写(或插入)代码。结果类似这样:
const express = require('express');
const fs = require('fs');
const path = require('path');
const marked = require('marked');
const app = express();
const PORT = process.env.PORT || 3000;
const NOTES_DIR = path.join(__dirname, 'notes');
app.use(express.json());
app.use(express.static(__dirname));
// Ensure notes directory exists
if (!fs.existsSync(NOTES_DIR)) {
fs.mkdirSync(NOTES_DIR, { recursive: true });
}
// GET /api/notes — list all notes
app.get('/api/notes', (req, res) => {
const files = fs.readdirSync(NOTES_DIR).filter(f => f.endsWith('.json'));
const notes = files.map(f => {
const data = JSON.parse(fs.readFileSync(path.join(NOTES_DIR, f), 'utf-8'));
return { id: f.replace('.json', ''), ...data };
});
res.json(notes.sort((a, b) => new Date(b.updated) - new Date(a.updated)));
});
// POST /api/notes — create a note
app.post('/api/notes', (req, res) => {
const { title, content } = req.body;
if (!title || !content) return res.status(400).json({ error: 'title and content required' });
const id = Date.now().toString(36);
const note = { title, content, html: marked.parse(content), created: new Date(), updated: new Date() };
fs.writeFileSync(path.join(NOTES_DIR, `${id}.json`), JSON.stringify(note, null, 2));
res.json({ id, ...note });
});
// GET /api/notes/:id — get one note
app.get('/api/notes/:id', (req, res) => {
const filePath = path.join(NOTES_DIR, `${req.params.id}.json`);
if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'not found' });
const note = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
res.json({ id: req.params.id, ...note });
});
// PUT /api/notes/:id — update a note
app.put('/api/notes/:id', (req, res) => {
const filePath = path.join(NOTES_DIR, `${req.params.id}.json`);
if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'not found' });
const { title, content } = req.body;
const note = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
if (title) note.title = title;
if (content) { note.content = content; note.html = marked.parse(content); }
note.updated = new Date();
fs.writeFileSync(filePath, JSON.stringify(note, null, 2));
res.json({ id: req.params.id, ...note });
});
// DELETE /api/notes/:id — delete a note
app.delete('/api/notes/:id', (req, res) => {
const filePath = path.join(NOTES_DIR, `${req.params.id}.json`);
if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'not found' });
fs.unlinkSync(filePath);
res.json({ ok: true });
});
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));关键差异: Cmd+K 不是对话,是原地改写。你选中的代码就是上下文,你的指令就是修改目标。
| 维度 | Tab 补全 | Cmd+K |
|---|---|---|
| 触发方式 | 自动,无需操作 | 手动选中 + 快捷键 |
| 输出形式 | 逐字补全 | 整段重写/插入 |
| 适合场景 | 你知道写什么,加快速度 | 你不知道怎么写,或想改一大段 |
| 交互深度 | 零交互 | 一条自然语言指令 |
心智模型: Cmd+K 是「选中 + 说要求」。把光标当画笔,把输入框当对讲机。你圈定范围,告诉 AI 你想要什么,它直接改文件。
05 · 第三层:Chat —— 深度对话
后端写完了,现在需要前端界面。创建一个 index.html,但这次我们换个方式。
按 Cmd+I(Mac)/ Ctrl+I(Windows)打开 Chat 面板。这是第三层。
在 Chat 里输入:
Create the frontend HTML for a markdown notes app. It should have:
- A sidebar listing all notes (click to select)
- A main area with title input and textarea for markdown content
- A live preview panel showing rendered HTML
- Buttons: New Note, Save, Delete
- Use clean CSS, no frameworks
- Communicate with the Express API at /api/notes
- Include the marked.js library from CDN for client-side previewChat 与 Cmd+K 的区别是:Chat 不修改你的文件,它在侧边栏里生成代码供你复制/参考。你可以追问、要求调整、讨论方案——它是一个对话伙伴。
你:Create the frontend HTML...
Chat:(生成完整 HTML 代码)
你:Can you make the preview update in real-time as I type?
Chat:(修改方案,使用 marked.js 的 debounced 监听)
你:What about dark mode?
Chat:(增加 CSS 变量和媒体查询方案)经过几轮对话,你会拿到一个包含以下核心结构的前端:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Markdown Notes</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="sidebar-header">
<h2>笔记</h2>
<button id="newNoteBtn">+ 新建</button>
</div>
<ul id="notesList"></ul>
</aside>
<main class="main-content">
<div class="editor-pane">
<input type="text" id="noteTitle" placeholder="笔记标题...">
<textarea id="noteContent" placeholder="写点什么..." rows="15"></textarea>
<div class="actions">
<button id="saveBtn" class="primary">保存</button>
<button id="deleteBtn" class="danger">删除</button>
</div>
</div>
<div class="preview-pane">
<div class="preview-header">预览</div>
<div id="preview"></div>
</div>
</main>
</div>
<script src="app.js"></script>
</body>
</html>| 维度 | Tab 补全 | Cmd+K | Chat |
|---|---|---|---|
| 交互模式 | 被动 | 单条指令 | 多轮对话 |
| 修改对象 | 光标处 | 选中区域 | 生成新代码或建议 |
| 上下文 | 当前文件 | 选中代码 | 整个项目(可以 @ 引用文件) |
| 最佳场景 | 加速已知模式 | 改写指定范围 | 设计方案、debug、学习 |
心智模型: Tab 是自动补词,Cmd+K 是选中后说要求,Chat 是请了一个坐在旁边的同事。你可以问它「这个怎么写」「那个为什么报错」「帮我看看这段代码有什么问题」。
06 · 第四层:Agent —— 放手让它做
前三层都是由你做主导。第四层 Agent 是反过来的——你告诉它目标,它自己规划并执行。
按 Cmd+Shift+I 打开 Agent 模式(或者在 Chat 面板顶部切换为 Agent)。
在输入框里写:
Add a search/filter feature to the notes app:
- A search input at the top of the sidebar
- Filter notes by title (case-insensitive, as you type)
- Update the notes list in real-timeAgent 不会只给你建议——它会:
- 读取项目中的相关文件(index.html, app.js)
- 制定修改计划
- 逐一修改文件(有时会创建新文件)
- 停下来问你要不要继续(需要确认的修改)
Agent: I'll need to modify app.js and index.html to add search.
1. Add search input to index.html
2. Add filter logic to app.js
Shall I proceed?
你:Go ahead.
Agent: (修改 index.html, 修改 app.js)
Done. The search input now filters notes in real-time.Agent 还可以执行终端命令:
你:Install the dependencies and start the server.
Agent: I'll run `npm install` and then `npm start`.它会读取终端输出,如果遇到错误会自己尝试修复。
| 维度 | Tab 补全 | Cmd+K | Chat | Agent |
|---|---|---|---|---|
| 主导方 | 你 | 你 | 对话双方 | AI |
| 操作粒度 | 字符级 | 代码块级 | 对话级 | 任务级 |
| 文件系统 | 不涉及 | 当前文件 | 建议不修改 | 读取/修改/创建文件 |
| 终端执行 | 不涉及 | 不涉及 | 不涉及 | 可以 |
| 适用场景 | 日常编码加速 | 局部重构/生成 | 讨论/调试 | 跨文件功能开发 |
心智模型: Agent 是一个有执行力的实习生。你给它一个任务描述,它会自己看代码、改代码、跑命令。你负责检查结果、给出反馈、决定是否接受修改。
四层协作的实际工作流
实战中你会交替使用四层:
你想给笔记加上标签功能:
1. Agent 模式 → "给笔记系统加上标签功能,笔记可以添加多个标签"
→ Agent 创建了数据库迁移、修改了模型
2. Chat 模式 → "帮我看看这个标签系统的数据结构设计合理吗"
→ 讨论优化方案
3. Cmd+K → 选中标签输入框的 HTML,Cmd+K "加一个自动补全下拉"
→ 局部增强
4. Tab → 在 CSS 里写 .tag-input,按 Tab 补出完整的样式块
→ 快速收尾07 · CLAUDE.md 的 Cursor 版本:.cursorrules
在项目根目录创建一个 .cursorrules 文件。这是 Cursor 的项目级 AI 指令——相当于告诉 AI 这个项目的规矩。
如果你用 Claude Code,它读的是
CLAUDE.md。Cursor 读的是.cursorrules。两者本质上都是给 AI 的项目上下文。
写入以下内容:
You are an expert in Node.js and vanilla JavaScript.
## Project Structure
- server.js — Express backend, handles REST API and file serving
- index.html — Main page layout
- style.css — All styles (no CSS frameworks)
- app.js — Frontend logic, DOM manipulation, API calls
- notes/ — JSON file storage (one file per note)
## Coding Rules
- Use vanilla JS, no frameworks (no React, no Vue)
- Error responses should be { error: string } format
- CSS variables for theming (--bg, --text, --primary colors)
- All API calls return JSON
- Use modern ES6+ syntax but no TypeScript
## Data Model
Note = { id: string, title: string, content: string, html: string, created: date, updated: date }
## Testing
- No unit tests for this project (too simple)
- Manual testing: run `node server.js` and open localhost:3000
## API Endpoints
GET /api/notes → list notes
POST /api/notes → create note { title, content }
GET /api/notes/:id → get one note
PUT /api/notes/:id → update note { title?, content? }
DELETE /api/notes/:id → delete note写完之后,你在 Chat 或 Agent 里问任何问题,Cursor 都会自动参考这个文件。它大幅提高 AI 输出的一致性和质量。
没有 .cursorrules 时:
你:"添加一个新 API 路由"
AI 可能用 Express、也可能用 Hono,写法风格随模型心情
有 .cursorrules 时:
AI 知道你要用 Express、用 JSON 文件存储、错误格式要返回 { error }心智模型:
.cursorrules是项目入职手册。每个新加入的 AI 工程师(每次 Chat/Agent 调用)上手先读它。没有它,AI 会猜;有了它,AI 按你的规矩办事。
08 · 样式与细节打磨
用 Cmd+K 选中 style.css(新建空白文件),输入:
Create a clean, modern CSS file for a markdown notes app with:
- Dark/light mode via CSS media query prefers-color-scheme
- Sidebar (250px) + main content split layout
- Preview pane renders markdown with nice typography (serif font)
- Responsive: on narrow screens, sidebar becomes top bar
- Smooth transitions on hover
- CSS variables for theming得到样式文件后,再用 Chat 问问改进建议:
你:The note list items look too plain. Can you suggest improvements?
Chat:Add hover effects, active state, truncate long titles, show timestamps...| 打磨项 | 使用层 | 描述 |
|---|---|---|
| 基础布局 | Cmd+K | 生成 sidebar + main 布局 |
| 交互反馈 | Chat | 讨论 hover、active、过渡动画 |
| 响应式 | Cmd+K | 选中媒体查询部分,让 AI 调整断点 |
| 配色微调 | Tab | 在 CSS 变量里改色值,Tab 补出色板 |
| 预览区排版 | Chat | 讨论字体、行高、代码块样式 |
09 · 版本控制:用 AI 写提交信息
功能开发完毕,准备提交。使用任何 Git 操作都可以在 Cursor 内置终端完成(`Ctrl+“ 打开终端)。
git init
git add .
git commit -m "Initial commit"但 Cursor 的 Agent 也可以帮你写更好的提交信息:
在 Agent 模式输入:
Stage all changes and create a meaningful commit messageAgent 会运行 git diff --staged(或者先 git add),分析变更内容,然后生成一条结构化的提交信息:
feat: complete markdown notes app with CRUD API and live preview
- Express server with full REST API for notes (create, read, update, delete)
- Markdown-to-HTML rendering via `marked` library
- Vanilla JS frontend with sidebar listing, editor pane, and live preview
- Dark/light mode support via CSS media queries
- Responsive layout for mobile and desktop
- JSON file-based storage in /notes directory你可以在 .cursorrules 里自定义提交信息的风格:
## Git
- Commit messages follow Conventional Commits (feat:, fix:, chore:, docs:, refactor:)
- First line under 72 chars
- Include bullet points for details之后每次 Agent 做提交都会遵守这个规范。
10 · 部署:从本地到线上
用 Vercel 部署。在 Agent 模式下输入:
Deploy this project to Vercel. Install Vercel CLI if needed, and guide me through the login.Agent 会一步步指导你完成部署:
# Agent 会在终端执行(先经你确认):
npm i -g vercel
vercel login
vercel --prod如果遇到问题(例如 Vercel 需要 vercel.json 配置),Agent 会为你创建它:
{
"version": 2,
"builds": [
{ "src": "server.js", "use": "@vercel/node" }
],
"routes": [
{ "src": "/(.*)", "dest": "server.js" }
]
}当 Cursor 检测到 vercel 命令输出中出现部署 URL 时,它会告诉你:
✅ Production: https://markdown-notes.vercel.app你的笔记应用上线了。
11 · 四个层级的对比总结
这是贯穿全文最核心的框架——Cursor 的四层 AI 能力,每一层解决不同粒度的问题。
| 层级 | 名称 | 触发方式 | 输入 | 输出 | 最佳用途 |
|---|---|---|---|---|---|
| L1 | Tab 补全 | 自动触发 | 你打字的上下文 | 字符/行级补全 | 加速已知模式,减少打字量 |
| L2 | Cmd+K | 选中 + 快捷键 | 自然语言指令 | 改写选中范围 | 局部生成、重构、格式化 |
| L3 | Chat | Cmd+I | 多轮对话 | 代码建议/解释 | 设计方案、调试、学习 |
| L4 | Agent | Cmd+Shift+I | 任务目标 | 跨文件修改 + CLI | 多步骤任务、跨文件开发 |

选择原则: 能用手臂够到的,不要用脚去走。层级越高,AI 自主性越强,但你也需要花更多精力去检查结果。写一行代码用 L1,写一个函数用 L2,设计一个功能用 L3,跨文件实现一个需求用 L4。
12 · 常见问题与调试
Q:AI 生成的代码有 Bug 怎么办?
- 小问题: 选中错误代码,Cmd+K 输入 “Fix this bug”
- 复杂问题: Chat 里贴入错误信息,让 AI 分析根因
- 跨文件问题: Agent 模式描述症状,让它自己追查
Q:Agent 改了我不同意的文件?
Agent 在修改前会显示 diff 并请求确认。你可以在设置里关闭自动确认,每次修改都手动审核。
Q:Tab 补全不准确?
Tab 补全质量取决于上下文。确保:
- 文件内容足够(空文件 Tab 无从猜起)
.cursorrules配置正确- 光标位置合理(在结构清晰的代码中间补全质量最高)
Q:Chat 和 Agent 哪个更适合写代码?
| 场景 | 推荐 |
|---|---|
| 你清楚写什么 | Tab 或 Cmd+K |
| 你不确定方案 | Chat 先讨论 |
| 你知道目标但不想动手 | Agent |
| 调试错误 | Chat 贴错误信息 |
| 跨文件重构 | Agent |
13 · 扩展练习
你已经完成了基础版。以下扩展练习可以帮你进一步熟悉四层能力:
- Agent 挑战: 给笔记添加 Markdown 文件导入功能(拖拽 .md 文件到应用窗口自动导入)
- Chat 挑战: 把存储从 JSON 文件换成 SQLite(让 AI 帮你设计方案并评估优劣)
- Cmd+K 挑战: 为应用添加键盘快捷键(
Ctrl+S保存,Ctrl+N新建) - Tab 挑战: 写一套新的主题 CSS 变量,用 Tab 提速
每个挑战建议先用 Chat 讨论方案,再用 Agent 执行,中间用 Cmd+K 微调,日常用 Tab 加速。
14 · 总结
这篇文章走完了一个完整路径:从创建项目文件夹开始,到部署上线结束。贯穿全程的是 Cursor 的四层 AI 能力:
Tab 补全 → 自动化日常编码的「肌肉记忆」
Cmd+K → 选中即改的「局部手术刀」
Chat → 随时请教的「结对编程搭档」
Agent → 交代任务就执行的「自主工程师」这四层不是互相替代的——它们是互补的。高手会在一分钟内切换使用全部四层:
用 Agent 创建新功能 → 用 Chat 讨论某段实现 → 用 Cmd+K 微调界面 → 用 Tab 加速收尾
.cursorrules 是你给所有 AI 能力的统一指挥手册。花 10 分钟写一份好的项目规则,之后每一次 AI 调用都会受益。
下一篇
33 · Cursor 与 Claude Code 双修指南:何时用 Cursor,何时用 Claude Code,两者如何配合
本教程使用的完整项目代码可以在 GitHub 上找到:github.com/bytesurging/cursor-guide-examples