Agent Scope Java 2.x 系列【16】Harness:工作区(Workspace)

文章目录

  • [1. 概述](#1. 概述)
    • [1.1 设计理念](#1.1 设计理念)
    • [1.2 四大核心设计原则](#1.2 四大核心设计原则)
      • [1.2.1 智能体定义与进化的唯一可信源](#1.2.1 智能体定义与进化的唯一可信源)
      • [1.2.2 文件按生命周期分层隔离存储](#1.2.2 文件按生命周期分层隔离存储)
      • [1.2.3 原生多租户数据隔离](#1.2.3 原生多租户数据隔离)
      • [1.2.4 工作区与文件存储层解耦](#1.2.4 工作区与文件存储层解耦)
  • [2. 工作区目录](#2. 工作区目录)
    • [2.1 工作区逻辑目录布局](#2.1 工作区逻辑目录布局)
    • [2.2 存储兼容特性](#2.2 存储兼容特性)
    • [2.3 自动生成规则](#2.3 自动生成规则)
    • [2.4 写入工作区安全规范](#2.4 写入工作区安全规范)
      • [2.4.1 路径入参安全校验规则](#2.4.1 路径入参安全校验规则)
      • [2.4.2 文件写入标准调用方式](#2.4.2 文件写入标准调用方式)
  • [3. 入门案例](#3. 入门案例)
    • [3.1 构建 HarnessAgent](#3.1 构建 HarnessAgent)
    • [3.2 编写 AGENTS.md](#3.2 编写 AGENTS.md)
    • [3.3 按需关闭子系统](#3.3 按需关闭子系统)
  • [4. 重点目录](#4. 重点目录)
    • [4.1 skills/ --- 可复用技能包](#4.1 skills/ — 可复用技能包)
    • [4.2 subagents/ --- 子 Agent 声明](#4.2 subagents/ — 子 Agent 声明)
    • [4.3 tools.json --- 工具白名单与 MCP 配置](#4.3 tools.json — 工具白名单与 MCP 配置)
    • [4.4 plans/ --- 计划文件](#4.4 plans/ — 计划文件)
    • [4.5 agents/<agentId>/ --- 运行时数据](#4.5 agents// — 运行时数据)
    • [4.6 knowledge/ --- 领域知识库](#4.6 knowledge/ — 领域知识库)

1. 概述

1.1 设计理念

工作区(Workspace)是 HarnessAgent 智能体定义与自我进化的唯一可信源source of truth)。

核心特性:

  • 智能体身份定位、行为规则、迭代学习成果全部通过目录结构 + Markdown/JSON 普通文件承载
  • 配置不硬编码嵌入业务代码、不强制绑定数据库表,文件即配置、文件即资产、文件即演化记录。

1.2 四大核心设计原则

1.2.1 智能体定义与进化的唯一可信源

所有智能体基础配置(它是谁、怎么行事)均可在工作区目录中以文件形式定义,全部配置项均为可选:

配置内容 存储文件路径
人设、行为约束、系统提示词 AGENTS.md
私有领域知识库、参考附件 knowledge/KNOWLEDGE.md + 配套资源文件
可复用技能能力包 skills/<技能名>/SKILL.md
内嵌子智能体配置 subagents/<子AgentID>.md
工具调用白名单、MCP服务配置 tools.json

双向等价适配

文件配置与代码 API 配置完全对等:代码可通过链式构建方法 systemPrompt()skill()subagent()toolsConfig() 传入一模一样的配置参数,两种方式可自由切换、混用。

原生多租户能力

文件化定义核心价值:同一套 Agent 业务代码逻辑,无需分支改造、无需多环境部署,仅新增用户专属覆盖目录,即可为不同用户分配独立人设、知识库、技能集合,快速实现千人千面定制。

智能体运行过程中跨会话学习、沉淀的内容由框架后台自动写入工作区,无需开发者手动维护生命周期:

  1. 长期记忆MEMORY.md + memory/ 分片文件;后台任务自动从对话抽取事实、压缩降噪,每轮推理自动注入系统提示词。
  2. 自学习技能 :存储于skills/目录;Agent 从成功执行案例中自主生成技能草稿,可配置人工审批闸门,审批通过后转为正式复用技能;后台托管过期技能老化归档。
  3. 任务计划文件 :存放于plans/;规划模式(Plan Mode)下生成的执行计划持久保存、跨调用复用,实现思考环节与执行环节解耦。
  4. 大体积工具输出压缩落盘 :超长工具返回内容写入磁盘,上下文仅保留首尾预览片段+文件读取指针,Agent 可按需重读完整内容,避免上下文窗口溢出。
  5. 全量会话日志 :路径agents/<agentId>/sessions/;原始对话完整追加存储,永不自动压缩删除,支持全量溯源排查。

进化数据默认长期留存:

  • 记忆持续累积、日志只增不删
  • 各模块生命周期维护规则可单独配置调控

关键区分:瞬时运行上下文 AgentState 不属于工作区

AgentState 是单次对话中途的易失快照(对话缓冲、滚动摘要、权限、任务、计划元数据等),独立存储在 AgentStateStore,和工作区文件树物理隔离。

1.2.2 文件按生命周期分层隔离存储

工作区同一目录树内,内部区分三条独立读写链路,三类数据互不干扰:

类型 写入方 读取方 典型文件示例
静态资产 研发/运维人工编辑 框架每轮推理注入、按需加载 AGENTS.md、knowledge/、skills/、subagents/、tools.json
运行时产物 框架/Agent自动写入 下次调用自动还原加载 agents//sessions/、agents//tasks/、plans/
长期累积记忆 Agent推理+后台托管任务 每轮注入提示词、Agent工具查询 MEMORY.md、memory/日期分片文件

目录统一打包仅为部署便捷性(复制整个目录即可迁移一套完整 Agent),底层读写逻辑完全分离。

1.2.3 原生多租户数据隔离

依靠单一隔离域 IsolationScope 对工作区文件、存储数据分桶隔离,业务层无需手写分区、过滤逻辑;隔离域定义数据共享边界:

IsolationScope 枚举 数据共享范围 适用场景
SESSION 单个会话完全独立隔离 一次性临时沙箱、单次任务隔离
USER(默认) 同一用户ID下全部会话互通记忆、技能 普通C端用户,多端会话同步学习;无userId时自动降级为SESSION
AGENT 该Agent实例下所有用户共用一套知识库 标准化公共知识库型智能体
GLOBAL 全局所有Agent、用户共用同一个存储桶 谨慎使用,多实例资源竞争风险高

注意事项:

  • 不同存储介质下隔离落地形态不同:本地磁盘为路径前缀、共享 KV 为命名空间、容器沙箱为独立状态槽位;
  • AgentState 拥有一套正交寻址逻辑:不受 IsolationScope 影响,始终以 (userId, sessionId) 作为唯一存储键存入独立 AgentStateStore
  • HarnessAgent 实例可支撑数千并发用户,租户之间数据物理隔离、零泄露。

1.2.4 工作区与文件存储层解耦

同一套标准目录结构可无缝对接三类存储载体,切换部署形态无需修改 Agent 业务代码:

  1. 本地本机磁盘文件系统
  2. 分布式共享 KV 存储(RedisJDBC数据库)
  3. 隔离沙箱容器内部文件系统

这一解耦设计是实现一套代码、多形态部署(单机/集群/容器沙箱) 的底层核心支撑。

2. 工作区目录

2.1 工作区逻辑目录布局

标准逻辑根路径.agentscope/workspace/

说明:该路径仅为本地磁盘默认物理位置,属于逻辑目录规范,存储载体可无缝切换,相对路径结构全程保持不变。

复制代码
.agentscope/workspace/
├── AGENTS.md                    # 静态资产:智能体人设、系统指令、行为约束规则
├── MEMORY.md                    # 长期记忆:汇总提炼后的全局事实摘要
├── tools.json                   # 静态资产:MCP服务配置、工具调用白名单(可选配置)
├── memory/                      # 长期记忆:按日期拆分的原始记忆流水
│   └── YYYY-MM-DD.md
├── knowledge/                   # 静态资产:专属领域知识库与附件资源
│   ├── KNOWLEDGE.md
│   └── 各类参考文档/素材文件
├── skills/                      # 静态资产:可复用技能包,一个技能对应一个子目录
│   └── <skill-name>/SKILL.md
├── subagents/                   # 静态资产:子智能体配置,文件名等于子Agent唯一ID
│   └── <agent-id>.md
├── plans/                       # 运行时产物:规划模式持久化执行方案
│   └── PLAN.md
└── agents/<agentId>/            # 运行时根目录:单个智能体专属运行数据
    ├── sessions/                # 运行时产物:全量会话日志与会话索引
    │   ├── sessions.json
    │   └── <sessionId>.log.jsonl # 完整原始对话日志,永久追加不压缩
    └── tasks/                   # 运行时产物:后台异步任务、子任务执行记录
        └── <sessionId>.json

2.2 存储兼容特性

  1. 布局为逻辑统一规范 ,不绑定物理存储介质:
    • 本地部署:直接映射服务器本机磁盘目录;
    • 分布式集群:依托 RemoteFilesystemSpec 对接 RedisJDBC、对象存储 OSS
    • 安全隔离场景:通过 SandboxFilesystemSpec 完整映射至容器沙箱内部;
  2. 所有文件相对路径在三种存储模式下完全对齐,切换存储后端无需修改 Agent 业务代码;
  3. 存储切换统一由框架 filesystem 配置项控制,全文档配置、读写逻辑均基于此套标准逻辑布局实现。

2.3 自动生成规则

AGENTS.md 核心手动文件

  • 仅此文件需要人工编写,属于非强制文件;
  • 缺失时 Agent 可正常运行,只是不会注入人设、行为约束、系统提示词。

tools.json 可选手动配置文件

  • MCP 服务、工具白名单配置,按需手动新建;
  • 不创建则无工具权限约束、未接入 MCP

其余目录/文件由框架按需自动创建

触发条件 自动生成资源
代码配置记忆压缩 .compaction(...) MEMORY.mdmemory/ 日期分片目录
注入子Agent配置 Subagent Spec subagents/ 子智能体配置目录
加载自定义技能包 skills/ 技能存放目录
开启规划模式 Plan Mode plans/ 持久化计划目录
执行任意一次 call() 调用任务 agents/<agentId>/ 运行时根目录(内含sessions、tasks)

2.4 写入工作区安全规范

2.4.1 路径入参安全校验规则

additionalContextFilewriteUtf8WorkspaceRelativememory_get 等读写接口统一接收工作区相对路径,框架内置路径穿越防护校验:

  • 拦截 ../../../ 等向上跳转路径写法;
  • 禁止访问工作区目录树以外的宿主系统文件(如 /etc/passwd、系统配置、宿主业务文件等);
  • 所有文件读写操作被约束在当前隔离域工作区逻辑目录内。

2.4.2 文件写入标准调用方式

写入、修改、读取工作区文件,必须通过 HarnessAgent#getWorkspaceManager() 获取管理器操作

禁止直接使用原生 java.nio.Files,原因:

  1. 沙箱部署模式:java.nio.Files 会写入宿主机磁盘,而非容器隔离沙箱内部工作区;
  2. 分布式共享存储(Redis/JDBC/OSS)模式:原生文件 API 无法操作 KV /对象存储,会直接落盘本地磁盘,数据存储错位、多实例数据不一致。

唯一豁免场景: 仅框架 Builder 装配初始化阶段可使用原生文件 API,允许使用 java.nio.Files,典型场景:

  • initWorkspaceIfAbsent 初始化种子文件(自动生成基础 AGENTS.md 模板);
  • 阶段特征:尚未生成完整运行时上下文、未初始化 WorkspaceManager 实例;
  • 设计目的:仅用于本地模板资源落地,不属于 Agent 运行期业务读写逻辑。

3. 入门案例

3.1 构建 HarnessAgent

最简构建,指定工作区路径即可运行。不传 workspace 则默认 ${user.dir}/.agentscope/workspace

java 复制代码
HarnessAgent agent = HarnessAgent.builder()
        .name("MyAgent")
        .model(model)
        .workspace(Paths.get(".agentscope/workspace"))
        .additionalContextFile("SOUL.md")         // 可选:额外注入工作区内的文件
        .additionalContextFile("PREFERENCES.md")
        .maxContextTokens(8000)                   // 可选:MEMORY 注入的 token 预算
        .build();

3.2 编写 AGENTS.md

workspace/AGENTS.md 中定义智能体的人设和行为约束,框架每轮推理自动注入 system prompt。不创建该文件 Agent 也能正常运行,只是没有人设注入。

markdown 复制代码
# MyAgent

你是 XX 助手,遵循以下行为约定。

## 行为
- 用中文回答用户问题
- 不确定时主动询问,不编造信息
- 涉及文件操作前先确认路径

## 限制
- 不执行删除命令
- 不访问工作区以外的路径

3.3 按需关闭子系统

以下方法用于调试或自行接管子系统时关闭对应能力:

方法 关闭的子系统
disableWorkspaceContext() System prompt 注入(AGENTS.md / MEMORY.md / knowledge/
disableMemoryHooks() 记忆 flush + 后台维护
disableMemoryTools() memory_search / memory_get / session_search 工具
disableSubagents() 整个子 Agent 子系统
disableDynamicSkills() 每轮动态合并技能(改为 build 时一次性加载)
disableToolsConfig() 不读取 tools.json
disableSessionPersistence() AgentState 自动持久化

4. 重点目录

4.1 skills/ --- 可复用技能包

技能是"写好的能力包"------一个子目录放一份 SKILL.mdYAML frontmatter + 指令正文),可附带参考文档和脚本。

复制代码
skills/code-reviewer/
├── SKILL.md                     # name + description (YAML) + 给 agent 的指令
├── references/style-guide.md    # 可选:agent 按需 read_file
└── scripts/run-checks.sh        # 可选:agent 通过 shell 工具调用

注册优先级(低 → 高,重名时上层覆盖):

优先级 注册方式 示例
1(最低) projectGlobalSkillsDir(Path) ~/.agentscope/skills/
2 skillRepository(...) Git / Nacos / MySQL / classpath
3 workspace/skills/ 工作区共用
4(最高) <userId>/skills/ 用户隔离,覆盖以上所有

每轮推理前 DynamicSkillMiddleware 重新合成 → 在 system prompt 中渲染为 <available_skills> 块(只列 name + description),agent 判断相关后通过 load_skill_through_path 按需加载详情。

4.2 subagents/ --- 子 Agent 声明

每个 <agent-id>.md 声明一个子 Agent(文件名即 agent_id)。YAML frontmatter 描述身份和约束,正文是子 Agent 的系统提示。

markdown 复制代码
---
description: 代码评审专家。当用户需要 review PR、找代码风格问题时使用。
workspace:
  mode: isolated          # isolated(默认)| shared
model: qwen3-max          # 可选;默认继承父 Agent
tools: [read_file, grep_files]  # 可选;工具白名单
---

你是一个专注代码评审的子 agent...

加载机制AgentSpecLoader 在构建期非递归扫描 workspace/subagents/*.md,再合并通过 .subagent(SubagentDeclaration...) 编程注册的声明。主 Agent 通过 agent_spawn agent_id="reviewer" task="..." 调用。

4.3 tools.json --- 工具白名单与 MCP 配置

工作区根目录下的 JSON 文件,框架在 build() 时一次性读取。

json 复制代码
{
  "allow": ["read_file", "grep_files", "execute"],
  "deny":  ["write_file"],
  "mcpServers": {
    "amap": {
      "transport": "streamableHttp",
      "url": "https://mcp.amap.com/mcp?key=${AMAP_API_KEY}"
    },
    "local-py": {
      "transport": "stdio",
      "command": "python",
      "args": ["mcp_servers/my_server.py"],
      "env": {"PYTHONUNBUFFERED": "1"}
    }
  }
}

关键行为:

规则 说明
allow 非空时只允许列出的工具(白名单模式)
deny 列出的工具一律不暴露,优先级高于 allow
过滤范围 allow / deny所有工具注册完成后 应用,也会过滤 Harness 内置工具(read_filememory_searchagent_spawn 等)。用白名单时务必把要保留的内置工具一并列出
环境变量 ${ENV_VAR} 语法替换;未设置时 warning + 空字符串
编程替代 可用 builder.toolsConfig(ToolsConfig.builder()...) 编程注入;disableToolsConfig() 完全关闭读取
共享存储 远端为上层、本机模板为下层的 overlay 模式

4.4 plans/ --- 计划文件

Plan Modeplan_write 写入的当前计划。默认路径 plans/PLAN.md,可通过 .planFileDirectory("design-docs") 修改。

复制代码
plans/
└── PLAN.md    # plan_write 写入的当前计划内容

PlanModeContext(是否处于 plan 阶段、当前计划文件路径)属于运行时状态,跟随 AgentState 通过 AgentStateStore 持久化(默认 ~/.agentscope/state/<agentId>/,在工作区之外)。plans/ 下仅存储 markdown 内容本身。

4.5 agents// --- 运行时数据

框架自动维护的运行时根目录,一般无需手动操作:

复制代码
agents/<agentId>/
├── sessions/
│   ├── sessions.json            # 该 agent 的会话索引
│   └── <sessionId>.log.jsonl    # 原始对话日志,append-only,永不压缩
└── tasks/
    └── <sessionId>.json         # 子 agent 后台任务记录 (taskId → TaskRecord)

AgentState 序列化数据不在此处------它存储在配置的 AgentStateStore(默认 ~/.agentscope/state/<agentId>/)。跨节点恢复 / 多副本部署时需共享这些数据(RedisAgentStateStore + RemoteFilesystemSpec,或沙箱 + 分布式状态)。

4.6 knowledge/ --- 领域知识库

复制代码
knowledge/
├── KNOWLEDGE.md          # 入口/概览,全文注入 system prompt
├── api-reference.md
├── domain-terms.md
└── ...

加载策略:

  • KNOWLEDGE.md 全文进入 <domain_knowledge_context> 注入 system prompt
  • 同目录下其他文件(任意深度)只列出路径清单agent 通过 read_file / grep_files / glob_files 按需读取

这种目录存细节prompt 放索引 的模式,避免将整个知识库塞入 token 预算。