前端 + AI 学习记录(Day 31–40):多模态 / 多会话 / 工程化能力
这一篇是第四阶段总结,覆盖 Day 31–40:重点是 多模态输入、多会话管理、调试 & SDK 抽象,把聊天类 AI 应用从「能用」拉向「好用、易扩展」。
一、阶段目标:让前端 AI 用起来更像“产品”,而不是“Demo”
这 10 天主要想解决三类问题:
- 不只是纯文本:支持图片/文件/结构化数据 等多模态输入;
- 不只是一个对话:多会话 + 历史 + 多 Tab 同步;
- 不只是项目里零碎的 hooks:沉淀成一个 可复用的前端 AI SDK。
二、Day 31–32:多模态输入 & 流式请求封装
1. 多模态前端(Day 31)
-
核心抽象:把各种输入(文本/图片/文件)统一成一个结构:
type InputKind = 'text' | 'image' | 'file' | 'json'interface BaseInputItem {id: stringkind: InputKindcreatedAt: numbermeta?: Record<string, any> } -
典型前端交互:
- 上传/拖拽/粘贴图片 → 生成
InputItem(带预览 URL); - 点击发送时,把
question + files[]一起传给后端; - AI 回答中可以标注“本回答基于 文件1/截图1”。
- 上传/拖拽/粘贴图片 → 生成
-
思维转变:
以前只想“怎么发字符串给 AI”,现在开始想“如何围绕输入构建交互 + 元信息”。
2. SSE 流式 hook & 重试工具(Day 32)
-
把之前写过的流式请求封装成
useSSE(url):- 统一处理:
loading状态;- 解析
text/event-stream; AbortController中断。
- 提供简单 API:
start(payload)/abort()/text/loading。
- 统一处理:
-
再抽一个 重试工具:
async function requestWithRetry(fn, maxRetries, baseDelay) {// 指数退避 + 只对网络/超时错误重试 } -
收益:之后任何 AI 流式接口(RAG / Agent / Code Assistant)都能直接用这一套,不再重复写 reader/decoder。
三、Day 33–35:状态管理、多会话 & 调试面板
1. 多会话 + 本地缓存(Day 33)
-
设计了多会话模型:
interface Session {id: stringtitle: stringupdatedAt: numberarchived?: boolean }interface SessionState {sessions: Session[]currentSessionId: string | nullmessagesBySession: Record<string, Message[]> } -
用 Zustand 或 Context 管理:
setCurrentSession(id);addMessage(sessionId, msg);saveToStorage()/loadFromStorage()(localStorage)。
-
结果:刷新页面仍能看到最近会话,切换对话就像普通 IM 一样自然。
2. AI 调试面板(Day 35)
-
为每次调用记录 DebugLogEntry:
interface DebugLogEntry {id: stringtimestamp: numberprompt: stringanswer?: stringdurationMs?: numberstatus: 'ok' | 'error'errorMessage?: stringmeta?: { model?: string; useRag?: boolean; useAgent?: boolean } } -
调试面板 UI:
- 左侧:最近 N 条调用(时间/模型/耗时/状态);
- 右侧:选中的调用详情(Prompt + Answer + Error)。
-
意义:
AI 应用不再是“黑箱”,你能随时知道到底发了什么 Prompt、返回了什么,方便调优和排错。
四、Day 36–38:Prompt 实验台 & 性能优化 & 多 Tab 同步
1. Prompt 实验台(Day 36)
-
抽象
PromptVariant:interface PromptVariant {id: stringname: stringtemplate: string // '你是前端专家...\n问题:{{question}}' } -
用一个页面实现:
- 输入同一个问题;
- 对不同 PromptVariant 分别调用后端;
- 对每种 Prompt 生成的答案进行主观评分(⭐ 1–5)。
-
这相当于一个“本地 Prompt A/B 平台”,配合后端日志,可以不断迭代出更好的 Prompt 模板。
2. 聊天性能优化(Day 37)
-
解决两个问题:
- 消息越来越多 → DOM 爆炸;
- 流式更新太频繁 → 重渲染卡顿。
-
主要手段:
- 只渲染最近 N 条消息(比如 100 条),其余折叠成“查看更多历史”;
- 用节流 hook(如
useThrottledText)合并流式内容的 setState 调用。
3. 多 Tab 同步(Day 38)
- 使用
localStorage + window.storage事件:- 在一个 Tab 中修改了会话/消息 → 写入 localStorage;
- 其他 Tab 监听
storage事件,自动同步 state;
- 体验目标:
同一个用户开多个 Tab 时,各个窗口里的 AI 聊天内容保持一致,而不是“各自为战”。
五、Day 39–40:Agent Trace 可视化 & AI SDK 抽象
1. Agent 执行过程可视化(Day 39)
-
抽象 Agent 的执行步骤为时间线:
type AgentStepType = 'thought' | 'action' | 'observation' | 'final'interface AgentStep {id: stringtype: AgentStepTypecontent: stringtoolName?: stringcreatedAt: number } -
前端用一个 Timeline 组件,把:
- 思考:
- “我需要先查天气,再...”
- 行动:
- “调用 get_weather(city=Beijing)”
- 观察:
- “温度 26℃,晴”
- 最终回答:
- “北京现在 26℃,建议穿...”
全部可视化出来,对排查 Agent 行为、解释“模型到底干了啥”非常有用。
- 思考:
2. 前端 AI SDK 抽象(Day 40)
-
定义统一的
AIClient接口:interface AIClient {chat(req: ChatRequest): Promise<ChatResponse>streamChat(req: ChatRequest): AsyncIterable<ChatChunk> } -
然后实现一个基于 HTTP 的
HttpAIClient,对接你的/api/chat和/api/chat/stream。 -
在
hooks里只依赖AIClient,而不是直接调fetch:useChat({ client });useStreamingChat({ client })。
这一步的意义:
- 之后你换后端(例如从自建服务切到 OpenAI 直连),只要换一个
client实现即可; - 你的 hook / 组件都不用动,实现了前端对后端的“松耦合”。
六、这一阶段的 3 个关键“产品感”提升
-
多模态 + 多会话
- 从“文本小玩具”进化到能处理截图/文档/多轮会话的真实工作助手。
-
Developer Experience(开发体验)提升
- 调试面板、Prompt 实验台、Agent Timeline,让你迭代 AI 行为不再是黑箱试错。
-
前端 SDK 化
- 初步形成自己的
ai-frontend-kit:
hooks + components + utils,可以为后面任何新业务的 AI 化做“通用底座”。
- 初步形成自己的