Skip to content
cccskills
FreePublished on GitHub

use-x-chat

专注讲解如何使用 useXChat Hook,包括自定义 Provider 的集成、消息管理、错误处理、多会话管理等

The English summary is being prepared. Showing the original description.

Works withOpenAI
See how to install

Files included (4)

  • SKILL.md14.1 KB
  • reference/API.md4.8 KB
  • reference/CORE.md8.3 KB
  • reference/EXAMPLES.md11.5 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

🎯 技能定位

核心定位:使用 useXChat Hook 构建专业级 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 是必须的
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: '正在思考中...',
      role: 'assistant',
    }),
    requestFallback: (_, { error, messageInfo }) => {
      if (error.name === 'AbortError') {
        return { content: messageInfo?.message?.content || '已取消回复', role: 'assistant' };
      }
      return { content: '网络异常,请稍后重试', role: 'assistant' };
    },
  });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          {msg.message.role}: {msg.message.content}
        </div>
      ))}
      <button onClick={() => onRequest({ query: '你好' })}>发送</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
        // ✅ 正确:使用 role(不是 roles)
        role={{
          user: { placement: 'end' },
          assistant: { placement: 'start' },
        }}
        items={messages.map(({ id, message, status }) => ({
          key: id,
          role: message.role, // 用于匹配 role 配置
          content: message.content, // 消息内容
          loading: status === 'loading', // 加载动画
        }))}
      />
      <Sender
        loading={isRequesting}
        onSubmit={(content) => onRequest({ query: content })}
        onCancel={abort}
      />
    </div>
  );
};

当 ChatMessage 是对象类型时(非字符串)

当 ChatMessage 是复杂对象(如有 content、attachments 等字段),需用 contentRender 渲染:

<Bubble.List
  role={{
    assistant: {
      placement: 'start',
      // contentRender 接收 content 参数,就是 message 字段本身
      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, // ⚠️ 传整个 message 对象,contentRender 会处理渲染
    loading: status === 'loading',
  }))}
/>

🧩 核心概念

数据模型

⚠️ 重要:messages 类型是 MessageInfo<ChatMessage>[],消息内容在 msg.message 中

interface MessageInfo<ChatMessage> {
  id: number | string; // 消息唯一标识
  message: ChatMessage; // 实际消息内容(你的 ChatMessage 类型)
  status: MessageStatus; // 消息状态
  extraInfo?: AnyObject; // 扩展信息(注意:是 extraInfo,不是 extra)
}

type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';
// local: 用户发送的本地消息
// loading: AI 回复占位中(requestPlaceholder 对应此状态)
// updating: AI 正在流式输出
// success: AI 回复完成
// error: 请求失败
// abort: 用户主动取消

useXChat 配置项

配置项类型说明
providerAbstractChatProvider<ChatMessage, Input, Output>必填,Provider 实例
conversationKeystring会话唯一标识,多会话必填
defaultMessagesDefaultMessageInfo[] | () => ... | async () => ...默认展示消息,支持异步加载
requestPlaceholderChatMessage | (requestParams, { messages }) => ChatMessage请求中的占位消息
requestFallbackChatMessage | (requestParams, { error, errorInfo, messages, messageInfo }) => ChatMessage | Promise<ChatMessage>请求失败/中止时的兜底消息
parser(message: ChatMessage) => BubbleMessage | BubbleMessage[]将 ChatMessage 转为组件消费格式,支持一转多

requestFallback 中 messageInfo 类型为 MessageInfo<ChatMessage>,是请求失败时正在更新的那条消息。 requestFallback 同时处理网络错误(error)和主动取消(error.name === 'AbortError')。

useXChat 返回值

返回值类型说明
messagesMessageInfo<ChatMessage>[]消息列表,需映射后传给 Bubble.List
parsedMessagesMessageInfo<ParsedMessage>[]经过 parser 转译后的消息列表(有 parser 时用这个)
onRequest(params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void添加消息并触发请求
isRequestingboolean是否正在请求
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队列化请求,等待会话初始化后发送
isDefaultMessagesRequestingboolean默认消息是否在异步加载中

🔧 核心功能详解

核心功能参考 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[]:会话列表
  activeConversationKey, // string:当前激活会话的 key
  setActiveConversationKey, // (key: string) => void:切换会话
  addConversation, // ( ConversationData, placement?) => boolean
  removeConversation, // (key: string) => boolean
  setConversation, // (key: string, data: ConversationData) => boolean
  getConversation, // (key: string) => ConversationData | undefined
  setConversations, // (list: ConversationData[]) => void
  getMessages, // (key: string) => MessageInfo[] | undefined(跨组件读取消息)
} = useXConversations({
  defaultConversations: [
    { key: 'conv-1', label: '会话 1' },
    { key: 'conv-2', label: '会话 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';

// ⚠️ 每个会话必须有独立的 Provider 实例,否则状态会混用
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: '新对话' }],
      defaultActiveConversationKey: 'conv-1',
    });

  const { messages, onRequest, isRequesting, abort, queueRequest } = useXChat({
    provider: getProvider(activeConversationKey),
    conversationKey: activeConversationKey,
    // 异步加载默认消息
    defaultMessages: async ({ conversationKey }) => {
      // 根据 conversationKey 从服务器加载历史消息
      return [];
    },
    requestFallback: (_, { error, messageInfo }) => {
      if (error.name === 'AbortError') {
        return { content: messageInfo?.message?.content || '已取消', role: 'assistant' };
      }
      return { content: '请求失败', role: 'assistant' };
    },
  });

  // 切换会话时清空输入框
  useEffect(() => {
    senderRef.current?.clear?.();
  }, [activeConversationKey]);

  const handleNewConversation = () => {
    const newKey = `conv-${Date.now()}`;
    addConversation({ key: newKey, label: `新对话 ${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:会话切换后延迟发送

// 场景:用户切换到新会话,同时触发一条初始消息
// queueRequest 会等 defaultMessages 异步加载完成后,再发送请求

const handleNewConversationWithFirstMessage = () => {
  const newKey = `conv-${Date.now()}`;
  addConversation({ key: newKey, label: '新对话' });
  setActiveConversationKey(newKey);

  // 把消息加入队列,等 newKey 会话的 defaultMessages 加载完后自动发送
  queueRequest(newKey, {
    messages: [{ role: 'user', content: '你好!请自我介绍' }],
  });
};

📋 使用前提和依赖

使用场景需要的技能/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 确保无类型错误
  • 保持代码整洁:移除所有未使用的变量和导入

🔗 参考资源

📚 核心参考文档

🌐 SDK 官方文档

💻 示例代码

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Focus on explaining how to use the useXChat Hook, including custom Provider integration, message management, error handling, multi-conversation management, and more

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

x-card

Free

Use when building AI-driven UIs with @ant-design/x-card — covers XCard.Box, XCard.Card, A2UI v0.9 commands, data binding, catalogs, actions, and streaming patterns.

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

x-card

Free

当需要用 @ant-design/x-card 让 AI Agent 动态渲染富交互 UI 时使用——涵盖 XCard.Box、XCard.Card、A2UI v0.9 命令、数据绑定、Catalog、Actions 和流式渲染模式。

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

专注于自定义 Chat Provider 的实现,帮助将任意流式接口适配为 Ant Design X 标准格式

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

Focus on implementing custom Chat Provider, helping to adapt any streaming interface to Ant Design X standard format

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

Use when building AI chat UIs with @ant-design/x components — covers Bubble, Sender, Conversations, Prompts, ThoughtChain, Actions, Welcome, Attachments, Sources, Suggestion, Think, FileCard, CodeHighlighter, Mermaid, Folder, XProvider, and Notification.

The English summary is being prepared. Showing the original description.

ant-design/x4.8KUpdated Oct 12, 2026

See all skills by ant-design

Report a problem with this skill