useXChat 数据管理
配合 Agent hook 进行对话数据管理。
何时使用
通过 Agent 进行会话数据管理,并产出供页面渲染使用的数据。
代码演示
基本
基础用法。
ts
<script setup lang="tsx">
import { UserOutlined } from '@ant-design/icons-vue';
import { Flex } from 'ant-design-vue';
import { Bubble, Sender, useXAgent, useXChat, type BubbleListProps } from 'ant-design-x-vue';
import { ref } from 'vue';
defineOptions({ name: 'AXUseXChatBasic' });
const sleep = () => new Promise((resolve) => setTimeout(resolve, 1000));
const roles: BubbleListProps['roles'] = {
ai: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
typing: { step: 5, interval: 20 },
style: {
maxWidth: '600px',
},
},
local: {
placement: 'end',
avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
},
};
const mockSuccess = ref(false);
const content = ref('');
const senderLoading = ref(false);
const setContent = (v: string) => {
content.value = v;
}
// Agent for request
const [agent] = useXAgent({
request: async ({ message }, { onSuccess, onError }) => {
senderLoading.value = true;
await sleep();
senderLoading.value = false;
mockSuccess.value = !mockSuccess.value;
if (mockSuccess.value) {
onSuccess(`Mock success return. You said: ${message}`);
}
onError(new Error('Mock request failed'));
},
});
// Chat messages
const { onRequest, messages } = useXChat({
agent: agent.value,
requestPlaceholder: 'Waiting...',
requestFallback: 'Mock failed return. Please try again later.',
});
defineRender(() => {
return (
<Flex vertical gap="middle">
<Bubble.List
roles={roles}
style={{ maxHeight: '300px' }}
items={messages.value.map(({ id, message, status }) => ({
key: id,
loading: status === 'loading',
role: status === 'local' ? 'local' : 'ai',
content: message,
}))}
/>
<Sender
loading={senderLoading.value}
value={content.value}
onChange={setContent}
onSubmit={(nextContent) => {
onRequest(nextContent);
setContent('');
}}
/>
</Flex>
)
});
</script>
隐藏源代码
流式输出
使用流式输出更新内容。
ts
<script setup lang="tsx">
import { UserOutlined } from '@ant-design/icons-vue';
import { Flex } from 'ant-design-vue';
import { Bubble, Sender, useXAgent, useXChat } from 'ant-design-x-vue';
import { ref } from 'vue';
defineOptions({ name: 'AXUseXChatStream' });
const roles: (typeof Bubble.List)['roles'] = {
ai: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
},
local: {
placement: 'end',
avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
},
};
const content = ref('');
const senderLoading = ref(false);
// Agent for request
const [ agent ] = useXAgent({
request: async ({ message }, { onSuccess, onUpdate }) => {
senderLoading.value = true;
const fullContent = `Streaming output instead of Bubble typing effect. You typed: ${message}`;
let currentContent = '';
const id = setInterval(() => {
currentContent = fullContent.slice(0, currentContent.length + 2);
onUpdate(currentContent);
if (currentContent === fullContent) {
senderLoading.value = false;
clearInterval(id);
onSuccess(fullContent);
}
}, 100);
},
});
// Chat messages
const { onRequest, messages } = useXChat({
agent: agent.value,
});
defineRender(() => {
return (
<Flex vertical gap="middle">
<Bubble.List
roles={roles}
style={{ maxHeight: 300 }}
items={messages.value.map(({ id, message, status }) => ({
key: id,
role: status === 'local' ? 'local' : 'ai',
content: message,
}))}
/>
<Sender
loading={senderLoading.value}
value={content.value}
onChange={(v) => content.value = v}
onSubmit={(nextContent) => {
onRequest(nextContent);
content.value = '';
}}
/>
</Flex>
)
});
</script>
隐藏源代码
多项建议
通过定制能力,返回多个推荐内容。
Hello, what can I do for you?
ts
<script setup lang="tsx">
import { SmileOutlined, UserOutlined } from '@ant-design/icons-vue';
import { Flex } from 'ant-design-vue';
import { Bubble, Prompts, Sender, useXAgent, useXChat, type BubbleListProps } from 'ant-design-x-vue';
import { ref } from 'vue';
defineOptions({ name: 'AXUseXChatSuggestions' });
const sleep = () => new Promise((resolve) => setTimeout(resolve, 1000));
const roles: BubbleListProps['roles'] = {
user: {
placement: 'end',
avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
},
text: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
typing: true,
},
suggestion: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { visibility: 'hidden' } },
variant: 'borderless',
messageRender: (content) => (
<Prompts
vertical
items={(content as any as string[]).map((text) => ({
key: text,
icon: <SmileOutlined style={{ color: '#FAAD14' }} />,
description: text,
}))}
/>
),
},
};
type AgentUserMessage = {
type: 'user';
content: string;
};
type AgentAIMessage = {
type: 'ai';
content?: string;
list?: (
| {
type: 'text';
content: string;
}
| {
type: 'suggestion';
content: string[];
}
)[];
};
type AgentMessage = AgentUserMessage | AgentAIMessage;
type BubbleMessage = {
role: string;
};
const content = ref('');
const senderLoading = ref(false);
// Agent for request
const [ agent ] = useXAgent<AgentMessage>({
request: async ({ message }, { onSuccess }) => {
senderLoading.value = true;
await sleep();
const { content } = message || {};
senderLoading.value = false;
onSuccess({
type: 'ai',
list: [
{
type: 'text',
content: `Do you want?`,
},
{
type: 'suggestion',
content: [`Look at: ${content}`, `Search: ${content}`, `Try: ${content}`],
},
],
});
},
});
// Chat messages
const { onRequest, parsedMessages } = useXChat<AgentMessage, BubbleMessage>({
agent: agent.value,
defaultMessages: [
{
id: 'init',
message: {
type: 'ai',
content: 'Hello, what can I do for you?',
},
status: 'success',
},
],
requestPlaceholder: {
type: 'ai',
content: 'Waiting...',
},
// Convert AgentMessage to BubbleMessage
parser: (agentMessages) => {
const list = agentMessages.content ? [agentMessages] : (agentMessages as AgentAIMessage).list;
return (list || []).map((msg) => ({
role: msg.type,
content: msg.content,
}));
},
});
defineRender(() => {
return (
<Flex vertical gap="middle">
<Bubble.List
roles={roles}
style={{ maxHeight: 300 }}
items={parsedMessages.value.map(({ id, message, status }) => ({
key: id,
loading: status === 'loading',
...message,
}))}
/>
<Sender
loading={senderLoading.value}
value={content.value}
onChange={(v) => content.value = v}
onSubmit={(nextContent) => {
onRequest({
type: 'user',
content: nextContent,
});
content.value = '';
}}
/>
</Flex>
)
});
</script>
隐藏源代码
模型接入
接入云服务平台,可发送消息、处理数据、终止消息。
ts
<script lang="tsx" setup>
import { UserOutlined } from '@ant-design/icons-vue';
import { Flex } from 'ant-design-vue';
import { Bubble, Sender, useXAgent, useXChat } from 'ant-design-x-vue';
import { ref, watch } from 'vue';
defineOptions({ name: 'AXUseXChatModel' });
const BASE_URL = 'https://api.siliconflow.cn/v1/chat/completions';
const MODEL = 'deepseek-ai/DeepSeek-R1-Distill-Qwen-7B';
const API_KEY = 'Bearer sk-ravoadhrquyrkvaqsgyeufqdgphwxfheifujmaoscudjgldr';
/**
* 🔔 Please replace the BASE_URL, PATH, MODEL, API_KEY with your own values.
*/
type YourMessageType = {
role: string;
content: string;
};
const roles: (typeof Bubble.List)['roles'] = {
assistant: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
},
user: {
placement: 'end',
avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
},
};
const content = ref('');
const [agent] = useXAgent<YourMessageType>({
baseURL: BASE_URL,
model: MODEL,
dangerouslyApiKey: API_KEY,
/** 🔥🔥 Its dangerously! */
});
const abortController = ref<AbortController>(null);
// Chat messages
const { onRequest, messages } = useXChat({
agent: agent.value,
requestFallback: (_, { error }) => {
if (error.name === 'AbortError') {
return {
content: 'Request is aborted',
role: 'assistant',
};
}
return {
content: 'Request failed, please try again!',
role: 'assistant',
};
},
requestPlaceholder: () => {
return {
content: 'Please wait...',
role: 'assistant',
};
},
transformMessage: (info) => {
const { originMessage, currentMessage, status } = info || {};
let currentText = '';
let originText = '';
if (status === 'loading' && currentMessage.data && !currentMessage.data.includes('DONE')) {
const message = JSON.parse(currentMessage.data);
currentText =
message?.choices?.[0].delta?.reasoning_content === null
? ''
: message?.choices?.[0].delta?.reasoning_content;
}
if (originMessage) {
originText = originMessage.content || '';
}
return {
content: originText + currentText,
role: 'assistant',
};
},
resolveAbortController: (controller) => {
abortController.value = controller;
},
});
const senderLoading = ref(false);
watch(() => agent.value.isRequesting(), () => {
senderLoading.value = agent.value.isRequesting();
});
defineRender(() => {
return (
<Flex vertical gap="middle">
<Bubble.List
roles={roles}
style={{ maxHeight: 300 }}
items={messages.value.map(({ id, message }) => ({
key: id,
role: message.role,
content: message.content,
}))}
/>
<Sender
loading={senderLoading.value}
value={content.value}
onCancel={() => {
abortController?.value?.abort?.();
}}
onChange={(v) => {
content.value = v;
}}
onSubmit={(nextContent) => {
onRequest({
stream: true,
message: {
role: 'user',
content: nextContent,
},
});
content.value = '';
}}
/>
</Flex>
);
});
</script>
隐藏源代码
API
tsx
type useXChat<AgentMessage, ParsedMessage = AgentMessage> = (
config: XChatConfig<AgentMessage, ParsedMessage>,
) => XChatConfigReturnType;
XChatConfig
属性 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
agent | 通过 useXAgent 生成的 agent ,当使用 onRequest 方法时, agent 参数是必需的。 | XAgent | - | |
defaultMessages | 默认展示信息 | { status, message }[] | - | |
parser | 将 AgentMessage 转换成消费使用的 ParsedMessage,不设置时则直接消费 AgentMessage。支持将一条 AgentMessage 转换成多条 ParsedMessage | (message: AgentMessage) => BubbleMessage | BubbleMessage[] | - | |
requestFallback | 请求失败的兜底信息,不提供则不会展示 | AgentMessage | () => AgentMessage | - | |
requestPlaceholder | 请求中的占位信息,不提供则不会展示 | AgentMessage | () => AgentMessage | - | |
transformMessage | 可在更新数据时对messages 做转换,同时会更新到messages | (info: {originMessage?: AgentMessage,currentMessage: any,status: MessageStatus}) => AgentMessage | - | - |
transformStream | 可选的转换函数,用于处理流数据 | XStreamOptions<Output>['transformStream'] | - | - |
resolveAbortController | AbortController 控制器,用于控制流状态 | (abortController: AbortController) => void | - | - |
XChatConfigReturnType
属性 | 说明 | 类型 | 版本 |
---|---|---|---|
messages | 当前管理的内容 | AgentMessages[] | |
parsedMessages | 经过 parser 转译过的内容 | ParsedMessages[] | |
onRequest | 添加一条 Message,并且触发请求,若无key 为message 的数据则会将整个数据做为消息处理 | (requestParams: AgentMessage | RequestParams) => void | |
setMessages | 直接修改 messages,不会触发请求 | (messages: { message, status }[]) => void |
RequestParams
继承 XRequestParams。
属性 | 说明 | 类型 | 默认值 | 版本 |
---|---|---|---|---|
message | 当前消息的内容 | AgentMessage | - | - |