本章导读
本章介绍AgentScope的PlanNotebook系统,这是处理复杂多步骤任务的关键工具。
PlanNotebook允许Agent自主创建和管理分阶段的计划,跨越多个推理循环执行复杂的、需要规划的任务,并在执行过程中动态调整计划。
本章概览:
- What(是什么):理解PlanNotebook的结构和生命周期
- Why(为什么):明确什么时候需要使用计划管理
- How(怎样做):完整的实现示例和生产可用案例
11.1 PlanNotebook设计理念
什么是PlanNotebook?
PlanNotebook是一个结构化的任务管理系统,为Agent提供:
- ✓ 分阶段计划:将复杂任务分解为多个子任务
- ✓ 状态管理:跟踪每个子任务的执行状态
- ✓ 动态调整:在执行过程中修改计划
- ✓ 持久化支持:保存计划以供后续恢复
PlanNotebook的核心概念
1. Plan(计划)
一个Plan包含:
├─ 名称和描述
├─ 创建时间和完成时间
├─ 优先级和进度
└─ 多个SubTask(子任务)
代码表示:
public class Plan {
private String id;
private String name;
private String description;
private LocalDateTime createdAt;
private LocalDateTime completedAt;
private PlanState state; // CREATED, IN_PROGRESS, PAUSED, COMPLETED, ABANDONED
private double progress; // 0.0 - 1.0
private List<SubTask> subTasks;
private Map<String, String> metadata;
}
2. SubTask(子任务)
每个SubTask有:
├─ 名称和描述
├─ 状态:TODO, IN_PROGRESS, DONE, ABANDONED
├─ 关键信息(需要完成什么)
├─ 完成条件(如何判断完成)
└─ 执行结果
代码表示:
public class SubTask {
private String id;
private String name;
private String description;
private TaskState state; // TODO, IN_PROGRESS, DONE, ABANDONED
private String objective; // 需要完成什么
private String completion_criteria; // 完成条件
private LocalDateTime startedAt;
private LocalDateTime completedAt;
private String result; // 执行结果
private Map<String, Object> context; // 上下文信息
}
3. PlanNotebook的生命周期
创建阶段:
User Input → Agent creates Plan
↓
Plan contains: SubTask1(TODO), SubTask2(TODO), SubTask3(TODO)
执行阶段:
Loop {
Get current SubTask
SubTask: TODO → IN_PROGRESS
Execute and gather result
SubTask: IN_PROGRESS → DONE (if successful)
Update progress
If not done, continue to next SubTask
}
暂停/恢复:
If user pauses: Plan → PAUSED, current SubTask → PAUSED
If user resumes: Plan → IN_PROGRESS, current SubTask → IN_PROGRESS
完成阶段:
All SubTasks: DONE → Plan: COMPLETED
Plan: COMPLETED → save to storage
11.2 PlanNotebook的工作原理(Why - 为什么需要)
为什么需要PlanNotebook?
1. 处理复杂的多步骤任务
问题:简单的推理循环无法处理需要严格顺序的复杂任务
示例场景(产品上线):
第1步:需求评审 → 需要1-2个推理循环
第2步:技术设计 → 需要2-3个推理循环,依赖第1步结果
第3步:开发实现 → 需要多个推理循环
第4步:测试验证 → 需要并行执行
第5步:上线发布 → 需要前面步骤都完成
问题:没有计划,Agent会陷入循环推理,不知道什么时候停止
解决:PlanNotebook将整个过程分解为明确的步骤
2. 跨越推理循环持久化
问题:单个推理循环可能用时数分钟,用户不想等待
解决:PlanNotebook允许保存中间进度,支持恢复继续
场景:
- 长时间报告生成:每个小时执行一个子任务
- 持续优化:每天运行一个优化循环
- 定时任务:每周执行一次计划检查
3. 支持计划调整和自适应
问题:执行中发现初始计划不合理,需要修改
示例:
初始计划:分析过去12个月的数据
执行中发现:数据量太大,超时了
调整方案:改为按季度分析
解决:PlanNotebook支持在执行过程中添加、删除、修改子任务
PlanNotebook的核心价值
┌─────────────────────────────────────┐
│ 复杂任务分解 │
│ (Decomposition) │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 明确的执行顺序 │
│ (Ordered Execution) │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 状态跟踪与恢复 │
│ (State Tracking & Recovery) │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 动态调整与自适应 │
│ (Dynamic Adjustment) │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ 任务完成和知识积累 │
│ (Task Completion & Learning) │
└─────────────────────────────────────┘
11.3 PlanNotebook的实现方式
基础使用示例
public class BasicPlanNotebookDemo {
public static void main(String[] args) throws Exception {
Model model = DashScopeModel.builder()
.modelName("qwen-turbo")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
// 1. 创建支持PlanNotebook的Agent
ReActAgent agent = ReActAgent.builder()
.name("ProjectManager")
.model(model)
.withPlanNotebook() // 启用PlanNotebook工具
.toolkit(new Toolkit()
.registerObject(new ProjectManagementTools()))
.build();
// 2. 向Agent提出规划任务
System.out.println("=== 请求制定项目计划 ===\n");
Msg planRequest = Msg.builder()
.role(MsgRole.USER)
.textContent("""
请为"智能推荐系统"项目制定一个详细的实现计划:
项目目标:构建一个基于用户行为的推荐引擎
时间限制:2周内完成
请:
1. 分析项目需求
2. 制定具体的分阶段计划
3. 为每个阶段制定开发工具和资源
4. 识别关键风险点
""")
.build();
Msg planResponse = agent.call(planRequest).block();
System.out.println("Agent制定的计划:\n" + planResponse.getTextContent());
// 3. 查询当前计划
System.out.println("\n=== 查询当前计划 ===\n");
List<Plan> activePlans = agent.getPlanNotebook().getActivePlans();
System.out.println("活跃计划数:" + activePlans.size());
for (Plan plan : activePlans) {
System.out.println("\n计划:" + plan.getName());
System.out.println("描述:" + plan.getDescription());
System.out.println("进度:" + (plan.getProgress() * 100) + "%");
System.out.println("状态:" + plan.getState());
System.out.println("\n子任务:");
for (SubTask task : plan.getSubTasks()) {
System.out.println(" [" + task.getState() + "] " +
task.getName() + ": " + task.getDescription());
}
}
// 4. 执行计划
System.out.println("\n=== 执行计划 ===\n");
Msg executeRequest = Msg.builder()
.role(MsgRole.USER)
.textContent("请开始执行第一个任务:需求分析")
.build();
Msg executeResponse = agent.call(executeRequest).block();
System.out.println("执行结果:\n" + executeResponse.getTextContent());
// 5. 再次查询计划进度
System.out.println("\n=== 更新后的计划进度 ===\n");
Plan plan = activePlans.get(0);
System.out.println("计划进度:" + (plan.getProgress() * 100) + "%");
System.out.println("已完成任务:");
for (SubTask task : plan.getSubTasks()) {
if (task.getState() == TaskState.DONE) {
System.out.println(" ✓ " + task.getName());
}
}
}
/**
* 项目管理相关工具
*/
public static class ProjectManagementTools {
@Tool(description = "分析项目需求")
public String analyzeRequirements(String projectName, String description) {
return "需求分析完成:\n" +
"- 功能需求:3个核心功能\n" +
"- 非功能需求:性能、安全、可维护性\n" +
"- 技术栈:Java、Spring Boot、Redis";
}
@Tool(description = "分配开发资源")
public String allocateResources(String taskName, int devCount, String skills) {
return "资源分配完成:" +
"\n- 开发人员:" + devCount + "人\n" +
"- 技能要求:" + skills;
}
@Tool(description = "评估风险")
public String assessRisks(String taskName) {
return "风险评估完成:\n" +
"- 高风险:1项\n" +
"- 中风险:2项\n" +
"- 低风险:3项";
}
}
}
高级:动态调整计划
public class DynamicPlanAdjustment {
public static void main(String[] args) throws Exception {
Model model = DashScopeModel.builder()
.modelName("qwen-turbo")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
ReActAgent agent = ReActAgent.builder()
.name("AdaptiveProjectManager")
.model(model)
.withPlanNotebook()
.toolkit(new Toolkit()
.registerObject(new AdaptiveTools()))
.build();
// 1. 创建初始计划
System.out.println("=== 创建初始计划 ===\n");
agent.call(Msg.builder()
.textContent("为数据分析项目制定计划:收集数据 → 清洗数据 → 分析数据 → 生成报告")
.build()).block();
// 2. 在执行过程中发现问题
System.out.println("\n=== 执行中发现问题 ===\n");
agent.call(Msg.builder()
.textContent("执行中发现:数据量超过预期,原计划的清洗步骤会超时。" +
"请调整计划,将'清洗数据'分为两个步骤:'样本清洗'和'批量清洗'")
.build()).block();
// 3. 添加新的风险应对任务
System.out.println("\n=== 添加风险应对措施 ===\n");
agent.call(Msg.builder()
.textContent("识别到新风险:数据质量不达标。请在'分析数据'前插入一个'质量验证'步骤")
.build()).block();
// 4. 查询最终的计划
System.out.println("\n=== 最终的计划结构 ===\n");
PlanNotebook notebook = agent.getPlanNotebook();
List<Plan> plans = notebook.getActivePlans();
if (!plans.isEmpty()) {
Plan plan = plans.get(0);
System.out.println("计划名称:" + plan.getName());
System.out.println("总任务数:" + plan.getSubTasks().size());
System.out.println("\n任务顺序:");
for (int i = 0; i < plan.getSubTasks().size(); i++) {
SubTask task = plan.getSubTasks().get(i);
System.out.println(" " + (i + 1) + ". " + task.getName() +
" [" + task.getState() + "]");
}
}
}
public static class AdaptiveTools {
@Tool(description = "添加任务到计划")
public String addTaskToplan(String planId, int position, String taskName, String description) {
return "任务已添加到计划中:位置=" + position + ", 名称=" + taskName;
}
@Tool(description = "修改任务")
public String modifyTask(String taskId, String newName, String newDescription) {
return "任务已修改:" + taskId;
}
@Tool(description = "标记任务完成")
public String completeTask(String taskId, String result) {
return "任务已标记为完成:" + taskId;
}
}
}
11.4 生产场景:产品上线流程管理
场景描述
完整的产品上线流程,从需求评审到上线后运维:
第一阶段(评审)
├─ 需求分析
├─ 技术评审
└─ 风险评估
第二阶段(开发)
├─ 详细设计
├─ 开发实现
└─ 单元测试
第三阶段(测试)
├─ 集成测试
├─ 性能测试
├─ 安全测试
└─ UAT
第四阶段(上线)
├─ 灰度发布
├─ 线上验证
└─ 全量发布
第五阶段(运维)
├─ 性能监控
├─ 告警管理
└─ 问题处理
实现代码
public class ProductReleaseManagementSystem {
/**
* 产品上线计划管理器
*/
public static class ReleaseManager {
private final ReActAgent agent;
private final ReleaseStorage storage;
public ReleaseManager(Model model, ReleaseStorage storage) {
this.storage = storage;
this.agent = ReActAgent.builder()
.name("ReleaseManager")
.model(model)
.withPlanNotebook()
.toolkit(new Toolkit()
.registerObject(new ReleaseTools()))
.hooks(List.of(
new ReleaseCheckpointHook(storage),
new ReleaseNotificationHook()))
.build();
}
/**
* 创建产品上线计划
*/
public void createReleaseplan(String productName, String version) {
System.out.println("=== 创建产品上线计划 ===");
System.out.println("产品:" + productName + " v" + version + "\n");
String prompt = String.format("""
请为产品 %s v%s 创建一个完整的上线计划:
需要包含以下阶段:
1. 需求/设计评审
2. 开发实现
3. 测试验证
4. 上线发布
5. 运维监控
对每个阶段:
- 列出具体的子任务
- 标识关键决策点
- 评估风险
- 估计完成时间
特别注意:
- 上线前需要经过3个阶段的测试
- 灰度发布需要监控至少1小时
- 全量发布后需要24小时的密集监控
""", productName, version);
Msg response = agent.call(Msg.builder()
.textContent(prompt)
.build()).block();
System.out.println("计划内容:\n" + response.getTextContent());
}
/**
* 执行计划的某个阶段
*/
public void executePhase(String phaseName) {
System.out.println("\n=== 执行阶段:" + phaseName + " ===\n");
Msg response = agent.call(Msg.builder()
.textContent("请开始执行'" + phaseName + "'阶段," +
"并通过相应的工具完成该阶段的所有子任务")
.build()).block();
System.out.println("执行结果:\n" + response.getTextContent());
// 保存执行进度
storage.savePhaseCompletion(phaseName);
}
/**
* 处理上线过程中发现的问题
*/
public void handleIssue(String issueName, String severity, String impact) {
System.out.println("\n=== 处理上线问题 ===");
System.out.println("问题:" + issueName);
System.out.println("严重性:" + severity);
System.out.println("影响:" + impact + "\n");
String prompt = String.format("""
在上线过程中发现以下问题:
问题名称:%s
严重性:%s
影响范围:%s
请:
1. 分析问题的根本原因
2. 评估是否需要回滚
3. 如果不回滚,制定快速修复方案
4. 更新上线计划
""", issueName, severity, impact);
Msg response = agent.call(Msg.builder()
.textContent(prompt)
.build()).block();
System.out.println("问题处理方案:\n" + response.getTextContent());
}
/**
* 查询计划进度
*/
public void displayProgress() {
System.out.println("\n=== 上线计划进度 ===\n");
PlanNotebook notebook = agent.getPlanNotebook();
List<Plan> plans = notebook.getActivePlans();
if (!plans.isEmpty()) {
Plan plan = plans.get(0);
System.out.println("计划名称:" + plan.getName());
System.out.println("总进度:" + String.format("%.1f%%", plan.getProgress() * 100));
System.out.println("状态:" + plan.getState());
System.out.println("\n阶段进度:");
for (SubTask task : plan.getSubTasks()) {
String status = task.getState() == TaskState.DONE ? "✓" :
task.getState() == TaskState.IN_PROGRESS ? "⚙" : "○";
System.out.println(" " + status + " " + task.getName() +
" [" + task.getState() + "]");
if (!task.getResult().isEmpty()) {
System.out.println(" 结果:" + task.getResult());
}
}
}
}
}
/**
* 上线相关工具集
*/
public static class ReleaseTools {
@Tool(description = "执行代码审查")
public String codeReview(String commitHash, int reviewerCount) {
return "代码审查已执行:\n" +
"- 提交:" + commitHash + "\n" +
"- 审查人数:" + reviewerCount + "\n" +
"- 结果:已通过";
}
@Tool(description = "运行测试套件")
public String runTestSuite(String testType, String environment) {
return "测试套件执行完成:\n" +
"- 测试类型:" + testType + "\n" +
"- 环境:" + environment + "\n" +
"- 通过率:98.5%";
}
@Tool(description = "部署到特定环境")
public String deploy(String version, String environment, double grayPercentage) {
return "部署完成:\n" +
"- 版本:" + version + "\n" +
"- 环境:" + environment + "\n" +
"- 灰度比例:" + grayPercentage + "%";
}
@Tool(description = "检查系统监控指标")
public String checkMetrics(String metricName, String environment) {
return "监控指标检查完成:\n" +
"- 指标:" + metricName + "\n" +
"- 环境:" + environment + "\n" +
"- 状态:正常";
}
@Tool(description = "回滚到上一个版本")
public String rollback(String version) {
return "已回滚到版本:" + version;
}
}
/**
* 上线检查点Hook:在关键步骤保存进度
*/
public static class ReleaseCheckpointHook implements Hook {
private final ReleaseStorage storage;
public ReleaseCheckpointHook(ReleaseStorage storage) {
this.storage = storage;
}
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostActingEvent post) {
// 在执行完每个工具调用后保存进度
String toolName = extractToolName(post.getActingMessage());
storage.saveCheckpoint(toolName);
System.out.println("✓ 检查点已保存:" + toolName);
}
return Mono.just(event);
}
private String extractToolName(Msg msg) {
// 从消息中提取工具名称
String content = msg.getTextContent();
if (content.contains("code-review")) return "CodeReview";
if (content.contains("test")) return "Testing";
if (content.contains("deploy")) return "Deployment";
return "Unknown";
}
@Override
public int getPriority() {
return 100;
}
}
/**
* 上线通知Hook:通知相关人员
*/
public static class ReleaseNotificationHook implements Hook {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PostReasoningEvent post) {
// 每个推理循环后通知进度
return Mono.just(event)
.doOnNext(e -> {
System.out.println("\n[通知] 上线计划更新");
System.out.println("时间:" + LocalDateTime.now());
System.out.println("推理轮次:" + post.getReasoningCount());
});
}
return Mono.just(event);
}
@Override
public int getPriority() {
return 50;
}
}
/**
* 上线进度存储接口
*/
public interface ReleaseStorage {
void savePhaseCompletion(String phaseName);
void saveCheckpoint(String checkpointName);
List<String> getCompletedPhases();
}
/**
* 测试主程序
*/
public static void main(String[] args) throws Exception {
Model model = DashScopeModel.builder()
.modelName("qwen-turbo")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
ReleaseStorage storage = new SimpleReleaseStorage();
ReleaseManager manager = new ReleaseManager(model, storage);
// 创建上线计划
manager.createReleaseplan("推荐系统", "2.1.0");
// 执行各个阶段
manager.displayProgress();
manager.executePhase("需求/设计评审");
manager.displayProgress();
manager.executePhase("开发实现");
manager.displayProgress();
manager.executePhase("测试验证");
manager.displayProgress();
// 处理上线过程中发现的问题
manager.handleIssue(
"缓存预热不足导致首页加载缓慢",
"HIGH",
"影响用户体验,但不影响功能"
);
manager.executePhase("上线发布");
manager.displayProgress();
}
/**
* 简单的存储实现
*/
public static class SimpleReleaseStorage implements ReleaseStorage {
private final List<String> completedPhases = new CopyOnWriteArrayList<>();
private final List<String> checkpoints = new CopyOnWriteArrayList<>();
@Override
public void savePhaseCompletion(String phaseName) {
completedPhases.add(phaseName);
}
@Override
public void saveCheckpoint(String checkpointName) {
checkpoints.add(checkpointName);
}
@Override
public List<String> getCompletedPhases() {
return new ArrayList<>(completedPhases);
}
}
}
11.5 最佳实践
✅ 最佳实践
1. 计划设计
- 遵循SMART原则(Specific, Measurable, Achievable, Relevant, Time-bound)
- 子任务数不超过20个(否则难以跟踪)
- 每个子任务耗时不超过1小时(便于检查点恢复)
- 明确定义"完成条件"
2. 执行管理
- 每个推理循环处理一个子任务
- 在Task完成前保存检查点
- 定期检查计划进度并显示给用户
- 发现偏差时及时调整
3. 错误恢复
- 支持从任意检查点恢复
- 记录所有失败的尝试和修改
- 为每个阶段准备备选方案
- 定期验证恢复机制
4. 生产运维
- 将计划持久化到数据库
- 支持多个并行计划
- 实现计划的版本控制
- 提供计划审计日志
本章总结
本章介绍了PlanNotebook系统,这是处理复杂多步骤任务的核心工具:
核心要点
- What:PlanNotebook是结构化的任务管理系统
- Why:支持复杂任务分解、跨循环执行、动态调整
- How:通过Plan和SubTask进行阶段化管理
关键特性
- ✓ 任务分解:将复杂任务拆分为可管理的子任务
- ✓ 状态跟踪:明确的状态转移和进度追踪
- ✓ 动态调整:在执行过程中修改计划
- ✓ 持久化:支持保存和恢复计划进度
使用场景
- 复杂的产品上线流程
- 长时间的数据分析项目
- 涉及多个部门的协作任务
- 需要人工干预的自动化工作流
下一章预告
第12章:RAG(检索增强生成)
当Agent需要回答基于最新知识库的问题时,仅依赖训练数据是不够的。第12章将介绍RAG系统,它允许Agent:
- 从海量文档中快速检索相关信息
- 基于最新知识生成准确的回答
- 支持多种知识库后端集成
- 实现私有知识库的保护