关于 use-x-chat
use-x-chat 是面向 React AI 对话应用开发者的技能指南,介绍如何用 @ant-design/x-sdk 的 useXChat Hook 管理消息和请求。它涵盖占位与错误处理、消息转换、请求中止及多会话管理,并要求先准备 Chat Provider。
主要功能
- 01管理对话消息与请求状态
- 02配置请求占位内容和失败回退
- 03转换消息以适配 UI 组件
- 04中止请求及重新生成回复
- 05结合 useXConversations 管理多会话
适用场景
- 01为 React 对话界面接入消息状态
- 02在请求失败或中止时显示回退消息
- 03实现会话切换与延迟发送首条消息
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ant-design/ x --skill use-x-chat安装后在 Claude Code 中输入/use-x-chat确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
reference/API.mdCORE.mdEXAMPLES.md详细介绍
🎯 技能定位
核心定位:使用
useXChatHook 构建专业的 AI 对话应用。前置条件:已拥有自定义 Chat Provider(请参阅 x-chat-provider 技能)
目录
🚀 快速开始
1. 依赖管理
- @ant-design/x-sdk:2.2.2+
- @ant-design/x:最新版本(UI 组件)
npm install @ant-design/x-sdk@latest @ant-design/x@latest
2. 三步集成
步骤 1:准备 Provider
由 x-chat-provider 技能处理。请注意,XRequest 必须传入 manual: true:
import { MyChatProvider } from './MyChatProvider';
import { XRequest } from '@ant-design/x-sdk';
// ⚠️ manual: true is required
const provider = new MyChatProvider({
request: XRequest('https://your-api.com/chat', { manual: true }),
});
步骤 2:基本用法
import { useXChat } from '@ant-design/x-sdk';
const ChatComponent = () => {
const { messages, onRequest, isRequesting } = useXChat({
provider,
requestPlaceholder: (_, { messages }) => ({
content: 'Thinking...',
role: 'assistant',
}),
requestFallback: (_, { error, messageInfo }) => {
if (error.name === 'AbortError') {
return { content: messageInfo?.message?.content || 'Reply cancelled', role: 'assistant' };
}
return { content: 'Network error, please try again later', role: 'assistant' };
},
});
return (
<div>
{messages.map((msg) => (
<div key={msg.id}>
{msg.message.role}: {msg.message.content}
</div>
))}
<button onClick={() => onRequest({ query: 'Hello' })}>Send</button>
</div>
);
};
步骤 3:集成 UI
⚠️
messages的类型为MessageInfo<ChatMessage>[],不能直接传给Bubble.List。必须将其映射为{ key, role, content, loading }格式。Bubble.List使用role属性(而非roles)来配置角色样式。
import { Bubble, Sender } from '@ant-design/x';
const ChatUI = () => {
const { messages, onRequest, isRequesting, abort } = useXChat({ provider });
return (
<div style={{ height: 600 }}>
<Bubble.List
// ✅ Correct: use role (not roles)
role={{
user: { placement: 'end' },
assistant: { placement: 'start' },
}}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role, // matches role config key
content: message.content, // message content
loading: status === 'loading', // loading animation
}))}
/>
<Sender
loading={isRequesting}
onSubmit={(content) => onRequest({ query: content })}
onCancel={abort}
/>
</div>
);
};
当 ChatMessage 为对象类型(而非字符串)时
当 ChatMessage 是复杂对象(例如包含 content、attachments 字段)时,请使用 contentRender:
<Bubble.List
role={{
assistant: {
placement: 'start',
// contentRender receives content param, which is the message field itself
contentRender(content: MyMessage) {
return (
<div>
<div>{content.content}</div>
{content.attachments?.map((a) => (
<FileCard key={a.url} name={a.name} />
))}
</div>
);
},
},
user: {
placement: 'end',
contentRender(content: MyMessage) {
return content.content;
},
},
}}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role,
content: message, // ⚠️ Pass the entire message object; contentRender handles rendering
loading: status === 'loading',
}))}
/>
🧩 核心概念
数据模型
⚠️ 重要:
messages类型为MessageInfo<ChatMessage>[];消息内容位于msg.message中
interface MessageInfo<ChatMessage> {
id: number | string; // Message unique identifier
message: ChatMessage; // Actual message content (your ChatMessage type)
status: MessageStatus; // Message status
extraInfo?: AnyObject; // Extended info (note: extraInfo, not extra)
}
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';
// local: locally sent user message
// loading: AI reply placeholder (corresponds to requestPlaceholder)
// updating: AI streaming output in progress
// success: AI reply complete
// error: request failed
// abort: user actively cancelled
useXChat 配置选项
| 选项 | 类型 | 描述 |
|---|---|---|
provider | AbstractChatProvider<ChatMessage, Input, Output> | 必填,Provider 实例 |
conversationKey | string | 会话唯一标识,多会话场景必填 |
defaultMessages | DefaultMessageInfo[] | () => ... | async () => ... | 默认显示的消息,支持异步加载 |
requestPlaceholder | ChatMessage | (requestParams, { messages }) => ChatMessage | 请求期间显示的占位消息 |
requestFallback | ChatMessage | (requestParams, { error, errorInfo, messages, messageInfo }) => ChatMessage | Promise<ChatMessage> | 请求失败或中止时显示的备用消息 |
parser | (message: ChatMessage) => BubbleMessage | BubbleMessage[] | 将 ChatMessage 转换为组件可使用的格式,支持一对多转换 |
requestFallback的messageInfo类型为MessageInfo<ChatMessage>,即请求失败时正在更新的消息。requestFallback会处理网络错误(error)和用户中止(error.name === 'AbortError')。
useXChat 返回值
| 返回值 | 类型 | 描述 |
|---|---|---|
messages | MessageInfo<ChatMessage>[] | 消息列表;传给 Bubble.List 前必须先进行映射 |
parsedMessages | MessageInfo<ParsedMessage>[] | 经 parser 转换后的消息列表(设置了 parser 时使用) |
onRequest | (params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 添加消息并触发请求 |
isRequesting | boolean | 请求是否正在进行 |
abort | () => void | 中止当前请求 |
setMessages | (messages: Partial<MessageInfo<ChatMessage>>[]) => void | 直接修改消息列表,不会触发请求 |
setMessage | (id: string | number, info: Partial<MessageInfo<ChatMessage>>) => void | 修改单条消息,不会触发请求 |
removeMessage | (id: string | number) => boolean | 删除一条消息,并返回删除是否成功 |
onReload | (id: string | number, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 重新生成 AI 回复 |
queueRequest | (conversationKey: string | symbol, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 将请求加入队列,并在会话初始化后发送 |
isDefaultMessagesRequesting | boolean | 默认消息是否正在异步加载 |
🔧 核心函数详情
核心功能参考:CORE.md
🗂️ 多会话管理
useXConversations Hook
useXConversations 是 @ant-design/x-sdk 提供的会话列表管理 Hook,与 useXChat 搭配使用以实现多会话:
import { useXConversations } from '@ant-design/x-sdk';
import type { ConversationData } from '@ant-design/x-sdk';
const {
conversations, // ConversationData[]: conversation list
activeConversationKey, // string: currently active conversation key
setActiveConversationKey, // (key: string) => void: switch conversation
addConversation, // (ConversationData, placement?) => boolean
removeConversation, // (key: string) => boolean
setConversation, // (key: string, ConversationData) => boolean
getConversation, // (key: string) => ConversationData | undefined
setConversations, // (list: ConversationData[]) => void
getMessages, // (key: string) => MessageInfo[] | undefined (read messages across components)
} = useXConversations({
defaultConversations: [
{ key: 'conv-1', label: 'Conversation 1' },
{ key: 'conv-2', label: 'Conversation 2' },
],
defaultActiveConversationKey: 'conv-1',
});
多会话完整模式
import { useXChat, useXConversations } from '@ant-design/x-sdk';
import { OpenAIChatProvider, XRequest } from '@ant-design/x-sdk';
import { Bubble, Conversations, Sender } from '@ant-design/x';
import React, { useEffect, useRef } from 'react';
// ⚠️ Each conversation must have its own Provider instance, otherwise state mixes
const providerCache = new Map<string, OpenAIChatProvider>();
function getProvider(key: string): OpenAIChatProvider {
if (!providerCache.has(key)) {
providerCache.set(
key,
new OpenAIChatProvider({
request: XRequest(BASE_URL, { manual: true, params: { model: 'gpt-4o', stream: true } }),
}),
);
}
return providerCache.get(key)!;
}
const App = () => {
const senderRef = useRef<any>(null);
const { conversations, activeConversationKey, setActiveConversationKey, addConversation } =
useXConversations({
defaultConversations: [{ key: 'conv-1', label: 'New Conversation' }],
defaultActiveConversationKey: 'conv-1',
});
const { messages, onRequest, isRequesting, abort, queueRequest } = useXChat({
provider: getProvider(activeConversationKey),
conversationKey: activeConversationKey,
// Async load default messages
defaultMessages: async ({ conversationKey }) => {
// Load history from server based on conversationKey
return [];
},
requestFallback: (_, { error, messageInfo }) => {
if (error.name === 'AbortError') {
return { content: messageInfo?.message?.content || 'Cancelled', role: 'assistant' };
}
return { content: 'Request failed', role: 'assistant' };
},
});
// Clear input on conversation switch
useEffect(() => {
senderRef.current?.clear?.();
}, [activeConversationKey]);
const handleNewConversation = () => {
const newKey = `conv-${Date.now()}`;
addConversation({ key: newKey, label: `New Conversation ${conversations.length + 1}` });
setActiveConversationKey(newKey);
};
return (
<div style={{ display: 'flex', height: '100vh' }}>
<Conversations
items={conversations}
activeKey={activeConversationKey}
onActiveChange={setActiveConversationKey}
creation={{ onClick: handleNewConversation }}
/>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
<Bubble.List
role={{ assistant: { placement: 'start' }, user: { placement: 'end' } }}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role,
content: message.content,
loading: status === 'loading',
}))}
/>
<Sender
ref={senderRef}
loading={isRequesting}
onCancel={abort}
onSubmit={(val) => {
onRequest({ messages: [{ role: 'user', content: val }] });
}}
/>
</div>
</div>
);
};
queueRequest:切换会话后延迟发送
// Scenario: user switches to a new conversation and triggers an initial message simultaneously
// queueRequest waits for defaultMessages async loading to complete, then sends the request
const handleNewConversationWithFirstMessage = () => {
const newKey = `conv-${Date.now()}`;
addConversation({ key: newKey, label: 'New Conversation' });
setActiveConversationKey(newKey);
// Queue the message; sent automatically after newKey conversation's defaultMessages finish loading
queueRequest(newKey, {
messages: [{ role: 'user', content: 'Hello! Please introduce yourself.' }],
});
};
📋 前置条件和依赖项
| 使用场景 | 所需技能/Provider | 顺序 |
|---|---|---|
| 私有 API 适配 | x-chat-provider → use-x-chat | 先创建 Provider |
| 标准 API | 内置 Provider + use-x-chat | 直接使用 |
| 多会话 | Provider 工厂 + useXConversations + useXChat | 搭配使用 |
🚨 开发规则
使用 use-x-chat 前,请确认:
- 已有 Provider(自定义或内置 Provider)
- Provider 的 XRequest 已配置
manual: true - 了解
MessageInfo数据结构(消息内容位于msg.message中) -
Bubble.List使用role属性(不是roles) - 多会话场景:每个会话都有各自的 Provider 实例
测试用例规则
- 如果用户没有明确要求测试用例,不要添加测试文件
代码质量规则
- 完成后必须检查类型:运行
tsc --noEmit,确保没有类型错误 - 保持代码整洁:移除所有未使用的变量和导入
🔗 参考资源
📚 核心参考文档
- API.md - 完整的 API 参考文档
- CORE.md - 核心函数详情
- EXAMPLES.md - 实用示例代码
🌐 SDK 官方文档
💻 示例代码
- with-x-chat.tsx - 多会话完整示例
- openai-callback.tsx - 回调 + removeMessage 示例
- developer.tsx - 使用 developer 角色的系统提示词
- custom-provider-width-ui.tsx - 自定义 Provider 完整示例