Skip to main content
Alpha Notice: These docs cover the v1-alpha release. Content is incomplete and subject to change.For the latest stable version, see the v0 LangChain Python or LangChain JavaScript docs.

Overview

LangChain agents use LangGraph persistence to enable long-term memory. This is a more advanced topic and requires knowledge of LangGraph to use.

Memory storage

LangGraph stores long-term memories as JSON documents in a store. Each memory is organized under a custom namespace (similar to a folder) and a distinct key (like a file name). Namespaces often include user or org IDs or other labels that makes it easier to organize information. This structure enables hierarchical organization of memories. Cross-namespace searching is then supported through content filters.
import { InMemoryStore } from "@langchain/langgraph";

const embed = (texts: string[]): number[][] => {
    // Replace with an actual embedding function or LangChain embeddings object
    return texts.map(() => [1.0, 2.0]);
};

// InMemoryStore saves data to an in-memory dictionary. Use a DB-backed store in production use.
const store = new InMemoryStore({ index: { embed, dims: 2 } }); 
const userId = "my-user";
const applicationContext = "chitchat";
const namespace = [userId, applicationContext]; 

await store.put( 
    namespace,
    "a-memory",
    {
        rules: [
            "User likes short, direct language",
            "User only speaks English & TypeScript",
        ],
        "my-key": "my-value",
    }
);

// get the "memory" by ID
const item = await store.get(namespace, "a-memory"); 

// search for "memories" within this namespace, filtering on content equivalence, sorted by vector similarity
const items = await store.search( 
    namespace,
    {
        filter: { "my-key": "my-value" },
        query: "language preferences"
    }
);
For more information about the memory store, see the Persistence guide.

Read long-term memory in tools

A tool the agent can use to look up user information
import { z } from "zod";
import { createAgent, tool } from "langchain";
import { InMemoryStore, type Runtime } from "@langchain/langgraph";

// InMemoryStore saves data to an in-memory dictionary. Use a DB-backed store in production.
const store = new InMemoryStore(); 
const contextSchema = z.object({
    userId: z.string(),
});

// Write sample data to the store using the put method
await store.put( 
    ["users"], // Namespace to group related data together (users namespace for user data)
    "user_123", // Key within the namespace (user ID as key)
    {
        name: "John Smith",
        language: "English",
    } // Data to store for the given user
);

const getUserInfo = tool(
  // Look up user info.
  async (_, runtime: Runtime<z.infer<typeof contextSchema>>) => {
    // Access the store - same as that provided to `createAgent`
    const userId = runtime.context?.userId;
    if (!userId) {
      throw new Error("userId is required");
    }
    // Retrieve data from store - returns StoreValue object with value and metadata
    const userInfo = await runtime.store.get(["users"], userId);
    return userInfo?.value ? JSON.stringify(userInfo.value) : "Unknown user";
  },
  {
    name: "getUserInfo",
    description: "Look up user info by userId from the store.",
    schema: z.object({}),
  }
);

const agent = createAgent({
    model: "openai:gpt-4o-mini",
    tools: [getUserInfo],
    contextSchema,
    // Pass store to agent - enables agent to access store when running tools
    store, 
});

// Run the agent
const result = await agent.invoke(
    { messages: [{ role: "user", content: "look up user information" }] },
    { context: { userId: "user_123" } } 
);

console.log(result.messages.at(-1)?.content);
/**
 * Outputs:
 * User Information:
 * - Name: John Smith
 * - Language: English
 */

Write long-term memory from tools

Example of a tool that updates user information
import { z } from "zod";
import { tool, createAgent, type AgentRuntime } from "langchain";
import { InMemoryStore, type Runtime } from "@langchain/langgraph";

// InMemoryStore saves data to an in-memory dictionary. Use a DB-backed store in production.
const store = new InMemoryStore(); 

const contextSchema = z.object({
    userId: z.string(),
});

// Schema defines the structure of user information for the LLM
const UserInfo = z.object({
    name: z.string(),
});

// Tool that allows agent to update user information (useful for chat applications)
const saveUserInfo = tool(
  async (userInfo: z.infer<typeof UserInfo>, runtime: Runtime<z.infer<typeof contextSchema>>) => {
    const userId = runtime.context?.userId;
    if (!userId) {
      throw new Error("userId is required");
    }
    // Store data in the store (namespace, key, data)
    await runtime.store.put(["users"], userId, userInfo);
    return "Successfully saved user info.";
  },
  {
    name: "save_user_info",
    description: "Save user info",
    schema: UserInfo,
  }
);

const agent = createAgent({
    model: "openai:gpt-4o-mini",
    tools: [saveUserInfo],
    contextSchema,
    store, 
});

// Run the agent
await agent.invoke(
    { messages: [{ role: "user", content: "My name is John Smith" }] },
    // userId passed in context to identify whose information is being updated
    { context: { userId: "user_123" } } 
);

// You can access the store directly to get the value
const result = await store.get(["users"], "user_123");
console.log(result?.value); // Output: { name: "John Smith" }
I