TL;DR:
Claude Code 不只是编程助手——它是一个能把项目从空目录带到部署就绪的自主 AI Agent。本文走完完整生命周期:从 claude /init 到生产,使用 Explore → Plan → Execute 工作流、把 CLAUDE.md 作为项目上下文、Vertical Slice 架构,以及一个让人类判断留在关键决策上的 8 步 Feature 循环。因为这个 Agent 是带着对你文件、Shell 和仓库的真实访问权限在运行的,本文也一并讲清你需要守住的控制边界。
目录
- 为什么用 Claude Code 构建完整项目
- 阶段一:项目初始化与 CLAUDE.md
- 阶段二:用 Plan Mode 做需求分析
- 阶段三:架构设计
- 阶段四:逐步实现
- 阶段五:测试与调试
- 阶段六:代码审查与重构
- 阶段七:部署准备
- 当 Agent 拥有真实访问权限时如何保持掌控
- 完整工作流可视化
- 如何对比,以及如何自己度量收益
- 常见问题 FAQ
- 相关资源
核心要点
- Explore → Plan → Execute:Claude Code 的三阶段工作流,让你不再盲目动手——先理解,再规划,最后写代码。
- CLAUDE.md 是你的项目上下文:用
/init自动生成,跨会话保存约定、技术栈和架构——它是约定辅助,不是被强制执行的控制。 - Vertical Slice 架构:端到端构建完整功能(UI → API → DB),而不是横向按层开发,这更契合 Claude Code 的多文件协同能力。
- 8 步 Feature 循环:描述 → 探索 → 规划 → 批准 → 实现 → 审查 → 测试 → 提交,让架构决策在写代码之前就明确。
- 带作用域访问的 Auto-Accept:对已批准的低风险任务可以让 Claude 免确认执行——但免确认意味着它是以你的文件和 Shell 权限在动作,所以要限定它能碰的范围。
为什么用 Claude Code 构建完整项目
"AI 帮我写函数"和"AI 构建我整个项目"之间的鸿沟,就是 Copilot 和 Agent 之间的鸿沟。Claude Code 站在 Agent 一侧:它作为终端 Agent 运行,读取、写入、执行、迭代——不需要 GUI 或 IDE 集成。
与嵌入编辑器的工具不同,Claude Code 直接操作你的文件系统、运行 Shell 命令、管理 Git 分支,并通过 CLAUDE.md 维护上下文。这让它很适合端到端的项目创建——需要在前端、后端和基础设施层之间对几十个文件做协同修改的场景。
对收益要诚实:它是定性的。结构化的循环让你把机械性工作外包出去——脚手架、样板代码、首轮测试——同时把有风险的决策(需求、架构、安全)明确地留在自己手里。它不会免除审查;它把你的精力从敲键盘转移到指挥和验证上。如果你想要针对自己团队的数字,就在自己的工作上度量——本文末尾给了方法。
我们用一个任务管理应用作为贯穿全文的例子:React + TypeScript 前端、Python FastAPI 后端、PostgreSQL 数据库,两端都带测试。
阶段一:项目初始化与 CLAUDE.md
每个 Claude Code 项目都从正确的初始化开始。/init 命令会分析你的仓库(或空目录),生成一个 CLAUDE.md 文件,作为跨会话的持久记忆。
安装 Claude Code
# 原生安装器(推荐)
curl -fsSL https://claude.ai/install.sh | bash
# 或通过 npm
npm install -g @anthropic-ai/claude-code
# 验证安装
claude --version
/init 命令
进入项目目录(或新建一个),运行:
mkdir my-fullstack-app && cd my-fullstack-app
claude
# 在 Claude Code 会话内:
> /init
Claude Code 扫描项目结构(如已有文件)或询问你打算用的技术栈,然后生成 CLAUDE.md:
# CLAUDE.md - 项目配置
## 项目概述
全栈任务管理应用,React 前端 + Python FastAPI 后端。
## 技术栈
- 前端:React 18 + TypeScript + Vite + TailwindCSS
- 后端:Python 3.12 + FastAPI + SQLAlchemy + PostgreSQL
- 测试:Vitest(前端),Pytest(后端)
- 部署:Docker + docker-compose
## 常用命令
- `npm run dev` - 启动前端开发服务器
- `uvicorn main:app --reload` - 启动后端
- `npm run test` - 前端测试
- `pytest` - 后端测试
- `docker-compose up` - 全栈启动
## 架构决策
- 带 OpenAPI 规范的 REST API
- JWT 认证
- 数据访问采用 Repository 模式
- 基于 Feature 的目录结构
## 编码约定
- 使用 @ 前缀的绝对导入
- 所有 API 响应遵循 {data, error, meta} 信封
- 数据库模型用 snake_case,API DTO 用 camelCase
- 每个端点都需要用 Pydantic 做输入校验
为什么 CLAUDE.md 重要
CLAUDE.md 在每次会话启动时被读取。实际意义是:
- 你无需每次重复项目上下文。
- Claude Code 往往会一致地遵循你的约定。
- 架构说明跨越数天、数周依然保留。
- 队友的会话继承同一套标准。
但有一点要说清:CLAUDE.md 塑造 Agent 的产出,但不强制任何东西。写一句"客户端组件里绝不直接访问数据库"是有用的提醒,不是护栏——护栏在你的架构和代码审查里。
阶段二:用 Plan Mode 做需求分析
在写下第一行代码之前,用 Claude Code 的 Plan Mode 分析需求、建立共识。Plan Mode(按 Shift+Tab 激活)让 Claude 只思考、只提方案、不执行。
Explore → Plan → Execute 循环
这是 Claude Code 处理复杂任务的运作模型:
在实践中使用 Plan Mode
# 在 Claude Code 会话内,按 Shift+Tab 进入 Plan Mode
> [Plan Mode] 构建一个任务管理应用,包含:
- 用户认证(注册/登录/登出)
- 任务的 CRUD 操作
- 任务分类和优先级
- 带通知的截止日期
- 带 OpenAPI 文档的 REST API
Claude Code 会返回一份结构化方案:
## 分析
我将构建一个全栈任务管理器,架构如下:
### 前端(React + TypeScript)
- 页面:Login、Signup、Dashboard、TaskDetail
- 组件:TaskList、TaskCard、CategoryFilter、PriorityBadge
- 状态:服务端状态用 React Query,UI 状态用 Zustand
### 后端(FastAPI + PostgreSQL)
- 模型:User、Task、Category
- 端点:/auth/*、/tasks/*、/categories/*
- 中间件:JWT 认证、CORS、限流
### 数据库 Schema
- users (id, email, password_hash, created_at)
- categories (id, name, user_id, color)
- tasks (id, title, description, priority, due_date, category_id, user_id, status)
### 实现顺序(Vertical Slices)
1. 项目脚手架 + Docker 配置
2. 认证切片:User 模型 → 注册/登录端点 → 登录 UI
3. 任务切片:Task 模型 → CRUD 端点 → Dashboard UI
4. 分类切片:Category 模型 → 端点 → 筛选 UI
5. 打磨:通知、错误处理、测试
是否按此方案执行?
为什么"先规划"重要
先规划不是为了省下某个固定百分比的工作量——它关乎错误在哪里暴露。没有方案,Claude Code 可能选到与你意图冲突的约定或模式,而你要到代码写完之后才发现这种不匹配,那时纠正代价高昂。有了方案,架构上的分歧只是写代码之前的一行更正。这就是杠杆:在成本最低的时刻抓住错误的方向。
关于结构化 AI 开发方法论的更深入背景,见我们的 Spec Coding 完全指南,它把这种"先规划"的思路正式化了。
阶段三:架构设计
批准高层方案后,下一阶段是详细的架构设计。Claude Code 在这里很强,因为它能一次性提出具体的文件结构、API 契约和数据模型。
生成项目结构
> 按已批准的方案创建完整的项目结构。
前后端都采用基于 Feature 的组织方式。
Claude Code 生成:
my-fullstack-app/
├── frontend/
│ ├── src/
│ │ ├── features/
│ │ │ ├── auth/
│ │ │ │ ├── components/
│ │ │ │ ├── hooks/
│ │ │ │ ├── api.ts
│ │ │ │ └── types.ts
│ │ │ ├── tasks/
│ │ │ │ ├── components/
│ │ │ │ ├── hooks/
│ │ │ │ ├── api.ts
│ │ │ │ └── types.ts
│ │ │ └── categories/
│ │ ├── shared/
│ │ │ ├── components/
│ │ │ ├── hooks/
│ │ │ └── utils/
│ │ ├── App.tsx
│ │ └── main.tsx
│ ├── package.json
│ └── vite.config.ts
├── backend/
│ ├── app/
│ │ ├── features/
│ │ │ ├── auth/
│ │ │ │ ├── router.py
│ │ │ │ ├── service.py
│ │ │ │ ├── models.py
│ │ │ │ └── schemas.py
│ │ │ ├── tasks/
│ │ │ └── categories/
│ │ ├── core/
│ │ │ ├── config.py
│ │ │ ├── database.py
│ │ │ └── security.py
│ │ └── main.py
│ ├── tests/
│ ├── requirements.txt
│ └── alembic/
├── docker-compose.yml
├── CLAUDE.md
└── README.md
API 契约设计
Claude Code 能在实现之前生成 OpenAPI 规范,确保前端和后端(或不同的 Claude Code 会话)共享同一份契约:
# backend/app/features/tasks/schemas.py
from pydantic import BaseModel, Field
from datetime import datetime
from enum import Enum
from typing import Optional
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
URGENT = "urgent"
class TaskStatus(str, Enum):
TODO = "todo"
IN_PROGRESS = "in_progress"
DONE = "done"
class TaskCreate(BaseModel):
title: str = Field(..., min_length=1, max_length=200)
description: Optional[str] = Field(None, max_length=2000)
priority: Priority = Priority.MEDIUM
due_date: Optional[datetime] = None
category_id: Optional[int] = None
class TaskResponse(BaseModel):
id: int
title: str
description: Optional[str]
priority: Priority
status: TaskStatus
due_date: Optional[datetime]
category_id: Optional[int]
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
人类审查检查点
这是工作流中的关键节点:架构是人类判断不可替代的地方。Claude Code 提议,你来审查:
- 安全性(认证流程、数据暴露、谁能操作谁的记录)
- 可扩展性影响(数据库设计、缓存策略)
- 团队约定(命名、目录结构)
- 业务逻辑准确性
一旦批准,Claude Code 就在一套确定下来的架构"轨道"上执行。
阶段四:逐步实现
架构批准后,实现遵循 Vertical Slice 模式:端到端构建完整功能,而不是先建所有模型、再建所有端点、最后建所有 UI。
Vertical Slice 工作流
实现认证切片
> 实现认证的 Vertical Slice:
1. User 模型和迁移
2. 带 JWT 的注册和登录端点
3. 登录和注册的 React 页面
遵循我们设计的 Schema。密码用 bcrypt。
Claude Code 生成跨多文件的协同改动:
后端 - User 模型:
# backend/app/features/auth/models.py
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.sql import func
from app.core.database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String(255), unique=True, index=True, nullable=False)
password_hash = Column(String(255), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
后端 - 认证端点:
# backend/app/features/auth/router.py
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.security import create_access_token, verify_password, hash_password
from .models import User
from .schemas import UserCreate, UserLogin, TokenResponse
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/signup", response_model=TokenResponse, status_code=201)
def signup(user_data: UserCreate, db: Session = Depends(get_db)):
existing = db.query(User).filter(User.email == user_data.email).first()
if existing:
raise HTTPException(status_code=409, detail="Email already registered")
user = User(
email=user_data.email,
password_hash=hash_password(user_data.password)
)
db.add(user)
db.commit()
db.refresh(user)
token = create_access_token({"sub": str(user.id)})
return {"access_token": token, "token_type": "bearer"}
@router.post("/login", response_model=TokenResponse)
def login(credentials: UserLogin, db: Session = Depends(get_db)):
user = db.query(User).filter(User.email == credentials.email).first()
if not user or not verify_password(credentials.password, user.password_hash):
raise HTTPException(status_code=401, detail="Invalid credentials")
token = create_access_token({"sub": str(user.id)})
return {"access_token": token, "token_type": "bearer"}
前端 - 登录页(TypeScript):
// frontend/src/features/auth/components/LoginPage.tsx
import { useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { authApi } from '../api';
import { useAuthStore } from '../../../shared/stores/authStore';
export function LoginPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const setToken = useAuthStore((s) => s.setToken);
const loginMutation = useMutation({
mutationFn: authApi.login,
onSuccess: (data) => {
setToken(data.access_token);
navigate('/dashboard');
},
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
loginMutation.mutate({ email, password });
};
return (
<div className="min-h-screen flex items-center justify-center">
<form onSubmit={handleSubmit} className="w-full max-w-md space-y-4 p-8">
<h1 className="text-2xl font-bold text-center">登录</h1>
{loginMutation.isError && (
<div className="bg-red-50 text-red-600 p-3 rounded">
邮箱或密码错误
</div>
)}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="邮箱"
className="w-full p-3 border rounded"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="密码"
className="w-full p-3 border rounded"
required
/>
<button
type="submit"
disabled={loginMutation.isPending}
className="w-full p-3 bg-blue-600 text-white rounded hover:bg-blue-700"
>
{loginMutation.isPending ? '登录中...' : '登录'}
</button>
</form>
</div>
);
}
注意:这个切片验证了用户身份,但它本身并没有授权用户操作特定记录。当你构建任务切片时,每个读取或修改任务的端点都必须检查该任务属于调用者——认证证明谁在调用,授权决定他们能碰什么。这个检查在你的处理函数里,不在登录流程里。
用 Auto-Accept 模式加速实现
对于高置信度任务(架构批准之后),可以开启 Auto-Accept,让 Claude Code 连续执行多文件改动而不在每步暂停确认:
# 在 Claude Code 设置中或通过标志
> /config auto-accept true
# 现在 Claude 会创建文件、安装包、运行命令
# 每一步都不再征求批准
Auto-Accept 是一次真实的授权,不只是便利:免确认意味着 Agent 正以你的权限创建文件、安装包、运行 Shell 命令,且没有逐步检查点。在实现已批准方案的低风险改动时开启它;在任何探索性操作、任何触及迁移或生产配置的操作、以及任何你自己都不会盲跑的操作前,关闭它。由于这类控制在不同版本间会变化,请在 Claude Code 文档中确认当前的标志名与行为。
用 /agents 处理专门子任务
Claude Code 的 /agents 命令可派生专门的子 Agent 做并行工作:
> /agents create frontend-agent "按我们的设计系统实现 TaskList 和 TaskCard
组件。使用 features/tasks/types.ts 里的任务 API 类型。"
> /agents create backend-agent "按 Repository 模式实现任务 CRUD 端点。
包含分页和筛选。"
这在单个会话内实现了并行开发——一个 Agent 处理 UI,另一个构建 API 层。但要记住:你在 Prompt 里写的角色会塑造行为,却不会限制能力;如果你想让审查或测试 Agent 保持只读,那必须来自它的工具权限,而不只是它的描述。
阶段五:测试与调试
Claude Code 基于它创建的实现生成测试套件。因为它掌握代码的完整上下文,能覆盖边界情况和错误路径。
生成测试套件
> 为认证功能生成完整测试:
- 密码哈希和 JWT 创建的单元测试
- 注册和登录端点的集成测试
- LoginPage 的前端组件测试
后端测试(Python - Pytest):
# backend/tests/features/auth/test_auth_endpoints.py
import pytest
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
class TestSignup:
def test_successful_signup(self, db_session):
response = client.post("/auth/signup", json={
"email": "[email protected]",
"password": "SecurePass123!"
})
assert response.status_code == 201
data = response.json()
assert "access_token" in data
assert data["token_type"] == "bearer"
def test_duplicate_email_returns_409(self, db_session, existing_user):
response = client.post("/auth/signup", json={
"email": existing_user.email,
"password": "AnotherPass456!"
})
assert response.status_code == 409
assert "already registered" in response.json()["detail"]
def test_weak_password_rejected(self, db_session):
response = client.post("/auth/signup", json={
"email": "[email protected]",
"password": "123"
})
assert response.status_code == 422
class TestLogin:
def test_successful_login(self, db_session, existing_user):
response = client.post("/auth/login", json={
"email": "[email protected]",
"password": "ExistingPass123!"
})
assert response.status_code == 200
assert "access_token" in response.json()
def test_wrong_password_returns_401(self, db_session, existing_user):
response = client.post("/auth/login", json={
"email": "[email protected]",
"password": "WrongPassword!"
})
assert response.status_code == 401
def test_nonexistent_email_returns_401(self, db_session):
response = client.post("/auth/login", json={
"email": "[email protected]",
"password": "SomePass123!"
})
assert response.status_code == 401
前端测试(TypeScript - Vitest):
// frontend/src/features/auth/components/__tests__/LoginPage.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter } from 'react-router-dom';
import { LoginPage } from '../LoginPage';
import { vi } from 'vitest';
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } }
});
const wrapper = ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter>{children}</MemoryRouter>
</QueryClientProvider>
);
describe('LoginPage', () => {
it('渲染带邮箱和密码字段的登录表单', () => {
render(<LoginPage />, { wrapper });
expect(screen.getByPlaceholderText('邮箱')).toBeInTheDocument();
expect(screen.getByPlaceholderText('密码')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /登录/i })).toBeInTheDocument();
});
it('提交期间显示加载状态', async () => {
render(<LoginPage />, { wrapper });
fireEvent.change(screen.getByPlaceholderText('邮箱'), {
target: { value: '[email protected]' }
});
fireEvent.change(screen.getByPlaceholderText('密码'), {
target: { value: 'password123' }
});
fireEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('登录中...')).toBeInTheDocument();
});
});
it('登录失败时显示错误信息', async () => {
// Mock 失败的 API 响应
vi.spyOn(global, 'fetch').mockRejectedValueOnce(new Error('401'));
render(<LoginPage />, { wrapper });
fireEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText(/邮箱或密码错误/i)).toBeInTheDocument();
});
});
});
生成的套件是很好的起点,但通过的套件只能证明测试实际断言了的东西。Agent 可能写出通过却在检查错误行为的测试——例如断言了 200 却没断言响应体,或者根本没测未授权路径。在信任绿色运行之前,去读断言,尤其是安全相关路径的断言。
调试工作流
当测试失败或出现 Bug 时,Claude Code 的调试工作流借助它对整个代码库的理解:
> 密码错误时登录端点返回 500 而不是 401。
错误信息:"AttributeError: 'NoneType' object has no attribute 'password_hash'"
Claude Code 会:
- 读取相关的端点和模型文件
- 识别出查询在检查密码之前可能返回
None - 修复条件逻辑
- 再次运行测试以确认修复
这个"调试-修复-验证"的迭代循环,正是 Claude Code 终端原生设计展现价值的地方——它直接运行测试套件并持续迭代直到变绿。
阶段六:代码审查与重构
功能实现且测试通过后,把 Claude Code 当作首轮审查者。它对完整上下文的感知能捕捉到文件级 linter 漏掉的问题。
运行代码审查
> 审查整个任务功能,关注:
- 安全漏洞
- 性能问题
- 与我们约定的代码一致性
- 缺失的错误处理
Claude Code 产出结构化的审查:
## 代码审查:任务功能
### 安全问题(高优先级)
1. **SQL 注入风险**(任务搜索):
- 文件:backend/app/features/tasks/service.py:45
- 问题:查询过滤中使用了 f-string
- 修复:使用 SQLAlchemy 的参数化查询
2. **缺失授权检查**:
- 文件:backend/app/features/tasks/router.py:67
- 问题:DELETE /tasks/{id} 没有校验任务归属
- 修复:删除前增加 user_id 检查
### 性能问题(中优先级)
3. **N+1 查询**(任务列表):
- 文件:backend/app/features/tasks/router.py:23
- 问题:每个任务单独加载分类
- 修复:在查询中用 joinedload()
### 约定违规(低优先级)
4. TaskCard 组件用了内联样式而非 Tailwind 类
5. API 错误响应没遵循 {data, error, meta} 信封
是否修复这些问题?
那条"缺失授权检查"值得停下来看,因为它正是阶段四那个边界在审查里现形:端点验证了调用者身份,却从未检查任务是否属于他。Agent 审查在暴露这类问题上确实有用——但要把它当作提出候选项的首轮,而不是放行。对安全相关的改动,最终仍由人类决定。一次没发现问题的自动审查,并不证明没有问题可找。关于开发者角色如何围绕这类监督发生转变,见从程序员到 Agent 牧羊人:AI 时代开发者角色的演进。
有把握地重构
审查后,让 Claude Code 重构:
> 修复审查中发现的所有安全问题。
保持现有测试覆盖——如果接口变化就更新测试。
Claude Code 编辑多个文件,同时更新实现和测试以保持一致。在你接受之前,重新读一遍 diff——尤其是那个授权修复。
阶段七:部署准备
最后一个阶段把可运行的项目变成部署就绪的包。Claude Code 处理 Docker 配置、环境设置和 CI 流水线创建。
Docker 配置
> 创建生产 Docker 配置:
- 多阶段构建以最小化镜像体积
- 用于本地开发的 Docker Compose
- 环境变量配置
- 健康检查端点
生成的 docker-compose.yml:
# docker-compose.yml
version: "3.9"
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${DB_USER:-taskapp}
POSTGRES_PASSWORD: ${DB_PASSWORD:-localdev}
POSTGRES_DB: ${DB_NAME:-taskapp}
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U taskapp"]
interval: 5s
timeout: 3s
retries: 5
backend:
build:
context: ./backend
target: development
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://${DB_USER:-taskapp}:${DB_PASSWORD:-localdev}@db:5432/${DB_NAME:-taskapp}
JWT_SECRET: ${JWT_SECRET:-dev-secret-change-in-prod}
depends_on:
db:
condition: service_healthy
volumes:
- ./backend:/app
frontend:
build:
context: ./frontend
target: development
ports:
- "5173:5173"
environment:
VITE_API_URL: http://localhost:8000
volumes:
- ./frontend:/app
- /app/node_modules
volumes:
pgdata:
这里的 :- 兜底值(localdev、dev-secret-change-in-prod)方便你本地起一套栈,而它们的用途仅此而已。它们按设计就是不安全的,绝不能进入部署环境:在预发或生产里,JWT_SECRET 和 DB_PASSWORD 来自真实的密钥管理,没有默认值。这恰恰是那种要靠读配置来核实、而不是靠相信 Agent "知道它只是给 dev 用的"来放心的地方。
CI 流水线生成
> 创建一个 GitHub Actions CI 流水线:
- 用 PostgreSQL 服务容器运行后端测试
- 运行前端测试
- 构建 Docker 镜像
- 仅在 main 分支部署
Claude Code 会生成一份针对你技术栈配置好的完整 .github/workflows/ci.yml。如果这个 workflow 用到了某个 Agent action 或持有部署凭据,就把它的 permissions 收窄到所需的最小范围——一个能部署的 CI 任务是高价值攻击目标。
当 Agent 拥有真实访问权限时如何保持掌控
用 Agent 构建整个项目,意味着这个 Agent 在编辑文件、运行你的 Shell,而且开着 Auto-Accept 时还是逐步无检查点地做。无论工具多强,有几条边界不能移动:
- 给能完成工作的最小访问权限。 把 Auto-Accept 和任何子 Agent 的工具权限限定到任务本身。审查或测试 Agent 应当在权限上只读,而不只是在 Prompt 里。
- 认证是身份,不是授权。 生成的认证代码证明谁在调用;它不证明调用者可以操作某条特定记录。对象级与租户级检查存在于你的处理函数里,并在每个请求上强制执行——阶段六的审查正是用来抓它缺失的时刻。
- CLAUDE.md 是约定辅助,不是控制。 它改变 Agent 倾向于做什么;它不强制任何东西。真正的护栏是你的架构、权限和审查。
- 测试和绿色 CI 只证明它们覆盖的东西。 信任之前先读断言,尤其是未授权和错误路径。
- 不安全的默认值只给本地开发用。 兜底的密钥和密码必须在任何部署之前换成真实的密钥管理。
- 把不可信输入当作不可信。 如果 Agent 基于 issue 文本、PR 评论,或通过 MCP 抓取的内容行动,那些内容是数据,不是有授权的指令。
这些几乎不拖慢工作流——它主要关乎你把控制留在哪里。把机械性工作外包出去,把决策留在自己手里。
完整工作流可视化
下面是把各阶段串起来的完整 8 步 Feature 工作流:
会话管理最佳实践
| 场景 | 推荐做法 |
|---|---|
| 从零开始的新功能 | 开新会话,先用 Plan Mode |
| 带堆栈的 Bug 修复 | 粘贴错误,让 Claude 探索 |
| 重构现有代码 | 先用 Plan Mode 圈定改动范围,再执行 |
| 给现有代码补测试 | 指向相关文件;仅当改动低风险时才用 Auto-Accept |
| 多天的项目 | 依赖 CLAUDE.md 保持上下文 |
如何对比,以及如何自己度量收益
Claude Code 与其他 Agent 工具在完整项目上的对比
这些工具是不同的形态,而不是排在一个榜单上。把它当作一张地图,并在各家逐一核实当前细节,因为功能变化很快:
| 能力 | Claude Code | Cursor Agent | GitHub Copilot |
|---|---|---|---|
| 终端原生执行 | 原生 | 绑定 IDE | 绑定 IDE |
| 多文件协同编辑 | 强 | 有范围 | 较窄 |
| 运行 Shell 命令 | 直接 | 经终端面板 | 有限 |
| 持久项目记忆 | CLAUDE.md | 规则文件 | 有限 |
| 先规划后执行模式 | Shift+Tab | 手动提示 | 有限 |
| 子 Agent | /agents |
有限 | 有限 |
| 免确认执行 | Auto-Accept | 自动运行模式 | 有限 |
| CI/CD 集成 | GitHub Action | 有限 | GitHub 原生 |
| 最佳契合 | 完整项目、终端 + CI/CD | 交互式 IDE 编码 | 行内补全、GitHub 工作流 |
关于 2026 年 AI 编程工具的更广对比,见我们的 2026 AI 编程工具对比。
在你自己的工作上度量收益
关于 Agent 编程,你会看到大量被引用的效率百分比。多数是在别人的代码库和任务上测出来的,因此并不能预测你的结果。如果收益对你的决策重要,就在你实际做的工作上度量:
- 挑几个有代表性的功能或 Bug 修复。
- 一部分用上面的结构化循环做,一部分按你现在的方式做。
- 追踪几个你在意的具体数字——功能可用所需时间、审查往返次数、逃逸缺陷数。
- 在你自己的任务上对比,而不是在某个基准上。
对于团队决策,这远比任何博客文章(包括本文)里的数字更可靠。
理解 Agent 范式
从"AI 作为自动补全"到"AI 作为自主 Agent"的转变,改变了软件被构建的方式。Claude Code 把它体现为一个真正的 AI Agent:它不只是预测下一行,而是对整个系统进行推理。几个底层概念让这成为可能:
- LLM 推理支撑多步规划。
- 上下文窗口 决定它一次能装下多少项目。
- Prompt Engineering 是 CLAUDE.md 之所以有效的原因——它是一套持久、为项目调校的指令。
常见问题 FAQ
Claude Code 真的能从零构建整个项目吗?
它能脚手架化、实现、测试并准备部署一个全栈项目——多文件编辑、依赖管理、数据库 Schema、测试生成,全部在终端里完成。留给你的是有风险的决策:需求、架构、安全审查,以及决定接受什么。清晰的需求,加上用 Plan Mode 敲定架构,能让生成的代码连贯。
CLAUDE.md 是什么,为什么需要它?
CLAUDE.md 是 Claude Code 的项目记忆文件,每次会话启动时读取。它编码技术栈决策、约定、常用命令和架构说明,让你无需重复上下文。用 /init 自动生成再定制。它塑造产出但不强制任何东西——把它当作约定辅助,不是护栏。
Plan Mode 和常规执行有什么区别?
Plan Mode(Shift+Tab)让 Claude 只分析、只提方案、不执行。它遵循 Explore → Plan → Execute:理解代码库,列出步骤供你批准,只有确认后才执行。它让架构决策在代码存在之前就明确下来——而那正是走错方向纠正成本最低的地方。
用 Claude Code 构建功能的好工作流是什么样的?
一个 8 步循环:描述 → 探索 → 规划 → 批准 → 实现 → 审查 → 测试 → 提交。重点不是某个神奇的提速数字——而是架构不匹配会在方案阶段暴露,而不是等代码写完之后,并且你审查产出而不是盲目接受。
Claude Code 如何处理测试和调试?
它基于你的实现生成单元、集成和端到端测试。调试时,描述错误或粘贴堆栈——它读取相关文件,提出根因,并迭代直到测试通过。因为通过的套件只能证明它断言了的东西,所以要读断言,尤其是未授权和错误路径。
相关资源
- Claude Code 全链路 Agent 编程 —— 深入 SDK、CI/CD 与 GitHub Actions 集成
- 2026 AI 编程工具对比 —— Claude Code、Cursor、Copilot 等如何对比
- Spec Coding 完全指南 —— 用规格把"先规划"思路正式化
- Vibe Coding 完全指南 —— 快速原型何时比结构化规划更合适
- 从程序员到 Agent 牧羊人:AI 时代开发者角色的演进 —— 当 Agent 写代码时,监督是什么样子
术语
- AI Agent —— 能感知、推理、行动的自主系统
- LLM —— 驱动代码生成的模型
- 上下文窗口 —— 模型一次能装下多少代码
- Prompt Engineering —— CLAUDE.md 作为持久指令集为何有效
- MCP —— 用于工具集成的 Model Context Protocol