3. DeepAgents 实战 - Memory Skills 与上下文工程

Memory、Skills 与上下文工程 ------ deepagents 第三阶段实战手记

这不是一个"给 Agent 多加几行配置"的简单升级。我们要做的,是让 Agent 从一个"每次对话都失忆的工具人"进化成一个 记住用户偏好按需调用领域知识自动压缩长对话 的智能助手。 整个过程基于前两篇文章的项目,增量改动集中在 agents.tsindex.ts,同时新增了 AGENTS.mdskills/ 目录。


目录

  1. [回顾:前两篇文章结束时 Agent 能做什么?](#回顾:前两篇文章结束时 Agent 能做什么? "#1-%E5%9B%9E%E9%A1%BE%E5%89%8D%E4%B8%A4%E7%AF%87%E6%96%87%E7%AB%A0%E7%BB%93%E6%9D%9F%E6%97%B6-agent-%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88")
  2. [Memory:让 Agent 拥有"长期记忆"](#Memory:让 Agent 拥有"长期记忆" "#2-memory%E8%AE%A9-agent-%E6%8B%A5%E6%9C%89%E9%95%BF%E6%9C%9F%E8%AE%B0%E5%BF%86")
  3. [Skills:给 Agent 装上"领域知识库"](#Skills:给 Agent 装上"领域知识库" "#3-skills%E7%BB%99-agent-%E8%A3%85%E4%B8%8A%E9%A2%86%E5%9F%9F%E7%9F%A5%E8%AF%86%E5%BA%93")
  4. [Context Engineering:对话太长怎么办?](#Context Engineering:对话太长怎么办? "#4-context-engineering%E5%AF%B9%E8%AF%9D%E5%A4%AA%E9%95%BF%E6%80%8E%E4%B9%88%E5%8A%9E")
  5. Multimodality:多模态能力边界
  6. [三个新测试:验证 Memory 和 Skills](#三个新测试:验证 Memory 和 Skills "#6-%E4%B8%89%E4%B8%AA%E6%96%B0%E6%B5%8B%E8%AF%95%E9%AA%8C%E8%AF%81-memory-%E5%92%8C-skills")
  7. 回顾与展望

1. 回顾:前两篇文章结束时 Agent 能做什么?

阶段 能力 不足
第一篇 计算器、报时、流式输出、多轮对话、Extended Thinking 每次重启就失忆,不知道用户是谁
第二篇 文件读写、搜索、执行 shell 命令 只有通用能力,没有领域知识

到了第三篇,我们要解决三个核心问题:

  1. 失忆 --- Agent 每次启动都是一张白纸,不知道用户偏好
  2. 无知 --- Agent 只有通用工具,不了解产品细节(FAQ、退款政策等)
  3. 窗口爆炸 --- 对话越来越长,上下文窗口迟早不够用

2. Memory:让 Agent 拥有"长期记忆"

2.1 Memory vs Checkpointer:两种"记忆"的区别

在第二篇文章中,我们已经用过 MemorySaver(checkpointer)。它能在同一个 session 内 记住多轮对话。但它有一个致命缺陷------进程重启就丢了

md 复制代码
MemorySaver(checkpointer)        Memory(AGENTS.md)
┌────────────────────────┐        ┌────────────────────────┐
│ 存储在进程内存中          │        │ 存储在磁盘文件中         │
│ 进程重启 → 丢失          │        │ 进程重启 → 仍在          │
│ 记住"这轮对话说了什么"    │        │ 记住"用户是谁、偏好什么"   │
│ 自动累积,不需要配置      │        │ 手动维护,按需更新        │
│ 短期记忆(对话级)        │        │ 长期记忆(用户级)        │
└────────────────────────┘        └────────────────────────┘

就像人的记忆一样:MemorySaver工作记忆 (当前正在做的事),Memory长期记忆(你是谁、你喜欢什么)。

2.2 创建 AGENTS.md

AGENTS.md 是一个 Markdown 文件,里面写着用户的偏好和项目上下文。Agent 启动时自动加载它,内容被注入系统提示词。

markdown 复制代码
# Agent 持久记忆

## 用户偏好

- 回复语言:中文
- 代码风格:TypeScript,使用 ES Module
- 命名规范:camelCase 变量/函数名,PascalCase 类/接口名
- 注释风格:中文行内注释,解释"为什么"而非"是什么"

## 项目上下文

- 项目类型:LangChain + TypeScript 学习项目
- 包管理器:pnpm
- 运行方式:`pnpm dev`(tsx 直接运行)

## 编码约束

- 不要使用 any 类型,除非处理 LangChain 消息流的 content 字段
- 工具函数必须有 Zod schema 描述
- 错误信息用中文返回

文件路径:workspace/AGENTS.md(在 Backend 的 rootDir 下)。

2.3 代码变化:一行配置

agents.ts 中,createDeepAgent 新增 memory 参数:

typescript 复制代码
export const agent = createDeepAgent({
  model,
  tools: [calculatorTool, getCurrentTimeTool],
  backend,
  // 持久记忆:启动时加载 AGENTS.md,内容注入系统提示词
  memory: ['/AGENTS.md'],
  // ...
});

就这么一行。deepagents 内部的 createMemoryMiddleware 会在 Agent 启动时:

  1. 从 Backend 读取 /AGENTS.md 的内容
  2. 将内容注入系统提示词(system prompt)
  3. Agent 的每次回复都会"参考"这些偏好

生产建议memory 支持多个路径,比如 ['~/.deepagents/AGENTS.md', './.deepagents/AGENTS.md'],按顺序加载,后面的覆盖前面的。适合全局配置 + 项目级配置的组合。


3. Skills:给 Agent 装上"领域知识库"

3.1 为什么需要 Skills?

Agent 有了 Memory 之后知道"用户喜欢中文、TypeScript",但如果用户问:

"我买了一个产品用了 2 次,现在想退款能退多少?"

Agent 完全不知道退款政策是什么。它只有通用工具(计算器、文件操作),没有领域知识

Skills 就是解决方案------把领域知识写成 Markdown 文件,Agent 按需加载。

3.2 Skills 的文件结构

md 复制代码
workspace/
├── AGENTS.md                          # 持久记忆
└── skills/
    ├── product-faq/SKILL.md           # 产品 FAQ
    ├── refund-policy/SKILL.md         # 退款政策
    └── code-review/SKILL.md           # 代码审查规范

每个 Skill 是一个目录,里面放一个 SKILL.md 文件。SKILL.md 需要一段 YAML frontmatter 声明名称和描述:

markdown 复制代码
---
name: product-faq
description: 产品常见问题解答知识库,涵盖功能介绍、使用方法、技术架构等高频问题
---

# 产品 FAQ

## Q: 这个项目是做什么的?
这是一个 LangChain + TypeScript 的 AI Agent 学习项目...

## Q: 支持哪些工具?
内置工具包括:calculator、get_current_time、文件系统工具...

frontmatter 中的 namedescription 是关键 ------deepagents 用它们注册 Skill 元数据,LLM 根据 description 判断什么时候需要读取这个 Skill 的完整内容。

3.3 Skills 的工作机制

md 复制代码
用户问:"退款能退多少?"
  ↓
LLM 看到系统提示词中列出了 3 个 skill 描述:
  - product-faq: 产品常见问题解答
  - refund-policy: 退款政策与售后服务规范   ← 匹配!
  - code-review: 代码审查规范
  ↓
LLM 决定读取 refund-policy skill
  → Agent 调用 read_file("/skills/refund-policy/SKILL.md")
  → 拿到完整退款政策内容
  ↓
LLM 根据退款政策回答用户问题

这就是按需加载------不是把所有 Skill 内容都塞进系统提示词(那会浪费 token),而是只注入描述,LLM 需要时再读取完整内容。

3.4 代码变化:一行配置

typescript 复制代码
export const agent = createDeepAgent({
  model,
  tools: [calculatorTool, getCurrentTimeTool],
  backend,
  memory: ['/AGENTS.md'],
  // 领域知识:扫描 /skills/ 下所有子目录
  // 每个含 SKILL.md 的子目录被注册为一个 skill
  skills: ['/skills/'],
  // ...
});

skills 参数接受路径数组。deepagentscreateSkillsMiddleware 会自动:

  1. 扫描 /skills/ 下的所有子目录
  2. 找到每个含 SKILL.md 的子目录
  3. 解析 frontmatter 提取 namedescription
  4. 将 skill 元数据注册到 Agent 中
Skill 名称 描述 触发场景
product-faq 产品常见问题解答 用户问"怎么用"、"支持什么"
refund-policy 退款政策与售后规范 用户问退款、售后、客服
code-review 代码审查规范 用户问代码质量、命名规范

进阶(S3.2) :当 Skill 数量超过 20 个时,"全量加载描述"策略会消耗太多 token。这时候可以用 Embedding + 向量检索做预筛选------把用户问题向量化,只加载语义最相关的几个 Skill。deepagents 目前还没内置这个功能,但架构上支持通过自定义 middleware 扩展。


4. Context Engineering:对话太长怎么办?

4.1 Token 限制与上下文窗口(S3.1)

LLM 的上下文窗口是有限的。我们的模型配置了 maxTokens: 10000,但整个上下文窗口的组成是:

md 复制代码
上下文窗口 = 系统提示词 + Memory + Skill 描述 + 工具定义 + 历史消息 + 新消息 + 模型回复
              ────────────── 共享一个固定大小的 token 预算 ──────────────

对话 10 轮后,历史消息可能已经占掉了 50% 的窗口。对话 50 轮后,新消息可能被截断。

4.2 摘要压缩(Summarization)

deepagents 提供了 createSummarizationMiddleware 来解决这个问题:

typescript 复制代码
import { createSummarizationMiddleware } from 'deepagents';

const summarizationMiddleware = createSummarizationMiddleware({
  backend,  // 复用已有的 LocalShellBackend
  // 当消息数超过 20 条时触发摘要压缩
  trigger: { type: 'messages', value: 20 },
  // 压缩后保留最近 10 条消息的原文
  keep: { type: 'messages', value: 10 },
});

工作原理:

md 复制代码
消息 1~50(触发条件:消息数 > 20)
  ↓
LLM 将消息 1~40 压缩成一段摘要
  ↓
保留消息 41~50 的原文
  ↓
上下文变成:[摘要] + [消息 41~50]

trigger 支持三种触发条件:

类型 含义 示例
messages 消息条数 { type: 'messages', value: 20 }
tokens token 数量 { type: 'tokens', value: 50000 }
fraction 占上下文窗口比例 { type: 'fraction', value: 0.7 }

4.3 Prompt 缓存(S3.3)

createMemoryMiddleware 还支持 cacheControl 选项:

typescript 复制代码
createMemoryMiddleware({
  backend,
  sources: ['/AGENTS.md'],
  cacheControl: true,  // 启用 prompt caching
});

开启后,Memory 内容块会被标记为 cache_control: { type: "ephemeral" }。对于支持 Prompt Caching 的模型(如 Claude),重复的 Memory 内容不会重复计费------省钱又省时间。

生产建议:Prompt Caching 在 Anthropic 原生模型上效果最好。通过兼容接口调用的第三方模型(如本项目),缓存效果取决于代理服务器是否支持。

4.4 代码变化:加入 middleware

typescript 复制代码
export const agent = createDeepAgent({
  model,
  tools: [calculatorTool, getCurrentTimeTool],
  backend,
  memory: ['/AGENTS.md'],
  skills: ['/skills/'],
  // 摘要压缩中间件:对话过长时自动压缩旧消息
  middleware: [summarizationMiddleware],
  // ...
});

middleware 是一个数组,可以传入多个中间件。deepagents 会按顺序应用它们。


5. Multimodality:多模态能力边界

5.1 什么是多模态?

多模态(Multimodality)指模型能处理文本之外的输入:图片、PDF、音频等。

在 LangChain 中,发送多模态消息的方式是把 content 设为数组:

typescript 复制代码
await agent.stream({
  messages: [{
    role: 'user',
    content: [
      { type: 'text', text: '这张图片里有什么?' },
      { type: 'image_url', image_url: { url: 'https://example.com/cat.jpg' } },
    ],
  }],
}, { ...config, streamMode: 'messages' });

5.2 模型能力对照表(S3.4)

模型 图片理解 PDF 解析 音频转写 视频分析
Claude 3.5 Sonnet ✅(PDF 转图片)
GPT-4o
qwen3.7-plus ⚠️

本项目使用的 qwen3.7-plus 通过 Anthropic 兼容接口调用,多模态支持取决于代理服务器是否透传图片内容。发送图片不会报错,但如果模型不支持,会被忽略或返回"无法处理图片"。

实战建议:如果需要稳定的多模态能力,建议切换到 Claude 3.5 Sonnet 或 GPT-4o。本项目侧重 Agent 架构学习,多模态作为知识拓展点到为止。


6. 三个新测试:验证 Memory 和 Skills

index.ts 中,我们注释掉了第二篇的 shell 命令测试(测试 4~6),新增了 3 个测试来验证 Phase 3 的能力。

6.1 测试 7:验证 Memory(持久记忆)

typescript 复制代码
console.log('--- 测试 7:Memory(持久记忆) ---');
console.log('用户:帮我写一个简单的工具函数,把两个数组合并');

const stream7 = await agent.stream(
  { messages: [{ role: 'user', content: '帮我写一个简单的工具函数,把两个数组合并' }] },
  { ...config, streamMode: 'messages' },
);
await printStream(stream7);

虽然这是第一条消息(没有对话历史),但 Agent 会参考 AGENTS.md 中的偏好:

  • 用 TypeScript 写
  • 用 camelCase 命名
  • 中文注释
  • 不使用 any 类型

验证方法 :对比有/无 memory 配置时的输出差异。没有 Memory 时,Agent 可能用英文注释、用 JavaScript 写;有了 Memory,输出应该符合 AGENTS.md 中的约束。

6.2 测试 8:验证 Skills(产品 FAQ)

typescript 复制代码
console.log('--- 测试 8:Skills(产品 FAQ) ---');
console.log('用户:这个项目支持哪些工具?怎么运行?');

const stream8 = await agent.stream(
  { messages: [{ role: 'user', content: '这个项目支持哪些工具?怎么运行?' }] },
  { ...config, streamMode: 'messages' },
);
await printStream(stream8);

Agent 应该能从 product-faq skill 中找到答案,而不是凭空编造。

6.3 测试 9:验证 Skills(退款政策)

typescript 复制代码
console.log('--- 测试 9:Skills(退款政策) ---');
console.log('用户:我买了一个产品,用了 2 次,现在想退款,能退多少?');

const stream9 = await agent.stream(
  { messages: [{ role: 'user', content: '我买了一个产品,用了 2 次,现在想退款,能退多少?' }] },
  { ...config, streamMode: 'messages' },
);
await printStream(stream9);

这是一个需要精确回答的问题。Agent 应该读取 refund-policy skill,根据退款金额表回答:

md 复制代码
7 天内使用 ≤ 3 次 → 退款 80%

如果 Agent 回答"80%"或"可以退 80%",说明 Skills 加载成功了。如果它说"抱歉我不清楚退款政策",说明 Skill 没有被正确读取。

7. 回顾与展望

我们做了什么

在前两篇文章的基础上,Agent 获得了三项新能力:

  1. Memory(持久记忆) --- AGENTS.md 让 Agent 记住用户偏好,不再每次启动都失忆
  2. Skills(领域知识) --- skills/ 目录下的 SKILL.md 文件,Agent 按需加载领域知识回答问题
  3. Context Engineering(上下文工程) --- createSummarizationMiddleware 自动压缩长对话,防止上下文窗口爆炸
  4. Multimodality(多模态) --- 了解模型的能力边界,知道什么能做、什么不能做

完整运行

bash 复制代码
pnpm dev

输出三个新测试场景:Memory 验证(写工具函数时遵循偏好)、Skills FAQ(项目问题)、Skills 退款(精确政策回答)。

项目结构总览

md 复制代码
lingshi/
├── src/
│   ├── tools.ts          # 工具定义(calculator、get_current_time)
│   ├── agents.ts         # Agent 创建(Memory + Skills + Summarization)
│   └── index.ts          # 入口,流式输出 + 测试场景
├── workspace/
│   ├── AGENTS.md         # 📝 持久记忆(用户偏好)
│   ├── skills/
│   │   ├── product-faq/SKILL.md     # 📚 产品 FAQ
│   │   ├── refund-policy/SKILL.md   # 📚 退款政策
│   │   └── code-review/SKILL.md     # 📚 代码审查规范
│   ├── public/           # Agent 可读写文件
│   └── private/          # Agent 可读写文件
├── .env
├── package.json
└── tsconfig.json

后续可以做什么

  • Subagents(子 Agent):让主 Agent 把复杂任务分发给专门的子 Agent 处理
  • Structured Output(结构化输出):让 Agent 返回 JSON schema 校验的结构化数据
  • Human-in-the-loop:关键操作前要求用户确认
  • 持久化存储 :把 MemorySaver 换成 PostgresSaver,让会话记忆跨重启保留

从"会算数"到"会操作电脑"再到"有记忆有知识能压缩",Agent 从一个玩具变成了一个真正有用的助手。

相关推荐
Bigger1 小时前
对不起!我错怪你了,UnoCSS:一次和 AI 一起排查 DevTools 卡顿的经历
前端·css·人工智能
Yeats_Liao1 小时前
18:JavaBean简介及其在表单处理与DAO设计模式中的应用-Java Web
java·后端·架构
CaffeinePro1 小时前
Langchain环境搭建与LCEL核心语法
人工智能·agent
不懂的浪漫1 小时前
Andrew Ng(吴恩达)谈 Loop Engineering:AI 编程中的三个关键循环
人工智能
人工智能培训1 小时前
大模型驱动下传统大数据架构的变革方向
大数据·人工智能·重构·架构·agent·agi
一次旅行2 小时前
AI 前沿日报 | 2026年7月6日
人工智能
AI科技星2 小时前
全域谱分析:无穷维超复数信息场分形统一场论——自然、量子、金融多重分形第一性原理完整体系(中英双语终稿)
人工智能·python·算法·金融·乖乖数学·全域数学
lzx186488437022 小时前
【AH8966】可替代 KP3211 非隔离 AC110220V转12V 0.5A 降压转换芯片
人工智能·单片机·嵌入式硬件·集成测试·硬件工程·ic
王者鳜錸2 小时前
解决方案十八-企业级客服通话录音/销售录音对话分析
人工智能·客户录音分析·房产销售录音分析·试驾录音分析·销售录音分析