| name | x-chat-provider |
| version | 2.8.1 |
| description | 专注于自定义 Chat Provider 的实现,帮助将任意流式接口适配为 Ant Design X 标准格式 |
🎯 技能定位
本技能专注解决一个问题:如何将你的流式接口快速适配为 Ant Design X 的 Chat Provider。
不涉及的:useXChat 的使用教程(那是另一个技能)。
目录导航
📦 技术栈概览
| 层级 | 包名 | 核心作用 |
|---|
| UI层 | @ant-design/x | React UI 组件库 |
| 逻辑层 | @ant-design/x-sdk | 开发工具包 |
| 渲染层 | @ant-design/x-markdown | Markdown 渲染器 |
import { Bubble } from '@ant-design/x';
import { AbstractChatProvider, OpenAIChatProvider, XRequest } from '@ant-design/x-sdk';
🚀 快速开始
🎯 Provider 选择决策树
graph TD
A[开始] --> B{使用标准OpenAI/DeepSeek API?}
B -->|是| C[使用内置Provider]
B -->|否| D{消息格式是原始数据格式?}
D -->|是| E[使用DefaultChatProvider]
D -->|否| F[自定义Provider]
C --> G[OpenAIChatProvider / DeepSeekChatProvider]
E --> H[直接透传,无需转换]
F --> I[四步创建自定义Provider]
🏭 内置 Provider 速览
| Provider 类型 | 适用场景 | 导入方式 |
|---|
| OpenAIChatProvider | 标准 OpenAI API 格式 | import { OpenAIChatProvider } from '@ant-design/x-sdk' |
| DeepSeekChatProvider | 标准 DeepSeek API 格式 | import { DeepSeekChatProvider } from '@ant-design/x-sdk' |
| DefaultChatProvider | 透传原始响应,无需格式转换 | import { DefaultChatProvider } from '@ant-design/x-sdk' |
⚠️ 导出名是 OpenAIChatProvider / DeepSeekChatProvider / DefaultChatProvider,注意拼写
DefaultChatProvider 使用场景
DefaultChatProvider 会透传原始响应数据,不做任何转换。适用于:
- 接口返回格式已经是你想展示的格式
- 你想完全控制
Bubble.List 的 contentRender 来渲染消息
import { DefaultChatProvider, XRequest } from '@ant-design/x-sdk';
interface ChatInput {
query: string;
stream?: boolean;
}
interface ChatOutput {
choices: Array<{ message: { content: string; role: string } }>;
}
const provider = new DefaultChatProvider<ChatOutput | ChatInput, ChatInput, ChatOutput>({
request: XRequest('https://your-api.com/chat', {
manual: true,
params: { stream: false },
}),
});
⚠️ DefaultChatProvider 使用时 ChatMessage 类型通常是你的 Output 类型或联合类型,渲染需要配合 contentRender
📋 四步实现自定义 Provider
步骤1:分析接口格式 ⏱️ 2分钟
| 信息类型 | 示例值 |
|---|
| 接口URL | https://your-api.com/chat |
| 请求格式 | JSON,POST |
| 响应格式 | Server-Sent Events |
| 认证方式 | Bearer Token |
步骤2:创建 Provider 类 ⏱️ 5分钟
import { AbstractChatProvider } from '@ant-design/x-sdk';
import type { TransformMessage } from '@ant-design/x-sdk';
import type { XRequestOptions } from '@ant-design/x-sdk';
interface MyInput {
query: string;
model?: string;
stream?: boolean;
}
interface MyOutput {
content: string;
finish_reason?: string;
}
interface MyMessage {
content: string;
role: 'user' | 'assistant';
}
export class MyChatProvider extends AbstractChatProvider<MyMessage, MyInput, MyOutput> {
transformParams(
requestParams: Partial<MyInput>,
options: XRequestOptions<MyInput, MyOutput, MyMessage>,
): MyInput {
return {
...(options?.params || {}),
query: requestParams.query || '',
model: 'gpt-3.5-turbo',
stream: true,
};
}
transformLocalMessage(requestParams: Partial<MyInput>): MyMessage {
return {
content: requestParams.query || '',
role: 'user',
};
}
transformMessage(info: TransformMessage<MyMessage, MyOutput>): MyMessage {
const { originMessage, chunk } = info;
if (!chunk?.content || chunk.content === '[DONE]') {
return { ...(originMessage || { content: '', role: 'assistant' }) };
}
return {
content: `${originMessage?.content || ''}${chunk.content}`,
role: 'assistant',
};
}
}
步骤3:检查验证 ⏱️ 1分钟
| 检查项 | 说明 |
|---|
| 只实现3个方法 | transformParams、transformLocalMessage、transformMessage |
| transformParams 签名 | 必须包含第二个参数 options: XRequestOptions<...> |
| 无 status 返回 | transformMessage 返回值中无 status 字段 |
| 无 request 方法 | 确认没有实现 request 方法 |
| 类型检查通过 | tsc --noEmit 无错误 |
步骤4:使用 Provider ⏱️ 1分钟
import { MyChatProvider } from './MyChatProvider';
import { XRequest } from '@ant-design/x-sdk';
const provider = new MyChatProvider({
request: XRequest('https://your-api.com/chat', {
manual: true,
headers: {
Authorization: 'Bearer your-token',
'Content-Type': 'application/json',
},
params: {
model: 'gpt-3.5-turbo',
stream: true,
},
}),
});
export { provider };
🔑 核心类型与导出
从 @ant-design/x-sdk 导出的关键类型:
import type {
XModelMessage,
XModelParams,
XModelResponse,
SSEFields,
SSEOutput,
TransformMessage,
XRequestOptions,
XRequestCallbacks,
MessageInfo,
} from '@ant-design/x-sdk';
XModelMessage 结构(OpenAI 消息格式)
const userMessage: XModelMessage = { role: 'user', content: 'Hello' };
const systemMessage: XModelMessage = { role: 'system', content: '你是一个助手' };
const developerMessage: XModelMessage = { role: 'developer', content: '系统提示词' };
SSEOutput 与 SSEFields
import { DeepSeekChatProvider, XRequest } from '@ant-design/x-sdk';
import type { SSEFields, XModelParams, XModelResponse } from '@ant-design/x-sdk';
const provider = new DeepSeekChatProvider({
request: XRequest<XModelParams, Partial<Record<SSEFields, XModelResponse>>>(
'https://api.deepseek.com/v1/chat/completions',
{
manual: true,
params: { model: 'deepseek-chat', stream: true },
},
),
});
⚙️ XRequest 进阶配置
callbacks 回调
callbacks 允许在 Provider 层面监听请求事件。回调中的第三个参数是经过 transformMessage 处理后的 MessageInfo:
const provider = new OpenAIChatProvider({
request: XRequest<XModelParams, XModelResponse, XModelMessage>(BASE_URL, {
manual: true,
callbacks: {
onUpdate: (chunk, responseHeaders, message) => {
console.log('流式更新:', message?.message?.content);
},
onSuccess: (chunks, responseHeaders, message) => {
console.log('请求完成:', message?.message?.content);
},
onError: (error, errorInfo, responseHeaders, message) => {
console.error('请求失败:', error.message);
},
},
params: { model: 'gpt-4o', stream: true },
}),
});
⚠️ callbacks 与 useXChat 的 requestFallback 不冲突,两者都会执行。callbacks 更适合日志/上报,requestFallback 用于控制 UI 展示
retryInterval 重试
const request = XRequest('https://your-api.com/chat', {
manual: true,
retryInterval: 3000,
retryTimes: 3,
callbacks: {
onError: (error) => {
if (error.name === 'AbortError') return;
return 5000;
},
},
});
transformStream 自定义流
当服务端返回的流格式不是标准 SSE 时使用:
const request = XRequest('https://your-api.com/chat', {
manual: true,
transformStream: new TransformStream({
transform(chunk, controller) {
controller.enqueue(JSON.parse(chunk));
},
}),
transformStream: (baseURL, responseHeaders) => {
if (responseHeaders.get('x-stream-type') === 'ndjson') {
return new TransformStream({
});
}
return undefined;
},
});
🔧 常见场景适配
📖 完整示例:EXAMPLES.md
| 场景类型 | 难度 | 说明 |
|---|
| 标准OpenAI | 🟢 | 直接使用内置 OpenAIChatProvider |
| 标准DeepSeek | 🟢 | 直接使用内置 DeepSeekChatProvider |
| 透传原始数据 | 🟢 | 使用 DefaultChatProvider |
| 私有SSE API | 🟡 | 四步实现自定义 Provider |
| 多字段响应 | 🟡 | 自定义 Provider + 复杂 ChatMessage |
| 非SSE流 | 🔴 | 自定义 Provider + transformStream |
⚠️ 重要提醒
🚨 强制规则:禁止自己写 request 方法!
class MyProvider extends AbstractChatProvider {
async request(params: any) {
}
}
class MyProvider extends AbstractChatProvider {
transformParams(params, options) {
}
transformLocalMessage(params) {
}
transformMessage(info) {
}
}
⚠️ transformMessage 禁止返回 status
transformMessage(info) {
return { content: '...', status: 'error' };
}
transformMessage(info) {
return { content: '...' };
}
⚠️ Provider 实例化注意事项
const [provider] = React.useState(
new MyChatProvider({
request: XRequest(URL, { manual: true }),
}),
);
⚡ 快速检查清单
创建 Provider 前:
完成后:
🚨 开发规则
- 如果用户没有明确需要测试用例,则不要添加测试文件
- 完成编写后必须检查类型:运行
tsc --noEmit 确保无类型错误
- 保持代码整洁:移除所有未使用的变量和导入
🔗 参考资源
📚 核心参考文档
🌐 SDK 官方文档
💻 示例代码