目录:
1. 如何优雅地驾驭长期运行的 AI Agent
2. 上下文压缩:让长期 Agent 永不“失忆“
3. 工作区(Workspace)文件即真理,目录即架构
4. 双层记忆系统 让 Agent 拥有真正的“长期大脑“
5. 文件系统一套代码,三种部署,零改动切换
6. 沙箱(Sandbox)让 Agent 在安全笼子里自由奔跑
7. 子 Agent 编排 文件驱动的多智能体协作架构
8. Skill技能让 Agent 从“会说话“进化为“会做事“
9. Plan Mode 让 Agent 先想清楚再动手
10. Channel Agent 通信的“神经系统“设计

工具(Tool)是 Agent 的双手,而技能(Skill)是 Agent 的"操作手册"。没有技能的 Agent 拿着锤子不知道该怎么敲;有了技能的 Agent,才能把工具组合成可复用的工作流。

一、引言:Tool ≠ Skill,这是两个层次的能力

在 Agent 开发中,一个常见的误区是把"注册了工具"等同于"具备了能力"。

// 注册了三个工具
agent.registerTool(new SearchFlightsTool());
agent.registerTool(new BookHotelTool());
agent.registerTool(new GetWeatherTool());

Agent 现在"有手"了,但它知道什么时候用哪个工具、按什么顺序、传什么参数、如何处理异常吗?

维度 Tool(工具) Skill(技能)
本质 原子操作 工作流编排知识
粒度 单次函数调用 多步骤流程 + 决策逻辑
载体 Java/Python 代码 Markdown 文档
谁编写 开发者 开发者 / 领域专家 / Agent 自己
可复用性 代码级复用 知识级复用,跨 Agent 共享
运行时开销 函数调用 Prompt 注入(零执行开销)

AgentScope Harness 的技能系统正是为了填补这个鸿沟:用 Markdown 文件定义可复用的工作流知识,让 Agent 不仅"有手",还"知道怎么用"。

二、核心设计:文件即技能

2.1 技能的物理形态

每个技能是一个独立的 Markdown 文件,存放在工作区的 skills/ 目录下:

workspace/
└── skills/
    ├── flight-booking.md        ← 机票预订技能
    ├── hotel-recommendation.md  ← 酒店推荐技能
    ├── expense-report.md        ← 报销单生成技能
    └── data-pipeline.md         ← 数据处理流水线技能

2.2 技能文件结构

每个 .md 文件遵循 Front Matter + Body 的标准格式:

---
name: flight-booking
description: 根据用户需求搜索、比较并预订航班,支持多条件筛选和价格优化
tags: [travel, booking, flight]
tools:
  - search_flights
  - get_flight_details
  - book_flight
  - get_airport_info
version: "1.2"
author: travel-team
---

# Flight Booking Skill

## Trigger
当用户表达以下意图时激活本技能:
- 查询/搜索航班
- 比较机票价格
- 预订机票
- 询问航线信息

## Workflow

### Step 1: 需求澄清
确认以下必要信息(缺失则主动询问):
- 出发城市、到达城市
- 出发日期(返程日期,如适用)
- 乘客人数和舱位偏好
- 预算范围(可选)

### Step 2: 搜索与筛选
1. 调用 `search_flights` 获取候选航班列表
2. 如果用户指定了机场偏好,调用 `get_airport_info` 验证机场代码
3. 按用户优先级排序(价格 / 时间 / 直飞优先)

### Step 3: 结果呈现
以表格形式展示 Top 3 选项:

| 航班号 | 起飞-到达 | 时长 | 价格 | 备注 |
每个选项附带简短推荐理由。

### Step 4: 确认与预订
1. 用户选择后,调用 `get_flight_details` 获取详细信息
2. 向用户确认关键信息(日期、乘客、价格)
3. 调用 `book_flight` 完成预订
4. 返回预订确认号和行程摘要

## Error Handling
- `search_flights` 无结果:建议调整日期或邻近机场
- `book_flight` 失败:保留候选列表,提示用户重新选择
- 超时:告知用户稍后重试,不自动重复预订

## Constraints
- 绝不未经用户确认就执行 `book_flight`
- 价格信息必须来自工具返回值,禁止估算
- 儿童/婴儿票价需特别标注

2.3 Front Matter 字段详解

字段 必填 类型 说明
name String 技能唯一标识
description String 能力描述,用于匹配和展示
tags List 标签,支持分类检索
tools List 技能依赖的工具白名单
version String 版本号,支持演进管理
author String 作者/团队
enabled Boolean 是否启用(默认 true)

三、技能装配机制:从文件到 Prompt

3.1 构建期扫描

HarnessAgent agent = HarnessAgent.builder()
    .name("travel-assistant")
    .model(model)
    .workspace(Path.of("./workspace"))
    // 框架自动扫描 workspace/skills/*.md
    // 无需手动注册任何技能
    .build();

扫描流程:

HarnessAgent.build()
    │
    ▼ WorkspaceContextHook
    │
    ├── listDir("skills/")
    │     → [flight-booking.md, hotel-recommendation.md, ...]
    │
    ├── 逐个解析 Front Matter
    │     → SkillSpec(name, description, tools, ...)
    │
    ├── 过滤 enabled=true 的技能
    │
    └── 注入主 Agent system prompt
          → 技能摘要列表(name + description)

3.2 两阶段注入策略

技能内容不会全部塞进 system prompt(那会撑爆上下文)。框架采用两阶段注入

┌─────────────────────────────────────────────────────────────┐
│  Stage 1: System Prompt(每轮都有)                           │
│                                                              │
│  ## Available Skills                                         │
│  - flight-booking: 根据用户需求搜索、比较并预订航班...          │
│  - hotel-recommendation: 基于偏好推荐酒店...                  │
│  - expense-report: 自动生成差旅报销单...                      │
│                                                              │
│  Use `load_skill` tool to load full skill instructions.      │
└─────────────────────────────────────────────────────────────┘

                    ↓ Agent 判断需要某个技能时

┌─────────────────────────────────────────────────────────────┐
│  Stage 2: load_skill 工具调用(按需加载)                      │
│                                                              │
│  Agent 调用: load_skill(name="flight-booking")               │
│  框架返回: flight-booking.md 的完整 Body 内容                  │
│  Agent 将完整工作流纳入当前推理上下文                            │
└─────────────────────────────────────────────────────────────┘

3.3 为什么是两阶段?

方案 Token 消耗 信息完整性 适用场景
全量注入所有技能 💥 爆炸 ✅ 完整 技能极少(<3个)
仅注入摘要 + 按需加载 ✅ 可控 ✅ 完整 技能较多(推荐)
完全不注入 ✅ 零 ❌ Agent 不知道有哪些技能 不可用

两阶段注入在 token 效率和信息完整性之间取得了最佳平衡:

  • 摘要列表让 Agent “知道自己会什么”;
  • load_skill 让 Agent “在需要时学会怎么做”。

四、技能 vs 工具 vs 子 Agent:三者定位辨析

这是 Harness 中最容易混淆的三个概念。它们不是替代关系,而是互补的不同抽象层:

┌─────────────────────────────────────────────────────────────┐
│                    能力分层模型                                │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Skill(技能)= 工作流知识                             │   │
│  │  "如何组合工具完成一个业务目标"                          │   │
│  │  载体:Markdown · 注入方式:Prompt · 执行者:当前 Agent │   │
│  └──────────────────────┬──────────────────────────────┘   │
│                         │ 使用                              │
│                         ▼                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Tool(工具)= 原子操作                               │   │
│  │  "执行一个具体的函数调用"                              │   │
│  │  载体:代码 · 注入方式:Function Schema · 执行者:运行时 │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Sub-Agent(子 Agent)= 独立能力单元                   │   │
│  │  "委派一个完整任务给另一个 Agent"                       │   │
│  │  载体:Markdown · 注入方式:委派工具 · 执行者:独立实例  │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

4.1 决策指南

你的需求 选择 理由
封装一个 API 调用 Tool 原子操作,不需要流程知识
定义"如何用多个工具完成一个业务目标" Skill 工作流知识,当前 Agent 自己执行
需要一个完全独立的能力单元 Sub-Agent 独立上下文、独立工具集、独立推理
让非技术人员定义业务流程 Skill Markdown 编辑,无需写代码
需要跨 Agent 复用工作流 Skill 复制 .md 文件即可
需要并行执行多个独立任务 Sub-Agent 子 Agent 可并行委派

4.2 协作示例

用户:"帮我订明天去上海的出差行程"

主 Agent 推理:
  → 加载 skill: travel-planning(工作流知识)
  → 按技能定义的 Workflow 执行:
      Step 1: 调用 search_flights(Tool)
      Step 2: 调用 search_hotels(Tool)
      Step 3: delegate_to_expense_calculator(Sub-Agent)
      Step 4: 整合结果,生成行程单

技能定义了"做什么、怎么做",工具提供了"做的能力",子 Agent 承担了"独立子任务"。

五、技能的运行时生命周期

5.1 完整执行流程

用户发送消息
    │
    ▼ WorkspaceContextHook
    │  扫描 skills/ → 注入摘要列表到 system prompt
    │
    ▼ ReAct 推理循环
    │
    ├── Agent 判断需要某个技能
    │     │
    │     ▼ 调用 load_skill(name="flight-booking")
    │     │
    │     ▼ 框架读取 skills/flight-booking.md
    │        返回完整 Body 内容
    │     │
    │     ▼ Agent 将工作流纳入推理上下文
    │        按 Workflow 步骤依次执行
    │     │
    │     ├── 调用 search_flights(Tool)
    │     ├── 调用 get_flight_details(Tool)
    │     └── 调用 book_flight(Tool)
    │
    ▼ 返回结果给用户

5.2 技能内容的缓存

load_skill 的结果在当前会话内缓存,避免重复读取文件:

第 1 轮: load_skill("flight-booking") → 读文件 → 缓存
第 2 轮: load_skill("flight-booking") → 命中缓存 → 零 IO
第 3 轮: 新会话 → 缓存失效 → 重新读文件

5.3 热更新

由于技能是从文件实时读取的,修改 .md 文件后,下一次 load_skill 立即获取最新内容:

# 更新技能
vim workspace/skills/flight-booking.md

# 无需重启服务
# 下一次 call() 中 Agent 调用 load_skill 时自动获取新版本

六、高级特性

6.1 技能依赖声明

技能可以在 Front Matter 中声明对其他技能的依赖:

---
name: travel-planning
description: 端到端差旅规划,包含机票、酒店、报销
depends_on:
  - flight-booking
  - hotel-recommendation
  - expense-report
---

当 Agent 加载 travel-planning 时,框架可以:

  • 自动预加载依赖技能的摘要
  • 在技能 Body 中引用依赖技能的名称
  • 校验依赖技能是否存在

6.2 技能模板变量

技能 Body 支持运行时变量替换:

## 约束
- 当前用户:{{user.name}}
- 报销标准:{{policy.max_flight_price}} 元/程
- 当前日期:{{current_date}}

变量来源:

  • RuntimeContext 中的用户信息
  • 工作区中的配置文件
  • 框架内置变量(如 current_date)

6.3 技能版本管理

---
name: flight-booking
version: "1.2"
---

结合 Git 版本控制,技能的演进历史完全可追溯:

git log --oneline workspace/skills/flight-booking.md
# a3f2c1d v1.2: 增加儿童票价标注
# b8e4a2f v1.1: 增加邻近机场建议
# c9d5b3e v1.0: 初始版本

6.4 技能禁用与灰度

---
name: experimental-booking
enabled: false  # 暂时禁用
---

或通过标签实现灰度:

---
name: flight-booking-v2
tags: [travel, booking, beta]
enabled: true
---

框架可以根据配置决定是否加载带特定标签的技能。

七、与其他子系统的协作

┌─────────────────────────────────────────────────────────────┐
│                     技能系统生态                               │
│                                                              │
│  ┌──────────────┐                                           │
│  │ skills/*.md  │ ← 技能文件(人类/Agent 编辑)               │
│  └──────┬───────┘                                           │
│         │ 构建期扫描                                         │
│         ▼                                                   │
│  ┌──────────────┐    Stage 1: 摘要注入                      │
│  │ System Prompt│ ◀── name + description                    │
│  └──────┬───────┘                                           │
│         │ Agent 判断需要                                     │
│         ▼                                                   │
│  ┌──────────────┐    Stage 2: load_skill                    │
│  │ 完整技能内容  │ ──▶ Agent 推理上下文                       │
│  └──────┬───────┘                                           │
│         │ 按 Workflow 执行                                   │
│         ▼                                                   │
│  ┌──────────────────────────────────────────────────┐      │
│  │              执行面                                │      │
│  │  ┌──────┐  ┌──────────┐  ┌──────────────────┐   │      │
│  │  │Tools │  │Sub-Agents│  │ Memory/Knowledge │   │      │
│  │  │原子  │  │委派      │  │ 查阅/写入         │   │      │
│  │  │操作  │  │独立任务  │  │                   │   │      │
│  │  └──────┘  └──────────┘  └──────────────────┘   │      │
│  └──────────────────────────────────────────────────┘      │
└─────────────────────────────────────────────────────────────┘
子系统 与技能的关系
Workspace 技能文件存储在工作区,天然 Git 友好
工具 技能声明依赖的工具白名单,框架可校验
子 Agent 技能 Workflow 中可以包含委派步骤
记忆 技能执行过程中可读写 MEMORY.md
知识 技能 Body 可引用 knowledge/ 中的领域知识
沙箱 技能中涉及的命令执行在沙箱内隔离运行
压缩 技能内容作为工具结果参与压缩策略

八、实战:从零构建一个技能

8.1 场景:报销单生成

Step 1: 创建技能文件
touch workspace/skills/expense-report.md
Step 2: 编写规格
---
name: expense-report
description: 根据差旅行程自动生成符合公司政策的报销单
tags: [finance, travel, reimbursement]
tools:
  - calculate_expense
  - validate_policy
  - generate_pdf
version: "1.0"
---

# Expense Report Generation

## Trigger
当用户要求生成报销单、提交差旅费用时激活。

## Workflow

### Step 1: 收集行程信息
从对话上下文中提取或主动询问:
- 出差日期范围
- 交通费用明细(航班/火车/打车)
- 住宿费用明细
- 餐饮补贴天数

### Step 2: 政策校验
调用 `validate_policy` 检查:
- 机票是否超出经济舱标准
- 酒店单价是否在限额内
- 餐饮补贴天数是否合理

如有违规项,列出并请求用户确认或调整。

### Step 3: 费用计算
调用 `calculate_expense` 汇总:
- 交通费小计
- 住宿费小计
- 餐饮补贴小计
- 总计

### Step 4: 生成报销单
调用 `generate_pdf` 生成 PDF 文件。
返回文件路径和费用摘要。

## Output Format

📋 差旅报销单
━━━━━━━━━━━━━━━
出差人:{{user.name}}
日期:{{trip.start_date}} ~ {{trip.end_date}}
交通费:¥{{transport_total}}
住宿费:¥{{hotel_total}}
餐饮补贴:¥{{meal_total}}
━━━━━━━━━━━━━━━
合计:¥{{grand_total}}
📎 报销单 PDF:{{pdf_path}}

## Constraints
- 所有金额必须来自工具计算结果,禁止手动加总
- 政策校验未通过时,不得生成报销单
- PDF 文件名格式:报销单_姓名_YYYYMMDD.pdf
Step 3: 验证生效
// 无需改代码,下一轮 call() 自动发现新技能
agent.call(List.of(new UserMessage("帮我生成这次出差的报销单")));
// Agent 会自动 load_skill("expense-report") 并按 Workflow 执行

九、最佳实践

9.1 技能编写指南

原则 说明
Trigger 要明确 清晰定义激活条件,避免误触发
Workflow 要分步 每步有明确的输入、动作、输出
Error Handling 要覆盖 每个工具调用都要考虑失败场景
Constraints 要具体 “不要编造"不如"价格必须来自工具返回值”
Output Format 要标准化 便于下游消费和用户阅读
description 要精确 这是 Agent 决定是否加载技能的唯一依据

9.2 技能组织策略

策略 适用场景
一个业务目标一个技能 大多数场景
大技能拆分为小技能 + 组合技能 复杂流程
通用技能放公共目录,专用技能放 Agent 专属目录 多 Agent 共享
技能命名使用 - 格式 提高可读性和检索效率

9.3 常见反模式

# ❌ description 太模糊
description: 处理各种事务

# ❌ Workflow 没有分步
## Workflow
调用所有相关工具然后生成结果。   # Agent 不知道顺序和逻辑

# ❌ 缺少 Error Handling
# 工具失败了怎么办?Agent 只能猜

# ❌ Constraints 太笼统
## Constraints
- 要准确                    # 什么叫"准确"?
- 要安全                    # 什么叫"安全"?

# ❌ 技能体过大(>2000 tokens)
# 考虑拆分为多个小技能 + 组合技能

十、设计哲学总结

1. 知识外置,能力内化

技能将"怎么做"的知识从代码和模型权重中外置为 Markdown 文件。这使得知识可以被人类审查、编辑、版本管理,也使得同一个模型可以通过加载不同技能获得不同能力。

2. 按需加载,Token 友好

两阶段注入确保了只有真正需要的技能才会占用上下文窗口。摘要列表是"目录",完整内容是"正文"——你不会把整本书塞进脑子里,只在需要时翻开对应章节。

3. 文件即接口,人机共编

技能文件是人类和 Agent 的共同接口。开发者写初始版本,领域专家补充业务细节,Agent 自己在实践中提出改进建议。这种"人机共编"模式让技能持续进化。

4. 组合优于继承

技能之间是组合关系,不是继承关系。一个大技能可以引用多个小技能,一个小技能可以被多个大技能复用。这种扁平的组合模型比深层继承更容易理解和维护。

5. 技能是可治理的能力单元

每个技能有名称、版本、作者、标签、启用状态。这不是"随意的 prompt 片段",而是可治理、可审计、可演进的能力资产。

十一、结语

AgentScope Harness 的技能系统,回答了一个关键问题:

如何让 Agent 从"拥有工具"进化为"掌握工作流"?

答案是:把工作流知识从代码和模型中解放出来,变成人类可读、机器可解析、Agent 可按需加载的文件。
当你把技能看作"操作手册"而非"prompt 模板"时,很多设计决策就变得自然而然了:

  • 操作手册可以独立于执行者存在 → 跨 Agent 复用
  • 操作手册可以分章节按需查阅 → 两阶段注入
  • 操作手册可以由专家编写 → 领域知识沉淀
  • 操作手册可以有版本号 → 能力演进可追溯
  • 操作手册可以包含错误处理 → 鲁棒性工作流

如果你正在构建需要复杂工作流的 Agent 系统,这套"文件即技能"的设计思路值得深入研究和借鉴。它让 Agent 的能力建设从"写代码"变成了"写文档"——这不仅是技术范式的转变,更是让 AI 能力回归人类可理解、可参与、可治理的工程哲学。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐