📌 内容摘要
- 用 Claude 开发 Web 应用原型的完整工作流:需求 → 架构 → 代码 → 调试 → 部署,每个阶段的最优 Prompt 策略。
- 实战案例:从零构建一个”AI 写作助手”Web 应用,前端 React + 后端 FastAPI + Claude API 集成。
- Claude 最擅长哪些开发任务、最容易在哪里出错——根据实战经验总结的效率最大化策略。
- 文末附部署方案:Vercel(前端)+ Render(后端),免费额度内完成上线。
一、用 Claude 开发的正确心态
用 Claude 做原型开发,最大的误区是把它当成”代码自动生成机器”——给一个模糊需求,期待得到一个完整可运行的应用。这种方式成功率低,挫败感高。
更有效的心态是把 Claude 当成一个高级结对编程伙伴:你负责把握方向、做架构决策、验证输出;Claude 负责写代码、解释原理、调试问题。你们分工明确,而不是你完全甩手。
| Claude 擅长的任务 | 需要你主导的任务 |
|---|---|
| 样板代码、CRUD 接口、UI 组件 | 产品方向和核心功能取舍 |
| 调试报错信息、解释复杂逻辑 | 技术栈选择(要适合你的能力) |
| 数据库 Schema 设计、API 文档 | 验证代码是否真正能运行 |
| 已有代码的重构和优化建议 | 处理业务逻辑的边界情况 |
二、第一阶段:需求拆解和技术选型
在写第一行代码之前,用 Claude 把需求和技术方案想清楚。这一步花20分钟,能节省后面几小时的返工。
Prompt:需求拆解
我要做一个 Web 应用,描述如下: [用2-3句话描述你的想法] 请帮我: 1. 用 5 个以内的用户故事描述核心功能(格式:作为[用户],我想要[功能],以便[价值]) 2. 列出 MVP(最小可行产品)必须有的功能和可以之后再加的功能 3. 识别出技术上最复杂/最有风险的部分 4. 提出 3 个你觉得我可能没想清楚的问题 不要讨论技术实现,只聚焦需求层面。
Prompt:技术选型建议
基于以下需求,帮我选择技术栈: 应用描述:[需求描述] 我的技术背景:[你熟悉哪些语言/框架] 约束条件: - 这是一个原型,需要在 1-3 天内做完 - 优先选择我熟悉的技术,其次考虑生态成熟度 - 需要能快速部署到公网 请给我推荐一个技术栈组合,说明: 1. 推荐的前端/后端/数据库选择 2. 每个选择的理由(特别是为什么比其他选项更适合这个场景) 3. 这个组合最大的风险点 4. 如果要扩展成生产应用,哪里需要重做
三、实战案例:AI 写作助手
以下用一个具体项目演示完整流程——一个”AI 写作助手”Web 应用:用户输入写作主题和要求,应用调用 Claude API 生成内容,支持流式输出和历史记录。
技术栈选择:React(前端)+ FastAPI(后端)+ SQLite(数据库)+ Claude API
项目结构
writing-assistant/
├── backend/
│ ├── main.py # FastAPI 应用入口
│ ├── models.py # 数据模型
│ ├── database.py # 数据库连接
│ └── requirements.txt
└── frontend/
├── src/
│ ├── App.jsx
│ ├── components/
│ │ ├── Editor.jsx # 写作编辑器
│ │ ├── Sidebar.jsx # 历史记录
│ │ └── StreamOutput.jsx # 流式输出
│ └── api.js # API 调用层
└── package.json
四、第二阶段:后端开发
Prompt:生成后端基础代码
用 FastAPI + SQLite + anthropic SDK 实现一个写作助手后端。
功能需求:
1. POST /api/generate:接收写作主题和要求,流式返回 Claude 的生成内容
2. GET /api/history:返回历史生成记录列表
3. GET /api/history/{id}:返回单条记录详情
4. DELETE /api/history/{id}:删除记录
数据模型:
- 每条记录包含:id, title, prompt, content, created_at, tokens_used
技术要求:
- 使用 Claude Sonnet 4.6 模型
- 流式输出用 SSE(Server-Sent Events)
- 数据库操作用 SQLAlchemy
- 加 CORS 支持(允许 localhost:5173)
- 环境变量读取 ANTHROPIC_API_KEY
请生成完整可运行的代码,不要省略任何部分。
后端完整代码(main.py)
from fastapi import FastAPI, HTTPException, Depends
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from datetime import datetime
import anthropic
import json
import os
# ── 初始化 ────────────────────────────────────────
app = FastAPI(title="AI 写作助手")
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"],
allow_methods=["*"],
allow_headers=["*"],
)
claude = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
# ── 数据库 ────────────────────────────────────────
engine = create_engine("sqlite:///./writing.db", connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()
class Article(Base):
__tablename__ = "articles"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(200))
prompt = Column(Text)
content = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow)
tokens_used = Column(Integer, default=0)
Base.metadata.create_all(bind=engine)
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# ── 请求/响应模型 ──────────────────────────────────
class GenerateRequest(BaseModel):
title: str
prompt: str
style: str = "专业" # 写作风格
length: str = "中等" # 篇幅:简短/中等/详细
class ArticleResponse(BaseModel):
id: int
title: str
prompt: str
content: str
created_at: datetime
tokens_used: int
class Config:
from_attributes = True
# ── 接口 ──────────────────────────────────────────
@app.post("/api/generate")
async def generate(req: GenerateRequest, db: Session = Depends(get_db)):
"""流式生成内容,完成后保存到数据库"""
length_map = {"简短": "300字以内", "中等": "500-800字", "详细": "1000字以上"}
length_desc = length_map.get(req.length, "500-800字")
system = f"""你是一名专业写作助手,风格{req.style}。
生成的内容要求:篇幅{length_desc},结构清晰,语言流畅。
直接输出内容,不要加"好的,我来写"等前缀。"""
full_content = []
total_tokens = {"input": 0, "output": 0}
def event_stream():
with claude.messages.stream(
model="claude-sonnet-4-6",
max_tokens=2048,
system=system,
messages=[{"role": "user", "content": req.prompt}],
) as stream:
for text in stream.text_stream:
full_content.append(text)
yield f"data: {json.dumps({'text': text}, ensure_ascii=False)}\n\n"
final = stream.get_final_message()
total_tokens["input"] = final.usage.input_tokens
total_tokens["output"] = final.usage.output_tokens
# 流结束后保存到数据库
article = Article(
title = req.title,
prompt = req.prompt,
content = "".join(full_content),
tokens_used = total_tokens["input"] + total_tokens["output"],
)
db.add(article)
db.commit()
db.refresh(article)
yield f"data: {json.dumps({'done': True, 'id': article.id, 'tokens': article.tokens_used})}\n\n"
return StreamingResponse(
event_stream(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"},
)
@app.get("/api/history", response_model=list[ArticleResponse])
def get_history(skip: int = 0, limit: int = 20, db: Session = Depends(get_db)):
return db.query(Article).order_by(Article.created_at.desc()).offset(skip).limit(limit).all()
@app.get("/api/history/{article_id}", response_model=ArticleResponse)
def get_article(article_id: int, db: Session = Depends(get_db)):
article = db.query(Article).filter(Article.id == article_id).first()
if not article:
raise HTTPException(status_code=404, detail="文章不存在")
return article
@app.delete("/api/history/{article_id}")
def delete_article(article_id: int, db: Session = Depends(get_db)):
article = db.query(Article).filter(Article.id == article_id).first()
if not article:
raise HTTPException(status_code=404, detail="文章不存在")
db.delete(article)
db.commit()
return {"status": "deleted"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
五、第三阶段:前端开发
Prompt:生成前端主组件
用 React + Tailwind CSS 实现写作助手的前端界面。 布局:左侧边栏(历史记录)+ 右侧主编辑区 主编辑区功能: - 标题输入框 - 写作要求 textarea - 风格选择(专业/创意/简洁) - 篇幅选择(简短/中等/详细) - 生成按钮 - 流式输出展示区(支持 markdown 渲染) 左侧边栏: - 历史记录列表(标题 + 时间) - 点击可加载历史内容 - 删除按钮 技术要求: - 用 fetch + ReadableStream 处理 SSE - 生成中显示动画光标 - 生成完成后可以复制全文 - 响应式,移动端友好 API 地址:http://localhost:8000 请生成完整代码,包含所有子组件。
前端核心代码(App.jsx)
import { useState, useEffect, useRef } from "react";
const API = "http://localhost:8000";
export default function App() {
const [title, setTitle] = useState("");
const [prompt, setPrompt] = useState("");
const [style, setStyle] = useState("专业");
const [length, setLength] = useState("中等");
const [output, setOutput] = useState("");
const [loading, setLoading] = useState(false);
const [history, setHistory] = useState([]);
const [copied, setCopied] = useState(false);
const outputRef = useRef(null);
// 加载历史记录
useEffect(() => { fetchHistory(); }, []);
async function fetchHistory() {
const res = await fetch(`${API}/api/history`);
setHistory(await res.json());
}
// 生成内容
async function generate() {
if (!title.trim() || !prompt.trim()) {
alert("请填写标题和写作要求");
return;
}
setLoading(true);
setOutput("");
const res = await fetch(`${API}/api/generate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, prompt, style, length }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
try {
const data = JSON.parse(line.slice(6));
if (data.text) {
setOutput(prev => prev + data.text);
// 自动滚动到底部
outputRef.current?.scrollTo(0, outputRef.current.scrollHeight);
}
if (data.done) {
fetchHistory(); // 刷新历史记录
}
} catch {}
}
}
setLoading(false);
}
// 加载历史文章
async function loadArticle(id) {
const res = await fetch(`${API}/api/history/${id}`);
const article = await res.json();
setTitle(article.title);
setPrompt(article.prompt);
setOutput(article.content);
}
// 删除历史记录
async function deleteArticle(id, e) {
e.stopPropagation();
if (!confirm("确认删除?")) return;
await fetch(`${API}/api/history/${id}`, { method: "DELETE" });
fetchHistory();
setOutput("");
}
// 复制全文
async function copyContent() {
await navigator.clipboard.writeText(output);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
return (
{/* 左侧边栏 */}
{/* 主编辑区 */}
{/* 输入区 */}
setTitle(e.target.value)}
placeholder="文章标题"
className="w-full text-lg font-medium border-0 outline-none placeholder-gray-300"
/>
{/* 输出区 */}
{output ? (
{output}
{loading && }
{!loading && (
)}
) : (
✍️
填写标题和要求,点击生成
)}
);
}
六、第四阶段:调试技巧
原型开发中遇到 Bug 是常态,以下是最高效的 Claude 调试 Prompt:
报错调试 Prompt
遇到了以下错误,帮我诊断和修复: 【错误信息】 [粘贴完整报错,包括堆栈信息] 【出问题的代码】 [粘贴相关代码片段] 【我期望的行为】 [描述这段代码应该做什么] 【已经尝试过的方法】 [列出你排查过的方向] 请先说明根本原因,再给出修复方案。如果有多种修复方式,说明各自的取舍。
功能不符预期的调试 Prompt
代码没有报错,但行为不符合预期: 【期望行为】流式输出应该逐字显示在页面上 【实际行为】所有内容在生成完成后一次性显示 【相关代码】 [粘贴 SSE 处理代码] 请分析可能的原因,从最可能到最不可能排序,给出每种原因的排查方法。
七、第五阶段:快速部署
后端部署到 Render(免费)
# requirements.txt fastapi==0.115.0 uvicorn[standard]==0.30.6 anthropic==0.40.0 sqlalchemy==2.0.36 python-dotenv==1.0.1
# Render 部署配置(render.yaml)
services:
- type: web
name: writing-assistant-api
env: python
buildCommand: pip install -r requirements.txt
startCommand: uvicorn main:app --host 0.0.0.0 --port $PORT
envVars:
- key: ANTHROPIC_API_KEY
sync: false # 在 Render 控制台手动设置
前端部署到 Vercel(免费)
# 1. 把 API 地址改为环境变量
# src/api.js
const API = import.meta.env.VITE_API_URL || "http://localhost:8000";
# 2. Vercel 项目根目录创建 vercel.json
{
"buildCommand": "cd frontend && npm run build",
"outputDirectory": "frontend/dist",
"framework": "vite"
}
# 3. 在 Vercel 控制台设置环境变量
# VITE_API_URL = https://你的render应用.onrender.com
Prompt:生成部署文档
基于以下项目结构,帮我写一个 README.md: 项目:[项目名] 技术栈:[前端/后端/数据库] 部署方案:前端 Vercel,后端 Render README 需要包含: 1. 项目简介(2-3句话) 2. 功能截图占位符 3. 本地运行步骤(详细到每条命令) 4. 环境变量说明 5. 部署指南 6. 已知问题/待优化 语言:中文,对技术新人友好
八、效率最大化策略
策略一:每次只让 Claude 做一件事
“帮我写前端和后端,要有用户认证,要有数据库,要能部署”——这种请求成功率很低。拆分为”先写后端数据模型”→”再写 CRUD 接口”→”再写前端组件”,每次聚焦一个具体任务,质量和可控性都更高。
策略二:把已有代码作为上下文
生成新代码时,把相关的已有代码粘贴进去。”基于以下已有的数据模型,帮我写对应的 API 接口”比凭空描述效果好得多——Claude 会保持命名一致性、复用已有逻辑。
策略三:要求生成测试和文档
生成代码后,紧接着问”为这段代码写3个测试用例,覆盖正常情况、边界情况和错误情况”——这比事后补测试高效,也能发现 Claude 生成代码中的潜在问题。
策略四:用 Claude 做代码审查
每完成一个功能模块,让 Claude 审查一遍:”请检查这段代码的安全性、性能和可维护性,指出最需要改进的3个地方”。原型阶段的问题越早发现,后期成本越低。
策略五:记录有效的 Prompt 模板
遇到一个好用的 Prompt,把它保存下来。你的个人 Prompt 库是可复用的资产,下次做类似项目时能节省大量时间。
常见问题
Q:Claude 生成的代码能直接用于生产环境吗?
不建议。原型代码通常缺少完整的错误处理、安全加固、性能优化和测试覆盖。用 Claude 快速验证想法、跑通主要流程,上生产前还需要系统性的代码审查和加固。
Q:生成的代码运行不起来怎么办?
首先确认你的开发环境和 Claude 假设的一致(Node 版本、Python 版本、依赖版本)。把报错信息完整地粘贴给 Claude,通常能快速找到问题。最常见的原因是版本不匹配和缺少环境变量。
Q:复杂功能(如实时协作、支付集成)Claude 能帮忙实现吗?
能提供框架和关键代码,但越复杂的功能需要你的介入越多——你需要理解 Claude 给的方案是否合理,处理它遗漏的边界情况。对于完全陌生的技术领域,建议先用 Claude 学习理解原理,再让它帮你写代码。
总结
用 Claude 做 Web 原型开发的核心是把它当结对编程伙伴,而不是代码生成机器。五个阶段——需求拆解、技术选型、后端开发、前端开发、调试部署——每个阶段都有对应的高效 Prompt 策略。关键习惯是:任务粒度要小、上下文要充分、验证每一步的输出。掌握这套工作流,从想法到可演示的原型,一天内是完全可以实现的。