Back to skills
SkillHub ClubShip Full StackFull Stack

use-x-chat

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

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
4,393
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
C62.8

Install command

npx @skill-hub/cli install ant-design-x-use-x-chat

Repository

ant-design/x

Skill path: packages/x-skill/skills-zh/use-x-chat

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

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: ant-design.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install use-x-chat into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/ant-design/x before adding use-x-chat to shared team environments
  • Use use-x-chat for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: use-x-chat
version: 2.4.0
description: 专注讲解如何使用 useXChat Hook,包括自定义 Provider 的集成、消息管理、错误处理等
---

# 🎯 技能定位

> **核心定位**:使用 `useXChat` Hook 构建专业级 AI 对话应用 **前置要求**:已具备自定义 Chat Provider(参考 [x-chat-provider 技能](../x-chat-provider))

## 目录导航

- [🚀 快速开始](#-快速开始)
  - [依赖管理](#1-依赖管理)
  - [三步集成](#2-三步集成)
- [🧩 核心概念](#-核心概念)
  - [技术栈架构](#技术栈架构)
  - [数据模型](#数据模型)
- [🔧 核心功能详解](#-核心功能详解)
  - [消息管理](#1-消息管理)
  - [请求控制](#2-请求控制)
  - [错误处理](#3-错误处理)
  - [完整示例项目](#-完整示例项目)
- [📋 使用前提和依赖](#-使用前提和依赖)
- [🚨 开发规则](#-开发规则)
- [🔗 参考资源](#-参考资源)
  - [📚 核心参考文档](#-核心参考文档)
  - [🌐 SDK官方文档](#-SDK官方文档)
  - [💻 示例代码](#-示例代码)

# 🚀 快速开始

## 1. 依赖管理

### 🎯 自动依赖处理

### 📋 系统要求

- **@ant-design/x-sdk**: 2.2.2+(自动安装)
- **@ant-design/x**: 最新版(UI组件,自动安装)

### ⚠️ 版本问题自动修复

如果检测到版本不匹配,技能会自动:

- ✅ 提示当前版本状态
- ✅ 提供修复建议
- ✅ 使用相对路径确保兼容性

#### 🎯 技能内置版本检查

use-x-chat 技能已内置版本检查功能,启动时自动检查版本兼容性:

**🔍 自动检查功能** 技能启动时会自动检查 `@ant-design/x-sdk` 版本是否符合要求(≥2.2.2):

**📋 检查内容包括:**

- ✅ 当前安装的版本
- ✅ 是否符合最低要求(≥2.2.2)
- ✅ 自动提供修复建议
- ✅ 友好的错误提示

**🛠️ 版本问题修复** 如果检测到版本不匹配,技能会提供具体的修复命令:

```bash
# 自动提示的修复命令
npm install @ant-design/x-sdk@^2.2.2

# 或安装最新版本
npm install @ant-design/x-sdk@latest
```

## 2. 三步集成

### 步骤1:准备 Provider

这部分由 x-chat-provider 技能负责

```ts
import { MyChatProvider } from './MyChatProvider';
import { XRequest } from '@ant-design/x-sdk';

// 推荐使用 XRequest 作为默认请求方式
const provider = new MyChatProvider({
  // 默认使用 XRequest,无需自定义 fetch
  request: XRequest('https://your-api.com/chat'),
  // 当设置 requestPlaceholder 时,会在请求开始前显示占位消息
  requestPlaceholder: {
    content: '正在思考中...',
    role: 'assistant',
    timestamp: Date.now(),
  },
  // 当设置 requestFallback 时,会在请求失败时显示兜底消息
  requestFallback: (_, { error, errorInfo, messageInfo }) => {
    if (error.name === 'AbortError') {
      return {
        content: messageInfo?.message?.content || '已取消回复',
        role: 'assistant' as const,
        timestamp: Date.now(),
      };
    }
    return {
      content: errorInfo?.error?.message || '网络异常,请稍后重试',
      role: 'assistant' as const,
      timestamp: Date.now(),
    };
  },
});
```

### 步骤2:基础使用

```tsx
import { useXChat } from '@ant-design/x-sdk';

const ChatComponent = () => {
  const { messages, onRequest, isRequesting } = useXChat({ provider });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          {msg.message.role}: {msg.message.content}
        </div>
      ))}
      <button onClick={() => onRequest({ query: '你好' })}>发送</button>
    </div>
  );
};
```

### 步骤3:UI集成

```tsx
import { Bubble, Sender } from '@ant-design/x';

const ChatUI = () => {
  const { messages, onRequest, isRequesting, abort } = useXChat({ provider });

  return (
    <div style={{ height: 600 }}>
      <Bubble.List items={messages} />
      <Sender
        loading={isRequesting}
        onSubmit={(content) => onRequest({ query: content })}
        onCancel={abort}
      />
    </div>
  );
};
```

# 🧩 核心概念

## 技术栈架构

```mermaid
graph TD
    A[useXChat Hook] --> B[Chat Provider]
    B --> C[XRequest]
    A --> D[Ant Design X UI]
    D --> E[Bubble组件]
    D --> F[Sender组件]
```

### 数据模型

> ⚠️ **重要提醒**:`messages` 类型是 `MessageInfo<MessageType>[]`,不是直接的 `MessageType`

```ts
interface MessageInfo<Message> {
  id: number | string; // 消息唯一标识
  message: Message; // 实际消息内容
  status: MessageStatus; // 发送状态
  extraInfo?: AnyObject; // 扩展信息
}

// 消息状态枚举
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';
```

# 🔧 核心功能详解

> 💡 **提示**:API可能会随版本更新,建议查看[官方文档](https://github.com/ant-design/x/blob/main/packages/x/docs/x-sdk/use-x-chat.zh-CN.md)获取最新信息

核心功能参考内容 [CORE.md](reference/CORE.md)

# 📋 使用前提和依赖

## ⚠️ 重要依赖

**use-x-chat 必须依赖以下技能之一:**

| 依赖类型 | 技能 | 说明 | 是否必须 |
| --- | --- | --- | --- |
| **核心依赖** | **x-chat-provider** | 提供自定义 Provider 实例,默认使用 XRequest, **必须**配合 use-x-chat | **必须** |
| **或** | **内置 Provider** | OpenAI/DeepSeek 等内置 Provider,默认使用 XRequest | **必须** |
| **推荐依赖** | **x-request** | 配置请求参数和认证,作为默认请求方式 | **推荐** |

## 🎯 使用场景对照表

| 使用场景         | 需要的技能组合                           | 使用顺序               |
| ---------------- | ---------------------------------------- | ---------------------- |
| **私有API适配**  | x-chat-provider → use-x-chat             | 先创建Provider,再使用 |
| **标准API使用**  | use-x-chat(内置Provider)               | 直接使用               |
| **需要认证配置** | x-request → use-x-chat                   | 先配置请求,再使用     |
| **完整自定义**   | x-chat-provider → x-request → use-x-chat | 完整工作流             |

# 🚨 开发规则

## 使用 use-x-chat 前必须确认:

- [ ] **已有 Provider 来源**(以下二选一):
  - [ ] 已用 **x-chat-provider** 创建自定义 Provider
  - [ ] 决定使用内置 Provider(OpenAI/DeepSeek)
- [ ] 已安装 @ant-design/x-sdk
- [ ] 已了解 MessageInfo 数据结构
- [ ] 已准备好 UI 组件

### 测试用例规则

- **如果用户没有明确需要测试用例,则不要添加测试文件**
- **仅在用户明确要求时才创建测试用例**

### 代码质量规则

- **完成编写后必须检查类型**:运行 `tsc --noEmit` 确保无类型错误
- **保持代码整洁**:移除所有未使用的变量和导入

# 🔗 参考资源

## 📚 核心参考文档

- [API.md](reference/API.md) - 完整的 API 参考文档
- [EXAMPLES.md](reference/EXAMPLES.md) - 所有实战示例代码

## 🌐 SDK官方文档

- [useXChat 官方文档](https://github.com/ant-design/x/blob/main/packages/x/docs/x-sdk/use-x-chat.zh-CN.md)
- [XRequest 官方文档](https://github.com/ant-design/x/blob/main/packages/x/docs/x-sdk/x-request.zh-CN.md)
- [Chat Provider 官方文档](https://github.com/ant-design/x/blob/main/packages/x/docs/x-sdk/chat-provider.zh-CN.md)

## 💻 示例代码

- [custom-provider-width-ui.tsx](https://github.com/ant-design/x/blob/main/packages/x/docs/x-sdk/demos/chat-providers/custom-provider-width-ui.tsx) - 自定义 Provider 完整示例


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### reference/CORE.md

```markdown
### 1. 消息管理

#### 获取消息列表

```ts
const { messages } = useXChat({ provider });
// messages 结构: MessageInfo<MessageType>[]
// 实际消息数据在 msg.message 中
```

#### 手动设置消息

```ts
const { setMessages } = useXChat({ provider });

// 清空消息
setMessages([]);

// 添加欢迎消息 - 注意是 MessageInfo 结构
setMessages([
  {
    id: 'welcome',
    message: {
      content: '欢迎使用 AI 助手',
      role: 'assistant',
    },
    status: 'success',
  },
]);
```

#### 更新单条消息

```ts
const { setMessage } = useXChat({ provider });

// 更新消息内容 - 需要更新 message 对象
setMessage('msg-id', {
  message: { content: '新的内容', role: 'assistant' },
});

// 标记为错误 - 更新 status
setMessage('msg-id', { status: 'error' });
```

### 2. 请求控制

#### 发送消息

```ts
const { onRequest } = useXChat({ provider });

// 基础使用
onRequest({ query: '用户问题' });

// 带额外参数
onRequest({
  query: '用户问题',
  context: '之前的对话内容',
  userId: 'user123',
});
```

#### 中断请求

```tsx
const { abort, isRequesting } = useXChat({ provider });

// 中断当前请求
<button onClick={abort} disabled={!isRequesting}>
  停止生成
</button>;
```

#### 重新发送

重新发送功能允许用户重新生成特定消息的回复,这在AI回答不满意或出现错误时非常有用。

#### 基础使用

```tsx
const ChatComponent = () => {
  const { messages, onReload } = useXChat({ provider });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          <span>{msg.message.content}</span>
          {msg.message.role === 'assistant' && (
            <button onClick={() => onReload(msg.id)}>重新生成</button>
          )}
        </div>
      ))}
    </div>
  );
};
```

#### 重新发送的注意事项

1. **只能重新生成AI回复**:通常只能对 `role === 'assistant'` 的消息使用重新发送
2. **状态管理**:重新发送会将对应消息状态设为 `loading`
3. **参数传递**:可以通过 `extra` 参数传递额外信息给Provider
4. **错误处理**:建议配合 `requestFallback` 处理重新发送失败的情况

### 3. 错误处理

#### 统一错误处理

```tsx
const { messages } = useXChat({
  provider,
  requestFallback: (_, { error, errorInfo, messageInfo }) => {
    // 网络错误
    if (!navigator.onLine) {
      return {
        content: '网络连接失败,请检查网络',
        role: 'assistant' as const,
      };
    }

    // 用户中断
    if (error.name === 'AbortError') {
      return {
        content: messageInfo?.message?.content || '已取消回复',
        role: 'assistant' as const,
      };
    }

    // 服务器错误
    return {
      content: errorInfo?.error?.message || '网络异常,请稍后重试',
      role: 'assistant' as const,
    };
  },
});
```

### 4. 请求中的消息展示

一般情况下无需配置,默认配合 Bubble 组件的 loading 状态使用,如需自定义 loading 时的内容可参考:

```tsx
const ChatComponent = () => {
  const { messages, onRequest } = useXChat({ provider });
  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          {msg.message.role}: {msg.message.content}
        </div>
      ))}
      <button onClick={() => onRequest({ query: '你好' })}>发送</button>
    </div>
  );
};
```

#### 自定义请求占位符

当设置 requestPlaceholder 时,会在请求开始前显示占位消息,配合 Bubble 组件的 loading 状态使用。

```tsx
const { messages } = useXChat({
  provider,
  requestPlaceholder: (_, { error, messageInfo }) => {
    return {
      content: '正在生成中...',
      role: 'assistant',
    };
  },
});
```

```

### reference/API.md

```markdown
### useXChat

```tsx | pure
type useXChat<
  ChatMessage extends SimpleType = object,
  ParsedMessage extends SimpleType = ChatMessage,
  Input = RequestParams<ChatMessage>,
  Output = SSEOutput,
> = (config: XChatConfig<ChatMessage, ParsedMessage, Input, Output>) => XChatConfigReturnType;
```

<!-- prettier-ignore -->
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| ChatMessage | 消息数据类型,定义聊天消息的结构 | object | object | - |
| ParsedMessage | 解析后的消息类型,用于组件消费的消息格式 | ChatMessage | ChatMessage | - |
| Input | 请求参数类型,定义发送请求的参数结构 | RequestParams\<ChatMessage\> | RequestParams\<ChatMessage\> | - |
| Output | 响应数据类型,定义接收响应的数据格式 | SSEOutput | SSEOutput | - |

### XChatConfig

<!-- prettier-ignore -->
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| provider | 数据提供方,用于将不同结构的数据及请求转换为useXChat能消费的格式,平台内置了`DefaultChatProvider`和`OpenAIChatProvider`,你也可以通过继承`AbstractChatProvider`实现自己的Provider。详见:[Chat Provider文档](/x-sdks/chat-provider-cn) | AbstractChatProvider\<ChatMessage, Input, Output\> | - | - |
| conversationKey | 会话唯一标识(全局唯一),用于区分不同的会话 | string | Symbol('ConversationKey') | - |
| defaultMessages | 默认展示信息 | MessageInfo\<ChatMessage\>[] \| (info: { conversationKey?: string }) =>  MessageInfo\<ChatMessage\>[] \| (info: { conversationKey?: string }) => Promise\<MessageInfo\<ChatMessage\>[]\> | - | - |
| parser | 将 ChatMessage 转换成消费使用的 ParsedMessage,不设置时则直接消费 ChatMessage。支持将一条 ChatMessage 转换成多条 ParsedMessage | (message: ChatMessage) => BubbleMessage \| BubbleMessage[] | - | - |
| requestFallback | 请求失败的兜底信息,不提供则不会展示 | ChatMessage \| (requestParams: Partial\<Input\>,info: { error: Error; errorInfo: any; messages: ChatMessage[], message: ChatMessage }) => ChatMessage\|Promise\<ChatMessage\> | - | - |
| requestPlaceholder | 请求中的占位信息,不提供则不会展示 | ChatMessage \| (requestParams: Partial\<Input\>, info: { messages: Message[] }) => ChatMessage \|Promise\<Message\>| - | - |

### XChatConfigReturnType

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| abort | 取消请求 | () => void | - | - |
| isRequesting | 是否在请求中 | boolean | - | - |
| isDefaultMessagesRequesting | 默认消息列表是否在请求中 | boolean | false | 2.2.0 |
| messages | 当前管理消息列表的内容 | MessageInfo\<ChatMessage\>[] | - | - |
| parsedMessages | 经过 `parser` 转译过的内容 | MessageInfo\<ParsedMessages\>[] | - | - |
| onReload | 重新生成,会发送请求到后台,使用新返回数据更新该条消息 | (id: string \| number, requestParams: Partial\<Input\>,opts: { extra: AnyObject }) => void | - | - |
| onRequest | 添加一条 Message,并且触发请求 | (requestParams: Partial\<Input\>,opts: { extra: AnyObject }) => void | - | - |
| setMessages | 直接修改 messages,不会触发请求 | (messages: Partial\<MessageInfo\<ChatMessage\>\>[]) => void | - | - |
| setMessage | 直接修改单条 message,不会触发请求 | (id: string \| number, info: Partial\<MessageInfo\<ChatMessage\>\>) => void | - | - |
| removeMessage | 删除单条 message,不会触发请求 | (id: string \| number) => void | - | - |
| queueRequest | 会将请求加入队列,等待 conversationKey 初始化完成后再发送 | (conversationKey: string \| symbol, requestParams: Partial\<Input\>, opts?: { extraInfo: AnyObject }) => void | - | - |

#### MessageInfo

```ts
interface MessageInfo<ChatMessage> {
  id: number | string;
  message: ChatMessage;
  status: MessageStatus;
  extra?: AnyObject;
}
```

#### MessageStatus

```ts
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';
```

```

### reference/EXAMPLES.md

```markdown
# 完整示例项目

## 带有对话管理的完整项目

```tsx
import React, { useRef, useState } from 'react';
import { useXChat } from '@ant-design/x-sdk';
import { chatProvider } from '../services/chatService';
import type { ChatMessage } from '../providers/ChatProvider';
import { Bubble, Sender, Conversations, type ConversationsProps } from '@ant-design/x';
import { GetRef } from 'antd';

const App: React.FC = () => {
  const [conversations, setConversations] = useState([{ key: '1', label: '新对话' }]);
  const [activeKey, setActiveKey] = useState('1');
  const senderRef = useRef<GetRef<typeof Sender>>(null);
  // 新建对话
  const handleNewConversation = () => {
    const newKey = Date.now().toString();
    const newConversation = {
      key: newKey,
      label: `对话 ${conversations.length + 1}`,
    };
    setConversations((prev) => [...prev, newConversation]);
    setActiveKey(newKey);
  };

  // 删除对话
  const handleDeleteConversation = (key: string) => {
    setConversations((prev) => {
      const filtered = prev.filter((item) => item.key !== key);
      if (filtered.length === 0) {
        // 如果没有对话了,创建一个新的
        const newKey = Date.now().toString();
        return [{ key: newKey, label: '新对话' }];
      }
      return filtered;
    });

    // 如果删除的是当前激活的对话,切换到第一个
    if (activeKey === key) {
      setActiveKey(conversations[0]?.key || '1');
    }
  };

  const { messages, onRequest, isRequesting, abort } = useXChat<
    ChatMessage,
    ChatMessage,
    { query: string },
    { content: string; time: string; status: 'success' | 'error' }
  >({
    provider: chatProvider,
    conversationKey: activeKey,
    requestFallback: (_, { error }) => {
      if (error.name === 'AbortError') {
        return { content: '已取消', role: 'assistant' as const, timestamp: Date.now() };
      }
      return { content: '请求失败', role: 'assistant' as const, timestamp: Date.now() };
    },
  });

  const menuConfig: ConversationsProps['menu'] = (conversation) => ({
    items: [
      {
        label: '删除',
        key: 'delete',
        danger: true,
      },
    ],
    onClick: ({ key: menuKey }) => {
      if (menuKey === 'delete') {
        handleDeleteConversation(conversation.key);
      }
    },
  });

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      {/* 会话列表 */}
      <div
        style={{
          width: 240,
          borderRight: '1px solid #f0f0f0',
          display: 'flex',
          flexDirection: 'column',
        }}
      >
        <Conversations
          creation={{
            onClick: handleNewConversation,
          }}
          items={conversations}
          activeKey={activeKey}
          menu={menuConfig}
          onActiveChange={setActiveKey}
        />
      </div>

      {/* 聊天区域 */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div
          style={{ padding: 16, borderBottom: '1px solid #f0f0f0', fontSize: 16, fontWeight: 500 }}
        >
          {conversations.find((c) => c.key === activeKey)?.label || '对话'}
        </div>

        <div style={{ flex: 1, padding: 16, overflow: 'auto' }}>
          <Bubble.List
            role={{
              assistant: {
                placement: 'start',
              },
              user: {
                placement: 'end',
              },
            }}
            items={messages.map((msg) => ({
              key: msg.id,
              content: msg.message.content,
              role: msg.message.role,
              loading: msg.status === 'loading',
            }))}
          />
        </div>

        <div style={{ padding: 16, borderTop: '1px solid #f0f0f0' }}>
          <Sender
            loading={isRequesting}
            ref={senderRef}
            onSubmit={(content: string) => {
              onRequest({ query: content });
              senderRef.current?.clear?.();
            }}
            onCancel={abort}
            placeholder="输入消息..."
          />
        </div>
      </div>
    </div>
  );
};
export default App;
```

## 带状态管理的重新发送

```tsx
import React, { useRef, useState } from 'react';
import { useXChat } from '@ant-design/x-sdk';
import { Bubble, Sender } from '@ant-design/x';
import { Button, type GetRef } from 'antd';
import { chatProvider } from '../services/chatService';
import type { ChatMessage } from '../providers/ChatProvider';

const ChatWithRegenerate: React.FC = () => {
  const senderRef = useRef<GetRef<typeof Sender>>(null);
  const { messages, onReload, isRequesting, onRequest, abort } = useXChat<
    ChatMessage,
    ChatMessage,
    { query: string },
    { content: string; time: string; status: 'success' | 'error' }
  >({
    provider: chatProvider,
    requestPlaceholder: {
      content: '正在思考中...',
      role: 'assistant',
      timestamp: Date.now(),
    },
    requestFallback: (_, { error, errorInfo, messageInfo }) => {
      if (error.name === 'AbortError') {
        return {
          content: messageInfo?.message?.content || '已取消回复',
          role: 'assistant' as const,
          timestamp: Date.now(),
        };
      }
      return {
        content: errorInfo?.error?.message || '网络异常,请稍后重试',
        role: 'assistant' as const,
        timestamp: Date.now(),
      };
    },
  });

  // 跟踪正在重新生成的消息ID
  const [regeneratingId, setRegeneratingId] = useState<string | number | null>(null);

  const handleRegenerate = (messageId: string | number): void => {
    setRegeneratingId(messageId);
    onReload(
      messageId,
      {},
      {
        extraInfo: { regenerate: true },
      },
    );
  };

  return (
    <div>
      <Bubble.List
        role={{
          assistant: {
            placement: 'start',
          },
          user: {
            placement: 'end',
          },
        }}
        items={messages.map((msg) => ({
          key: msg.id,
          content: msg.message.content,
          role: msg.message.role,
          loading: msg.status === 'loading',
          footer: msg.message.role === 'assistant' && (
            <Button
              type="text"
              size="small"
              loading={regeneratingId === msg.id && isRequesting}
              onClick={() => handleRegenerate(msg.id)}
              disabled={isRequesting && regeneratingId !== msg.id}
            >
              {regeneratingId === msg.id ? '生成中...' : '重新生成'}
            </Button>
          ),
        }))}
      />
      <div>
        <Sender
          loading={isRequesting}
          onSubmit={(content: string) => {
            onRequest({ query: content });
            senderRef.current?.clear?.();
          }}
          onCancel={abort}
          ref={senderRef}
          placeholder="输入消息..."
          allowSpeech
          prefix={
            <Sender.Header
              title="AI 助手"
              open={false}
              styles={{
                content: { padding: 0 },
              }}
            />
          }
        />
      </div>
    </div>
  );
};

export default ChatWithRegenerate;
```

```

use-x-chat | SkillHub