> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 计划模式

> 为智能体提供结构化任务清单，用于规划、追踪并协调复杂工作

## 概述

Planning（规划）是 agent 把复杂请求拆分成离散、有序、可追踪步骤的方式。AgentScope 不让模型仅靠自由形式的推理来同时兼顾多步目标，而是提供一小组内置工具，让 agent 通过普通的工具调用来维护一份**显式、结构化的任务清单** —— 任务的创建、查询与更新都走工具调用。

AgentScope 内置了四个 plan 工具：

| Tool         | 操作                         | 只读 |
| ------------ | -------------------------- | -- |
| `TaskCreate` | 向任务清单末尾追加新任务               | 否  |
| `TaskGet`    | 按 ID 获取单个任务的完整信息（描述、状态、依赖） | 是  |
| `TaskList`   | 列出所有任务及其状态、owner、阻塞关系      | 是  |
| `TaskUpdate` | 更新任务的状态、字段或依赖边，亦可删除任务      | 否  |

四者都是状态注入式工具（`is_state_injected = True`）：agent 运行时把当前的 `AgentState` 注入每次调用，工具直接读写 `agent.state.tasks_context`。这意味着任务清单**以 agent 为作用域**，并随 agent 的其余持久化状态一同跨越推理步骤、ReAct 轮次以及 human-in-the-loop 暂停而保留下来。

<Tip>
  当工作跨越**三步以上的非平凡步骤**、涉及**子任务之间的依赖**，或需要把**进度对用户可见**时，plan 工具最有用。对于一锤子或纯对话的请求，即使装配了 plan 工具，agent 也会按设计跳过 —— 工具的 prompt 已明确告诉它不要为琐碎工作做计划。
</Tip>

## 使用 Plan 工具

### 装配工具

像其他内置工具一样实例化并注册到 `Toolkit`：

```python theme={null}
from agentscope.agent import Agent
from agentscope.tool import (
    Toolkit,
    TaskCreate,
    TaskGet,
    TaskList,
    TaskUpdate,
)

toolkit = Toolkit(
    tools=[
        TaskCreate(),
        TaskGet(),
        TaskList(),
        TaskUpdate(),
    ],
)

agent = Agent(
    name="planner",
    system_prompt="You are a planning assistant.",
    model=model,
    toolkit=toolkit,
)
```

每个工具的 `description` 已经包含详细 prompt，说明何时调用、何时跳过以及如何解读输出，因此不需要额外的 system prompt 工程。`check_permissions()` 硬编码为 `ALLOW` —— plan 工具是纯内存状态变更，不会触发用户提示。

### 任务生命周期

典型的规划循环如下：

<Steps>
  <Step title="登记工作">
    收到新指令时，agent 对每个离散步骤分别调用一次 `TaskCreate`，提供一句简短的命令式 `subject` 和更详尽的 `description`。新任务按创建顺序追加；`id` 是稳定且单调递增的数字串（`"1"`、`"2"`……）。
  </Step>

  <Step title="查看队列">
    `TaskList` 返回每个任务一行的紧凑摘要（id、状态、subject、owner、blocked-by），agent 据此挑选下一个可做的任务 —— 通常是 ID 最小且无未解 `blocked_by` 的 `pending` 任务。
  </Step>

  <Step title="认领并开始">
    开始工作前，agent 调用 `TaskUpdate` 把任务的 `status` 置为 `in_progress`（多 agent 场景下还可设置 `owner`）。
  </Step>

  <Step title="获取完整上下文">
    `TaskGet` 返回特定任务的完整描述、依赖边与元数据 —— 当描述较长时，在执行前调用很有帮助。
  </Step>

  <Step title="完成或重新规划">
    完成时，`TaskUpdate` 把状态翻转为 `completed`。若 agent 发现了新工作，则回到 `TaskCreate`；若某个任务已无需做，则把状态置为 `deleted`（硬删除，同时会修正所有引用了该任务的其他任务的依赖边）。
  </Step>
</Steps>

状态流转刻意保持线性：

```
pending → in_progress → completed
                          (或)
                      ↘ deleted（任意状态均可，硬删除）
```

### 表达依赖

任务暴露两条对称的依赖边：

* `blocks` —— 在本任务完成前不能开始的任务 ID 列表。
* `blocked_by` —— 必须在本任务开始前完成的任务 ID 列表。

`TaskUpdate` 接受 `add_blocks` 与 `add_blocked_by` 参数。每次调用都会**自动修改两端**，保持数据一致：

```python theme={null}
# 创建好任务 "1" 与 "2" 后，让 "2" 依赖 "1"：
await TaskUpdate()(
    task_id="2",
    add_blocked_by=["1"],
    _agent_state=agent.state,
)
# 此时：task "2".blocked_by == ["1"] 且 task "1".blocks == ["2"]
```

任务被删除时，其 ID 会从其他所有任务的 `blocks` 与 `blocked_by` 中移除，保证依赖图始终有效。

<Note>
  `TaskList` 会标注每个仍有未解 `blocked_by` 的任务，`TaskGet` 则返回完整的依赖边列表。agent 据此优先选择无阻塞的工作，但**执行层面是仅建议性的** —— 运行时不会阻止模型去做一个被阻塞的任务。请把依赖边视为协调信号，而非硬性闸门。
</Note>

## 存储

所有任务状态都存在 agent 自身上，位于 `agent.state.tasks_context`。相关类型如下：

```python theme={null}
class Task(BaseModel):
    id: str                       # 单调递增的数字串，由 TaskCreate 分配
    subject: str                  # 一句话命令式描述
    description: str              # 详细的需求 / 上下文
    state: Literal["pending", "in_progress", "completed"] = "pending"
    owner: str | None = None
    blocks: list[str] = []        # 被本任务阻塞的任务 ID
    blocked_by: list[str] = []    # 阻塞本任务的任务 ID
    metadata: dict[str, Any] = {}
    created_at: str               # 创建时设置的 ISO-8601 时间戳

class TaskContext(BaseModel):
    tasks: list[Task] = []
```

`AgentState.tasks_context` 是 agent state 模型上的常规字段，这意味着：

* **可被序列化保存。** 调用 `agent.state_dict()`（或宿主平台用于持久化 `AgentState` 的任何机制）都会完整保存任务清单，恢复 state 时计划也一并恢复。
* **以 agent 为单位。** 两个 agent 默认不共享任务清单；多 agent 协调由开发者自行处理（如把所有 plan 工具调用路由到一个专门的 planner agent，或手动在 agent 之间同步 state）。
* **可在 LLM 循环之外修改。** 任何能拿到 `agent.state` 的代码 —— middleware、应用代码、评测器 —— 都可以直接读写任务。plan 工具没有特权访问；它们只是面向 LLM 的便利接口，操作的是同一份数据结构。

## 自定义任务

由于任务存在 `agent.state.tasks_context`，开发者可以绕过 LLM 直接以编程方式管理任务。常见场景：

* **预置（Seeding）**：用其他渠道（另一个 agent、工作流引擎、静态分析）生成的现成计划喂给 agent。
* **导入（Importing）**：从外部追踪系统（Jira、GitHub issues、内部任务库）导入既有工作项。
* **迁移（Migrating）**：把 state 从一个 agent 实例迁移到另一个，或恢复部分已完成的计划。
* **评测（Evaluation）**：在 agent 推理前由测试 harness 注入 ground-truth 任务。

下面的示例在 agent 第一次 reply 之前预置了两个有依赖关系的任务：

```python theme={null}
from agentscope.agent import Agent
from agentscope.state import Task
from agentscope.tool import Toolkit, TaskCreate, TaskGet, TaskList, TaskUpdate

agent = Agent(
    name="planner",
    system_prompt="You are a planning assistant.",
    model=model,
    toolkit=Toolkit(
        tools=[TaskCreate(), TaskGet(), TaskList(), TaskUpdate()],
    ),
)

agent.state.tasks_context.tasks.extend(
    [
        Task(
            id="1",
            subject="Fetch project requirements",
            description="Read README.md and CONTRIBUTING.md in the repo root.",
            metadata={"source": "seed"},
        ),
        Task(
            id="2",
            subject="Draft an implementation plan",
            description="Produce a step-by-step plan based on the requirements.",
            blocked_by=["1"],
            metadata={"source": "seed"},
        ),
    ],
)
# 保持反向边一致：
agent.state.tasks_context.tasks[0].blocks.append("2")
```

<Warning>
  直接修改 `tasks_context` 时，你需要自行保证：

  * **ID 唯一且可解析。** `TaskCreate` 取下一个 ID 的方式是 `max(int(task.id) for task in tasks) + 1`。非数字 ID 在计算下一个 ID 时被忽略，但也不会被重新分配 —— 请使用数字串 ID（`"1"`、`"2"`……）以让自动分配持续工作。
  * **依赖边双向一致。** `blocks` 与 `blocked_by` 必须同步。`TaskUpdate` 会自动维护；手动修改不会。
  * **状态值合法。** `Task.state` 只接受 `pending`、`in_progress`、`completed`。`deleted` 是 `TaskUpdate` 暴露的*操作*，而非存储的状态 —— 想手动删除任务，直接从列表中移除（并清理它的依赖边）即可。
</Warning>

也可以随时清空或重置计划：

```python theme={null}
agent.state.tasks_context.tasks.clear()
```

agent 下一轮就会看到一个空计划并从头开始。

## 延伸阅读

* [Tool](/versions/2.0.3/zh/building-blocks/tool) —— toolkit、`ToolBase` 接口，以及状态注入式工具如何拿到 `AgentState`。
* [Agent](/versions/2.0.3/zh/building-blocks/agent) —— agent 生命周期，包括 `AgentState` 的创建、恢复与持久化。
