草案 智能体设计模式 - 内存管理

aiagentsmemorylangchainlanggraphtypescriptvercel
By sko X opus 4.19/20/202514 min read

使用 TypeScript、LangChain、LangGraph 和 Vercel 无服务器平台构建能够记住过往交互、跨会话维护上下文并从经验中学习的 AI 智能体。

心智模型:构建内存优先的智能体

将智能体内存想象成一个加强版的 Web 应用状态管理系统。就像 React 应用使用 Redux 管理状态、Context API 共享数据、localStorage 持久化数据一样,AI 智能体需要工作内存(类似 useState)、情节内存(类似会话存储)、语义内存(类似数据库)和过程内存(类似缓存计算)。LangGraph 充当您的内存编排器(类似 Redux),而 Redis 和向量数据库等外部存储作为持久化层。关键区别在于:智能体内存必须处理结构化数据和语义理解,在无服务器约束下高效运行。

基础示例:对话缓冲内存

1. 简单缓冲内存实现

// lib/memory/buffer-memory.ts
import { BufferMemory } from 'langchain/memory';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ConversationChain } from 'langchain/chains';
import { map, take } from 'es-toolkit';

export function createBasicMemoryChain() {
  const model = new ChatGoogleGenerativeAI({
    modelName: 'gemini-2.5-flash',
    temperature: 0.7,
  });

  const memory = new BufferMemory({
    returnMessages: true,
    memoryKey: 'history',
  });

  const chain = new ConversationChain({
    llm: model,
    memory,
    verbose: false, // Set to true for debugging
  });

  return chain;
}

// app/api/chat-memory/route.ts
import { createBasicMemoryChain } from '@/lib/memory/buffer-memory';
import { NextResponse } from 'next/server';

export const runtime = 'nodejs';
export const maxDuration = 60;

const chain = createBasicMemoryChain();

export async function POST(req: Request) {
  const { message } = await req.json();

  const result = await chain.call({ input: message });

  return NextResponse.json({
    response: result.response,
    memorySize: chain.memory.chatHistory.messages.length
  });
}

创建一个具有 BufferMemory 的基本对话链,在会话期间在内存中维护所有消息。

2. 带限制上下文的窗口内存

// lib/memory/window-memory.ts
import { BufferWindowMemory } from 'langchain/memory';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ConversationChain } from 'langchain/chains';
import { takeRight } from 'es-toolkit';

interface WindowMemoryConfig {
  windowSize?: number;
  returnMessages?: boolean;
}

export class WindowMemoryManager {
  private chain: ConversationChain;
  private windowSize: number;

  constructor(config: WindowMemoryConfig = {}) {
    const model = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-flash',
      temperature: 0.7,
    });

    this.windowSize = config.windowSize || 10;

    const memory = new BufferWindowMemory({
      k: this.windowSize,
      returnMessages: config.returnMessages ?? true,
    });

    this.chain = new ConversationChain({
      llm: model,
      memory,
    });
  }

  async processMessage(message: string) {
    const result = await this.chain.call({ input: message });

    // Get current window
    const messages = this.chain.memory.chatHistory.messages;
    const windowMessages = takeRight(messages, this.windowSize * 2); // User + AI messages

    return {
      response: result.response,
      windowSize: windowMessages.length,
      droppedMessages: Math.max(0, messages.length - windowMessages.length)
    };
  }
}

实现一个滑动窗口内存,只保留最近的 K 个消息对,自动丢弃较旧的上下文以保持在限制内。

3. 长对话的摘要内存

// lib/memory/summary-memory.ts
import { ConversationSummaryMemory } from 'langchain/memory';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ConversationChain } from 'langchain/chains';
import { debounce } from 'es-toolkit';

export class SummaryMemoryManager {
  private chain: ConversationChain;
  private summaryModel: ChatGoogleGenerativeAI;
  private updateSummary: Function;

  constructor() {
    const model = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-pro',
      temperature: 0.7,
    });

    this.summaryModel = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-flash',
      temperature: 0,
    });

    const memory = new ConversationSummaryMemory({
      llm: this.summaryModel,
      returnMessages: false,
      inputKey: 'input',
      outputKey: 'response',
    });

    this.chain = new ConversationChain({
      llm: model,
      memory,
    });

    // Debounce summary updates for performance
    this.updateSummary = debounce(
      () => this.chain.memory.predictNewSummary(
        this.chain.memory.chatHistory.messages,
        ''
      ),
      5000
    );
  }

  async processWithSummary(message: string) {
    const result = await this.chain.call({ input: message });

    // Trigger summary update (debounced)
    this.updateSummary();

    return {
      response: result.response,
      currentSummary: this.chain.memory.buffer
    };
  }
}

使用 LLM 逐步总结对话,在减少令牌使用的同时维护长交互的上下文。

高级示例:LangGraph 多层内存系统

1. 基于状态的 LangGraph 内存

// lib/memory/langgraph-memory.ts
import { StateGraph, Annotation } from '@langchain/langgraph';
import { BaseMessage, HumanMessage, AIMessage } from '@langchain/core/messages';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { MemorySaver } from '@langchain/langgraph';
import { groupBy, orderBy, take } from 'es-toolkit';

// Define the state structure
const StateAnnotation = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (x, y) => [...x, ...y],
    default: () => [],
  }),
  summary: Annotation<string>({
    reducer: (x, y) => y || x,
    default: () => '',
  }),
  userProfile: Annotation<Record<string, any>>({
    reducer: (x, y) => ({ ...x, ...y }),
    default: () => ({}),
  }),
  sessionMetadata: Annotation<Record<string, any>>({
    reducer: (x, y) => ({ ...x, ...y }),
    default: () => ({ startTime: Date.now() }),
  }),
});

export function createStatefulMemoryAgent() {
  const model = new ChatGoogleGenerativeAI({
    modelName: 'gemini-2.5-pro',
    temperature: 0.7,
  });

  const summaryModel = new ChatGoogleGenerativeAI({
    modelName: 'gemini-2.5-flash',
    temperature: 0,
  });

  const workflow = new StateGraph(StateAnnotation)
    .addNode('processMessage', async (state) => {
      // Process with full context
      const contextMessages = [
        new SystemMessage(`用户档案: ${JSON.stringify(state.userProfile)}`),
        new SystemMessage(`过往摘要: ${state.summary}`),
        ...take(state.messages, 10), // Recent messages
      ];

      const response = await model.invoke(contextMessages);

      return {
        messages: [response],
      };
    })
    .addNode('updateProfile', async (state) => {
      // Extract user preferences from conversation
      const recentMessages = take(state.messages, 5);
      const analysis = await summaryModel.invoke([
        new SystemMessage('以 JSON 格式提取用户偏好和事实'),
        ...recentMessages,
      ]);

      try {
        const preferences = JSON.parse(analysis.content as string);
        return { userProfile: preferences };
      } catch {
        return {};
      }
    })
    .addNode('summarizeIfNeeded', async (state) => {
      // Summarize when messages exceed threshold
      if (state.messages.length > 20) {
        const oldMessages = state.messages.slice(0, -10);
        const summary = await summaryModel.invoke([
          new SystemMessage('简洁地总结这次对话'),
          ...oldMessages,
        ]);

        return {
          summary: summary.content as string,
          messages: state.messages.slice(-10), // Keep only recent
        };
      }
      return {};
    });

  // Define the flow
  workflow.addEdge('__start__', 'processMessage');
  workflow.addEdge('processMessage', 'updateProfile');
  workflow.addEdge('updateProfile', 'summarizeIfNeeded');
  workflow.addEdge('summarizeIfNeeded', '__end__');

  // Add persistence
  const checkpointer = new MemorySaver();

  return workflow.compile({ checkpointer });
}

// app/api/stateful-chat/route.ts
import { createStatefulMemoryAgent } from '@/lib/memory/langgraph-memory';
import { HumanMessage } from '@langchain/core/messages';

export const runtime = 'nodejs';
export const maxDuration = 300;

const agent = createStatefulMemoryAgent();

export async function POST(req: Request) {
  const { message, threadId } = await req.json();

  const result = await agent.invoke(
    {
      messages: [new HumanMessage(message)],
    },
    {
      configurable: { thread_id: threadId || 'default' },
    }
  );

  return NextResponse.json({
    response: result.messages[result.messages.length - 1].content,
    profile: result.userProfile,
    messageCount: result.messages.length,
  });
}

使用 LangGraph 实现了一个具有自动摘要、用户档案分析和基于线程持久化的复杂内存系统。

2. 语义搜索向量内存

// lib/memory/vector-memory.ts
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { GoogleGenerativeAIEmbeddings } from '@langchain/google-genai';
import { VectorStoreRetrieverMemory } from 'langchain/memory';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ConversationChain } from 'langchain/chains';
import { Document } from '@langchain/core/documents';
import { uniqBy, sortBy } from 'es-toolkit';

export class SemanticMemoryManager {
  private vectorStore: MemoryVectorStore;
  private memory: VectorStoreRetrieverMemory;
  private chain: ConversationChain;
  private embeddings: GoogleGenerativeAIEmbeddings;

  constructor() {
    this.embeddings = new GoogleGenerativeAIEmbeddings({
      modelName: 'embedding-001',
    });

    this.vectorStore = new MemoryVectorStore(this.embeddings);

    this.memory = new VectorStoreRetrieverMemory({
      vectorStoreRetriever: this.vectorStore.asRetriever(5),
      memoryKey: 'history',
      inputKey: 'input',
      outputKey: 'response',
      returnDocs: true,
    });

    const model = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-pro',
      temperature: 0.7,
    });

    this.chain = new ConversationChain({
      llm: model,
      memory: this.memory,
    });
  }

  async addMemory(content: string, metadata: Record<string, any> = {}) {
    const doc = new Document({
      pageContent: content,
      metadata: {
        ...metadata,
        timestamp: Date.now(),
      },
    });

    await this.vectorStore.addDocuments([doc]);
  }

  async searchMemories(query: string, k: number = 5) {
    const results = await this.vectorStore.similaritySearchWithScore(query, k);

    // Sort by relevance and recency
    const sorted = sortBy(results, [
      (r) => -r[1], // Score (descending)
      (r) => -r[0].metadata.timestamp, // Timestamp (descending)
    ]);

    return sorted.map(([doc, score]) => ({
      content: doc.pageContent,
      metadata: doc.metadata,
      relevanceScore: score,
    }));
  }

  async processWithSemanticMemory(message: string) {
    // Search for relevant past interactions
    const relevantMemories = await this.searchMemories(message, 3);

    // Add relevant context to the conversation
    const contextualMessage = relevantMemories.length > 0
      ? `相关上下文: ${relevantMemories.map(m => m.content).join('\n')}\n\n用户: ${message}`
      : message;

    const result = await this.chain.call({ input: contextualMessage });

    // Store the interaction
    await this.addMemory(
      `用户: ${message}\n助手: ${result.response}`,
      { type: 'conversation' }
    );

    return {
      response: result.response,
      relevantMemories: relevantMemories.slice(0, 2),
      totalMemories: await this.vectorStore.memoryVectors.length,
    };
  }
}

使用向量嵌入创建语义内存系统,基于意义而不是时间顺序查找相关的过往交互。

3. 无服务器 Redis 持久化内存

// lib/memory/redis-memory.ts
import { Redis } from '@upstash/redis';
import { BufferMemory, ChatMessageHistory } from 'langchain/memory';
import { AIMessage, HumanMessage, BaseMessage } from '@langchain/core/messages';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ConversationChain } from 'langchain/chains';
import { memoize, chunk } from 'es-toolkit';

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_URL!,
  token: process.env.UPSTASH_REDIS_TOKEN!,
});

export class RedisMemoryManager {
  private sessionTTL = 3600; // 1 hour
  private maxMessagesPerSession = 100;

  // Memoize session loading for performance
  private loadSession = memoize(
    async (sessionId: string) => {
      const data = await redis.get(`session:${sessionId}`);
      return data as any || { messages: [], metadata: {} };
    },
    {
      resolver: (sessionId) => sessionId,
      ttl: 5000, // Cache for 5 seconds
    }
  );

  async getMemory(sessionId: string): Promise<BufferMemory> {
    const session = await this.loadSession(sessionId);

    const messages = session.messages.map((msg: any) =>
      msg.type === 'human'
        ? new HumanMessage(msg.content)
        : new AIMessage(msg.content)
    );

    const chatHistory = new ChatMessageHistory(messages);

    return new BufferMemory({
      chatHistory,
      returnMessages: true,
      memoryKey: 'history',
    });
  }

  async saveMemory(sessionId: string, messages: BaseMessage[]) {
    // Keep only recent messages for serverless constraints
    const recentMessages = messages.slice(-this.maxMessagesPerSession);

    const serialized = recentMessages.map(msg => ({
      type: msg._getType(),
      content: msg.content,
    }));

    const session = {
      messages: serialized,
      metadata: {
        lastAccess: Date.now(),
        messageCount: serialized.length,
      },
    };

    await redis.setex(
      `session:${sessionId}`,
      this.sessionTTL,
      JSON.stringify(session)
    );

    // Update session index for cleanup
    await redis.zadd('sessions:active', {
      score: Date.now(),
      member: sessionId,
    });
  }

  async processWithPersistence(
    sessionId: string,
    message: string
  ) {
    const model = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-flash',
      temperature: 0.7,
    });

    const memory = await this.getMemory(sessionId);

    const chain = new ConversationChain({
      llm: model,
      memory,
    });

    const result = await chain.call({ input: message });

    // Save updated memory
    await this.saveMemory(
      sessionId,
      chain.memory.chatHistory.messages
    );

    // Get session stats
    const stats = await redis.get(`session:${sessionId}:stats`) as any || {};
    stats.messageCount = (stats.messageCount || 0) + 1;
    stats.lastActive = Date.now();

    await redis.setex(
      `session:${sessionId}:stats`,
      this.sessionTTL,
      JSON.stringify(stats)
    );

    return {
      response: result.response,
      sessionId,
      stats,
    };
  }

  async cleanupOldSessions() {
    // Remove sessions older than 24 hours
    const cutoff = Date.now() - 24 * 60 * 60 * 1000;
    const oldSessions = await redis.zrangebyscore(
      'sessions:active',
      0,
      cutoff
    );

    // Batch delete in chunks for efficiency
    const sessionChunks = chunk(oldSessions, 10);

    for (const batch of sessionChunks) {
      await Promise.all(
        batch.map(sessionId =>
          redis.del(`session:${sessionId}`)
        )
      );
    }

    await redis.zremrangebyscore('sessions:active', 0, cutoff);

    return oldSessions.length;
  }
}

实现了专为 Vercel 无服务器环境优化的基于 Redis 的持久化内存,具有自动清理和会话管理功能。

4. 分层内存与档案存储

// lib/memory/hierarchical-memory.ts
import { StateGraph, Annotation, MemorySaver } from '@langchain/langgraph';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { Redis } from '@upstash/redis';
import { pick, omit, merge } from 'es-toolkit';

interface UserProfile {
  preferences: Record<string, any>;
  facts: string[];
  interests: string[];
  lastUpdated: number;
}

interface SessionMemory {
  messages: any[];
  summary: string;
  topics: string[];
}

interface WorkingMemory {
  currentTopic: string;
  context: string[];
  activeGoal: string;
}

const HierarchicalStateAnnotation = Annotation.Root({
  // Working memory - immediate context
  working: Annotation<WorkingMemory>({
    reducer: (x, y) => ({ ...x, ...y }),
    default: () => ({
      currentTopic: '',
      context: [],
      activeGoal: '',
    }),
  }),
  // Session memory - current conversation
  session: Annotation<SessionMemory>({
    reducer: (x, y) => ({ ...x, ...y }),
    default: () => ({
      messages: [],
      summary: '',
      topics: [],
    }),
  }),
  // Long-term memory - user profile
  profile: Annotation<UserProfile>({
    reducer: (x, y) => merge(x, y),
    default: () => ({
      preferences: {},
      facts: [],
      interests: [],
      lastUpdated: Date.now(),
    }),
  }),
});

export class HierarchicalMemorySystem {
  private redis: Redis;
  private graph: ReturnType<typeof StateGraph.compile>;
  private model: ChatGoogleGenerativeAI;

  constructor() {
    this.redis = new Redis({
      url: process.env.UPSTASH_REDIS_URL!,
      token: process.env.UPSTASH_REDIS_TOKEN!,
    });

    this.model = new ChatGoogleGenerativeAI({
      modelName: 'gemini-2.5-pro',
      temperature: 0.7,
    });

    this.graph = this.buildMemoryGraph();
  }

  private buildMemoryGraph() {
    const workflow = new StateGraph(HierarchicalStateAnnotation)
      .addNode('processInput', async (state) => {
        // Extract topic and intent from input
        const analysis = await this.model.invoke([
          new SystemMessage('以 JSON 格式提取主要话题和用户意图'),
          new HumanMessage(state.working.context[state.working.context.length - 1]),
        ]);

        try {
          const { topic, intent } = JSON.parse(analysis.content as string);
          return {
            working: {
              currentTopic: topic,
              activeGoal: intent,
            },
          };
        } catch {
          return {};
        }
      })
      .addNode('retrieveRelevantMemory', async (state) => {
        // Get relevant long-term memories
        const profileKey = `profile:${state.working.currentTopic}`;
        const relevantProfile = await this.redis.get(profileKey) || {};

        // Get relevant session memories
        const sessionKey = `session:recent:${state.working.currentTopic}`;
        const relevantSessions = await this.redis.get(sessionKey) || [];

        return {
          working: {
            context: [
              ...state.working.context,
              `档案上下文: ${JSON.stringify(relevantProfile)}`,
              `过往讨论: ${JSON.stringify(relevantSessions)}`,
            ],
          },
        };
      })
      .addNode('generateResponse', async (state) => {
        // Generate response with full context
        const contextMessage = [
          new SystemMessage(`用户档案: ${JSON.stringify(state.profile)}`),
          new SystemMessage(`当前话题: ${state.working.currentTopic}`),
          new SystemMessage(`会话上下文: ${state.session.summary}`),
          ...state.working.context.map(c => new SystemMessage(c)),
        ];

        const response = await this.model.invoke(contextMessage);

        return {
          session: {
            messages: [...state.session.messages, response.content],
          },
        };
      })
      .addNode('updateMemoryTiers', async (state) => {
        // Promote important information up the hierarchy
        const importantFacts = await this.extractImportantFacts(
          state.session.messages
        );

        if (importantFacts.length > 0) {
          return {
            profile: {
              facts: [...state.profile.facts, ...importantFacts],
              lastUpdated: Date.now(),
            },
          };
        }

        return {};
      })
      .addNode('persistMemory', async (state) => {
        // Save to Redis with different TTLs
        // Working memory - 5 minutes
        await this.redis.setex(
          `working:${state.working.currentTopic}`,
          300,
          JSON.stringify(state.working)
        );

        // Session memory - 1 hour
        await this.redis.setex(
          `session:${Date.now()}`,
          3600,
          JSON.stringify(state.session)
        );

        // Profile - permanent (or very long TTL)
        await this.redis.set(
          `profile:user`,
          JSON.stringify(state.profile)
        );

        return {};
      });

    workflow.addEdge('__start__', 'processInput');
    workflow.addEdge('processInput', 'retrieveRelevantMemory');
    workflow.addEdge('retrieveRelevantMemory', 'generateResponse');
    workflow.addEdge('generateResponse', 'updateMemoryTiers');
    workflow.addEdge('updateMemoryTiers', 'persistMemory');
    workflow.addEdge('persistMemory', '__end__');

    const checkpointer = new MemorySaver();
    return workflow.compile({ checkpointer });
  }

  private async extractImportantFacts(messages: string[]): Promise<string[]> {
    if (messages.length === 0) return [];

    const extraction = await this.model.invoke([
      new SystemMessage('以 JSON 数组格式提取关于用户的重要事实'),
      ...messages.map(m => new HumanMessage(m)),
    ]);

    try {
      return JSON.parse(extraction.content as string);
    } catch {
      return [];
    }
  }

  async process(userId: string, message: string) {
    // Load existing profile
    const profile = await this.redis.get(`profile:${userId}`) as UserProfile || {
      preferences: {},
      facts: [],
      interests: [],
      lastUpdated: Date.now(),
    };

    const result = await this.graph.invoke(
      {
        working: {
          context: [message],
        },
        profile,
      },
      {
        configurable: { thread_id: userId },
      }
    );

    return {
      response: result.session.messages[result.session.messages.length - 1],
      memoryStats: {
        workingMemorySize: result.working.context.length,
        sessionMessages: result.session.messages.length,
        profileFacts: result.profile.facts.length,
      },
    };
  }
}

实现了三层内存层次结构,包括即时上下文的工作内存、对话的会话内存和长期档案存储。

5. 带内存状态的前端集成

// components/MemoryChat.tsx
'use client';

import { useState, useEffect } from 'react';
import { useMutation } from '@tanstack/react-query';
import { groupBy, debounce } from 'es-toolkit';

interface MemoryStats {
  workingMemory: number;
  sessionMessages: number;
  profileFacts: number;
  relevantMemories?: Array<{
    content: string;
    relevanceScore: number;
  }>;
}

export default function MemoryChat() {
  const [message, setMessage] = useState('');
  const [sessionId] = useState(() =>
    `session-${Date.now()}-${Math.random()}`
  );
  const [memoryStats, setMemoryStats] = useState<MemoryStats>({
    workingMemory: 0,
    sessionMessages: 0,
    profileFacts: 0,
  });
  const [messages, setMessages] = useState<Array<{
    role: 'user' | 'assistant';
    content: string;
    timestamp: number;
  }>>([]);

  const sendMessage = useMutation({
    mutationFn: async (text: string) => {
      const response = await fetch('/api/memory-chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          message: text,
          sessionId
        }),
      });
      return response.json();
    },
    onSuccess: (data) => {
      setMessages(prev => [
        ...prev,
        {
          role: 'user',
          content: message,
          timestamp: Date.now()
        },
        {
          role: 'assistant',
          content: data.response,
          timestamp: Date.now()
        },
      ]);
      setMemoryStats(data.memoryStats || memoryStats);
      setMessage('');
    },
  });

  // Auto-save session periodically
  useEffect(() => {
    const saveSession = debounce(async () => {
      await fetch('/api/memory-chat/save', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ sessionId, messages }),
      });
    }, 10000);

    if (messages.length > 0) {
      saveSession();
    }
  }, [messages, sessionId]);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (message.trim()) {
      sendMessage.mutate(message);
    }
  };

  // Group messages by time period
  const messageGroups = groupBy(messages, (msg) => {
    const date = new Date(msg.timestamp);
    return date.toLocaleDateString();
  });

  return (
    <div className="flex flex-col h-screen max-h-[800px] bg-base-100">
      {/* Memory Status Bar */}
      <div className="navbar bg-base-200 px-4">
        <div className="flex-1">
          <h2 className="text-xl font-bold">AI 内存聊天</h2>
        </div>
        <div className="flex-none">
          <div className="stats stats-horizontal shadow">
            <div className="stat place-items-center py-2 px-4">
              <div className="stat-title text-xs">工作内存</div>
              <div className="stat-value text-lg">
                {memoryStats.workingMemory}
              </div>
            </div>
            <div className="stat place-items-center py-2 px-4">
              <div className="stat-title text-xs">会话</div>
              <div className="stat-value text-lg">
                {memoryStats.sessionMessages}
              </div>
            </div>
            <div className="stat place-items-center py-2 px-4">
              <div className="stat-title text-xs">档案</div>
              <div className="stat-value text-lg">
                {memoryStats.profileFacts}
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Messages Area */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {Object.entries(messageGroups).map(([date, msgs]) => (
          <div key={date}>
            <div className="divider text-sm">{date}</div>
            {msgs.map((msg, idx) => (
              <div
                key={idx}
                className={`chat ${
                  msg.role === 'user' ? 'chat-end' : 'chat-start'
                }`}
              >
                <div className="chat-header">
                  {msg.role === 'user' ? '您' : 'AI'}
                </div>
                <div
                  className={`chat-bubble ${
                    msg.role === 'user'
                      ? 'chat-bubble-primary'
                      : 'chat-bubble-secondary'
                  }`}
                >
                  {msg.content}
                </div>
              </div>
            ))}
          </div>
        ))}

        {/* Show relevant memories if available */}
        {memoryStats.relevantMemories &&
         memoryStats.relevantMemories.length > 0 && (
          <div className="alert alert-info">
            <div>
              <h4 className="font-bold">相关记忆:</h4>
              {memoryStats.relevantMemories.map((mem, idx) => (
                <div key={idx} className="text-sm mt-1">
                  • {mem.content} (相关性: {mem.relevanceScore.toFixed(2)})
                </div>
              ))}
            </div>
          </div>
        )}

        {sendMessage.isPending && (
          <div className="flex justify-start">
            <div className="chat-bubble">
              <span className="loading loading-dots loading-sm"></span>
            </div>
          </div>
        )}
      </div>

      {/* Input Area */}
      <form onSubmit={handleSubmit} className="p-4 bg-base-200">
        <div className="join w-full">
          <input
            type="text"
            value={message}
            onChange={(e) => setMessage(e.target.value)}
            placeholder="输入您的消息..."
            className="input input-bordered join-item flex-1"
            disabled={sendMessage.isPending}
          />
          <button
            type="submit"
            className="btn btn-primary join-item"
            disabled={sendMessage.isPending || !message.trim()}
          >
            发送
          </button>
        </div>
      </form>
    </div>
  );
}

React 组件实时可视化内存统计,显示工作内存、会话消息和档案事实。

结论

内存管理将无状态的 AI 交互转变为智能的、上下文感知的对话,随着时间建立关系。本指南展示了从简单缓冲内存到专为 Vercel 无服务器约束优化的复杂分层系统的演进过程。关键模式包括使用 LangGraph 的 StateGraph 管理复杂内存流、实现 Redis 无服务器持久化、利用向量存储进行语义检索,以及构建模拟人类认知系统的多层架构。工作内存、情节内存、语义内存和过程内存的结合使智能体能够维护上下文、从交互中学习,并在无服务器执行限制下高效运行的同时提供越来越个性化的协助。