| name | ai-blueking-dev |
| description | 蓝鲸 AI 小鲸组件开发指南。基于 @blueking/chat-x(UI 组件)和 @blueking/chat-helper(业务 SDK)开发 AI 聊天应用、智能体、对话界面。涵盖 ChatBot 独立使用、嵌入模式业务 Header(会话名称 + asideCollapsed 侧栏开关)、AIBlueking 完整集成、流式响应、快捷指令、划词选择、模型选择(Model Select)、自定义消息渲染(图表/表单/iframe)、HITL 人机协同(工具审批/用户提问/中断恢复)、流程化智能体节点重试跳过、渲染模式(chat/share/test 分享态)、字号主题、消息时间(timezone / MessageTime 四档格式)、侧栏自定义与自定义 Tab、欢迎区 `#welcome` 插槽、消息工具栏扩展(messageTools/updateTools)、非 Vue 宿主挂载等。触发场景:开发 AI 小鲸、集成 AI Agent、使用 chat-x/chat-helper、构建 AI 对话 UI、实现流式聊天、模型热切换、自定义消息组件渲染、human-in-the-loop、interrupt/resume、flow agent、自定义欢迎页、自定义消息工具按钮、嵌入式 ChatBot Header、侧栏展开收起、消息时间、timezone。 |
| metadata | {"author":"blueking","version":"5.28","packages":{"ai-blueking":"2.2.4","chat-x":"0.0.49-beta.13","chat-helper":"0.0.12-beta.25"}} |
AI 小鲸组件开发指南
何时激活此 Skill
- 开发 AI 聊天界面、对话应用
- 集成
@blueking/chat-x 或 @blueking/chat-helper
- 使用
ChatBot、AIBlueking、ChatContainer、MessageContainer 等组件
- 实现流式响应、会话管理、快捷指令、模型选择
- 基于
ai-blueking 组件进行二次开发
- 自定义消息渲染(
parseCustomBlocks、custom-component 代码块、#message 插槽自定义组件)
- 人机协同 HITL(工具审批、用户提问、流程节点重试/跳过、中断与恢复)
- 渲染模式(
renderMode:chat/share/test)、字号主题、侧栏自定义渲染与自定义 Tab
- 欢迎区
#welcome 插槽;消息工具栏 messageTools / updateTools 扩展与 agent-action / confirm-share(source);Claw 智能体(agentType === 'claw')自动隐藏编辑/删除/重新生成
- 非 Vue 宿主挂载(
mountAIBlueking / mountChatBot)
- 嵌入式 ChatBot 业务 Header(会话名称 +
v-model:asideCollapsed 侧栏开关)
- 消息时间展示(
timezone、MessageTime 四档格式、createdAt 来源)
架构概览
┌──────────────────────────────────────────────────────┐
│ 应用层 (Your App) │
├──────────────────────────────────────────────────────┤
│ @blueking/ai-blueking (业务组件层) │
│ AIBlueking ── 完整面板(Header + ChatBot + 拖拽) │
│ ChatBot ───── 独立聊天组件(composable 组装层) │
│ Managers ──── 业务管理器(Session/Chat/Shortcut) │
├────────────────────┬─────────────────────────────────┤
│ @blueking/chat-x │ @blueking/chat-helper │
│ (纯 UI 组件库) │ (AG-UI 业务 SDK) │
│ ChatContainer │ useChatHelper() │
│ ChatInput │ AGUIProtocol (流式协议) │
│ MessageContainer │ agent / session / message 模块 │
├────────────────────┴─────────────────────────────────┤
│ 后端 API │
└──────────────────────────────────────────────────────┘
关键约束:chat-x 和 chat-helper 互不依赖,ai-blueking 是唯一的组装层。
使用模式选择
| 场景 | 推荐模式 | 说明 |
|---|
| 需要完整面板(Header、拖拽、悬浮球、划词选择) | AIBlueking | 开箱即用的完整体验 |
| 只需聊天区域,嵌入到自定义布局中 | ChatBot 独立模式 | 轻量、灵活;Header / 侧栏开关需业务自建 |
| 需要精细控制每个 UI 组件 | 原子组件 + chat-helper | 最大灵活度,自行组装 |
快速开始
ChatBot 独立使用
<template>
<div style="width: 600px; height: 800px;">
<ChatBot
ref="chatBotRef"
url="https://your-api.com/api/"
:shortcuts="shortcuts"
:request-options="requestOptions"
hello-text="欢迎使用 AI 助手"
@send-message="handleSendMessage"
@error="handleError"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ChatBot } from '@blueking/ai-blueking';
import type { ChatBotExpose } from '@blueking/ai-blueking';
const chatBotRef = ref<ChatBotExpose>();
const requestOptions = {
headers: () => ({ Authorization: `Bearer ${getToken()}` }),
};
const shortcuts = [{ id: 'summary', name: '总结内容', icon: 'icon-summary' }];
const handleSendMessage = (message: string) => console.log('发送:', message);
const handleError = (error: Error) => console.error('错误:', error);
</script>
嵌入模式不是开箱即用的完整工作台:ChatBot 只有聊天区。会话标题、侧栏展开/收起必须由业务 Header 提供(v-model:asideCollapsed + CollapsedAsideIcon)。可运行样例:packages/ai-blueking/playground/views/EmbeddedHeaderView.vue(标题栏「查看源码」可复制最小接入代码);生产级实现:publish-template/src/views/ChatWindow.vue。详见 集成模式 · 嵌入式业务 Header。
AIBlueking 完整面板
<template>
<AIBlueking
ref="aiBluekingRef"
url="https://your-api.com/api/"
:request-options="requestOptions"
:shortcuts="shortcuts"
:enable-popup="true"
:draggable="true"
@send-message="handleSendMessage"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { AIBlueking } from '@blueking/ai-blueking';
import type { AIBluekingExpose } from '@blueking/ai-blueking';
const aiBluekingRef = ref<AIBluekingExpose>();
const showPanel = () => aiBluekingRef.value?.show();
</script>
原子组件自行组装的完整示例见 集成模式与示例。
关键陷阱
嵌入式 ChatBot 没有 Header / 侧栏开关
浮窗(AIBlueking)的展开/收起在 AIHeader。嵌入式 ChatBot 不提供该按钮;不传 asideCollapsed 时内部自持(默认折叠),业务无法从外部切换。必须:
- 自己画 Header(左侧会话名,右侧开关)
v-model:asideCollapsed 绑定(只写 :aside-collapsed 会让文件卡片 / addCustomTab 的内部展开失效)
- 图标复用
@blueking/chat-x 的 CollapsedAsideIcon(它是 VNode,模板里用 cloneVNode 包一层组件)
侧栏固定从右侧展开,已移除 placement。
Vue2:ChatBotV2 未注册 asideCollapsed / enableModelSelect / models / renderMode / errorToast / skills。嵌入式侧栏开关与模型选择请用 Vue3 ChatBot。
#welcome 与消息工具栏扩展
#welcome:AIBlueking → ChatBot → ChatContainer,scope { openingRemark, welcomeTitle };无插槽时默认欢迎 UI 不变
messageTools / updateTools:透传 chat-x 按 id 合并;triggerSelection 确认走 confirm-share(messages, source);其它自定义按钮走 agent-action
- 仅
!source || source.id === 'share' 执行内置分享(方案 A)
详见 ChatBot API。
#message 插槽透传 (CRITICAL)
自定义 ChatContainer / ChatBot / AIBlueking 的 #message 插槽时,必须透传用户消息工具回调 和 onInterruptResume,否则:
- 缺用户消息工具回调 → 用户消息的删除/编辑/复制/引用全部失效(AI 消息不受影响)
- 缺
onInterruptResume → HITL 中断卡片能渲染,但审批取消 / 用户提问作答 / 流程节点重试跳过全部失效(详见 HITL)
原理:AI 消息的 MessageTools 在 MessageContainer 内部渲染(不经过 #message 插槽),但用户消息的工具回调通过 MessageRender → UserMessage 的 onAction prop 传递、中断恢复通过 onInterruptResume 传递,二者都走 #message 插槽。
v2.2 变更:#message 插槽作用域现在提供第三个参数 onInterruptResume(除既有的 message、messageToolsStatus)。
<!-- ❌ 错误:用户消息工具 + HITL 恢复动作全部失效 -->
<template #message="{ message, messageToolsStatus }">
<MessageRender :message="message" :message-tools-status="messageToolsStatus" />
</template>
<!-- ✅ 正确:必须透传回调 + onInterruptResume -->
<template #message="{ message, messageToolsStatus, onInterruptResume }">
<MessageRender
:message="message"
:message-tools-status="messageToolsStatus"
:on-interrupt-resume="onInterruptResume"
:on-action="tool => handleUserAction(tool, message)"
:on-input-confirm="(content, docSchema) => handleUserInputConfirm(message, content, docSchema)"
:on-shortcut-confirm="formModel => handleUserShortcutConfirm(message, formModel)"
:tippy-options="messageToolsTippyOptions"
/>
</template>
requestOptions 响应式
requestOptions(及 chat-helper 的 requestData.headers / requestData.data)支持:
- 普通对象、
() => object
ref / computed(修改 .value 后后续请求自动生效)
- 外层
requestOptions 可为 ref / computed(AIBlueking / ChatBot / useChatBootstrap)
context:合并到消息 property.extra.context(简单 KV 自动转结构化条目;与 shortcuts 表单数据同级,key 冲突时 context 覆盖)
旧写法无需修改;需要动态 token、租户 ID 时可直接传 ref,不必再包一层稳定闭包。
requestOptions.data 注入规则
requestOptions.data(及 chat-helper requestData.data)按方法自动分流:
- POST/PUT/PATCH/DELETE → 合并进请求体
- GET/HEAD/OPTIONS → 合并进 query(
params),不会写入 body
context 不走 HTTP 分流,始终写入消息 property.extra.context
编程式渲染事件只用 emit
通过 h() + render() 渲染的组件,事件只用 emit,不要在 props 中定义 on* 回调,否则会导致同一事件触发两次。详见项目规则 vue3-h-render-events.mdc。
new-chat vs new-chat-created 事件
AIHeader 新增会话成功后触发两个事件,职责不同:
| 事件 | 参数 | 触发时机 | 说明 |
|---|
new-chat | 无 | 每次点击新增按钮 | V1 兼容,仅通知"用户点了新增",不携带数据 |
new-chat-created | (session: { sessionCode: string; sessionName?: string; createdAt?: string }) | sessionBusinessManager.createNewSession() 成功后 | 携带新会话信息,仅 V2 有 sessionBusinessManager 时触发 |
<!-- AIBlueking 中监听(事件会从 AIHeader 透传到 AIBlueking) -->
<AIBlueking
@new-chat="handleNewChat"
@new-chat-created="handleNewChatCreated"
/>
<script setup>
const handleNewChat = () => {
// V1 兼容:仅知道用户点击了新增
};
const handleNewChatCreated = (session) => {
// V2:拿到新会话的 sessionCode、sessionName、createdAt
console.log('新会话:', session.sessionCode, session.sessionName);
};
</script>
注意:当无 sessionBusinessManager(V1 模式)时,new-chat-created 不会触发。依赖此事件的业务需处理该情况。
addNewSession 接受 CreateSessionOptions
AIBluekingExpose.addNewSession 签名为 (options?: CreateSessionOptions) => Promise<void>,不传参数则自动生成 sessionCode/name。CreateSessionOptions 包含 sessionCode?、name?、isTemporary?。
beforeNimbusClick 拦截 Nimbus 点击
AIBluekingProps.beforeNimbusClick 可拦截 Nimbus 悬浮球点击。返回 false 阻止默认 showPanel,返回 true 或不返回继续默认行为。支持 async。Vue2 wrapper 中此 prop 已加入 deepWatchProps,动态切换时会重新 mount 内部 Vue3 组件。
错误处理:ChatBot @error vs AIBlueking @sdk-error
两种模式的错误事件接口不同:
| 模式 | 事件 | 参数 | 说明 |
|---|
| ChatBot 独立模式 | @error | (error: Error) | 原始 Error 对象;默认同时弹 Message(errorToast,文案 error.message) |
| AIBlueking 集成模式 | @sdk-error | { apiName, code, message, data } | 结构化错误数据;父层统一 toast,内嵌 ChatBot 关闭 toast 防双弹 |
AIBlueking 不对外暴露 @error 事件,所有错误统一通过 @sdk-error 输出。apiName 为 'chat' | 'getAgentInfo' | 'init' | 'session' | 'share',另有可选 action?、source?('business' | 'http' | 'protocol'):
init — 初始化(会话加载 / bootstrap)
getAgentInfo — 拉取 Agent 信息失败
chat — 流式对话(SSE onError、ChatBot 内部错误)
session — 会话操作(切换 / 删除 / 重命名等)
share — 分享确认失败
<!-- ChatBot 独立模式 -->
<ChatBot url="/api/" @error="(err) => console.error(err)" />
<!-- AIBlueking 集成模式 -->
<AIBlueking url="/api/" @sdk-error="handleSdkError" />
<script setup>
const handleSdkError = ({ apiName, code, message, data, action, source }) => {
if (apiName === 'init' || apiName === 'getAgentInfo') {
// 初始化 / Agent 信息失败
} else if (apiName === 'chat') {
// 对话错误
} else if (apiName === 'session') {
// 会话操作失败(看 action:historySwitch / rename 等)
}
};
</script>
@error 的触发范围(重要)
ChatBot 内部所有错误都汇聚到单一出口 useErrorReporter(src/components/composables/use-error-reporter.ts),覆盖两类来源:
- 调用点 catch:初始化、切换会话、发送消息、快捷指令、消息工具操作(重发 / 删除 / 反馈)、中断恢复、
updateAgentInfo、停止生成,以及独立模式下 AGUI 流式协议的 onError。
- 业务管理器失败事件:
ChatBusinessManager / SessionBusinessManager 的 chat-error / receive-error / session-error 经 managerErrorBridge 汇入同一出口,覆盖调用点没有 catch 的路径。
这个出口保证两件事:
- 参数一定是
Error 实例。非 Error 的 reject(字符串、裸对象)会经 toError() 归一化,对象带 message 字段时取该字段作为 error.message。不要再假设 @error 可能收到字符串。
- 同一个错误只触发一次。业务管理器普遍「emit 失败事件后 rethrow」,同一个 Error 实例会同时经桥接和调用点 catch 抵达,出口按实例去重。注意去重按实例而非 message,两次独立请求失败仍会触发两次。
仍有边界:纯 HTTP 层失败(既不在上述调用点,业务管理器也没包)不会触发 @error。要覆盖全部 HTTP 错误,用 AIBlueking 的 @sdk-error(内部注册了 chatHelper.onError 全局兜底),或自行对 getChatHelper()?.onError(...) 注册处理器。
停止生成(stopChat)的行为:接口成功才 emit stop,失败改为 emit error。此前失败会被静默吞掉并照常 emit stop,业务方无法感知;如果代码里依赖「stop 一定会触发」做收尾,需改为同时监听 error。
abortChat vs stopChat(重要):
| API | 作用 | 何时调用 |
|---|
abortChat() | 仅断开前端 chat_completion SSE,后端 agent 继续跑 | URL 变化 / 组件卸载 / 切会话 / 静默重连替换旧连接 |
stopChat(sessionCode) | 通知后端真正停止生成;后端经 SSE 推 RUN_ERROR(用户已取消)后关流 | 仅用户主动点击停止(stopGeneration) |
ChatBot 在 url / chatHelper 变化或卸载时只会 abortChat(),不会自动调 stopChat。
stopGeneration 只调 stopChat,不断开 SSE:前端 abort 会打乱后端 stop 时序。流由后端 RUN_ERROR 收尾;RUN_ERROR / RUN_FINISHED 均为终端事件,关流后不静默重连。
#headerLeft 插槽自定义 Header 左侧
AIBlueking 的 Header 区域分为 .left-section(logo + 标题 + 更多)和 .right-section(工具栏图标),两者之间提供 #headerLeft 插槽,用于在标题右侧、工具栏左侧插入自定义内容(如标签、状态指示器、自定义按钮)。
Vue3 用法:
<AIBlueking :url="apiUrl">
<template #headerLeft>
<span class="pro-tag">Pro</span>
</template>
</AIBlueking>
Vue2 用法:
Vue2 的 createElement 产生的是 Vue2 VNode,无法被内部 Vue3 应用渲染。需使用包导出的 h 函数:
import AIBluekingV2, { h } from '@blueking/ai-blueking/vue2';
<AIBluekingV2 :url="apiUrl">
<template #headerLeft>
<span class="pro-tag">Pro</span>
</template>
</AIBluekingV2>
render(h2) {
return h2(AIBluekingV2, {
props: { url: apiUrl },
scopedSlots: {
headerLeft: () => h('span', { class: 'pro-tag' }, 'Pro'),
},
});
}
插槽链路:AIBlueking #headerLeft → AIHeader #headerLeft,无 slot props。
右侧工具栏顺序(对齐设计稿):新增 → 历史 → 转人工 → 压缩 → 关闭 → 竖线分隔 → 侧栏展开/收起。
约束:
- 插槽内容应保持简洁(推荐单行),避免破坏 Header 高度(48px)和拖拽交互
- 插槽内容不可见时(如条件渲染)不影响 Header 布局
自定义消息渲染 (v2.1.4+)
AI 输出中嵌入图表、表单、iframe 等任意自定义组件。核心流程:
- AI 回复中使用
```custom-component 代码块输出 JSON 数据
parseCustomBlocks()(从 @blueking/ai-blueking 导出)解析为 ContentBlock[]
CustomMessageRenderer 根据 block.data.type 分发到业务组件
<ChatBot :url="apiUrl">
<template #message="{ message }">
<CustomMessageRenderer :message="message" />
</template>
</ChatBot>
完整实现代码(ChartWidget / IframeWidget / FormWidget / 扩展指南 / Prompt 指南)见 自定义消息渲染。
HITL 人机协同(v2.2+)
Agent 可在流式执行中中断,把控制权交回用户,处理后再恢复。三类场景:
| 场景 | 中断/操作 | UI |
|---|
| 工具审批 | InterruptReason.AIDevToolApproval | 审批卡片(会话流内) |
| 用户提问 | InterruptReason.UserQuestion | 提问浮层(输入框上方) |
| 流程节点失败 | FlowNodeRetry / FlowNodeSkip | 节点重试/跳过按钮 |
ChatBot / AIBlueking 开箱即用,无需额外代码。唯一注意点是上面的 #message 插槽必须透传 onInterruptResume。原子组件模式需自行把 onInterruptResume 接到 MessageContainer,并用 agent.streamRequest / agent.userOperationStreamRequest 实现恢复。
- 恢复统一入口:chat-x 的
OnInterruptResume = (payload: InterruptResume, interrupt?) => Promise<void> | void
- 底层原语:chat-helper 的
agent.streamRequest({ sessionCode, resume }) 与 agent.userOperationStreamRequest(sessionCode, operation, payload)
- HITL / 新发送默认
streamMode: 'start';刷新、切会话、静默重连走 resumeStreamingChat(stream_mode=attach),详见 chat-helper SDK API
- chat-helper 没有
onInterruptResume 方法(它只提供原语 + IResume 结构);统一回调在 chat-x/ai-blueking 层
完整协议、组件、集成示例(含用户「直接在输入框作答」旁路、流程节点重试/跳过、只读回显)见 HITL 人机协同。
渲染模式 renderMode(chat / share / test)
RenderMode(从 @blueking/chat-x / @blueking/ai-blueking 导出)控制整体交互形态,AIBlueking / ChatBot / ChatContainer 均支持(ChatContainer 为 v-model):
| 值 | 说明 |
|---|
RenderMode.Chat(默认) | 正常对话 |
RenderMode.Share | 只读分享态:隐藏输入与交互元素、禁用审批取消、流程节点仅保留「详情」。这是「分享态开放流程智能体查看能力」的实现方式 |
RenderMode.Test | 测试态:隐藏 share 工具 |
renderMode 是现代分享方案,取代了手动切换 enableSelection 的旧写法(enableSelection 仍用于「多选消息以生成分享链接」的选择动作,二者职责不同)。字号主题(size: 'normal' | 'small')已在 AIBlueking / ChatBot / ChatContainer 全链路透传。
消息时间(≥ v2.2.3)
对话区默认在工具栏旁展示 createdAt,无需开关:
- 用户消息:工具栏左侧,取该条
createdAt
- AI 回复组:工具栏右侧,取组内最后一条带
createdAt 的消息(本轮完成时间);reasoning / activity 不单独展示
- 四档格式:今天
12:00 / 昨天 昨天 12:00 / 今年内 3-12 12:00 / 跨年 2025-3-12 12:00(时分补零、月日不补零;分档与展示取同一时区日历日)
- 时区:
timezone 为 IANA 名(如 Asia/Shanghai)。MessageTime 优先用自身 props,否则读 injectGlobalConfig().timezone(由 ChatContainer 注入),都未配置时按浏览器时区;非法时区名回退浏览器时区
- 数据:历史消息 REST
created_at → IMessage.createdAt;本轮流式用 RUN_FINISHED.timestamp 转 ISO 后补上(已有时间不覆盖);无值不渲染
详见 ChatBot API 与 chat-x 组件 API。
模型选择(Model Select,≥ v2.2.2)
默认 enableModelSelect: true。初始化并行拉取 GET llms/;列表非空时在输入区展示 ModelSelector。
<!-- 默认开启 -->
<AIBlueking url="/api/" />
<!-- 关闭 -->
<ChatBot url="/api/" :enable-model-select="false" />
<!-- 外部列表(跳过内部拉取) -->
<ChatBot url="/api/" :models="myModels" />
关键语义:
| 规则 | 说明 |
|---|
| 展示 | enableModelSelect !== false 且列表非空 |
| 选中值 | UI 绑定 llm_name;发送传 llm_code(agent.chat 第 6 参) |
| 跟随 session | 切换历史会话时,用 session.model 同步 ModelSelector(命中列表时) |
| 写回 | 用户切换模型 → ModelSelectionManager.persistSessionModel(session.model 唯一写回出口) |
| 新建 | 所有建会话路径(含初始化 loadRecentSession)统一经 resolveModelForSession:优先当前选中 / preferred,校验落在可用列表内;enableModelSelect=false 时不强制写 model |
| 空列表 | 启用模型选择但无可用模型 → 抛 ModelUnavailableError,阻断建会话并上报 sdk-error(apiName: session) |
| 首次 / 兜底 | session.model 命中列表 → 选中;空/未知且无有效选中 → property.default / 首项 |
| 附件按钮 | 跟随选中模型 property.support_vision;快捷指令 supportUpload.vision 优先 |
编排入口:ModelSelectionManager(models / selectedLlmCode / resolveModelForSession / persistSessionModel)。
AIBlueking 创建实例并注入内嵌 ChatBot(modelSelectionManager prop),外壳层与聊天层共享同一份选中状态。
ChatBusinessManager / SessionBusinessManager 均委托该管理器,不再各自持有模型状态。
SDK:agent.getLlms() → agent.models;热切换 agent.chat(..., property, llm_code)。自定义请求参数(如 temperature)走 config.data,不要把 model 塞进 config.data。
参考资源
- ChatBot 组件 API — Props / Events / Slots / Expose、两种模式区别、初始化流程
- 架构设计原则 — 分层架构、数据流、职责边界、Composable 依赖图、开发检查清单
- chat-x 组件 API — ChatContainer / ChatInput / MessageContainer、
useMessageGroup、枚举与 IToolBtn
- chat-helper SDK API — agent / session / message 模块方法、AGUIProtocol、类型定义
- 集成模式与示例 — 各场景完整代码示例、包导出、常见任务速查;含 嵌入式业务 Header
- 内部开发模式 — Manager 使用、工具操作处理、文件上传、chatHelper 进阶用法
- 测试指南 — 测试配置、Mock 工厂、withSetup 模式、编写示例
- 自定义消息渲染 — 图表/表单/iframe 自定义组件、parseCustomBlocks、扩展指南
- HITL 人机协同 — 中断/恢复协议、工具审批、用户提问、流程节点重试跳过、
onInterruptResume 契约、只读回显
- Playground 实例索引 — 两套 playground 的可运行真实代码索引;HITL、侧栏自定义、自定义消息等「照着写」的权威参考
- 常见问题 — FAQ 和问题排查
💡 本 Skill 自包含,无需仓库即可使用——HITL 插槽接线、中断数据结构、侧栏自定义契约等关键示例均已内联在各 reference 文档中。若能访问源码仓库,packages/ai-blueking/playground(集成层)与 packages/chat-x/playground(组件层)另有可运行的完整示例,见 Playground 实例索引。