CopilotKit × CrewAI Conversational Flows:BYOC Hashbrown 声明式 UI 的端到端实战指南
【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit
本篇技术指南围绕 CopilotKit 仓库中showcase/integrations/crewai-conversational-flows的 BYOC Hashbrown 演示展开,完整讲解如何在 CrewAI 会话流(Conversational Flows)后端中驱动一个“自带 UI 组件库”(Bring Your Own Components,BYOC)的销售分析仪表盘:后端 LLM 直接输出 Hashbrown 线格式(wire format)的 JSON 信封,前端通过@hashbrownai/react的流式 JSON 解析器把组件渐进式渲染出来。读完本文,你将掌握从 CrewAI 系统提示词定制、FastAPI 端点挂载、Next.js 运行时代理到 Playwright 级 QA 验收的完整链路,可直接复用到你自己的声明式生成式 UI 集成中。
1. 前置条件
在运行或验证/demos/declarative-hashbrown(以及等价的旧路由/demos/byoc-hashbrown)之前,需要满足以下条件(依据 qa/declarative-hashbrown.md):
- 演示页面可访问:
/demos/declarative-hashbrown - 后端
agent_server.py正常运行且健康,它把该 Crew 挂载在/conversational_flows/byoc-hashbrown端点 - 路由代理 src/app/api/copilotkit-byoc-hashbrown/route.ts 将请求代理到
${AGENT_URL}/conversational_flows/byoc-hashbrown(AGENT_URL默认值为http://localhost:8000,可通过环境变量覆盖) - agent 后端已设置
OPENAI_API_KEY(Crew 的 chat LLM 使用gpt-5.4) - 前端包中已安装
@hashbrownai/core与@hashbrownai/react(版本0.5.0-beta.4)
2. 什么是 BYOC Hashbrown:概念与线格式
“BYOC”(Bring Your Own Components)指的是 UI 组件渲染能力由接入方自带的组件库提供,而不是依赖 CopilotKit 内置的固定组件集合。在本演示中,这个自带库就是 Hashbrown(@hashbrownai/react)。
关键设计决策在于线格式的选择:后端必须输出与 Hashbrown schema 形状完全一致的JSON 对象,而不是 Hashbrown 的 XML<ui>...</ui>DSL。原因在 src/agents/byoc_hashbrown_agent.py 的模块文档中写得很清楚:XML DSL 是 Hashbrown 自身驱动 LLM 时,由 Hashbrown 编译成 schema 文档的中间产物;而本演示是由 CrewAI 直接驱动 LLM,因此必须让模型直接产出最原始的 schema 形状,避免二次编译:
{ "ui": [ { "metric": { "props": { ... } } }, { "pieChart": { "props": { "title": "...", "data": "[{...}]" } } }, { "barChart": { "props": { ... } } }, { "dealCard": { "props": { ... } } }, { "Markdown": { "props": { "children": "..." } } } ] }前端则用@hashbrownai/react的useJsonParser(content, kit.schema)消费这个信封,在 token 逐段到达时渐进式组装 UI——这也是整个演示“边流式边渲染、无整页刷新”体验的基础。
一个容易踩坑的实现细节:pieChart与barChart的data字段必须是JSON 编码后的字符串(embedded JSON string)而非对象数组。这样在部分流式(partial streaming)期间 schema 仍能保持稳定,解析器不会因为字段类型在流式中间态发生变化而报错。
3. 后端实现:CrewAI 侧的纯 JSON 输出适配
3.1 最小单 Agent Crew
Crew 本体被刻意保持为“空壳”单 Agent 结构(byoc_hashbrown_agent.py):
- Agent 使用
gpt-5.4作为llm,tools=[](禁止调用任何工具) - Task 的描述与期望输出均为“返回单个符合 hashbrown schema 的 JSON 对象”
- Crew 使用
Process.sequential,并通过chat_llm="gpt-5.4"指定会话 LLM
Crew 之所以必须有 agent + task,仅仅是因为ChatWithCrewFlow需要至少一个 agent 和一个 task 才能完成平台侧样板(platform boilerplate)的装配;真正的行为完全由后续注入的自定义系统消息决定,Agent 的 role/backstory 只承担文档性作用。Crew 实例通过模块级_cached_crew缓存复用,避免每个请求重建。
3.2 系统提示词:约束 LLM 输出 hashbrown JSON
BYOC_HASHBROWN_SYSTEM_PROMPT(byoc_hashbrown_agent.py)是整条链路的“输出契约”,其要点包括:
- 强制形状:ALWAYS 输出单个形如
{"ui": [ { <componentName>: { "props": { ... } } }, ... ]}的 JSON 对象 - 禁止噪音:不得用代码围栏包裹、不得有任何前言或解释、必须是合法 JSON、不调用工具、不追问澄清信息
- 组件白名单:
metric、pieChart、barChart、dealCard、Markdown五个组件,各自 props schema 如下表
| 组件 | props schema | 说明 |
|---|---|---|
metric | { "label": string, "value": string } | KPI 卡片,value为已格式化字符串(如"$1.2M"、"248") |
pieChart | { "title": string, "data": string } | 环形图,data为 JSON 编码字符串,至少 3 段{label, value}对象 |
barChart | { "title": string, "data": string } | 纵向柱状图,data为 JSON 编码字符串,至少 3 根柱,通常按时间排序 |
dealCard | { "title": string, "stage": string, "value": number } | 单个销售机会;stage必须是prospect/qualified/proposal/negotiation/closed-won/closed-lost之一;value是裸数字(无货币符号与千分位逗号) |
Markdown | { "children": string } | 短说明文字,用于小节标题与摘要,children支持标准 Markdown |
- 数据纪律:用户要仪表盘或图表时必须生成合理示例数据而非拒绝;图表数据行数控制在 3–6 行、标签尽量简短;
Markdown只用于短标题/衔接句,不输出长段落;绝不输出白名单之外的组件;图表data必须是 JSON 字符串,内部引号需要转义
提示词内置了一个完整的 Q4 销售仪表盘示例响应,覆盖 Markdown 标题 + 两个 metric + 饼图 + 柱状图,可作为 prompt 工程层面的可直接复制范本。
3.3 两条注入管线:preseed 与 hard-override
CrewAI 桥接层(ag_ui_crewai.endpoint.add_crewai_crew_fastapi_endpoint)默认通过build_system_message(crew_chat_inputs)组装系统提示词,而generate_crew_chat_inputs会执行二次 AI 调用来描述 crew 及输入,并把固定的一套“CrewAI platform”样板话术(自我介绍、询问澄清等)包裹在提示词外层——这恰恰与纯 JSON 输出目标相冲突。因此 src/agents/_chat_flow_helpers.py 提供了两条互补的注入管线:
preseed_system_prompt(crew_name, description):在延迟的 Flow 构造发生之前,向桥接层的 chat-input 生成器注册一个手写的ChatInputs(crew_description=<我们的提示词>, inputs=[])。好处是build_system_message会把我们的描述原样嵌入,同时跳过启动期的二次 AI 描述调用,让 crew 构造变成同步且廉价的,首请求不再被 LLM 探测(LLM probe)阻塞。代码通过拦截crew_chat_generate_crew_chat_inputs实现,不直接写桥接层的 weakref 缓存,保持缓存不变式安全。install_custom_system_message(crew_name, full_system_message):针对 BYOC 这类必须精确控制输出形状的场景,通过 monkey-patchChatWithCrewFlow.__init__,在实例构造完成后立即把自定义系统消息覆盖到self.system_message上,彻底替换上游拼好的整套(含样板话术的)系统消息。钩子以crew_name为键,未注册自定义消息的 crew 自动回退到默认行为。
两个 helper 的调用顺序与幂等性都经过设计:可安全地在add_crewai_crew_fastapi_endpoint之前或之后调用(端点构造被延迟到首次请求),且模块级字典只在首次注入时打一次 patch。
3.4 后端路由与端点挂载
src/app/api/copilotkit-byoc-hashbrown/route.ts 是 Next.js 侧的运行时代理:
- 通过
@copilotkit/runtime/v2创建CopilotRuntime,用@ag-ui/client的HttpAgent指向http://localhost:8000/conversational_flows/byoc-hashbrown agents表中同时注册"byoc-hashbrown-demo"与default两个键,保证页面以agent="byoc-hashbrown-demo"挂载时能命中同一后端POST处理器使用createCopilotRuntimeHandler以single-route模式处理请求,basePath为/api/copilotkit-byoc-hashbrown;异常会以 500 +{error, stack}JSON 形式返回,便于排查
agent_server.py则负责把byoc_hashbrown_agent的 crew 挂到/conversational_flows/byoc-hashbrownFastAPI 端点,前端运行时 URL 与后端端点由此连通。
4. 前端消费方式与页面装配
前端页面src/app/demos/byoc-hashbrown/page.tsx只是对src/app/demos/declarative-hashbrown/page.tsx的再导出,两个 URL 渲染完全一致——旧路由/demos/byoc-hashbrown是为了兼容历史路径保留的别名。
装配链路(依据 qa/declarative-hashbrown.md 的集成说明与 route.ts 注释):
- 页面把
CopilotChat包裹在HashBrownDashboardprovider 中 - 用
runtimeUrl="/api/copilotkit-byoc-hashbrown"指向专属运行时,agent="byoc-hashbrown-demo" - 通过
useUiKit+useJsonParser覆写 assistant 消息槽位,把 hashbrown 形状的结构化输出渲染成 catalog 组件 - 页面根节点带
data-testid="byoc-hashbrown-root"标记 - 渲染器(如
hashbrown-renderer.tsx)负责把metric、pieChart、barChart、dealCard映射为对应 UI 卡片,Markdown组件允许在仪表盘上方渲染 Markdown 标题——这是预期行为,不算 catalog 违规
5. 端到端 QA 验收步骤
下面的验收清单可直接作为手动测试用例或转译为 Playwright 断言(参考 e2e 目录下的declarative-hashbrown.spec.ts与 claude-sdk-python 侧的tests/e2e/byoc-hashbrown.spec.ts)。
5.1 页面加载
- 导航到
/demos/declarative-hashbrown - 页头可见 “Declarative UI: Hashbrown”
- 页面可见提及
@hashbrownai/react的简短描述 - 聊天区底部可见输入框(composer)
- composer 内可见 3 个建议 pill,标签为:
Sales dashboard、Revenue by category、Expense trend - 控制台无红色报错(amber 水合警告可容忍)
5.2 Sales dashboard 建议
- 点击 “Sales dashboard” pill,
useConfigureSuggestions会自动派发该消息 - 45 秒内,至少一个
data-testid="metric-card"渲染进对话记录 - 45 秒内,至少一个图表(
data-testid="bar-chart"或data-testid="pie-chart")渲染 - 渲染内容渐进式出现——完整响应结束前先出现部分 UI(可选视觉检查)
5.3 Revenue by category
- 点击 “Revenue by category”
- 45 秒内渲染出饼图(
data-testid="pie-chart") - 图例至少 4 段,标签与数值可读
5.4 Expense trend
- 点击 “Expense trend”
- 45 秒内渲染出柱状图(
data-testid="bar-chart") - 图表至少 3 根柱,标签形似月份
5.5 自由输入
- 输入 “Show me revenue trends for the last six months” 并回车
- 至少一个 catalog 组件(metric、chart 或 deal)被渲染
5.6 多轮对话
- 首次渲染完成后,发送后续提示(如 “Now break it down by region”)
- 新渲染与之前的渲染并列出现在对话记录中,不清空历史
5.7 错误处理
- 空输入发送是 no-op(按钮保持禁用)
- 原始 JSON 信封对用户不可见——消息列表中只出现渲染后的 catalog 组件
- 成功流程中控制台保持干净
6. 期望结果与判定标准
- 建议 pill 在 45 秒内产出 hashbrown 渲染
- 流式渲染随 JSON chunk 到达而渐进组装
- 无未捕获异常,不出现
useHashBrownKit must be used within HashBrownDashboard错误 - 多轮对话不清空先前渲染
结合 claude-sdk-python 侧同名 QA 文档(showcase/integrations/claude-sdk-python/qa/byoc-hashbrown.md)补充的通用判定:聊天在 3 秒内加载、Agent 在 15 秒内响应、后端发出的是{ui: [...]}JSON 信封而绝不出 XML——这三条是判断“BYOC 输出契约是否被破坏”的快速哨兵。
7. 集成注意事项与已知约定
- hashbrown 信封提示词位于 src/agents/byoc_hashbrown_agent.py;后端模块上的
byoc_前缀是刻意的并保持不变 - 运行时侧尚未重命名:页面仍挂
runtimeUrl="/api/copilotkit-byoc-hashbrown"、agent="byoc-hashbrown-demo",页面根节点带data-testid="byoc-hashbrown-root"(与 north star 不同);旧路由/demos/byoc-hashbrown再导出同一页面,两个 URL 渲染一致 - assistant 会在仪表盘上方额外输出一个 Markdown 标题,这是预期行为,不属于 catalog 违规
- CrewAI 桥接层要求 agent + task 的最小结构才能完成平台样板装配;若你的 crew 目标是纯结构化输出,请复刻本文 3.3 节的
preseed_system_prompt+install_custom_system_message双管线方案,以绕开build_system_message中不利于结构化输出的固定话术
【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考