【AgentScope】3. 工作空间(Workspace)详解

工作空间(Workspace)详解

一句话概括

工作空间是 Agent 的"办公桌"------人格、记忆、知识、技能都以文件形式存放在这里,每次"上班"自动加载,每次"下班"自动保存。

你能学到什么

  • 工作空间的目录结构,每个文件/文件夹的作用
  • 两层读写机制:为什么需要"优先读远端,兜底读本地"
  • System Prompt 注入机制:工作空间内容如何变成 Agent 的"记忆"
  • 如何配置自己的 Agent 工作空间

前置知识

详见 README.md。此外需了解 Hook 机制和 Agent 调用流程(参考 02-architecture.md)。

核心概念

工作空间 --- Agent 的"办公桌"

想象你是一名员工,每天上班需要:

  1. 坐在固定的办公桌
  2. 桌上有你的工牌(告诉别人你是谁)
  3. 抽屉里有笔记本(记录重要的事情)
  4. 书架上有参考手册(查资料用)
  5. 旁边有工具箱(干活用的工具)

工作空间就是这个"办公桌"!它是 Agent 所有"随身物品"的存放地:

复制代码
办公桌(workspace/)                对应 Agent 的什么?
├── AGENTS.md                      工牌(我是谁、我该怎么做)
├── MEMORY.md                      核心笔记(最重要的记忆)
├── knowledge/                     书架(领域知识、参考手册)
├── memory/                        日记本(每日流水账)
├── skills/                        工具箱(专业技能)
├── subagents/                     下属名单(可以叫谁帮忙)
└── agents/<agentId>/sessions/     工作记录本(每次对话的详细记录)

AGENTS.md --- Agent 的"工牌"

生活类比:就像员工胸前挂的工牌,上面写着:

  • 你是谁(名字、职位)
  • 你的职责是什么(负责什么工作)
  • 你该怎么做(工作准则、行为规范)

每次 Agent "上班"(被调用),第一件事就是读取这个工牌,知道自己是谁、该怎么表现。

技术实现

markdown 复制代码
# 我是客服助手小美

## 身份
我是一个友好的客服助手,专门帮助用户解决订单问题。

## 行为准则
1. 先确认用户身份
2. 礼貌回复,不急不躁
3. 遇到无法解决的问题,转接人工客服

## 能力范围
- 查询订单状态
- 处理退款申请
- 修改收货地址

MEMORY.md --- Agent 的"核心笔记"

生活类比:就像你办公桌上最重要的那本笔记本,里面记着你"必须记住"的事情:

  • 老板的偏好
  • 重要客户的习惯
  • 上次项目遇到的坑

这本笔记会被"压缩"后注入到 Agent 的脑海中,但容量有限(默认 8000 tokens),超出会被截断。

技术实现

markdown 复制代码
# 长期记忆

## 用户偏好
- 张先生喜欢用邮件沟通
- 李女士每次下单都要加急

## 重要事件
- 2024-01-15:系统升级,暂停服务 2 小时
- 2024-01-20:新产品上线

knowledge/ --- Agent 的"书架"

生活类比:就像办公桌旁边的书架,放着各种参考书:

  • 产品说明书
  • 常见问题解答
  • 操作手册

MEMORY.md 不同,书架上的书不会全部塞进脑子里,而是给 Agent 一个"目录",需要时再查阅。

技术实现

复制代码
knowledge/
├── KNOWLEDGE.md          ← 书架目录(告诉 Agent 有哪些书)
├── faq.md                ← 常见问题解答
├── product-guide.md      ← 产品指南
└── troubleshooting.md   ← 故障排查手册

memory/ --- Agent 的"日记本"

生活类比:就像你每天写的日记,记录当天发生的事情:

  • 今天见了谁
  • 处理了什么事
  • 有什么感悟

这是"流水账",每天一个文件,由 Agent 运行时自动写入。

技术实现

复制代码
memory/
├── 2024-01-15.md         ← 1月15日的日记
├── 2024-01-16.md         ← 1月16日的日记
└── .consolidation_state  ← 日记整理进度(内部状态)

sessions/ --- Agent 的"工作记录本"

生活类比:就像你的工作日志,详细记录每一次任务:

  • 任务编号(sessionId)
  • 任务摘要(summary)
  • 完整的对话记录

技术实现

复制代码
agents/<agentId>/sessions/
├── sessions.json           ← 任务索引(快速查找)
├── <sessionId>.jsonl      ← 压缩后的对话上下文
└── <sessionId>.log.jsonl  ← 完整对话日志

关键代码解读

目录结构详解

复制代码
workspace/                           ← 默认路径: .agentscope/workspace
│
├── AGENTS.md                        ← 人格定义(每次推理都注入)
│   - 定义 Agent 的身份、行为准则
│   - 缺失时 Agent 仍可工作,但会丢失"人格"
│
├── MEMORY.md                        ← 长期记忆(每次注入,有 token 限制)
│   - 整理过的核心记忆
│   - 超出预算会被截断,并提示使用 memory_search
│
├── knowledge/
│   ├── KNOWLEDGE.md                 ← 知识入口(告诉 Agent 有哪些资料)
│   └── *                           ← 其他参考文件(按需读取)
│
├── memory/
│   ├── YYYY-MM-DD.md                ← 每日记忆流水账(运行时写入)
│   └── .consolidation_state         ← 记忆整理器的内部状态
│
├── skills/<skill-name>/SKILL.md     ← 自定义技能定义
│
├── subagents/<id>.md                ← 子 Agent 声明(自动发现)
│
└── agents/<agentId>/               ← 每个 Agent 的私有空间
    ├── workspace/                   ← 隔离子 Agent 的运行时根目录
    └── sessions/
        ├── sessions.json            ← 会话索引(id/summary/updatedAt)
        ├── <sessionId>.jsonl        ← LLM 可见的压缩上下文
        └── <sessionId>.log.jsonl   ← 完整对话日志(用于审计)

两层读写机制

生活类比:想象你在公司有两个文件柜:

  1. 共享文件柜(AbstractFilesystem):云端的、多人共享的柜子
  2. 个人文件柜(本地磁盘):你桌边的小柜子

当你找文件时:

  • 先去共享柜子找(因为可能有同事刚放进去的新文件)
  • 共享柜子没有,再去个人柜子找(兜底)

当你存文件时:

  • 默认存到共享柜子(其他人也能看到)

  • 共享柜子出问题时,存到个人柜子(兜底)

    读取流程:
    ┌─────────────┐ 读 ┌─────────────────────┐
    │ Hook / Tool │ ─────────▶ │ WorkspaceManager │
    └─────────────┘ └──────────┬──────────┘

    ┌──────────▼──────────┐
    │ AbstractFilesystem │ ← 优先(云端/多租户)
    │ (共享文件柜) │
    └──────────┬──────────┘

    没找到则 │

    ┌─────────────────────┐
    │ 本地磁盘 │ ← 兜底(本地文件)
    │ (个人文件柜) │
    └─────────────────────┘

代码解读

java 复制代码
// 创建工作空间管理器
// workspace: 工作空间根目录
// abstractFilesystem: 抽象文件系统(云端/多租户存储)
WorkspaceManager wm = new WorkspaceManager(workspace, abstractFilesystem);

// ========== 读取操作 ==========

// 读取 AGENTS.md(两层读:先云端,后本地)
wm.readAgentsMd();

// 读取 MEMORY.md(同上)
wm.readMemoryMd();

// 读取 knowledge/KNOWLEDGE.md
wm.readKnowledgeMd();

// 读取任意工作区文件(带路径穿越校验,防止恶意访问)
wm.readManagedWorkspaceFileUtf8("knowledge/faq.md");

// ========== 列表操作 ==========

// 列出知识库文件(两层并集,去重)
wm.listKnowledgeFiles();

// 列出记忆文件列表
wm.listMemoryFilePaths();

// 列出会话日志文件
wm.listSessionLogFiles();

// ========== 写入操作 ==========

// 追加内容到工作区文件(走 AbstractFilesystem)
wm.appendUtf8WorkspaceRelative("memory/2024-01-15.md", "新事件:用户咨询退款\n");

// 更新会话索引
wm.updateSessionIndex(agentId, sessionId, "会话摘要内容");

System Prompt 注入机制

生活类比:每次 Agent "上班"前,都要先"照镜子"------把办公桌上的重要物品信息"装进脑子"。

这个过程由 WorkspaceContextHook 在推理前自动完成:

复制代码
推理前自动注入的内容:
┌─────────────────────────────────────────────────────────────┐
│ ## Session Context                                          │
│ - 当前日期:2024-01-15                                       │
│ - 操作系统:Mac OS                                          │
│ - 工作空间路径:.agentscope/workspace                        │
│ - 会话ID:session-12345                                     │
├─────────────────────────────────────────────────────────────┤
│ ## Workspace Guidance                                       │
│ (内置模板:告诉 Agent 如何使用工作空间)                      │
├─────────────────────────────────────────────────────────────┤
│ <loaded_context>                                            │
│   <agents_context>                                          │
│     [AGENTS.md 全文内容]  ← 没有长度限制                      │
│   </agents_context>                                         │
│                                                             │
│   <memory_context>                                          │
│     [MEMORY.md 内容]  ← 受 token 预算限制(默认 8000)        │
│   </memory_context>                                         │
│                                                             │
│   <domain_knowledge_context>                                │
│     [KNOWLEDGE.md 内容]                                     │
│     可用文件列表:faq.md, product-guide.md, ...              │
│   </domain_knowledge_context>                               │
│                                                             │
│   <SOUL.md>  ← 额外配置的上下文文件                           │
│     [文件内容]                                               │
│   </SOUL.md>                                                │
│ </loaded_context>                                           │
└─────────────────────────────────────────────────────────────┘

Token 预算机制

java 复制代码
// 默认预算:8000 tokens
// 估算方式:字符数 / 4(粗略估算,中文可能不准确)

// 当 MEMORY.md 超出预算时:
// 1. 按字符截断
// 2. 追加提示:"... (memory truncated --- use memory_search for older entries) ..."
// 3. Agent 收到提示后,知道可以用 memory_search 工具查历史记忆

配置示例

java 复制代码
HarnessAgent agent = HarnessAgent.builder()
    .name("MyAgent")                                        // Agent 名称
    .model(model)                                           // 使用的 LLM 模型
    .workspace(Paths.get(".agentscope/workspace"))         // 工作空间路径(不传则用默认)
    .additionalContextFile("SOUL.md")                      // 额外注入的文件
    .additionalContextFile("PREFERENCES.md")               // 可以配置多个
    .maxContextTokens(8000)                                // MEMORY.md 的 token 上限
    .build();

配置说明

配置项 作用 默认值
workspace 工作空间根目录 .agentscope/workspace
additionalContextFile 额外注入到 system prompt 的文件
maxContextTokens MEMORY.md 的最大 token 数 8000

整体流程图

复制代码
                        ┌─────────────────────────────────────┐
                        │           Agent 启动                 │
                        │        HarnessAgent.build()          │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │         验证工作空间                  │
                        │   WorkspaceManager.validate()        │
                        │   检查目录和 AGENTS.md 是否存在        │
                        │   (缺失只 warn,不报错)              │
                        └──────────────────┬──────────────────┘
                                           │
                                           ▼
                        ┌─────────────────────────────────────┐
                        │          Agent 运行中                 │
                        └──────────────────┬──────────────────┘
                                           │
                              ┌────────────┴────────────┐
                              │                         │
                              ▼                         ▼
              ┌────────────────────────┐   ┌────────────────────────┐
              │   PreReasoningEvent    │   │   PostCallEvent 等      │
              │   (推理前)            │   │   (调用后)             │
              └───────────┬────────────┘   └───────────┬────────────┘
                          │                            │
                          ▼                            ▼
              ┌────────────────────────┐   ┌────────────────────────┐
              │  WorkspaceContextHook  │   │  MemoryFlushHook        │
              │  (注入 system prompt) │   │  SessionPersistenceHook │
              └───────────┬────────────┘   │  (写回记忆/会话)       │
                          │                └───────────┬────────────┘
                          ▼                            │
              ┌────────────────────────┐               │
              │ 读取并注入:            │               │
              │ - AGENTS.md            │               │
              │ - MEMORY.md            │               │
              │ - knowledge/            │               │
              │ - 额外文件              │               │
              └─────────────────────────┘               │
                                                        ▼
                                          ┌────────────────────────┐
                                          │ 写回到:                │
                                          │ - memory/YYYY-MM-DD.md  │
                                          │ - sessions/*.jsonl     │
                                          └────────────────────────┘

与其他模块的关系


⬅️ 上一篇:02-architecture | 📖 回到目录 | ➡️ 下一篇:04-session

学习要点

必须记住

  1. 工作空间 = Agent 的办公桌:所有 Agent 需要的"物品"都放在这里
  2. AGENTS.md 是人格:定义 Agent 是谁、该怎么做
  3. MEMORY.md 是核心记忆:有 token 限制,超出会被截断
  4. 两层读写机制:先读 AbstractFilesystem(云端),兜底读本地磁盘

容易混淆

  1. MEMORY.md vs memory/

    • MEMORY.md:整理过的核心记忆,每次都注入,有长度限制
    • memory/:每日流水账,按需查询,不自动注入
  2. knowledge/ vs MEMORY.md

    • knowledge/:领域知识、参考手册,给 Agent 一个"目录"
    • MEMORY.md:Agent 个人的记忆和经验
  3. 读取顺序

    • 不是"先本地后云端",而是**"先云端后本地"**
    • 因为云端可能有最新的数据(多租户场景)

实践建议

  1. 最小可行配置 :至少创建一个 AGENTS.md,定义 Agent 的基本人格
  2. 合理使用 token 预算MEMORY.md 不要写太多,重要内容放前面
  3. 善用 knowledge/:大文件放 knowledge/,让 Agent 按需读取
  4. 定期清理 memory/:旧日记可以归档,避免文件过多

调试技巧

java 复制代码
// 查看工作空间路径
System.out.println(agent.getWorkspace());

// 查看注入的 system prompt
// (需要在日志中开启 DEBUG 级别)
// 可以看到 AGENTS.md、MEMORY.md 等是否正确注入

上一篇02-architecture.md --- 架构深潜

下一篇04-session.md --- 会话管理

相关推荐
Artech1 小时前
[MAF预定义ChatClient中间件-02]FunctionInvokingChatClient——实现ReAct循环和人机交互的大功臣
ai·agent·react·maf·ichatclient
Devin~Y1 小时前
从Spring Boot到AI Agent:大厂Java微服务面试三轮实战问答解析
java·spring boot·redis·spring cloud·微服务·ai·kafka
brave_zhao1 小时前
http 403 HTTP 403(Forbidden)表示服务器理解请求,但拒绝授权访问
java
爱吃羊的老虎1 小时前
【JAVA】python转java:Spring Boot 如何处理 Web 请求
java·前端·spring boot·http
装不满的克莱因瓶1 小时前
DDD 设计与 Maven 多模块拆分:从单体项目到领域驱动架构实践
java·架构·maven·ddd
码不停蹄的玄黓1 小时前
SpringBoot 循环依赖解决方案
java·spring boot·后端
装不满的克莱因瓶1 小时前
Spring 全家桶与 Spring 6 新特性详解:从 IoC 到云原生时代
java·spring·云原生·jdk·新特性·spring6
ch.ju1 小时前
Java程序设计(第3版)第四章——私有属性
java·开发语言
装不满的克莱因瓶1 小时前
JSON 处理与内嵌 Tomcat 部署:Spring Boot 如何实现前后端数据交互与一键启动?
java·spring boot·spring·架构·tomcat·json