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

# 待办事项列表

> 通过与智能体状态同步的实时待办事项列表跟踪智能体进度。

并非每个智能体交互都是对话。有时智能体正在执行一个多步骤计划，而展示进度的最佳方式是一个实时更新的**待办事项列表**。深度智能体待办事项列表模式直接从智能体状态中读取`todos`数组，并在智能体执行计划的过程中以当前状态渲染每个项目。这是一个基于您用于对话的相同`useStream`钩子构建的进度仪表板。它表明智能体状态可以驱动任何 UI，而不仅仅是消息气泡。

交互示例暂不可用（上游文档源缺失：deep-agent-todo-list）

## 工作原理

深度智能体在您选择 @\[`TodoListMiddleware`]时可以暴露一个\*\*`todos`状态\*\*通道。该中间件添加了`write_todos`工具，并在智能体执行计划的过程中持久化任务进度。随着智能体的执行，它将每个待办事项的状态从`"pending"`更新为`"in_progress"`再到`"completed"`。@\[`useStream`]钩子通过`stream.values.todos`暴露此状态，您的 UI 反应式地渲染它。

> [!NOTE]
>
> 任务规划是可选的。如果没有 @\[`TodoListMiddleware`]，`stream.values.todos`不存在。参见[任务规划](https://langchain-docs-zh.mintlify.site/langchain/oss/deepagents/overview.md#任务规划)。

流程如下：

1. 用户提交请求
2. 智能体创建计划并在其状态中填充`todos`
3. 智能体开始执行每个待办事项的状态从`pending` → `in_progress` → `completed`
4. `stream.values.todos`随着智能体的进度实时更新
5. 您的 UI 重新渲染带有当前状态的待办事项列表

## 设置`useStream`

在智能体上启用 @\[`TodoListMiddleware`]。

:::python

```python Google theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[TodoListMiddleware()],
)
```

```python OpenAI theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="openai:gpt-5.5",
    middleware=[TodoListMiddleware()],
)
```

```python Anthropic theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="anthropic:claude-sonnet-5",
    middleware=[TodoListMiddleware()],
)
```

```python OpenRouter theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="openrouter:z-ai/glm-5.2",
    middleware=[TodoListMiddleware()],
)
```

```python Fireworks theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="fireworks:accounts/fireworks/models/glm-5p2",
    middleware=[TodoListMiddleware()],
)
```

```python Baseten theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="baseten:zai-org/GLM-5.2",
    middleware=[TodoListMiddleware()],
)
```

```python Ollama theme={null}
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware

agent = create_deep_agent(
    model="ollama:north-mini-code-1.0",
    middleware=[TodoListMiddleware()],
)
```

:::

:::js

```ts Google theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "google:gemini-3.6-flash",
  middleware: [todoListMiddleware()],
});
```

```ts OpenAI theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "openai:gpt-5.5",
  middleware: [todoListMiddleware()],
});
```

```ts Anthropic theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  middleware: [todoListMiddleware()],
});
```

```ts OpenRouter theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  middleware: [todoListMiddleware()],
});
```

```ts Fireworks theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  middleware: [todoListMiddleware()],
});
```

```ts Baseten theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  middleware: [todoListMiddleware()],
});
```

```ts Ollama theme={null}
import { createDeepAgent } from "deepagents";
import { todoListMiddleware } from "langchain";

const agent = await createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  middleware: [todoListMiddleware()],
});
```

:::

然后指向`useStream`该智能体，并从`stream.values`读取`todos`。

> [!NOTE]
>
> 代码示例使用 `useStream<typeof myAgent>` 进行类型安全的流状态管理。请参考 [Python](https://docs.langchain.com/oss/python/langchain/frontend/overview#type-inference) 或 [JavaScript](https://docs.langchain.com/oss/javascript/langchain/frontend/overview#type-inference) 后端的类型推断说明。

```tsx React theme={null}
import { useStream } from "@langchain/react";

const AGENT_URL = "http://localhost:2024";

export function TodoAgent() {
  const stream = useStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_todo_list",
  });

  const todos = stream.values?.todos ?? [];

  return (
    <div>
      <TodoList todos={todos} />
      {stream.messages.map((msg) => (
        <Message key={msg.id} message={msg} />
      ))}
    </div>
  );
}
```

```vue Vue theme={null}
<script setup lang="ts">
import { useStream } from "@langchain/vue";
import { computed } from "vue";

const AGENT_URL = "http://localhost:2024";

const stream = useStream<typeof myAgent>({
  apiUrl: AGENT_URL,
  assistantId: "deep_agent_todo_list",
});

const todos = computed(() => stream.values.value?.todos ?? []);
</script>

<template>
  <div>
    <TodoList :todos="todos" />
    <Message
      v-for="msg in stream.messages.value"
      :key="msg.id"
      :message="msg"
    />
  </div>
</template>
```

```svelte Svelte theme={null}
<script lang="ts">
  import { useStream } from "@langchain/svelte";

  const AGENT_URL = "http://localhost:2024";

  const stream = useStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_todo_list",
  });

  const todos = $derived(stream.values?.todos ?? []);
</script>

<div>
  <TodoList {todos} />
  {#each stream.messages as msg (msg.id)}
    <Message message={msg} />
  {/each}
</div>
```

```ts Angular theme={null}
import { Component, computed } from "@angular/core";
import { injectStream } from "@langchain/angular";

const AGENT_URL = "http://localhost:2024";

@Component({
  selector: "app-todo-agent",
  template: `
    <div>
      <app-todo-list [todos]="todos()" />
      @for (msg of stream.messages(); track msg.id) {
        <app-message [message]="msg" />
      }
    </div>
  `,
})
export class TodoAgentComponent {
  stream = injectStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_todo_list",
  });

  todos = computed(() => this.stream.values()?.todos ?? []);
}
```

## 构建TodoList组件

待办事项列表使用状态图标、颜色编码和反映当前状态的视觉样式渲染每个项目：

```tsx theme={null}
function TodoList({ todos }: { todos: Todo[] }) {
  const completed = todos.filter((t) => t.status === "completed").length;
  const percentage = todos.length
    ? Math.round((completed / todos.length) * 100)
    : 0;

  return (
    <div className="rounded-lg border bg-white p-4 shadow-sm">
      <div className="mb-4 flex items-center justify-between">
        <h2 className="text-lg font-semibold">Agent Progress</h2>
        <span className="text-sm text-gray-500">
          {completed}/{todos.length} tasks
        </span>
      </div>

      <ProgressBar percentage={percentage} />

      <ul className="mt-4 space-y-2">
        {todos.map((todo, i) => (
          <TodoItem key={i} todo={todo} />
        ))}
      </ul>
    </div>
  );
}
```

## 进度条

一个视觉进度条为用户提供了一个整体完成的概览：

```tsx theme={null}
function ProgressBar({ percentage }: { percentage: number }) {
  return (
    <div className="space-y-1">
      <div className="flex items-center justify-between text-xs text-gray-500">
        <span>Progress</span>
        <span>{percentage}%</span>
      </div>
      <div className="h-2 overflow-hidden rounded-full bg-gray-200">
        <div
          className="h-full rounded-full bg-green-500 transition-all duration-500"
          style={{ width: `${percentage}%` }}
        />
      </div>
    </div>
  );
}
```

## 单个待办事项

每个项目都获得一个状态图标、颜色编码文本和对已完成任务的删除线样式：

```tsx theme={null}
function TodoItem({ todo }: { todo: Todo }) {
  const config = {
    pending: {
      icon: "○",
      textClass: "text-gray-600",
      bgClass: "bg-gray-50",
      iconClass: "text-gray-400",
    },
    in_progress: {
      icon: "◉",
      textClass: "text-amber-800",
      bgClass: "bg-amber-50 border-amber-200",
      iconClass: "text-amber-500 animate-pulse",
    },
    completed: {
      icon: "✓",
      textClass: "text-green-800 line-through",
      bgClass: "bg-green-50 border-green-200",
      iconClass: "text-green-500",
    },
  };

  const style = config[todo.status];

  return (
    <li
      className={`flex items-start gap-3 rounded-md border px-3 py-2 ${style.bgClass}`}
    >
      <span className={`mt-0.5 text-lg leading-none ${style.iconClass}`}>
        {style.icon}
      </span>
      <span className={`text-sm ${style.textClass}`}>{todo.content}</span>
    </li>
  );
}
```

`in_progress`图标使用`animate-pulse`来吸引对当前活动任务的注意力。

## 计算进度

直接从待办事项数组中派生进度指标：

```ts theme={null}
const todos = stream.values?.todos ?? [];

const completed = todos.filter((t) => t.status === "completed").length;
const inProgress = todos.filter((t) => t.status === "in_progress").length;
const pending = todos.filter((t) => t.status === "pending").length;
const percentage = todos.length
  ? Math.round((completed / todos.length) * 100)
  : 0;
```

这些值随着智能体修改其状态而反应式更新，使进度条和计数器保持同步。

## 与聊天消息结合

待办事项列表与常规聊天界面协同工作。一个实用的布局显示待办事项列表作为持久侧边栏或标题面板，聊天消息在下方：

```tsx theme={null}
function TodoAgentLayout() {
  const stream = useStream<typeof myAgent>({
    apiUrl: AGENT_URL,
    assistantId: "deep_agent_todo_list",
  });

  const todos = stream.values?.todos ?? [];

  return (
    <div className="flex h-screen flex-col">
      {todos.length > 0 && (
        <div className="border-b bg-gray-50 p-4">
          <TodoList todos={todos} />
        </div>
      )}

      <main className="flex-1 overflow-y-auto p-6">
        <div className="mx-auto max-w-2xl space-y-4">
          {stream.messages.map((msg) => (
            <Message key={msg.id} message={msg} />
          ))}
        </div>
      </main>

      <ChatInput
        onSubmit={(text) =>
          stream.submit({ messages: [{ type: "human", content: text }] })
        }
        isLoading={stream.isLoading}
      />
    </div>
  );
}
```

> [!TIP]
>
> 仅在`todos.length > 0`时显示待办事项列表。在智能体创建其计划之前，没有内容要显示。显示空组件会浪费空间。

## 用例

待办事项列表模式适用于任何智能体执行结构化计划的场景：

* **项目规划**：智能体将项目分解为任务并按顺序处理它们
* **研究工作流**：每个研究问题都成为一个待办事项，智能体进行调查并完成
* **数据处理**：摄取、验证、转换和导出等步骤各自获得一个待办事项
* **引导流程**：智能体逐步引导设置，在配置服务时勾选每个步骤
* **报告生成**：报告的各个部分成为待办事项：收集数据、分析趋势、撰写摘要、格式化输出

## 处理空和加载状态

在智能体创建其计划之前处理初始状态：

```tsx theme={null}
function TodoList({ todos, isLoading }: { todos: Todo[]; isLoading: boolean }) {
  if (todos.length === 0 && !isLoading) {
    return null;
  }

  if (todos.length === 0 && isLoading) {
    return (
      <div className="rounded-lg border bg-white p-4 shadow-sm">
        <div className="flex items-center gap-2 text-sm text-gray-500">
          <span className="animate-spin">⟳</span>
          Agent is creating a plan...
        </div>
      </div>
    );
  }

  return (
    <div className="rounded-lg border bg-white p-4 shadow-sm">
      {/* ... full todo list rendering */}
    </div>
  );
}
```

## 最佳实践

* **突出显示待办事项列表**。它是基于计划的智能体的主要进度指示器。不要将其隐藏在折叠之下。
* **动画状态转换**。平滑的转换使智能体感觉更响应。使用 CSS 转换背景颜色、文本装饰和不透明度。
* **仅突出显示一个`in_progress`项目**。智能体通常一次处理一个任务。如果多个项目显示为`in_progress`，UI 会变得嘈杂。考虑仅脉冲第一个。
* **折叠或淡化已完成项目**。随着列表的增长，已完成项目变得不太相关。减少它们的视觉权重，以便用户专注于仍在进行的事情。
* **显示进度百分比**。像"67% 完成"这样的单个数字即使从房间另一边也能立即理解。
* **保持待办事项列表同步**。由于`stream.values`反应式更新，待办事项列表会自动保持最新。不要添加手动轮询或刷新逻辑。

## 相关LangChain指南

待办事项列表模式是 LangChain 方法在渲染结构化智能体状态方面的专业化。这些指南涵盖了与基于计划的智能体配合得很好的相关技术：

> [card] [Structured output](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/frontend/structured-output.md)
>
> 使用自定义 UI 组件而不是纯文本渲染任何结构化智能体状态——不仅仅是待办事项。

> [card] [Join & rejoin streams](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/frontend/join-rejoin.md)
>
> 在页面重新加载或标签切换后重新连接到正在运行的计划，而不会丢失进度。

> [card] [Message queues](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/frontend/message-queues.md)
>
> 在智能体仍在处理其当前计划时排队后续任务。

> [card] [Human-in-the-Loop](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/frontend/human-in-the-loop.md)
>
> 当智能体需要用户批准或输入时暂停和恢复计划执行。

***

> 官方原文：[src/oss/deepagents/frontend/todo-list.mdx](https://github.com/langchain-ai/docs/blob/main/src/oss/deepagents/frontend/todo-list.mdx) · 非官方翻译，译文由 AI 生成，以英文原文为准。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.