做了一个AI聊天应用后,我决定试试这个状态管理库

AI应用前端最大的坑,不是LLM调用,而是状态管理

背景

最近做了个AI聊天应用,类似ChatGPT的那种。

本来想用Redux,毕竟老牌方案,结果被毒打了一遍。

Redux的痛

痛点1:状态类型爆炸

tsx 复制代码
// AI聊天应用需要管理的状态
interface ChatState {
  // 对话
  messages: Message[];

  // 流式响应
  streamingText: string;
  isStreaming: boolean;

  // 工具调用
  toolCalls: ToolCall[];
  currentToolCall: ToolCall | null;
  toolResults: Record<string, any>;

  // 上下文
  contextWindow: Message[];
  longTermMemory: MemoryItem[];

  // 用户意图
  currentIntent: Intent | null;
  intentHistory: Intent[];

  // 执行状态
  currentStep: number;
  stepResults: Record<number, any>;

  // 错误处理
  errors: Error[];
  retryQueue: RetryItem[];

  // ...
}

这还只是一个聊天模块的状态。

痛点2:action type能写死你

tsx 复制代码
// 光是状态更新action就能写30个
const ADD_MESSAGE = "chat/ADD_MESSAGE";
const UPDATE_STREAMING = "chat/UPDATE_STREAMING";
const APPEND_STREAMING = "chat/APPEND_STREAMING";
const START_TOOL_CALL = "chat/START_TOOL_CALL";
const COMPLETE_TOOL_CALL = "chat/COMPLETE_TOOL_CALL";
const UPDATE_CONTEXT = "chat/UPDATE_CONTEXT";
const ADD_INTENT = "chat/ADD_INTENT";
// ... 还有几十个

痛点3:跨组件同步难

tsx 复制代码
// Chat组件
const messages = useSelector((s) => s.chat.messages);

// Status组件
const toolCalls = useSelector((s) => s.chat.toolCalls);

// 怎么保证两个组件状态一致?靠redux-thunk?middleware?

然后我用了easy-model

tsx 复制代码
// 一个类搞定AI聊天全状态
class AIChatModel {
  // 对话
  messages: Message[] = [];

  // 流式响应
  streamingText = "";
  isStreaming = false;

  // 工具调用
  toolCalls: ToolCall[] = [];
  currentToolCall: ToolCall | null = null;
  toolResults: Map<string, any> = new Map();

  // 上下文
  contextWindow: Message[] = [];
  longTermMemory: MemoryItem[] = [];

  // 用户意图
  currentIntent: Intent | null = null;
  intentHistory: Intent[] = [];

  // 执行
  currentStep = 0;
  stepResults: Map<number, any> = new Map();

  // 错误
  errors: Error[] = [];

  // 方法
  @loader.load()
  async sendMessage(content: string) {
    this.messages.push({ role: "user", content });
    this.isStreaming = true;

    const response = await llm.streamChat(this.messages);

    for await (const chunk of response) {
      this.streamingText += chunk;
    }

    this.messages.push({ role: "assistant", content: this.streamingText });
    this.streamingText = "";
    this.isStreaming = false;
  }

  async executeToolCall(tool: Tool, params: any) {
    this.currentToolCall = { tool, params, status: "running" };
    this.toolCalls.push(this.currentToolCall);

    const result = await tool.execute(params);

    this.currentToolCall.status = "completed";
    this.currentToolCall.result = result;
    this.toolResults.set(tool.name, result);
    this.currentToolCall = null;
  }
}

一个类,200行代码搞定Redux 500行都搞不定的事。

还能解决什么问题?

1. 撤销重做,调试AI回复

tsx 复制代码
const chat = useModel(AIChatModel, []);
const history = useModelHistory(chat);

// 用户想撤回AI的上一次回复?
history.back();

// 想重做?
history.forward();

2. 跨组件状态共享

tsx 复制代码
// 聊天区域
function ChatArea() {
  const chat = useModel(AIChatModel, ["main"]);
  return <MessageList messages={chat.messages} />;
}

// 状态显示
function StatusPanel() {
  const chat = useModel(AIChatModel, ["main"]);
  return <StatusBadge isStreaming={chat.isStreaming} />;
}

// 工具调用面板
function ToolPanel() {
  const chat = useModel(AIChatModel, ["main"]);
  return <ToolList calls={chat.toolCalls} />;
}

// 三个组件,状态自动同步

3. 深度监听

tsx 复制代码
// 监听任意状态变化
watch(chat, (keys, prev, next) => {
  console.log(`状态变化: ${keys.join(".")}`, prev, "→", next);

  // "messages.5.content" - 第6条消息内容变了
  // "toolCalls.0.status" - 第一个工具调用状态变了
  // "streamingText" - 流式文本更新了
});

对比其他方案

特性 Redux Zustand MobX easy-model
类模型 ❌ ❌ ✅ ✅
无装饰器 ✅ ✅ ❌ ✅
依赖注入 ❌ ❌ ❌ ✅
撤销重做 ❌ ❌ ❌ ✅
深度监听 ❌ ⚠️ ✅ ✅
TypeScript友好 ⚠️ ✅ ⚠️ ✅

结论

AI应用前端,状态管理选easy-model就对了。


GitHub : github.com/ZYF93/easy-...

npm: pnpm add @e7w/easy-model

做AI应用前端,状态管理别再踩坑了,点个⭐️!

相关推荐
卸任4 小时前
Vibe coding工具使用心得
前端·ai编程
brien94 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance5 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M5 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写5 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李5 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易5 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding5 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马5 小时前
前沿视界
前端
kyriewen5 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员