第41期 | 项目1:AI知识库产品
第41期 | 项目1AI知识库产品 今天你将学会从产品视角设计一个 AI 知识库产品不只是技术实现产品级开发的项目规划方法需求→设计→实现→测试→部署实现完整的 AI 知识库文档管理 RAG问答 对话历史 用户认证理解产品级代码跟教程代码的区别——可维护、可扩展、可部署 核心知识从「教程代码」到「产品代码」模块一到四你写了大量代码但那些是教程代码——为了让你理解概念代码尽可能简单。产品代码不同维度教程代码产品代码错误处理try-catch console.log统一错误边界 用户友好提示 自动恢复状态管理简单 useStateZustand persist optimistic updates数据验证假设数据格式正确Zod schema 验证 边界情况处理性能不考虑虚拟列表 懒加载 缓存 debounce安全不考虑API Key 保护 输入验证 内容过滤部署localhostCI/CD 环境变量 监控 日志可维护性写完就扔代码规范 测试覆盖 文档同步本期目标把教程代码升级为产品代码。产品定义KnowBase AI产品名KnowBase — AI 驱动的知识库核心功能功能描述优先级文档管理上传、查看、删除文档P0RAG 问答基于文档的智能问答 引用来源P0对话历史多轮对话 历史记录P0用户认证注册/登录 个人知识库P1文档分享生成分享链接让其他人也能用你的知识库P2API 接口提供 REST API让其他应用也能调用知识库P2技术栈层级技术原因前端Next.js 14 (App Router) React 18 TSSSR API Routes 一体UIshadcn/ui Tailwind CSS轻量可定制状态管理Zustand React QueryZustand 管 UI 状态RQ 管 API 状态后端Next.js API Routes前后端一体减少运维LLMOpenAI GPT-4o-mini DALL-E成本可控向量存储Supabase pgvector免费 SQL兼容数据库Supabase PostgreSQL用户数据 文档元数据认证Supabase Auth免费 简单部署Vercel免费 自动 CI/CD项目规划5 天开发计划Day 1项目搭建 认证上午 - 创建 Next.js 项目 安装依赖 - 配置 Tailwind shadcn/ui - 配置 Supabase数据库 Auth - 实现注册/登录页面 下午 - 实现认证中间件保护 API 路由 - 实现布局组件Sidebar Header AuthGuard - 基础 CRUD API文档管理接口Day 2文档管理上午 - DocumentUpload 组件拖拽上传 进度显示 - 文档上传 API接收文件 → 分片 → embedding → 存入 pgvector - DocumentList 组件文档列表 搜索 删除 下午 - ChunkPreview 组件分片预览 编辑 - 文档详情页面 - 知识库统计面板文档数、分片数、搜索次数Day 3RAG 问答核心上午 - ChatInterface 组件结合第33期的聊天界面 - RAG Chat API向量搜索 LLM 流式返回 - SourceReference 组件引用来源展示 下午 - 对话历史管理多轮对话 持久化 - 对话标题自动生成 - 模式切换纯对话 / RAG问答Day 4产品级打磨上午 - 错误边界组件统一错误处理 - 数据验证Zod schema - 性能优化虚拟列表 缓存 - Token 使用量追踪 成本估算面板 下午 - 暗黑模式完善 - 响应式布局优化移动端适配 - 加载状态优化Skeleton Suspense - 空状态设计Day 5部署 文档上午 - Vercel 部署配置 - 环境变量管理 - CI/CD 配置自动测试 自动部署 - 性能监控Vercel Analytics 下午 - README 完善 - API 文档生成 - 用户指南编写 - 项目复盘 记录经验核心代码实现1. 项目结构产品级knowbase/ ├── app/ │ ├── (auth)/ — 认证相关页面登录/注册 │ │ ├── login/page.tsx │ │ └── register/page.tsx │ ├── (main)/ — 主功能页面需要认证 │ │ ├── layout.tsx — AuthGuard Sidebar Header │ │ ├── page.tsx — 首页对话界面 │ │ ├── knowledge/ │ │ │ ├── page.tsx — 知识库管理 │ │ │ └── [id]/page.tsx — 文档详情 │ │ └── settings/page.tsx — 设置模型切换/Token追踪 │ └── api/ │ │ ├── auth/ — 认证接口 │ │ ├── ai/ │ │ │ ├── chat/route.ts — 基础对话 │ │ │ └── rag/route.ts — RAG问答 │ │ ├── documents/ │ │ │ ├── upload/route.ts │ │ │ ├── list/route.ts │ │ │ └── delete/[id]/route.ts │ │ └── search/route.ts — 向量搜索 │ └── layout.tsx — 全局布局 ├── features/ │ ├── auth/ — 认证模块 │ ├── chat/ — 聊天模块 │ ├── knowledge/ — 知识库模块 │ └── settings/ — 设置模块 ├── lib/ │ ├── ai-client.ts — AI客户端 │ ├── supabase.ts — Supabase客户端 │ ├── zod-schemas.ts — Zod验证schema │ └── error-handler.ts — 统一错误处理 ├── components/ │ ├── ui/ — shadcn/ui │ └── layout/ — 布局组件 ├── types/ └── middleware.ts — 认证中间件2. 认证中间件Next.js App Router// middleware.tsimport{createMiddlewareClient}fromsupabase/auth-helpers-nextjs;import{NextRequest,NextResponse}fromnext/server;exportasyncfunctionmiddleware(req:NextRequest){constresNextResponse.next();constsupabasecreateMiddlewareClient({req,res});const{data:{session}}awaitsupabase.auth.getSession();// 未登录 → 重定向到登录页if(!sessionreq.nextUrl.pathname.startsWith(/(main))){returnNextResponse.redirect(newURL(/login,req.url));}// 已登录 → 不允许访问登录页if(sessionreq.nextUrl.pathname.startsWith(/(auth))){returnNextResponse.redirect(newURL(/,req.url));}returnres;}exportconstconfig{matcher:[/(main):path*,/(auth):path*],};3. Zod 数据验证// lib/zod-schemas.tsimport{z}fromzod;// 文档上传验证exportconstdocumentUploadSchemaz.object({file:z.instanceof(File).refine(ff.size20*1024*1024,文件大小不能超过 20MB).refine(f[application/pdf,text/markdown,text/plain].includes(f.type)||f.name.endsWith(.md),请上传 PDF、Markdown 或纯文本文件),title:z.string().min(1).max(100),});// 聊天消息验证exportconstchatMessageSchemaz.object({message:z.string().min(1,消息不能为空).max(4000,消息太长),conversationId:z.string().uuid(),mode:z.enum([chat,rag]),});// API 响应验证exportconstapiResponseSchemaz.object({content:z.string(),sources:z.array(z.object({id:z.string(),title:z.string(),content:z.string(),source:z.string(),relevance:z.number().min(0).max(1),})).optional(),usage:z.object({prompt_tokens:z.number(),completion_tokens:z.number(),total_tokens:z.number(),}).optional(),});4. 统一错误处理// components/ErrorBoundary.tsx import { Component, ReactNode } from react; interface Props { children: ReactNode; fallback?: ReactNode; } interface State { hasError: boolean; error: Error | null; } export class ErrorBoundary extends ComponentProps, State { state: State { hasError: false, error: null }; static getDerivedStateFromError(error: Error): State { return { hasError: true, error }; } render() { if (this.state.hasError) { return this.props.fallback || ( div classNamep-8 text-center h2 classNametext-xl font-semibold mb-2出了点问题/h2 p classNametext-gray-500 mb-4{this.state.error?.message}/p button onClick{() this.setState({ hasError: false, error: null })} classNamepx-4 py-2 rounded-lg bg-blue-500 text-white 重试 /button /div ); } return this.props.children; } }5. Supabase 数据库 Schema-- 文档表CREATETABLEdocuments(id UUIDDEFAULTgen_random_uuid()PRIMARYKEY,user_id UUIDREFERENCESauth.usersNOTNULL,titleTEXTNOTNULL,file_typeTEXTNOTNULL,file_sizeINTEGERNOTNULL,chunk_countINTEGERDEFAULT0,statusTEXTDEFAULTprocessingCHECK(statusIN(processing,completed,error)),created_at TIMESTAMPTZDEFAULTNOW(),updated_at TIMESTAMPTZDEFAULTNOW());-- 文档分片表带向量CREATETABLEdocument_chunks(id UUIDDEFAULTgen_random_uuid()PRIMARYKEY,document_id UUIDREFERENCESdocumentsONDELETECASCADENOTNULL,contentTEXTNOTNULL,chunk_indexINTEGERNOTNULL,embedding VECTOR(1536),-- OpenAI embedding 维度created_at TIMESTAMPTZDEFAULTNOW());-- 向量搜索函数CREATEFUNCTIONmatch_documents(query_embedding VECTOR(1536),match_countINTDEFAULT5,match_thresholdFLOATDEFAULT0.5)RETURNSTABLE(id UUID,document_id UUID,contentTEXT,similarityFLOAT)AS$SELECTid,document_id,content,1-(embeddingquery_embedding)ASsimilarityFROMdocument_chunksWHERE1-(embeddingquery_embedding)match_thresholdORDERBYembeddingquery_embeddingLIMITmatch_count;$LANGUAGESQL;产品级 vs 教程级的关键差异环节教程做法产品做法为什么认证不做Supabase Auth middleware每个用户有自己的知识库数据验证假设格式正确Zod schema 验证防止无效数据进入系统错误处理console.logErrorBoundary 用户友好提示用户不看 console向量存储内存 mockSupabase pgvector生产环境需要持久化和高性能文档分片简单切分段落级分片 元数据搜索精度取决于分片质量部署localhostVercel CI/CD用户需要在线访问常见误区误区1产品级 更多功能产品级不是功能更多而是每个功能更可靠。错误处理、数据验证、性能优化——这些看不见的东西才是产品级的核心。误区2先写完所有功能再部署应该 Day 3 结束时就做第一次部署——尽早暴露生产环境的问题CORS、SSL、环境变量等。误区3认证不重要没有认证 所有用户共享一个知识库 数据混乱。认证是产品级应用的基础设施。 AI协作实战实战场景5 天用 AI 协作开发 KnowBase我给 Cursor Composer 的任务拆分Day 1 任务清单 1. 创建 Next.js 项目 安装所有依赖openai, supabase/supabase-js, zod, zustand, react-markdown, lucide-react 2. 配置 shadcn/ui Tailwind CSS 3. 配置 Supabase 客户端lib/supabase.ts 4. 实现注册/登录页面用 Supabase Auth 5. 实现认证中间件middleware.ts 6. 实现主布局Sidebar Header AuthGuard Day 2 任务清单 1. DocumentUpload 组件拖拽上传 进度 2. 文档上传 API/api/documents/upload 3. DocumentList 组件 4. ChunkPreview 组件 Day 3 任务清单 1. ChatInterface 组件 2. RAG Chat API/api/ai/rag 3. SourceReference 组件 4. 对话历史管理 Day 4 任务清单 1. ErrorBoundary zod-schemas 2. 性能优化虚拟列表 缓存 3. 暗黑模式 响应式 4. Token 追踪面板 Day 5 任务清单 1. Vercel 部署 2. README API 文档AI 协作效率统计天数我做决策AI 写代码审查时间总耗时Day 1架构 技术选型项目搭建 认证代码30min3hDay 2文档管理逻辑组件代码 API20min3hDay 3RAG 流程设计聊天 RAG 代码25min4hDay 4优化策略优化 打磨代码30min4hDay 5部署 文档策略配置 文档15min3h总计策略决策95%代码量2h17h对比纯手写预估50-60 小时。效率提升 3.5x。学到了什么5 天开发一个产品级项目是可行的——前提是 AI 写 95% 的代码你做 100% 的决策和审查。你的角色不是「写代码的人」而是「做产品决策的人」。 动手练习练习1简单搭建项目骨架 认证创建 Next.js 项目 安装依赖 配置 Supabase Auth 实现登录/注册页面 认证中间件。确保骨架能运行登录流程正常。练习2中等实现文档管理 RAG 问答在项目骨架上添加文档上传 列表 删除RAG 问答界面 引用来源展示对话历史管理练习3挑战完整 5 天开发计划按本期的 5 天计划完整开发 KnowBase AIDay 1-5 严格执行每天记录 AI 参与度和效率最终部署到 Vercel写一份项目复盘报告 本期要点产品级 vs 教程级不是功能更多而是每个功能更可靠错误处理/数据验证/性能优化/安全防护5 天开发计划Day1(认证) → Day2(文档管理) → Day3(RAG核心) → Day4(打磨) → Day5(部署)认证是基础设施Supabase Auth middleware每个用户有自己的知识库Zod 数据验证是必需的防止无效数据进入系统——教程代码假设格式正确产品代码不假设你的角色变了从「写代码的人」变成「做产品决策的人」——AI 写 95% 代码你做 100% 决策 下期预告下一期是项目1的续篇——部署与优化。你将学会把 KnowBase 部署到 Vercel、做性能优化、SEO 配置以及产品级监控。如果你没有苹果电脑需要上传ios到APPStore可以访问以下网站iPA上传工具 - IPA解析与AppStore提交