Skip to main content
客户端工具可通过允许Agent在客户端操作来增强您的Agent功能。
框架兼容性
  • ✅ AG-Kit (TypeScript)
  • ✅ LangGraph (TypeScript)
  • ✅ LangGraph (Python)
本文档假设您已配置好useChat(消息循环、渲染)。若尚未完成,请先阅读构建Copilot聊天界面

定义前端操作

AG-Kit AG-Kit提供两种定义不同行为前端操作的方式:
  • 自动运行:通过定义带有handler的前端操作来自动执行并重新生成响应。
  • 前端控制:通过定义带有renderAndWaitForResponse的前端操作来渲染组件,并决定何时执行及重新生成响应。

1) 自动运行

当Agent调用带有handler的工具时,一旦输入就绪便会自动在客户端执行。返回字符串作为工具结果,该结果将在handler完成后发送给Agent。 添加自动运行前端操作时,首先定义带有handler的工具:
const alertUser = tool({
  name: "alert",
  description: "Alert the user",
  parameters: z.object({ message: z.string() }),
  handler: async ({ message }) => {
    alert(message);
    return "done"; // 作为工具结果发送给Agent
  },
});
然后通过useChat构建UI,将工具传递给tools选项:
function Chat() {
  const { uiMessages, sendMessage, streaming } = useChat({
    url,
    clientTools: [alertUser],
  });
  const [input, setInput] = useState("");

  return (
    <div>
      <div>
        {uiMessages.map((m, mi) => (
          <div key={mi}>
            <p>Role: {m.role}</p>
            {m.parts.map((p, pi) => {
              switch (p.type) {
                case "text":
                  return (
                    <p key={pi}>
                      {m.role}: {p.text}
                    </p>
                  );
                case "tool-call":
                  return (
                    <div key={pi}>
                      <p>Tool Name: {p.name}</p>
                      <p>Tool Call Arguments: {p.arguments}</p>
                      {p.result && <p>Tool Call Result: {p.result}</p>}
                    </div>
                  );
                default:
                  return null;
              }
            })}
          </div>
        ))}
      </div>

      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={() => sendMessage(input)} disabled={streaming}>
        Send
      </button>
    </div>
  );
}
通过发送以下内容与UI交互:
Alert user about typhoon.
随后Agent将调用工具实际弹出警报。

2) 前端控制

此方式允许前端控制工具调用的执行过程,包括处理用户交互、渲染自定义UI以及决定何时及如何将结果提交回Agent。这为需要前端逻辑的复杂交互提供了更大灵活性。 添加完全受控的前端操作时,首先定义带有renderAndWaitForResponse的工具:
const alertUser = tool({
  name: "alert",
  description: "Alert the user",
  parameters: z.object({ message: z.string() }),
  renderAndWaitForResponse: ({ input, submitToolResult }) => (
    <div className="space-x-2">
      <span>{input.message}</span>
      <button
        onClick={() => {
          alert(input.message);
          submitToolResult?.("done");
        }}
      >
        Allow
      </button>
      <button onClick={() => submitToolResult?.("User refused the alert")}>
        Cancel
      </button>
    </div>
  ),
});
然后通过useChat构建UI,将工具传递给tools选项。由于我们已为工具调用定义了自定义UI,现在工具调用消息部分将包含可调用的render函数。
function Chat() {
  const { uiMessages, sendMessage, streaming } = useChat({
    url,
    clientTools: [alertUser],
  });
  const [input, setInput] = useState("");

  return (
    <div>
      <div>
        {uiMessages.map((m, mi) => (
          <div key={mi}>
            <p>Role: {m.role}</p>
            {m.parts.map((p, pi) => {
              switch (p.type) {
                case "text":
                  return (
                    <p key={pi}>
                      {m.role}: {p.text}
                    </p>
                  );
                case "tool-call":
                  return p.render?.();
                default:
                  return null;
              }
            })}
          </div>
        ))}
      </div>

      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={() => sendMessage(input)} disabled={streaming}>
        Send
      </button>
    </div>
  );
}
通过发送以下内容与UI交互:
Alert user about typhoon.
随后Agent将调用工具。与自动运行方式不同的是,现在我们会为工具调用渲染自定义UI,待用户与UI交互后再控制工具调用的执行过程。

选择方案

  • 从简开始:当不需要UI时使用handler
  • 需要用户输入:使用renderAndWaitForResponse渲染UI并提交结果。