Skip to content
CrewAI 文档版本 跟随上游 源快照 c14f84ff 更新于 2026-10-18

智能体化生成式 UI

将你的 CrewAI Flow 的实时状态渲染为 UI,随智能体执行多步任务而更新。

渲染智能体的实时状态

有些工作无法塞进单次工具调用。一项研究任务、一个多步计划、一个长时间运行的工作:值得展示给用户的不是某一个结果,而是进度。智能体化生成式 UI 渲染智能体的状态,并在该状态每次变化时重新渲染。

这个模式分为两部分:

  1. 你的 Flow 在工作过程中把进度写入自己的状态。
  2. 你的前端用 useAgent 读取该状态并渲染它,随状态流式传入而重新渲染。

Flow 的状态通过 AG-UI 到达前端,你无需搭建任何传输层。在 Flow 的每个步骤(方法)边界都会自动发出一次状态快照,你还可以在长时间运行的步骤中通过显式调用 copilotkit_emit_state 推送中间更新。你通过继承状态来添加自己的字段,在 Flow 中更新它们,并在 React 中读取它们。

NOTE

状态驱动的渲染需要一个带自定义状态的 Flow(Flow[AgentState])。Crew 是面向对话的,不会以这种方式暴露自定义状态,因此使用 Crew 时请改用工具渲染。

构建一个实时任务规划器

本示例构建一个规划器,它把请求拆成大约十个步骤,并以清单的形式流式输出到 UI。它假定你已经搭好 CrewAI 服务器和 CopilotKit 前端。如果还没有,请从前端概览开始。

Add your own fields to the agent state

通过继承 CopilotKitState 来声明 UI 所需的状态。CopilotKitState 已经携带了对话(messages);你再添加任何想要渲染的其他内容,这里是任务步骤列表。

python
from typing import List, Literal
from pydantic import BaseModel, Field
from ag_ui_crewai.sdk import CopilotKitState

class TaskStep(BaseModel):
    description: str
    status: Literal["enabled", "disabled"]

class AgentState(CopilotKitState):
    steps: List[TaskStep] = Field(default_factory=list)

AgentState 上的所有内容都会包含在前端收到的状态快照中。每个步骤边界都会自动发出一次快照,因此只需写入 self.state,UI 就能在步骤之间获取到更新。若要在长时间运行的步骤进行中更新 UI,请显式发出(见下文)。

Write progress into state from the Flow

用自定义状态为你的 Flow 标注类型(Flow[AgentState]),让模型去填充它。这里 LLM 调用 generate_task_steps 工具;流式输出的工具调用落入对话中,这些步骤就在状态中可见了。

python
from crewai.flow.flow import Flow, start
from litellm import acompletion
from ag_ui_crewai.sdk import copilotkit_stream

GENERATE_TASK_STEPS_TOOL = {
    "type": "function",
    "function": {
        "name": "generate_task_steps",
        "description": "Break a task into about 10 short imperative steps.",
        "parameters": {
            "type": "object",
            "properties": {
                "steps": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "description": {"type": "string"},
                            "status": {"type": "string", "enum": ["enabled"]},
                        },
                        "required": ["description", "status"],
                    },
                },
            },
            "required": ["steps"],
        },
    },
}

class TaskPlannerFlow(Flow[AgentState]):
    @start()
    async def chat(self):
        response = await copilotkit_stream(
            await acompletion(
                model="openai/gpt-4o",
                messages=[
                    {"role": "system", "content": "Plan the task the user asks for."},
                    *self.state.messages,
                ],
                tools=[GENERATE_TASK_STEPS_TOOL],
                parallel_tool_calls=False,
                stream=True,
            )
        )
        message = response.choices[0].message
        self.state.messages.append(message)

用 copilotkit_stream 包裹 LLM 调用,就能在助手产生的 token 和工具调用生成时即流式输出到前端。你写入 self.state 的 steps 会在本步骤结束时发出的状态快照中一并发送。

Stream progress during a long step (optional)

自动快照在步骤边界触发。如果单个步骤做了大量工作,而你希望清单在执行过程中逐步填充,可以用 copilotkit_emit_state 自行发出中间状态。每次调用都会立即把当前状态推送到前端。

python
from ag_ui_crewai.sdk import copilotkit_emit_state

class TaskPlannerFlow(Flow[AgentState]):
    @start()
    async def execute(self):
        for step in self.state.steps:
            step.status = "disabled"          # mark done as you go
            await copilotkit_emit_state(self.state)   # push update now
            await do_work(step)

从 ag_ui_crewai.sdk 导入 copilotkit_emit_state。它需要 CopilotKit SDK(pip install "copilotkit[crewai]")。只有当某个步骤长到等待其边界快照会显得毫无响应时,才需要用它。

Serve the Flow over AG-UI

像注册其他任何 Flow 一样,在它自己的路径上注册它:

python
# server.py
from fastapi import FastAPI
from ag_ui_crewai.endpoint import add_crewai_flow_fastapi_endpoint
from my_agents.task_planner import TaskPlannerFlow

app = FastAPI(title="CrewAI Agent Server")

add_crewai_flow_fastapi_endpoint(
    app=app,
    flow=TaskPlannerFlow(),
    path="/task_planner",
)

完整的服务器、运行时和 provider 配置见前端概览,并记得在 CopilotKit 运行时路由中注册该智能体(这里是 task_planner)。

Read the live state in React

在前端,useAgent 会给你智能体的实时状态。订阅状态变化,这样每次 Flow 写入更新时你的组件都会重新渲染。

tsx
"use client";
import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2";

function TaskPlan() {
  const { agent } = useAgent({
    agentId: "task_planner",
    updates: [UseAgentUpdate.OnStateChanged],
  });

  const steps = agent?.state?.steps ?? [];

  return (
    <ul>
      {steps.map((s, i) => (
        <li key={i}>{s.description}</li>
      ))}
    </ul>
  );
}

useAgent 返回 { agent }。有几点需要注意:

  • agent.state 是实时的 Flow 状态。它的形状与你添加到 AgentState 的字段一致,因此 agent.state.steps 就是你的任务步骤列表。
  • agent.isRunning 告诉你智能体何时正在积极工作,可用于显示加载指示器或禁用输入。
  • updates: [UseAgentUpdate.OnStateChanged] 会在状态变化时重新渲染组件,因此清单会随 Flow 流式输出步骤而逐步填充。

接下来往哪里走

读取状态是基础。有两篇指南直接建立在其之上:

  • 共享状态补充了另一个方向:从 UI 编辑智能体的状态,并让 Flow 接收这一改动。
  • 预测性状态会把工具正在进行中的参数流式写入状态,让 UI 在工作提交之前就能反映出来。

相关

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。