第19章 Plan任务规划管理
复杂任务的执行需要有条理的规划和跟踪。AgentScope-Java提供了PlanNotebook组件,让Agent能够创建、管理和追踪结构化的任务计划。本章将详细介绍Plan系统的设计和使用。
19.1 Plan系统概述
19.1.1 为什么需要任务规划
┌─────────────────────────────────────────────────────────────────┐
│ 无规划 vs 有规划 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 无规划执行: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 用户: "帮我建一个电商网站" │ │
│ │ Agent: (直接开始写代码...) → 遗漏功能、顺序混乱 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 有规划执行: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 用户: "帮我建一个电商网站" │ │
│ │ Agent: 创建计划... │ │
│ │ ├─ [x] 1. 项目初始化 │ │
│ │ ├─ [ ] 2. 用户认证模块 │ │
│ │ ├─ [ ] 3. 商品管理系统 │ │
│ │ ├─ [ ] 4. 购物车功能 │ │
│ │ ├─ [ ] 5. 支付集成 │ │
│ │ └─ [ ] 6. 部署上线 │ │
│ │ → 有序执行、进度可视、可追踪 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
19.1.2 Plan系统核心组件
| 组件 | 说明 | 职责 |
|---|---|---|
| Plan | 计划模型 | 包含名称、描述、预期结果和子任务列表 |
| SubTask | 子任务模型 | 单个任务单元,有独立的状态和结果 |
| PlanNotebook | 计划管理器 | 提供工具方法管理计划,自动注入提示 |
| PlanStorage | 存储接口 | 持久化历史计划 |
| PlanToHint | 提示生成器 | 将计划状态转换为Agent提示 |
┌─────────────────────────────────────────────────────────────────┐
│ Plan 系统架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PlanNotebook │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 工具方法 │ │ │
│ │ │ - create_plan - finish_subtask │ │ │
│ │ │ - revise_plan - finish_plan │ │ │
│ │ │ - update_subtask - view_subtasks │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Plan (当前计划) │ │ │
│ │ │ ├── name, description, expectedOutcome │ │ │
│ │ │ ├── state (TODO/IN_PROGRESS/DONE/ABANDONED) │ │ │
│ │ │ └── subtasks: List<SubTask> │ │ │
│ │ │ ├── SubTask 1 [DONE] │ │ │
│ │ │ ├── SubTask 2 [IN_PROGRESS] │ │ │
│ │ │ └── SubTask 3 [TODO] │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ ┌─────────────────┐ ┌─────────────────────────────┐ │ │
│ │ │ PlanStorage │ │ PlanToHint │ │ │
│ │ │ (历史计划存储) │ │ (生成上下文提示) │ │ │
│ │ └─────────────────┘ └─────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
19.2 Plan和SubTask模型
19.2.1 Plan模型
/**
* Plan - 计划模型
* 包含一系列有序的子任务
*/
public class Plan {
private String id; // 唯一标识(UUID)
private String name; // 计划名称(简洁,不超过10词)
private String description; // 详细描述(含约束和目标)
private String expectedOutcome; // 预期结果(具体可衡量)
private List<SubTask> subtasks; // 子任务列表
private PlanState state; // 计划状态
private String createdAt; // 创建时间
private String finishedAt; // 完成时间
private String outcome; // 实际结果
/**
* 创建计划
*/
public Plan(String name, String description,
String expectedOutcome, List<SubTask> subtasks) {
this.id = UUID.randomUUID().toString();
this.name = name;
this.description = description;
this.expectedOutcome = expectedOutcome;
this.subtasks = subtasks;
this.state = PlanState.TODO;
this.createdAt = ZonedDateTime.now().format(FORMATTER);
}
/**
* 完成计划
*/
public void finish(PlanState state, String outcome) {
this.state = state;
this.outcome = outcome;
this.finishedAt = ZonedDateTime.now().format(FORMATTER);
}
/**
* 转换为Markdown格式
*/
public String toMarkdown(boolean detailed) {
StringBuilder sb = new StringBuilder();
sb.append("# ").append(name).append("\n");
sb.append("**Description**: ").append(description).append("\n");
sb.append("**Expected Outcome**: ").append(expectedOutcome).append("\n");
sb.append("**State**: ").append(state.getValue()).append("\n");
sb.append("## Subtasks\n");
for (SubTask subtask : subtasks) {
sb.append(subtask.toMarkdown(detailed)).append("\n");
}
return sb.toString();
}
}
/**
* 计划状态枚举
*/
public enum PlanState {
TODO("todo"), // 待开始
IN_PROGRESS("in_progress"), // 进行中
DONE("done"), // 已完成
ABANDONED("abandoned"); // 已放弃
}
19.2.2 SubTask模型
/**
* SubTask - 子任务模型
* 计划中的单个工作单元
*/
public class SubTask {
private String name; // 任务名称
private String description; // 详细描述
private String expectedOutcome; // 预期结果
private SubTaskState state; // 任务状态
private String outcome; // 实际结果
private String createdAt; // 创建时间
private String finishedAt; // 完成时间
/**
* 创建子任务
*/
public SubTask(String name, String description, String expectedOutcome) {
this.name = name;
this.description = description;
this.expectedOutcome = expectedOutcome;
this.state = SubTaskState.TODO;
this.createdAt = ZonedDateTime.now().format(FORMATTER);
}
/**
* 完成子任务
*/
public void finish(String outcome) {
finish(SubTaskState.DONE, outcome);
}
/**
* 以指定状态完成子任务
*/
public void finish(SubTaskState state, String outcome) {
if (state != SubTaskState.DONE && state != SubTaskState.ABANDONED) {
throw new IllegalArgumentException(
"SubTask can only be finished with DONE or ABANDONED state");
}
this.state = state;
this.outcome = outcome;
this.finishedAt = ZonedDateTime.now().format(FORMATTER);
}
/**
* 转换为单行Markdown
*/
public String toOneLineMarkdown() {
String statusPrefix = switch (state) {
case TODO -> "- [ ]";
case IN_PROGRESS -> "- [ ] [WIP]";
case DONE -> "- [x]";
case ABANDONED -> "- [ ] [Abandoned]";
};
return statusPrefix + " " + name;
}
}
/**
* 子任务状态枚举
*/
public enum SubTaskState {
TODO("todo"), // 待开始
IN_PROGRESS("in_progress"), // 进行中
DONE("done"), // 已完成
ABANDONED("abandoned"); // 已放弃
}
19.3 PlanNotebook详解
19.3.1 创建和配置
import io.agentscope.core.plan.*;
import io.agentscope.core.plan.storage.*;
import io.agentscope.core.plan.hint.*;
// 使用Builder创建PlanNotebook
PlanNotebook planNotebook = PlanNotebook.builder()
.planToHint(new DefaultPlanToHint()) // 提示生成策略
.storage(new InMemoryPlanStorage()) // 存储后端
.maxSubtasks(10) // 最大子任务数
.needUserConfirm(true) // 是否需要用户确认
.keyPrefix("mainPlan") // 存储键前缀
.build();
// 将PlanNotebook添加到Agent
ReActAgent agent = ReActAgent.builder()
.name("PlanningAssistant")
.model(model)
.planNotebook(planNotebook) // 自动注册工具和Hook
.build();
// 或使用快捷方法启用默认配置
ReActAgent agent2 = ReActAgent.builder()
.name("PlanningAssistant")
.model(model)
.enablePlan() // 使用默认PlanNotebook
.build();
19.3.2 PlanNotebook工具方法
PlanNotebook提供10个工具方法供Agent调用:
| 工具名称 | 说明 | 参数 |
|---|---|---|
create_plan | 创建新计划 | name, description, expected_outcome, subtasks |
updateplaninfo | 更新计划信息 | name, description, expected_outcome |
revisecurrentplan | 修改子任务 | subtask_idx, action(add/revise/delete), subtask |
updatesubtaskstate | 更新子任务状态 | subtask_idx, state |
finish_subtask | 完成子任务 | subtask_idx, outcome |
view_subtasks | 查看子任务详情 | subtask_idx(可选) |
getsubtaskcount | 获取子任务数量 | 无 |
finish_plan | 完成或放弃计划 | outcome, abandoned |
viewhistoricalplans | 查看历史计划 | limit(可选) |
recoverhistoricalplan | 恢复历史计划 | plan_id |
19.3.3 工具方法示例
// create_plan - 创建计划
@Tool(name = "create_plan", description = "Create a plan by given name and sub-tasks")
public Mono<String> createPlan(
@ToolParam(name = "name",
description = "The plan name, should be concise and not exceed 10 words")
String name,
@ToolParam(name = "description",
description = "The plan description including constraints and targets")
String description,
@ToolParam(name = "expected_outcome",
description = "The expected outcome, specific and measurable")
String expectedOutcome,
@ToolParam(name = "subtasks",
description = "A list of subtasks with name, description, expected_outcome")
List<Map<String, Object>> subtasks
) {
// 创建计划逻辑...
Plan plan = new Plan(name, description, expectedOutcome, subtaskList);
currentPlan = plan;
return Mono.just("Plan '" + name + "' created successfully.");
}
// finish_subtask - 完成子任务
@Tool(name = "finish_subtask",
description = "Mark a subtask as done with actual outcome")
public Mono<String> finishSubtask(
@ToolParam(name = "subtask_idx",
description = "The index of subtask to finish, starting from 0")
int subtaskIdx,
@ToolParam(name = "outcome",
description = "The actual outcome achieved")
String outcome
) {
SubTask subtask = currentPlan.getSubtasks().get(subtaskIdx);
subtask.finish(outcome);
return Mono.just("Subtask '" + subtask.getName() + "' marked as done.");
}
// revise_current_plan - 修改计划
@Tool(name = "revise_current_plan",
description = "Revise the current plan by adding, revising or deleting a subtask")
public Mono<String> reviseCurrentPlan(
@ToolParam(name = "subtask_idx",
description = "The index of subtask to modify")
int subtaskIdx,
@ToolParam(name = "action",
description = "The action: add/revise/delete")
String action,
@ToolParam(name = "subtask",
description = "The subtask data for add/revise actions")
Map<String, Object> subtaskMap
) {
// 根据action执行相应操作...
}
19.4 自动提示注入
19.4.1 PlanToHint接口
/**
* 计划到提示的转换策略接口
*/
public interface PlanToHint {
/**
* 将计划转换为提示消息
*
* @param plan 当前计划
* @param needUserConfirm 是否需要用户确认
* @return 提示消息
*/
Msg toHint(Plan plan, boolean needUserConfirm);
}
19.4.2 DefaultPlanToHint实现
/**
* 默认的计划提示生成器
*/
public class DefaultPlanToHint implements PlanToHint {
@Override
public Msg toHint(Plan plan, boolean needUserConfirm) {
StringBuilder hint = new StringBuilder();
hint.append("<system-hint>\n");
hint.append("## Current Plan Status\n\n");
// 计划概览
hint.append("**Plan**: ").append(plan.getName()).append("\n");
hint.append("**State**: ").append(plan.getState().getValue()).append("\n");
hint.append("**Expected Outcome**: ").append(plan.getExpectedOutcome()).append("\n\n");
// 子任务列表
hint.append("### Subtasks:\n");
List<SubTask> subtasks = plan.getSubtasks();
int currentIdx = -1;
for (int i = 0; i < subtasks.size(); i++) {
SubTask subtask = subtasks.get(i);
hint.append(subtask.toOneLineMarkdown()).append("\n");
if (subtask.getState() == SubTaskState.IN_PROGRESS) {
currentIdx = i;
}
}
// 当前任务提示
if (currentIdx >= 0) {
SubTask current = subtasks.get(currentIdx);
hint.append("\n### Current Task:\n");
hint.append("**Name**: ").append(current.getName()).append("\n");
hint.append("**Description**: ").append(current.getDescription()).append("\n");
hint.append("**Expected Outcome**: ").append(current.getExpectedOutcome()).append("\n");
}
// 执行规则
hint.append("\n### Rules:\n");
hint.append("1. Focus on the current IN_PROGRESS subtask\n");
hint.append("2. Use `finish_subtask` when a subtask is completed\n");
hint.append("3. Use `update_subtask_state` to mark next task as IN_PROGRESS\n");
hint.append("4. Use `finish_plan` when all subtasks are done\n");
if (needUserConfirm) {
hint.append("5. Wait for user confirmation before proceeding\n");
}
hint.append("</system-hint>");
return Msg.builder()
.role(MsgRole.USER)
.content(new TextBlock(hint.toString()))
.build();
}
}
19.4.3 提示注入机制
PlanNotebook通过Hook机制在每次推理前注入提示:
// PlanNotebook内部Hook实现
public class PlanNotebookHook implements Hook {
private final PlanNotebook notebook;
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PreReasoningEvent e) {
Plan currentPlan = notebook.getCurrentPlan();
if (currentPlan != null) {
// 生成提示消息
Msg hint = notebook.getPlanToHint().toHint(
currentPlan,
notebook.isNeedUserConfirm()
);
// 注入到消息列表
List<Msg> messages = new ArrayList<>(e.getInputMessages());
messages.add(hint);
e.setInputMessages(messages);
}
}
return Mono.just(event);
}
}
19.5 计划存储
19.5.1 PlanStorage接口
/**
* 计划存储接口
*/
public interface PlanStorage {
/**
* 保存计划
*/
void save(Plan plan);
/**
* 获取所有历史计划
*/
List<Plan> getAll();
/**
* 根据ID获取计划
*/
Optional<Plan> getById(String id);
/**
* 删除计划
*/
void delete(String id);
}
19.5.2 InMemoryPlanStorage
/**
* 内存计划存储实现
*/
public class InMemoryPlanStorage implements PlanStorage {
private final Map<String, Plan> plans = new ConcurrentHashMap<>();
@Override
public void save(Plan plan) {
plans.put(plan.getId(), plan);
}
@Override
public List<Plan> getAll() {
return new ArrayList<>(plans.values());
}
@Override
public Optional<Plan> getById(String id) {
return Optional.ofNullable(plans.get(id));
}
@Override
public void delete(String id) {
plans.remove(id);
}
}
19.5.3 自定义存储实现
/**
* 数据库计划存储实现
*/
public class DatabasePlanStorage implements PlanStorage {
private final JdbcTemplate jdbcTemplate;
private final ObjectMapper objectMapper;
public DatabasePlanStorage(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.objectMapper = new ObjectMapper();
}
@Override
public void save(Plan plan) {
try {
String json = objectMapper.writeValueAsString(plan);
jdbcTemplate.update("""
INSERT INTO plans (id, name, data, created_at, state)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE
SET data = ?, state = ?, updated_at = NOW()
""",
plan.getId(),
plan.getName(),
json,
plan.getCreatedAt(),
plan.getState().getValue(),
json,
plan.getState().getValue()
);
} catch (Exception e) {
throw new RuntimeException("Failed to save plan", e);
}
}
@Override
public List<Plan> getAll() {
return jdbcTemplate.query(
"SELECT data FROM plans ORDER BY created_at DESC",
(rs, rowNum) -> {
try {
return objectMapper.readValue(rs.getString("data"), Plan.class);
} catch (Exception e) {
throw new RuntimeException("Failed to parse plan", e);
}
}
);
}
@Override
public Optional<Plan> getById(String id) {
List<Plan> results = jdbcTemplate.query(
"SELECT data FROM plans WHERE id = ?",
(rs, rowNum) -> {
try {
return objectMapper.readValue(rs.getString("data"), Plan.class);
} catch (Exception e) {
throw new RuntimeException("Failed to parse plan", e);
}
},
id
);
return results.isEmpty() ? Optional.empty() : Optional.of(results.get(0));
}
@Override
public void delete(String id) {
jdbcTemplate.update("DELETE FROM plans WHERE id = ?", id);
}
}
19.6 完整使用示例
19.6.1 基本使用流程
// 1. 创建带计划功能的Agent
ReActAgent agent = ReActAgent.builder()
.name("ProjectManager")
.model(OpenAIChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4")
.build())
.systemPrompt("""
你是一个项目管理助手。
当用户给你复杂任务时,请先创建一个详细的计划,
然后按计划逐步执行。
""")
.enablePlan() // 启用计划功能
.tools(fileTools, codeTools)
.build();
// 2. 用户发起复杂任务
Msg userRequest = Msg.user("帮我创建一个Spring Boot REST API项目,包含用户管理功能");
Msg response = agent.call(userRequest).block();
// Agent会自动:
// 1. 创建计划,包含多个子任务
// 2. 等待用户确认(如果needUserConfirm=true)
// 3. 逐步执行每个子任务
// 4. 在每步前接收计划状态提示
// 5. 完成后调用finish_plan
19.6.2 计划执行对话示例
用户: 帮我创建一个Spring Boot REST API项目,包含用户管理功能
Agent: 我来为您创建一个详细的执行计划。
[调用 create_plan]
Plan 'Spring Boot User Management API' created successfully.
计划概览:
# Spring Boot User Management API
**描述**: 创建一个包含用户CRUD操作的Spring Boot REST API项目
**预期结果**: 可运行的API项目,支持用户注册、登录、查询和更新
## 子任务:
- [ ] 1. 初始化Spring Boot项目
- [ ] 2. 设计数据模型
- [ ] 3. 创建Repository层
- [ ] 4. 实现Service层
- [ ] 5. 开发Controller层
- [ ] 6. 添加安全配置
- [ ] 7. 编写API文档
是否确认执行此计划?
用户: 确认
Agent: 好的,开始执行计划。
[调用 update_subtask_state: idx=0, state=in_progress]
开始第一个子任务:初始化Spring Boot项目
[执行文件创建工具...]
项目结构已创建完成。
[调用 finish_subtask: idx=0, outcome="项目初始化完成,包含基础依赖"]
子任务1完成。
[调用 update_subtask_state: idx=1, state=in_progress]
开始第二个子任务:设计数据模型...
[继续执行...]
19.6.3 计划变更监听
// 创建带变更监听的PlanNotebook
PlanNotebook notebook = PlanNotebook.builder()
.storage(new InMemoryPlanStorage())
.build();
// 注册变更监听器
notebook.registerChangeHook("ui-update", (planNotebook, plan) -> {
// 通知前端更新UI
webSocketService.broadcast(
new PlanUpdateEvent(plan.getId(), plan.toMarkdown(false))
);
});
notebook.registerChangeHook("logging", (planNotebook, plan) -> {
// 记录日志
log.info("Plan changed: {} - State: {}", plan.getName(), plan.getState());
});
// 创建Agent使用此notebook
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.planNotebook(notebook)
.build();
19.6.4 会话持久化
// PlanNotebook实现StateModule接口,支持会话持久化
Session session = JsonSession.builder()
.sessionDir(Path.of("./sessions"))
.build();
SessionKey key = new SessionKey("user123", "project-plan");
// 创建Agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.enablePlan()
.session(session) // 配置会话
.sessionKey(key) // 配置会话键
.build();
// 第一次对话
agent.call(Msg.user("创建一个TODO应用的开发计划")).block();
// 计划状态会自动保存
// 后续对话(可能是新的进程)
agent.call(Msg.user("继续执行下一个任务")).block();
// 计划状态会自动恢复
19.7 自定义提示生成
19.7.1 简化提示生成器
/**
* 简化的提示生成器
* 只显示当前任务信息
*/
public class SimplePlanToHint implements PlanToHint {
@Override
public Msg toHint(Plan plan, boolean needUserConfirm) {
StringBuilder hint = new StringBuilder();
hint.append("<plan-hint>\n");
// 找到当前任务
SubTask currentTask = null;
int currentIdx = -1;
for (int i = 0; i < plan.getSubtasks().size(); i++) {
SubTask task = plan.getSubtasks().get(i);
if (task.getState() == SubTaskState.IN_PROGRESS) {
currentTask = task;
currentIdx = i;
break;
}
}
if (currentTask != null) {
hint.append("当前任务 (").append(currentIdx + 1)
.append("/").append(plan.getSubtasks().size()).append("): ");
hint.append(currentTask.getName()).append("\n");
hint.append("目标: ").append(currentTask.getExpectedOutcome()).append("\n");
} else {
// 找到下一个待执行的任务
for (SubTask task : plan.getSubtasks()) {
if (task.getState() == SubTaskState.TODO) {
hint.append("下一个任务: ").append(task.getName()).append("\n");
break;
}
}
}
// 进度统计
long completed = plan.getSubtasks().stream()
.filter(t -> t.getState() == SubTaskState.DONE)
.count();
hint.append("进度: ").append(completed)
.append("/").append(plan.getSubtasks().size()).append("\n");
hint.append("</plan-hint>");
return Msg.builder()
.role(MsgRole.USER)
.content(new TextBlock(hint.toString()))
.build();
}
}
// 使用自定义提示生成器
PlanNotebook notebook = PlanNotebook.builder()
.planToHint(new SimplePlanToHint())
.build();
19.7.2 多语言提示生成器
/**
* 多语言提示生成器
*/
public class I18nPlanToHint implements PlanToHint {
private final Locale locale;
private final ResourceBundle bundle;
public I18nPlanToHint(Locale locale) {
this.locale = locale;
this.bundle = ResourceBundle.getBundle("plan-hints", locale);
}
@Override
public Msg toHint(Plan plan, boolean needUserConfirm) {
StringBuilder hint = new StringBuilder();
hint.append("<system-hint>\n");
hint.append("## ").append(bundle.getString("plan.status")).append("\n\n");
hint.append("**").append(bundle.getString("plan.name")).append("**: ")
.append(plan.getName()).append("\n");
hint.append("**").append(bundle.getString("plan.state")).append("**: ")
.append(bundle.getString("state." + plan.getState().getValue())).append("\n\n");
hint.append("### ").append(bundle.getString("subtasks")).append(":\n");
for (SubTask task : plan.getSubtasks()) {
hint.append(formatSubtask(task)).append("\n");
}
hint.append("\n### ").append(bundle.getString("rules")).append(":\n");
hint.append("1. ").append(bundle.getString("rule.focus")).append("\n");
hint.append("2. ").append(bundle.getString("rule.finish")).append("\n");
if (needUserConfirm) {
hint.append("3. ").append(bundle.getString("rule.confirm")).append("\n");
}
hint.append("</system-hint>");
return Msg.builder()
.role(MsgRole.USER)
.content(new TextBlock(hint.toString()))
.build();
}
private String formatSubtask(SubTask task) {
String status = switch (task.getState()) {
case TODO -> "- [ ]";
case IN_PROGRESS -> "- [ ] [" + bundle.getString("state.wip") + "]";
case DONE -> "- [x]";
case ABANDONED -> "- [ ] [" + bundle.getString("state.abandoned") + "]";
};
return status + " " + task.getName();
}
}
19.8 最佳实践
19.8.1 计划设计原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 具体可衡量 | 子任务应有明确的完成标准 | "创建User实体类" vs "写代码" |
| 适当粒度 | 任务不宜过大或过小 | 每个子任务1-2小时工作量 |
| 有序依赖 | 子任务按逻辑顺序排列 | 先建模型再写逻辑 |
| 可调整 | 允许在执行中修改计划 | 使用revisecurrentplan |
19.8.2 常见使用模式
// 模式1:自动执行(适合明确任务)
PlanNotebook autoNotebook = PlanNotebook.builder()
.needUserConfirm(false) // 不需要用户确认
.maxSubtasks(5) // 限制复杂度
.build();
// 模式2:交互式执行(适合复杂任务)
PlanNotebook interactiveNotebook = PlanNotebook.builder()
.needUserConfirm(true) // 需要用户确认
.maxSubtasks(15) // 允许更多子任务
.storage(new DatabasePlanStorage(dataSource)) // 持久化
.build();
// 模式3:模板化计划
public Plan createProjectTemplate(String projectType) {
return switch (projectType) {
case "springboot" -> new Plan(
"Spring Boot Project",
"创建Spring Boot项目",
"可运行的Spring Boot应用",
List.of(
new SubTask("初始化", "创建项目结构", "项目骨架完成"),
new SubTask("依赖配置", "添加必要依赖", "pom.xml配置完成"),
new SubTask("数据层", "创建实体和Repository", "数据访问层完成"),
new SubTask("业务层", "实现Service", "业务逻辑完成"),
new SubTask("接口层", "开发Controller", "API可访问"),
new SubTask("测试", "编写单元测试", "测试通过")
)
);
case "frontend" -> new Plan(/*...*/);
default -> throw new IllegalArgumentException("Unknown project type");
};
}
19.9 本章小结
本章详细介绍了AgentScope-Java的Plan任务规划系统:
- Plan/SubTask模型:结构化的计划表示,包含状态追踪和结果记录
- PlanNotebook:计划管理器,提供10个工具方法供Agent使用
- 自动提示注入:通过PlanToHint在每次推理前注入计划状态
- 存储与持久化:支持自定义存储后端和会话级持久化
- 变更监听:支持注册变更Hook用于UI更新和日志记录
Plan系统使Agent能够有条理地处理复杂任务,提供了可视化的进度追踪和灵活的计划调整能力。