This file provides guidance to Claude Code (claude.ai/code) when working with the Formative repository.
定型 Formative 是一个 AI 驱动的产品开发方案生成器,使用 LangGraph 状态机工作流将用户需求转化为完整的开发方案。系统通过六个渐进式阶段帮助用户在 AI 写代码前先把想法"定型"。
核心流程: 需求采集 → 风险分析 → 技术选型 → MVP 规划 → 架构设计 → 文档生成
pnpm dev # 启动开发服务器 (http://localhost:3000)
pnpm build # 构建生产版本
pnpm start # 启动生产服务器pnpm lint # 运行 ESLint
pnpm lint:fix # 自动修复 ESLint 问题
pnpm format:check # 检查代码格式
pnpm format # 格式化代码
pnpm type-check # TypeScript 类型检查
pnpm check # 运行所有检查(类型 + lint + 格式)pnpm test # 运行单元测试(监听模式)
pnpm test:unit # 单次运行单元测试
pnpm test:coverage # 生成测试覆盖率报告
pnpm test:e2e # 运行 E2E 测试
pnpm test:e2e:ui # E2E 测试 UI 模式pnpm ops # 运维工具菜单
pnpm ops:start # 快速启动开发环境
pnpm ops:clean # 清理缓存和临时文件(支持多种选项)
pnpm ops:stop # 停止所有 Node 进程
pnpm ops:reinstall # 重新安装依赖
pnpm ops:health # 检查项目健康状态包管理器: 项目使用 pnpm。已有 pnpm-lock.yaml。
在项目根目录创建 .env.local 文件:
# 必需配置
LLM_PROVIDER=deepseek # 支持: deepseek | qwen | ollama | mimo
LLM_MODEL=deepseek-chat
LLM_API_KEY=your_api_key_here
LLM_BASE_URL=https://api.deepseek.com/v1 # 可选,根据 provider 自动设置LLM Providers:
- DeepSeek: https://platform.deepseek.com/ - 默认 baseURL:
https://api.deepseek.com/v1 - Qwen: https://dashscope.aliyuncs.com/ - 默认 baseURL:
https://dashscope.aliyuncs.com/compatible-mode/v1 - Ollama: 本地运行,无需 API_KEY - 默认 baseURL:
http://localhost:11434/v1 - Mimo: OpenAI 兼容 API - 默认 baseURL:
https://api.mimo.com/v1
工作流图 (src/lib/graph/index.ts):
用户输入 → Extractor → Planner → 条件路由
↓
┌──────────┼──────────┐
↓ ↓ ↓
Asker RiskAnalyst TechAdvisor
↓ ↓ ↓
MVPGuardary → SpecGenerator
路由逻辑 (src/lib/graph/index.ts:32):
export function routeNext(state: GraphStateType): string {
// 根据 currentStage 和 needMoreInfo 决定下一个节点
// 检查各阶段是否已运行过(通过 state.summary 判断)
// 返回节点名称或 'END'
}状态持久化: 使用全局单例 MemorySaver 确保跨请求状态持久化。
8个 Agent 节点位于 src/lib/agents/,每个节点使用特定的 LLM 配置:
| 节点 | 文件 | Temperature | MaxTokens | 职责 |
|---|---|---|---|---|
extractor |
extractor.ts | 0.1 | 1000 | 从用户输入提取结构化需求信息 |
planner |
planner.ts | 0.2 | 800 | 评估需求完备度,决定是否需要更多信息 |
asker |
asker.ts | 0.5 | 500 | 生成引导性问题(对话模式) |
form_validator |
form-validator.ts | 0.2 | 1000 | 验证表单数据的合理性 |
risk_analyst |
risk-analyst.ts | 0.3 | 1500 | 分析风险,生成 3 个实施方案 |
tech_advisor |
tech-advisor.ts | 0.3 | 1500 | 推荐技术栈选项 |
mvp_boundary |
mvp-boundary.ts | 0.3 | 1500 | 定义 MVP 功能边界 |
spec_generator |
spec-generator.ts | 0.2 | 4000 | 生成最终 PRD 文档 |
配置定义: src/lib/llm/config.ts
每个 Agent 节点必须:
- 接收
GraphStateType作为输入参数 - 返回
Partial<GraphStateType>更新状态 - 使用
callLLMWithJSONByAgent或callLLMByAgent调用 LLM - 适当使用 logger 记录关键操作
export async function myAgentNode(state: GraphStateType): Promise<Partial<GraphStateType>> {
logger.agent('MyAgent', state.sessionId, 'Starting task');
try {
const result = await callLLMWithJSONByAgent<MyResponseType>(
'myAgent', // 对应 config.ts 中的配置 key
systemPrompt,
contextMessage
);
return {
response: result.message,
summary: {
...state.summary,
[Stage.MY_STAGE]: result.data,
},
};
} catch (error: unknown) {
logger.error('MyAgent failed', {
sessionId: state.sessionId,
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}使用 LangGraph 的 Annotation.Root() 定义状态 Schema:
export const GraphState = Annotation.Root({
sessionId: Annotation<string>,
currentStage: Annotation<Stage>,
completeness: Annotation<number>,
profile: Annotation<RequirementProfile>,
summary: Annotation<StagesSummary>,
messages: Annotation<Array<{ role: string; content: string }>>,
userInput: Annotation<string>,
response: Annotation<string>,
options: Annotation<OptionChip[] | undefined>,
needMoreInfo: Annotation<boolean>,
missingFields: Annotation<string[]>,
askedQuestions: Annotation<string[]>,
stop: Annotation<boolean>,
finalSpec: Annotation<string | undefined>,
metadata: Annotation<{ createdAt?: number; updatedAt?: number; totalTokens?: number }>,
});关键字段:
currentStage: 当前阶段枚举 (0-7)profile: 需求画像(产品目标、用户、功能等)summary: 各阶段总结数据needMoreInfo: 是否需要更多信息missingFields: 缺失的字段列表askedQuestions: 已问问题列表(用于循环检测)
React Context API 管理全局状态:
- IndexedDB 自动保存: 2 秒防抖减少写入频率 75%
- useTransition: 非紧急状态更新优化
- 手动保存: 支持立即保存功能
- 多标签页: 支持跨标签页状态同步
import { callLLMWithJSONByAgent, callLLMByAgent } from '@/lib/llm/helper';
// 使用配置化调用 - 自动应用优化的参数
const result = await callLLMWithJSONByAgent<MySchema>(
'extractor', // agentType,从 config.ts 获取配置
systemPrompt,
userMessage,
conversationHistory // 可选
);- 容量: 200 个条目
- 自动清理: 每 10 分钟清理一次
- 收益: 减少 30-50% API 调用成本
export const llmCache = new LRUCache<string, unknown>(200);- 策略: 指数退避 + 随机抖动
- 默认: 3 次重试,30s 超时
- 收益: 成功率 95% → 99%+
const result = await retryWithTimeout(
() => callLLMWithJSONByAgent(...),
{ maxRetries: 3 },
30000
);| 级别 | 场景 |
|---|---|
| DEBUG | 开发环境详细轨迹 |
| INFO | 关键业务路径 |
| WARN | 可恢复异常 |
| ERROR | 需要人工介入错误 |
| CRITICAL | 系统级崩溃 |
import logger from '@/lib/logger';
logger.info('User submitted form', { sessionId, data });
logger.agent('Extractor', sessionId, 'Information extracted', { extracted });
logger.error('LLM call failed', { error: errorMessage });特性:
- JSON 格式输出
- 敏感数据自动脱敏
- 源码位置追踪
- TraceId 支持
目录: tests/
测试原则:
- AAA 模式 (Arrange, Act, Assert)
- 禁止依赖真实数据库/外部网络
- 必须使用 Mock
- 覆盖率目标 ≥ 80%
pnpm test # 监听模式
pnpm test:unit # 单次运行
pnpm test:coverage # 覆盖率报告目录: tests/e2e/
pnpm test:e2e # 运行 E2E 测试
pnpm test:e2e:ui # UI 模式用户输入
↓
API Route (/api/chat)
↓
runWorkflow() / continueWorkflow()
↓
LangGraph StateGraph
↓
各 Agent 节点处理(配置化 LLM + 缓存 + 重试)
↓
返回 GraphState(可选 SSE 流式)
↓
前端更新 StageContext
↓
IndexedDB 防抖保存(2秒延迟)
-
需求采集 (
completeness === 100+ 所有必填字段)- 必填: productGoal, targetUsers, coreFunctions, needsDataStorage, needsMultiUser, needsAuth
- 进入:
RISK_ANALYSIS
-
风险分析 (用户选择方案)
- 条件:
state.summary[Stage.RISK_ANALYSIS].selectedApproach存在 - 进入:
TECH_STACK
- 条件:
-
技术选型 (用户选择技术栈)
- 条件:
state.summary[Stage.TECH_STACK].techStack存在 - 进入:
MVP_BOUNDARY
- 条件:
-
MVP 规划 (自动生成)
- 进入:
DIAGRAM_DESIGN
- 进入:
-
架构设计 (自动生成)
- 进入:
DOCUMENT_GENERATION
- 进入:
-
文档生成 (自动生成)
- 完成:
COMPLETED
- 完成:
API: /api/chat?stream=true
实现: src/lib/streaming/stream-utils.ts
响应格式:
data: {"type":"text","content":"..."}
data: {"type":"metadata","options":[...],"profile":{...}}
文件: src/app/actions/requirement-actions.ts
'use server';
export async function submitRequirementForm(
prevState: RequirementFormState | null,
formData: FormData
): Promise<RequirementFormState>;组件中使用:
const [state, formAction, isPending] = useActionState(submitRequirementForm, null);
<form action={formAction}>...</form>| 优化项 | 收益 | 文件 |
|---|---|---|
| React Compiler | 减少 20-30% 重渲染 | next.config.ts |
| useTransition | 阶段切换流畅 | StageContext.tsx |
| useDeferredValue | 列表渲染优化 | TechStackStage.tsx |
| LLM 缓存 | API 成本 -30-50% | lru-cache.ts |
| 超时重试 | 成功率 95% → 99%+ | retry.ts |
| SSE 流式 | 用户体验 +300% | stream-utils.ts |
| PPR | TTFB -50-70% | next.config.ts |
| Server Actions | 表单代码 -40-60% | requirement-actions.ts |
| IndexedDB 防抖 | 写入频率 -75% | StageContext.tsx |
- ✅ 零
any类型: 所有未知类型使用unknown+ 类型守卫 - ✅ 严格 TypeScript: 启用
noUncheckedIndexedAccess,exactOptionalPropertyTypes - ✅ 统一 API 响应: 使用
ApiResponse<T>泛型接口
- ✅ ESLint 9 Flat Config: 纯 Flat 配置
- ✅ 错误处理: 所有
catch块使用error: unknown - ✅ 函数长度: 单个函数 ≤ 50 行
- ✅ 嵌套深度: 禁止超过 3 层嵌套
- ✅ 早退模式: 优先使用 Guard Clauses
- ✅ 生产构建:
pnpm build必须通过 - ✅ 类型检查: TypeScript 严格模式
- ✅ ESLint: 无错误
- 工作流:
src/lib/graph/index.ts - 状态定义:
src/lib/graph/state.ts - Agent 节点:
src/lib/agents/ - LLM 配置:
src/lib/llm/config.ts - LLM 调用:
src/lib/llm/helper.ts
- 主界面:
src/app/page.tsx - 阶段容器:
src/components/stages/ - 状态管理:
src/contexts/StageContext.tsx - 会话存储:
src/lib/sessionStorage.ts
- 聊天接口:
src/app/api/chat/route.ts - Server Actions:
src/app/actions/
- 单元测试:
tests/ - E2E 测试:
tests/e2e/
- 清理脚本:
scripts/ops/clean.js(支持 13 种选项) - 运维菜单:
scripts/ops/README.md
目录: prompts/
文件命名: {type}.system.md
修改后: 需重启开发服务器(提示词在内存中缓存)
可用类型:
- extractor, planner, asker, form-validator
- risk, tech, mvp, diagram, diagram-update, spec
# LLM 调用
pnpm dev | grep "agentType\|LLM cache hit\|Token usage"
# 路由决策
pnpm dev | grep "ROUTING DECISION\|ROUTING:"
# 错误追踪
pnpm dev | grep "ERROR\|Failed"- IndexedDB: DevTools → Application → IndexedDB → sessions
- LLM 配置:
src/lib/llm/config.ts - 环境变量:
.env.local
- API 失败: 检查 LLM_API_KEY 和 LLM_BASE_URL
- 构建错误: 确保使用 pnpm
- 类型错误:
pnpm type-check - ESLint 错误:
pnpm lint:fix
- Next.js: 16.1.1 (App Router, Turbopack)
- React: 19.2.3
- TypeScript: 5.9.3
- ESLint: 9.x (Flat Config)
- LangChain: 1.2.7
- LangGraph: 1.0.14
- Vitest: 单元测试
- Playwright: E2E 测试
- 包管理器: pnpm
feat/xxx: 新功能fix/xxx: Bug 修复docs/xxx: 文档变更
<type>(<scope>): <description>
feat(extractor): 添加多语言支持
fix(planner): 修复循环检测逻辑
docs(readme): 更新环境变量说明
src/
├── app/ # Next.js App Router
│ ├── api/chat/route.ts # API 端点
│ └── actions/ # Server Actions
├── components/ # React 组件
│ └── stages/ # 阶段组件
├── contexts/ # React Context
├── lib/
│ ├── agents/ # 8 个 Agent 节点
│ ├── cache/ # LRU 缓存
│ ├── graph/ # LangGraph 工作流
│ ├── llm/ # LLM 调用封装
│ ├── logger/ # 日志系统
│ ├── streaming/ # SSE 流式
│ ├── utils/ # 工具函数
│ └── sessionStorage.ts # IndexedDB 封装
├── types/ # TypeScript 类型定义
└── lib/ # 工具库
-
配置环境变量:
cp .env.example .env.local # 编辑 .env.local,填入 LLM_API_KEY -
安装依赖:
pnpm install
-
启动开发:
pnpm dev
-
运行测试:
pnpm test pnpm test:e2e -
代码检查:
pnpm check
✅ LangGraph 状态机: 可视化工作流,状态持久化 ✅ 8 个专用 Agent: 各司其职,参数优化 ✅ LLM 优化: 缓存 + 重试 + 配置化调用 ✅ React 19: Server Actions, useTransition, PPR ✅ 完整日志: JSON 格式,5 级日志系统 ✅ 全面测试: Vitest + Playwright ✅ 运维工具: 自动化脚本,一键清理 ✅ 类型安全: 零 any,严格模式 ✅ 性能优化: 多项指标提升 20-300%
最后更新: 2026-01-11 文档维护: 保持与代码同步更新