Skip to content
On this page

Agent 接入案例:React

useAgent 适合多轮 Agent 对话、工具调用和状态管理场景。Agent 的 assistant 消息使用 message.parts 表示时序内容。

tsx
import { useEffect, useState } from 'react';
import { useAgent } from '@tencent/ssv-ai-sdk-react';
import { AGUIPlugin } from '@tencent/ssv-ai-sdk-plugin-agui';

const UI_ONLY_TOOLS = ['launchRocket'];

export function AgentChat() {
  const [input, setInput] = useState('');
  const [themeColor, setThemeColor] = useState('#1890ff');

  const {
    messages,
    status,
    assistantStatus,
    agentState,
    send,
    stop,
    setMessages,
    setTools,
    on,
    off,
  } = useAgent({
    api: {
      chatEndpoint: {
        url: 'https://your-api.com/agent',
      },
    },
    mode: 'stream',
    plugins: [new AGUIPlugin()],
  });

  useEffect(() => {
    setTools([
      {
        name: 'setThemeColor',
        description: 'Set the page theme color. Use hex format like #1890ff.',
        type: 'frontend',
        parameters: {
          type: 'object',
          properties: {
            color: { type: 'string', description: 'Hex color' },
          },
          required: ['color'],
        },
        handler: async ({ color }) => {
          setThemeColor(color);
          return { success: true, color };
        },
      },
    ]);
  }, [setTools]);

  useEffect(() => {
    const handleToolExecuted = ({ toolCallId, toolCallName, result }) => {
      if (UI_ONLY_TOOLS.includes(toolCallName)) return;

      const toolMessage = {
        id: `tool-${Date.now()}`,
        role: 'tool',
        content: typeof result === 'string' ? result : JSON.stringify(result),
        toolCallId,
        extraInfo: {},
      };

      setMessages([...messages, toolMessage]);
      send({}, { type: 'tools' });
    };

    on('toolExecuted', handleToolExecuted);
    return () => off('toolExecuted', handleToolExecuted);
  }, [messages, on, off, send, setMessages]);

  const handleSend = async () => {
    if (!input.trim() || status === 'loading') return;
    await send({ input });
    setInput('');
  };

  return (
    <div style={{ '--theme-color': themeColor }}>
      <div className="messages">
        {messages.map((message) => (
          <div key={message.id} className={`message ${message.role}`}>
            {message.role === 'user' && <div>{message.content}</div>}

            {message.role === 'assistant' && message.parts?.map((part, index) => {
              if (part.type === 'reasoning') {
                return <div key={index} className="reasoning">{part.reason}</div>;
              }
              if (part.type === 'text') {
                return <div key={index}>{part.text}</div>;
              }
              if (part.type === 'tool_call') {
                return (
                  <div key={part.id} className="tool-call">
                    工具:{part.name},状态:{part.status}
                    {part.result && <pre>{JSON.stringify(part.result, null, 2)}</pre>}
                    {part.error && <div className="error">{part.error}</div>}
                  </div>
                );
              }
              return null;
            })}
          </div>
        ))}
      </div>

      <div>助手状态:{assistantStatus}</div>
      <div>Agent 状态:{JSON.stringify(agentState)}</div>

      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && handleSend()}
        placeholder="输入消息..."
      />
      {status === 'loading' ? (
        <button onClick={stop}>停止</button>
      ) : (
        <button onClick={handleSend}>发送</button>
      )}
    </div>
  );
}

工具结果回传规则

Frontend 工具执行完成后会触发 toolExecuted。业务侧需要:

  1. 构造 role: 'tool' 的消息
  2. 调用 setMessages([...messages, toolMessage])
  3. 调用 send({}, { type: 'tools' }) 继续 Agent Run

Backend 工具的结果由后端返回,不触发 toolExecuted,前端只负责渲染 part.result

Released under the MIT License.