第36期 | 实战4:AI助手应用
2026/7/6 0:40:50 网站建设 项目流程

第36期 | 实战4:AI助手应用

🎯 今天你将学会

  • 从零开发一个完整的 AI 助手应用(对话 + 知识库 + 工具调用)
  • 整合模块四前三期的所有知识到一个产品级项目
  • 实现完整的数据流:用户输入 → RAG搜索 → Agent调用 → 流式展示
  • 理解项目级开发中的架构决策和代码组织

📖 核心知识

项目概览:TechAssist AI 助手

我们要做一个「技术文档 AI 助手」——用户可以:

  • 聊天提问(基础对话)
  • 上传文档到知识库(RAG)
  • Agent 自动搜索知识库 + 调用工具回答(Agent 交互)

功能清单:

功能描述对应期数
基础对话ChatGPT 风格聊天界面第33期
流式响应逐字渲染 AI 回复第32期
Markdown 渲染代码块、表格、链接第33期
知识库管理上传文档 + 分片预览第34期
RAG 问答基于真实文档回答 + 引用来源第34期
Agent 交互思考过程 + 工具调用展示第35期
显示模式切换精简/详细/实时第35期

项目架构设计

tech-assist/ ├── app/ │ ├── layout.tsx — 全局布局(侧边栏 + 主内容区) │ ├── page.tsx — 馊页(对话界面) │ └── api/ │ │ ├── ai/ │ │ │ ├── chat/route.ts — 基础聊天接口(SSE流式) │ │ │ ├── rag/route.ts — RAG聊天接口(搜索+回答+来源) │ │ │ └── agent/route.ts — Agent接口(思考+工具+回答) │ │ └── knowledge/ │ │ │ ├── upload/route.ts — 文档上传接口 │ │ │ ├── list/route.ts — 文档列表接口 │ │ │ └── search/route.ts — 知识库搜索接口 │ └── knowledge/ │ └── page.tsx — 知识库管理页面 ├── features/ │ ├── chat/ — 聊天模块(Store + Components) │ ├── knowledge/ — 知识库模块 │ └── agent/ — Agent 模块 ├── lib/ │ ├── ai-client.ts — AI API 客户端(非流式+流式+Agent流) │ ├── agent-stream-parser.ts — Agent SSE 流解析器 │ ├── ai-errors.ts — 错误处理 │ └── utils.ts — 工具函数 ├── components/ │ └── ui/ — shadcn/ui 组件 │ └── layout/ │ ├── Sidebar.tsx — 侧边栏(对话历史列表 + 知识库入口) │ └── Header.tsx — 顶部导航 └── types/ └── index.ts — 全局类型定义

核心数据流设计

场景1:基础对话

用户输入 → ChatStore.addMessage(userMsg) → aiClient.chatStream(messages) → SSE流 → 逐token追加 → ChatStore.updateLastAssistantMessage → UI渲染

场景2:RAG 问答

用户输入 → ChatStore.addMessage(userMsg) → aiClient.ragChat(messages) → 后端:向量搜索 + 构建RAG Prompt + LLM → SSE流(content + sources) → 前端:逐token追加 + 最后展示SourceReference → UI渲染

场景3:Agent 问答

用户输入 → AgentStore.addMessage(userMsg) → aiClient.agentChat(messages) → 后端:思考 → 工具调用 → 观察结果 → 再思考 → 最终回答 → SSE流 → 前端:AgentStreamParser 解析 → 逐type追加 → AgentMessage渲染 → UI渲染

全局状态管理

// store/appStore.tsinterfaceAppState{// 侧边栏状态sidebarOpen:boolean;conversations:Conversation[];activeConversationId:string|null;// 知识库状态documents:Document[];// 显示模式agentDisplayMode:'compact'|'detailed'|'live';// Token 使用追踪tokenUsage:TokenUsage;}interfaceConversation{id:string;title:string;// 自动从第一条消息生成mode:'chat'|'rag'|'agent';messages:Message[];createdAt:string;updatedAt:string;}

侧边栏:对话历史管理

// components/layout/Sidebar.tsx export function Sidebar() { const { conversations, activeConversationId, sidebarOpen } = useAppStore(); return ( <aside className={`w-64 border-r bg-gray-50 transition-all ${sidebarOpen ? '' : 'w-0'} dark:bg-gray-900`}> {/* 新建对话按钮 */} <div className="p-4"> <button className="w-full rounded-lg border px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-800"> + 新建对话 </button> </div> {/* 对话模式选择 */} <div className="px-4 mb-2"> <div className="flex gap-1"> <button className="px-3 py-1 text-xs rounded bg-blue-500 text-white">对话</button> <button className="px-3 py-1 text-xs rounded bg-gray-200 text-gray-600">知识库问答</button> <button className="px-3 py-1 text-xs rounded bg-gray-200 text-gray-600">Agent</button> </div> </div> {/* 对话历史列表 */} <div className="px-4 space-y-1 overflow-y-auto"> {conversations.map((conv) => ( <button key={conv.id} onClick={() => setActiveConversation(conv.id)} className={`w-full text-left px-3 py-2 rounded text-sm truncate ${conv.id === activeConversationId ? 'bg-gray-200 dark:bg-gray-700' : 'hover:bg-gray-100 dark:hover:bg-gray-800'}`} > {conv.title} </button> ))} </div> {/* 知识库入口 */} <div className="mt-auto p-4 border-t"> <Link href="/knowledge" className="flex items-center gap-2 text-sm text-gray-500 hover:text-gray-700"> <BookOpen size={16} /> 知识库管理 <span className="text-xs text-gray-400">{documents.length} 份文档</span> </Link> </div> </aside> ); }

对话模式切换

根据用户选择的模式(chat/rag/agent),主内容区渲染不同的界面:

// app/page.tsx export function HomePage() { const { activeConversationId } = useAppStore(); const conversation = useAppStore(state => state.conversations.find(c => c.id === activeConversationId) ); if (!conversation) return <EmptyState />; switch (conversation.mode) { case 'chat': return <ChatInterface />; case 'rag': return <RAGChatInterface />; case 'agent': return <AgentInterface />; } }

完整项目搭建步骤

Step 1:创建 Next.js 项目

pnpmcreate next-app tech-assist--typescript--tailwind--appcdtech-assistpnpmaddopenai zustand react-markdown remark-gfm lucide-reactpnpmadd-D@types/react

Step 2:搭建目录结构

mkdir-pfeatures/chat/store features/chat/componentsmkdir-pfeatures/knowledge/store features/knowledge/componentsmkdir-pfeatures/agent/store features/agent/componentsmkdir-papp/api/ai app/api/knowledgemkdir-plib components/layout components/ui types

Step 3:实现核心模块

按照 32-35 期学到的知识,逐模块实现:

  1. lib/ai-client.ts— AI API 客户端(第32期)
  2. lib/ai-errors.ts— 错误处理(第32期)
  3. lib/agent-stream-parser.ts— Agent SSE 解析(第35期)
  4. features/chat/— 聊天模块(第33期)
  5. features/knowledge/— 知识库模块(第34期)
  6. features/agent/— Agent 模块(第35期)
  7. app/api/— 后端接口(第32-35期)
  8. components/layout/— 布局组件

Step 4:集成测试

每个模块完成后立即测试:

  • 聊天模块:发送消息 → 流式渲染 → Markdown 正常
  • 知识库模块:上传文档 → 搜索 → 引用展示
  • Agent 模块:提问 → 思考/工具/回答完整流程

产品级细节

1. 对话标题自动生成

// 对话标题从第一条消息的前 20 个字生成consttitle=messages[0]?.content.slice(0,20)+(messages[0]?.content.length>20?'...':'');

2. 对话持久化

// 在 appStore 中 persist 对话历史exportconstuseAppStore=create<AppState>()(persist((set,get)=>({...}),{name:'tech-assist-storage',partialize:(state)=>({conversations:state.conversations,documents:state.documents,tokenUsage:state.tokenUsage,}),}));

3. 模型切换

// 在设置面板中切换模型 <Select value={selectedModel} onValueChange={setSelectedModel}> <SelectItem value="gpt-4o-mini">GPT-4o Mini(快速/低成本)</SelectItem> <SelectItem value="gpt-4o">GPT-4o(精确/高成本)</SelectItem> </Select>

4. Token 使用量展示

// 在 Header 中展示今日 Token 使用量 <span className="text-xs text-gray-400"> 今日: {tokenUsage.totalTokens} tokens | ¥{tokenUsage.totalCost.toFixed(2)} </span>

常见误区

误区1:先写完所有功能再测试
应该每个模块完成后立即测试。集成 5 个模块后发现 Bug → 很难定位问题出在哪个模块。

误区2:所有功能共用一个 Store
聊天/知识库/Agent 有不同的数据结构。每个模块有自己的 Store,全局状态只在 appStore 中管理共享数据。

误区3:不做持久化
用户刷新页面后对话历史全没了——这是灾难性体验。用 Zustand persist 持久化关键数据。

🤖 AI协作实战

实战场景:用 AI 协作开发整个项目

我给 AI(Cursor Composer)的总任务描述:

我要开发一个 AI 技术助手应用 TechAssist,包含三个核心模式: 1. 基础对话(ChatGPT风格聊天) 2. 知识库问答(RAG:搜索文档 + 引用来源) 3. Agent问答(思考过程 + 工具调用展示) 请先列出完整的项目文件清单和每个文件的核心职责, 然后逐模块实现,每个模块完成后我会测试验证。 参考 .cursorrules 中的项目规范。

AI 列出的文件清单(50+ 文件):

  • 核心文件 12 个(Store/Client/Layout/API)
  • 组件文件 18 个(Chat/Knowledge/Agent/UI)
  • 类型/工具 5 个
  • 配置文件 3 个

我的执行策略:不是让 AI 一次性生成 50 个文件,而是:

  1. 先让它生成文件清单 → 我确认
  2. 按模块逐个生成 → 每个模块完成后我运行测试
  3. 发现问题时追加修改指令 → 逐个修正

5 轮 Composer 交互后的结果:

  • 所有核心模块代码生成完毕
  • 2 个 Bug 在测试中发现并修正(流式解析遗漏 DONE 标记、Agent 消息类型缺少 thinking)
  • 总耗时约 2 小时 vs 预估手写时间 8-10 小时

学到了什么:大型项目的 AI 协作关键是分模块逐步执行——不要一次性让 AI 生成所有代码。每个模块独立测试后再整合,Bug 更容易定位。

💻 动手练习

练习1(简单):搭建项目骨架

创建 Next.js 项目 + 安装依赖 + 搭建目录结构 + 实现 appStore 基础状态管理。先不实现具体功能,确保骨架能运行。

练习2(中等):实现核心对话功能

实现 ChatInterface + ChatStore + aiClient + SSE流式渲染:

  • 用户输入 → 流式显示 AI 回复
  • Markdown 渲染正常
  • 自动滚动到底部
  • 停止生成按钮

练习3(挑战):实现完整的三模式应用

按本期项目架构,完整实现三种模式:

  • 基础对话模式
  • RAG 知识库问答模式
  • Agent 交互模式
  • 侧边栏对话历史管理
  • 持久化存储
  • Token 使用量追踪

📌 本期要点

  1. 三种模式统一架构:chat/rag/agent 共用 ChatInput + MarkdownRenderer,各自有不同的 SSE 解析和消息渲染
  2. 模块化 Store:chatStore / knowledgeStore / agentStore 各管各的,appStore 只管全局共享数据
  3. 分模块逐步实现:大项目不要一次性让 AI 生成所有代码——逐模块生成 + 独立测试
  4. 产品级细节:对话标题自动生成、持久化存储、模型切换、Token 追踪——这些是「能用」和「好用」的区别
  5. 侧边栏是入口:对话历史 + 模式切换 + 知识库入口,用户的所有操作从这里开始

🔗 下期预告

下一期进入 AI 绘画前端——图片生成界面、参数调节、历史管理。你将学会如何设计一个让用户轻松生成 AI 图片的 Web 界面。
如果你没有苹果电脑,需要上传ios到APPStore可以访问以下网站
iPA上传工具 - IPA解析与AppStore提交

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询