主题
预测式状态更新
将进行中的工具调用参数流式写入智能体状态,使 UI 在智能体仍在生成时就乐观地更新。
让工作过程实时可见
通常,从 UI 的角度看,工具调用是原子的:智能体决定写什么,而你的界面只有在调用完成后才能看到结果。对于一个会产出大文档的工具来说,这意味着漫长的等待,然后所有内容一次性到位。
预测式状态更新消除了这种等待。你把流式传输的工具参数投射到智能体状态的某个字段上,于是当模型逐个 token 生成参数时,该状态字段会实时填充。智能体正在写的文档会随着输入出现在编辑器中,而不是等到最后。
NOTE
预测式状态依赖带有自定义状态的 Flow(Flow[AgentState])。它把流式工具参数投射到状态字段上,因此裸 Crew 没有对应的实现。
与共享状态的对比
两种模式都从前端读取智能体状态,但它们解决的问题不同:
| 模式 | 作用 |
|---|---|
| 预测式状态 | 单向。将进行中的工具参数流式写入状态字段,使 UI 在生成期间、调用完成之前就更新。 |
| 共享状态 | 双向。UI 读取并写入智能体已提交的状态,使应用与智能体在多轮之间保持同步。 |
当你想要对智能体正在产出的内容做乐观的、生成中的预览时,选用预测式状态。当用户需要把状态编辑回去时,选用共享状态。
分步讲解
这里假设你已经有一个通过 AG-UI 提供服务的 Crew 或 Flow,并已接好 CopilotKit 前端。如果没有,请先看前端概览。
Define a Flow with custom state
预测式状态会把工具参数投射到状态字段上,因此你的 Flow 需要一个有类型的字段来接收它。将你想流式写入的字段添加到 CopilotKitState 子类中。
python
from typing import Optional
from crewai.flow.flow import Flow, start, router, listen
from litellm import acompletion
from ag_ui_crewai.sdk import copilotkit_stream, copilotkit_predict_state, CopilotKitState
WRITE_DOCUMENT_TOOL = {
"type": "function",
"function": {
"name": "write_document",
"description": "Write the full document in markdown.",
"parameters": {
"type": "object",
"properties": {
"document": {"type": "string", "description": "The document to write"},
},
},
},
}
class AgentState(CopilotKitState):
document: Optional[str] = None
class DocumentFlow(Flow[AgentState]):
@start()
@listen("route_follow_up")
async def start_flow(self):
passMap a state field to a tool argument
在开始流式输出补全内容之前调用 copilotkit_predict_state。它告诉运行时把指定的工具参数投射到指定的状态字段上:当 write_document 调用流式输出其 document 参数时,document 状态字段会实时更新。
python
@router(start_flow)
async def chat(self):
# Map the `document` state field to the `document` argument of write_document.
# As the tool call streams, the state field updates live.
await copilotkit_predict_state({
"document": {"tool_name": "write_document", "tool_argument": "document"},
})
response = await copilotkit_stream(
await acompletion(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": "Write and edit the document with write_document."},
*self.state.messages,
],
tools=[*self.state.copilotkit.actions, WRITE_DOCUMENT_TOOL],
parallel_tool_calls=False,
stream=True,
)
)
message = response.choices[0].message
self.state.messages.append(message)关键在于 copilotkit_predict_state({ "<state_field>": {"tool_name": ..., "tool_argument": ...} })。没有它,前端只有在工具调用完成后才能看到 document。有了它,部分参数会在智能体仍在生成时流式写入该字段。
如前端概览所示,用 add_crewai_flow_fastapi_endpoint(...) 为该 Flow 提供服务。
Read the predicted state on the frontend
在前端,用 useAgent 读取该字段并订阅状态变化。由于后端正在把流式参数投射到 document,该组件会随着智能体“打字”而重新渲染。
tsx
"use client";
import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2";
function DocumentView() {
const { agent } = useAgent({
agentId: "document",
updates: [UseAgentUpdate.OnStateChanged],
});
const document = (agent?.state as { document?: string })?.document ?? "";
return <article>{document}</article>; // updates as the agent types
}document 字段会随着智能体生成 write_document 调用而逐步填充,因此编辑器会实时更新,而不是在最后一次性到位。