Skip to content

记忆系统 (Memory) ​

使用 AGENTS.md 文件为你的 deep agent 赋予跨对话的持久上下文

记忆为你的 deep agent 提供了跨会话延续的上下文能力,例如编程偏好、约定俗成的规范、用户习惯以及项目专属准则。

记忆采用遵循 AGENTS.md 规范 的 Markdown 文件,在创建智能体时通过 memory 参数传入。与技能(Skills)不同,记忆文件在智能体启动时始终全量加载,其内容持久化保存在配置的后端(StateBackend、StoreBackend 或 FilesystemBackend)中。

智能体还可以在交互和反馈过程中主动更新记忆,从而将最新的偏好和经验沉淀下来,无需用户在每次新对话中反复交代背景。

记忆工作原理解析 ​

  1. 启动加载:在每次调用智能体时,运行框架会从后端读取声明的 AGENTS.md 文件,并将其无缝注入到系统提示词中。
  2. 读写自愈:智能体配备了文件读写工具,可以在识别到新的用户偏好或团队共识时,自主调用 edit_file 对 AGENTS.md 进行追加或修正。
  3. 跨会话持久:配合 StoreBackend,这些沉淀下来的记忆即使在对话结束或服务重启后依然永久有效。

作用域限定的记忆 (Scoped memory) ​

在多用户生产系统中,必须对记忆的隔离范围进行合理规划:

助手级记忆 (Agent-scoped memory) ​

适用于属于智能体自身的通用知识库、全局行为准则或公共代码约定。所有与该助手交互的用户都能看到相同的记忆内容。

typescript
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";

const agent = createDeepAgent({
  memory: ["/memories/AGENTS.md"],
  skills: ["/skills/"],
  backend: new CompositeBackend(
    new StateBackend(),
    {
      "/memories/": new StoreBackend({
        namespace: (rt) => [rt.serverInfo.assistantId],  
      }),
      "/skills/": new StoreBackend({
        namespace: (rt) => [rt.serverInfo.assistantId],  
      }),
    },
  ),
});

用户级记忆 (User-scoped memory) ​

适用于与特定最终用户强绑定的个人偏好、专属配置和个性化习惯。 通过命名空间工厂将用户 ID 映射为独立的存储路径,实现严格的用户数据隔离:

typescript
> import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend, createFileData } from "deepagents";
> import { InMemoryStore } from "@langchain/langgraph";
> import { uuid7 } from "langsmith";
>
> const store = new InMemoryStore();  // Use platform store when deploying to LangSmith
>
> // Seed the memory file
> await store.put(
>   ["my-agent"],
>   "/memories/AGENTS.md",
>   createFileData(`## Response style
> - Keep responses concise
> - Use code examples where possible
> `),
> );
>
> // Seed a skill
> await store.put(
>   ["my-agent"],
>   "/skills/langgraph-docs/SKILL.md",
>   createFileData(`---
> name: langgraph-docs
> description: Fetch relevant LangGraph documentation to provide accurate guidance.
> ---
>
> # langgraph-docs
>
> Use the fetch_url tool to read https://docs.langchain.com/llms.txt, then fetch relevant pages.
> `),
> );
>
> const agent = createDeepAgent({
>   memory: ["/memories/AGENTS.md"],
>   skills: ["/skills/"],
>   backend: (rt) => new CompositeBackend(
>     new StateBackend(rt),
>     {
>       "/memories/": new StoreBackend(rt, {
>         namespace: (rt) => ["my-agent"],
>       }),
>       "/skills/": new StoreBackend(rt, {
>         namespace: (rt) => ["my-agent"],
>       }),
>     },
>   ),
>   store,
> });
>
> // Thread 1: the agent learns a new preference and saves it to memory
> const config1 = { configurable: { thread_id: uuid7() } };
> await agent.invoke({
>   messages: [{ role: "user", content: "I prefer detailed explanations. Remember that." }],
> }, config1);
>
> // Thread 2: the agent reads memory and applies the preference
> const config2 = { configurable: { thread_id: uuid7() } };
> await agent.invoke({
>   messages: [{ role: "user", content: "Explain how transformers work." }],
> }, config2);
> ```

## 高级进阶模式 (Advanced usage)

### 情景记忆 (Episodic memory)
记录特定任务的历史执行过程与教训(例如“上周在重构支付模块时遇到了死锁问题,解决方案是调整事务提交顺序”)。智能体在后续遇到类似任务时可自动检索并借鉴过往经验。

### 组织级记忆 (Organization-level memory)
针对企业级部署,将全员共享的合规准则、安全策略设为组织级记忆,由管理员统一维护。

### 后台记忆整理与合并 (Background consolidation)
随着对话轮次增加,原始记忆可能会出现冗余或相互矛盾的描述。
* **整理智能体 (Consolidation agent)**:启动一个专门的轻量级后台子智能体,定期审阅并压缩 `AGENTS.md`,合并重复项,去除已失效的过时约定。
* **定时任务 (Cron)**:通过 LangSmith 定时调度器每日夜间运行记忆合并任务。

### 只读记忆与可写记忆
通过[文件系统权限](/ai-engineering/deepagents/execution-environment/permissions.md)设置,你可以将底层的企业合规规范设为严格只读,同时允许智能体自由读写用户专属的个人偏好文件。

### 并发写入处理
当多个任务或子智能体同时尝试写入同一份记忆文件时,底层的 Store 存储提供了基于版本的乐观并发锁,防止内容被意外覆盖。

## 另请参阅

* [技能体系 (Skills)](/ai-engineering/deepagents/context-management/skills.md):按需加载的动态专业指南。
* [上下文工程 (Context engineering)](/ai-engineering/deepagents/context-management/context-engineering.md):上下文压缩与 Token 治理。

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";

const agent = createDeepAgent({
  memory: ["/memories/preferences.md"],
  skills: ["/skills/"],
  backend: new CompositeBackend(
    new StateBackend(),
    {
      "/memories/": new StoreBackend({
        namespace: (rt) => [rt.serverInfo.user.identity],
      }),
      "/skills/": new StoreBackend({
        namespace: (rt) => [rt.serverInfo.user.identity],
      }),
    },
  ),
});

Full example: isolated memory across users

Seed per-user memories and invoke the agent as two different users. Each user sees only their own preferences.

typescript
> import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend, createFileData } from "deepagents";
> import { InMemoryStore } from "@langchain/langgraph";
> import { uuid7 } from "langsmith";
>
> const store = new InMemoryStore();  // Use platform store when deploying to LangSmith
>
> // Seed preferences for two users
> await store.put(
>   ["user-alice"],
>   "/memories/preferences.md",
>   createFileData(`## Preferences
> - Likes concise bullet points
> - Prefers Python examples
> `),
> );
> await store.put(
>   ["user-bob"],
>   "/memories/preferences.md",
>   createFileData(`## Preferences
> - Likes detailed explanations
> - Prefers TypeScript examples
> `),
> );
>
> // Seed a skill for Alice
> await store.put(
>   ["user-alice"],
>   "/skills/langgraph-docs/SKILL.md",
>   createFileData(`---
> name: langgraph-docs
> description: Fetch relevant LangGraph documentation to provide accurate guidance.
> ---
>
> # langgraph-docs
>
> Use the fetch_url tool to read https://docs.langchain.com/llms.txt, then fetch relevant pages.
> `),
> );
>
> const agent = createDeepAgent({
>   memory: ["/memories/preferences.md"],
>   skills: ["/skills/"],
>   backend: (rt) => new CompositeBackend(
>     new StateBackend(rt),
>     {
>       "/memories/": new StoreBackend(rt, {
>         namespace: (rt) => [rt.serverInfo.user.identity],
>       }),
>       "/skills/": new StoreBackend(rt, {
>         namespace: (rt) => [rt.serverInfo.user.identity],
>       }),
>     },
>   ),
>   store,
> });
>
> // When deployed, each authenticated request resolves
> // `rt.serverInfo.user.identity` to the calling user, so Alice and Bob
> // automatically see only their own preferences.
> await agent.invoke(
>   { messages: [{ role: "user", content: "How do I read a CSV file?" }] },
>   { configurable: { thread_id: uuid7() } },
> );
> ```

## Advanced usage

On top of the basic configuration options for memory paths and scope, you can also configure more advanced parameters for memory:

| Dimension | Question it answers | Options |
| - | - | - |
| **Duration** | How long does it last? | [Short-term](/oss/javascript/deepagents/context-engineering.md) (single conversation) or [long-term](#scoped-memory) (across conversations) |
| **Information type** | What kind of information is it? | [Episodic](#episodic-memory) (past experiences), [procedural](/oss/javascript/deepagents/skills.md) (instructions and skills), or [semantic](/oss/javascript/concepts/memory.md#semantic-memory) (facts) |
| **Scope** | Who can see and modify it? | [User](#user-scoped-memory), [agent](#agent-scoped-memory), or [organization](#organization-level-memory) |
| **Update strategy** | When are memories written? | During conversation (default) or [between conversations](#background-consolidation) |
| **Retrieval** | How are memories read? | Loaded into prompt (default) or on demand (e.g., [skills](/oss/javascript/deepagents/skills.md)) |
| **Agent permissions** | Can the agent write to memory? | [Read-write](#read-only-vs-writable-memory) (default) or [read-only](#read-only-vs-writable-memory) (for shared policies) |

### Episodic memory

Episodic memory stores records of past experiences: what happened, in what order, and what the outcome was. Unlike semantic memory (facts and preferences stored in files like `AGENTS.md`), episodic memory preserves the full conversational context so the agent can recall *how* a problem was solved, not just *what* was learned from it. To generate and maintain a repository-level wiki for coding agents, see [OpenWiki](/oss/openwiki/overview.md).

Deep Agents already use [checkpointers](/oss/javascript/langgraph/checkpointers.md#checkpoints) which is the mechanism that supports episodic memory: every conversation is persisted as a checkpointed thread.

To make past conversations searchable, wrap thread search in a tool. The `user_id` is pulled from the runtime context rather than passed as a parameter:

```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import { Client } from "@langchain/langgraph-sdk";
import { tool } from "@langchain/core/tools";

const client = new Client({ apiUrl: "<DEPLOYMENT_URL>" });

const searchPastConversations = tool(
  async ({ query }, runtime) => {
    const userId = runtime.serverInfo.user.identity;  
    const threads = await client.threads.search({
      metadata: { userId },
      limit: 5,
    });
    const results = [];
    for (const thread of threads) {
      const history = await client.threads.getHistory(thread.threadId);
      results.push(history);
    }
    return JSON.stringify(results);
  },
  {
    name: "search_past_conversations",
    description: "Search past conversations for relevant context.",
  }
);

You can scope thread search by user or organization by adjusting the metadata filter:

typescript
// Search conversations for a specific user
const userThreads = await client.threads.search({
  metadata: { userId },
  limit: 5,
});

// Search conversations across an organization
const orgThreads = await client.threads.search({
  metadata: { orgId },
  limit: 5,
});

This is useful for agents that perform complex, multi-step tasks. For example, a coding agent can look back at a past debugging session and skip straight to the likely root cause.

Organization-level memory ​

Organization-level memory follows the same pattern as user-scoped memory, but with an organization-wide namespace instead of a per-user one. Use it for policies or knowledge that should apply across all users and agents in an organization.

Organization memory is typically read-only to prevent prompt injection via shared state. See read-only vs writable memory for details.

typescript
import { createDeepAgent, CompositeBackend, StateBackend, StoreBackend } from "deepagents";

const agent = createDeepAgent({
  memory: [
    "/memories/preferences.md",
    "/policies/compliance.md",
  ],
  backend: new CompositeBackend(
    new StateBackend(),
    {
      "/memories/": new StoreBackend({
        namespace: (rt) => [rt.serverInfo.user.identity],
      }),
      "/policies/": new StoreBackend({
        namespace: (rt) => [rt.context.orgId],
      }),
    },
  ),
});

Populate organization memory from your application code:

typescript
import { Client } from "@langchain/langgraph-sdk";
import { createFileData } from "deepagents";

const client = new Client({ apiUrl: "<DEPLOYMENT_URL>" });

await client.store.putItem(
  [orgId],
  "/compliance.md",
  createFileData(`## Compliance policies
- Never disclose internal pricing
- Always include disclaimers on financial advice
`),
);

Use permissions to enforce that org-level memory is read-only, or policy hooks for custom validation logic.

Background consolidation ​

By default, the agent writes memories during the conversation (hot path). An alternative is to process memories between conversations as a background task, sometimes called sleep time compute. A separate deep agent reviews recent conversations, extracts key facts, and merges them with existing memories.

ApproachProsCons
Hot path (during conversation)Memories available immediately, transparent to userAdds latency, agent must multitask
Background (between conversations)No user-facing latency, can synthesize across multiple conversationsMemories not available until next conversation, requires a second agent

For most applications, the hot path is sufficient. Add background consolidation when you need to reduce latency or improve memory quality across many conversations.

The recommended pattern is to deploy a consolidation agent alongside your main agent — a deep agent that reads recent conversation history, extracts key facts, and merges them into the memory store — and trigger it on a cron schedule. Pick a cadence that reflects how often your users actually interact with the agent: a chat product with steady daily traffic might consolidate every few hours, while a tool used a handful of times per week only needs to run nightly or weekly. Consolidating much more often than users converse just burns tokens on no-op runs.

Consolidation agent ​

The consolidation agent reads recent conversation history and merges key facts into the memory store. Register it alongside your main agent in langgraph.json:

typescript
import { createDeepAgent } from "deepagents";
import { Client } from "@langchain/langgraph-sdk";
import { tool } from "@langchain/core/tools";

const sdkClient = new Client({ apiUrl: "<DEPLOYMENT_URL>" });

const searchRecentConversations = tool(
  async ({ query }, runtime) => {
    const userId = runtime.serverInfo.user.identity;  

    const since = new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString();
    const threads = await sdkClient.threads.search({
      metadata: { userId },
      updatedAfter: since,
      limit: 20,
    });
    const conversations = [];
    for (const thread of threads) {
      const history = await sdkClient.threads.getHistory(thread.threadId);
      conversations.push(history.values.messages);
    }
    return JSON.stringify(conversations);
  },
  {
    name: "search_recent_conversations",
    description: "Search this user's conversations updated in the last 6 hours.",
  }
);

const agent = createDeepAgent({
  model: "google:gemini-3.6-flash",
  systemPrompt: `Review recent conversations and update the user's memory file.
Merge new facts, remove outdated information, and keep it concise.`,
  tools: [searchRecentConversations],
});

export { agent };
json
{
  "dependencies": ["."],
  "graphs": {
    "agent": "./src/agent.ts:agent",
    "consolidation_agent": "./src/consolidation-agent.ts:agent"
  },
  "env": ".env"
}

Cron ​

A cron job runs the consolidation agent on a fixed schedule. The agent searches recent conversations and synthesizes them into memory. Match the schedule to your usage patterns so consolidation runs roughly track real activity.

mermaid
graph LR
    Store[(Memory store)] -.->|reads| Conv1[Conversation 1]
    Store -.->|reads| Conv2[Conversation 2]
    Cron[Cron schedule] -->|periodic| Agent[Consolidation agent]
    Agent -->|writes| Store

    classDef trigger fill:#F6FFDB,stroke:#6E8900,stroke-width:2px,color:#2E3900
    classDef process fill:#E5F4FF,stroke:#006DDD,stroke-width:2px,color:#030710
    classDef output fill:#EBD0F0,stroke:#885270,stroke-width:2px,color:#441E33
    classDef schedule fill:#FDF3FF,stroke:#7E65AE,stroke-width:2px,color:#504B5F

    class Conv1,Conv2 trigger
    class Agent process
    class Store output
    class Cron schedule

Schedule the consolidation agent with a cron job:

typescript
import { Client } from "@langchain/langgraph-sdk";

const client = new Client({ apiUrl: "<DEPLOYMENT_URL>" });

const cronJob = await client.crons.create(
  "consolidation_agent",
  {
    schedule: "0 */6 * * *",
    input: { messages: [{ role: "user", content: "Consolidate recent memories." }] },
  },
);

NOTE

All cron schedules are interpreted in UTC. See cron jobs for details on managing and deleting cron jobs.

WARNING

The cron interval must match the lookback window inside the consolidation agent. The example above runs every 6 hours (0 */6 * * *) and the agent's search_recent_conversations tool looks back timedelta(hours=6) — keep these in sync. If the cron runs more often than the lookback, you'll reprocess the same conversations; if it runs less often, you'll drop memories that fall outside the window.

For more on deploying agents with background processes, see going to production.

Read-only vs writable memory ​

By default, the agent can both read and write memory files. For shared state like organization policies or compliance rules, you may want to make memory read-only so the agent can reference it but not modify it. This prevents prompt injection via shared memory and ensures that only your application code controls what's in the file.

PermissionUse caseHow it works
Read-write (default)User preferences, agent self-improvement, learned skillsAgent updates files via edit_file tool
Read-onlyOrganization policies, compliance rules, shared knowledge bases, developer-defined skillsPopulate via application code or the Store API. Use permissions to deny writes to specific paths, or policy hooks for custom validation logic.

Security considerations: If one user can write to memory that another user reads, a malicious user could inject instructions into shared state. To mitigate this:

  • Default to user scope (user_id) unless you have a specific reason to share
  • Use read-only memory for shared policies (populate via application code, not the agent)
  • Add human-in-the-loop validation before the agent writes to shared memory. Use an interrupt to require human approval for writes to sensitive paths.

To enforce read-only memory, use permissions to declaratively deny writes to specific paths. For custom validation logic (rate limiting, audit logging, content inspection), use backend policy hooks.

Concurrent writes ​

Multiple threads can write to memory in parallel, but concurrent writes to the same file can cause last-write-wins conflicts. For user-scoped memory this is rare since users typically have one active conversation at a time. For agent-scoped or organization-scoped memory, consider using background consolidation to serialize writes, or structure memory as separate files per topic to reduce contention.

In practice, if a write fails due to a conflict, the LLM is usually smart enough to retry or recover gracefully, so a single lost write is not catastrophic.

Multiple agents in the same deployment ​

To give each agent its own memory in a shared deployment, add assistant_id to the namespace:

typescript
new StoreBackend({
  namespace: (rt) => [
    rt.serverInfo.assistantId,  
    rt.serverInfo.user.identity,
  ],
})

Use assistant_id alone if you only need per-agent isolation without per-user scoping.

TIP

Use LangSmith tracing to audit what your agent writes to memory. Every file write appears as a tool call in the trace.

See also ​

  • OpenWiki: Generate and maintain repository wikis that coding agents find through AGENTS.md
  • Backends: Choose where memory files are stored
  • Context engineering: Short-term memory, offloading, and summarization
  • Skills: On-demand procedural memory

Connect these docs to your agent of choice via MCP for real-time answers.

Edit this page on GitHub or file an issue.