文档
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
类引用
函数引用
接口引用
类型别名引用
变量引用
指南

服务器工具

服务器工具在被 LLM 调用时自动执行。它们可以完全访问服务器资源,例如数据库、API 和环境变量。

mermaid

工作原理

  1. 工具调用接收:服务器从 LLM 接收到 tool_call 数据块
  2. 参数解析:工具参数(JSON 字符串)将被解析并根据输入模式进行验证
  3. 执行:使用解析后的参数调用工具的 execute 函数
  4. 结果处理:结果将被
    • 根据输出模式验证(如果已定义)
    • 转换为工具结果消息
    • 添加到对话历史记录
  5. 继续:聊天将使用工具结果继续,允许 LLM 根据结果生成响应

自动与手动执行

自动(默认)

  • 带有 execute 函数的服务器工具将自动运行
  • 结果会立即添加到对话中
  • 无需客户端处理

手动(高级)

  • 您可以通过拦截流来手动处理工具调用
  • 适用于自定义编排或审批流程

服务器工具定义

typescript
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";

const getUserDataDef = toolDefinition({
  name: "get_user_data",
  description: "Get user information from the database",
  inputSchema: z.object({
    userId: z.string().describe("The user ID to look up"),
  }),
  outputSchema: z.object({
    name: z.string(),
    email: z.string().email(),
    createdAt: z.string(),
  }),
});

const getUserData = getUserDataDef.server(async ({ userId }) => {
  // This runs on the server - secure access to database
  const user = await db.users.findUnique({ where: { id: userId } });
  return {
    name: user.name,
    email: user.email,
    createdAt: user.createdAt.toISOString(),
  };
});

定义服务器工具

服务器工具使用具有 .server() 方法的同构 toolDefinition() API

typescript
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";

// Step 1: Define the tool schema
const getUserDataDef = toolDefinition({
  name: "get_user_data",
  description: "Get user information from the database",
  inputSchema: z.object({
    userId: z.string().describe("The user ID to look up"),
  }),
  outputSchema: z.object({
    name: z.string(),
    email: z.string().email(),
    createdAt: z.string(),
  }),
});

// Step 2: Create server implementation
const getUserData = getUserDataDef.server(async ({ userId }) => {
  // This runs on the server - can access database, APIs, etc.
  const user = await db.users.findUnique({ where: { id: userId } });
  return {
    name: user.name,
    email: user.email,
    createdAt: user.createdAt.toISOString(),
  };
});

// Example: API call tool
const searchProductsDef = toolDefinition({
  name: "search_products",
  description: "Search for products in the catalog",
  inputSchema: z.object({
    query: z.string().describe("Search query"),
    limit: z.number().optional().describe("Maximum number of results"),
  }),
});

const searchProducts = searchProductsDef.server(async ({ query, limit = 10 }) => {
  const response = await fetch(
    `https://api.example.com/products?q=${query}&limit=${limit}`,
    {
      headers: {
        Authorization: `Bearer ${process.env.API_KEY}`, // Server-only access
      },
    }
  );
  return await response.json();
});

使用服务器工具

将工具传递给 chat 函数

typescript
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { getUserData, searchProducts } from "./tools";

export async function POST(request: Request) {
  const { messages } = await request.json();

  const stream = chat({
    adapter: openaiText("gpt-5.2"),
    messages,
    tools: [getUserData, searchProducts],
  });

  return toServerSentEventsResponse(stream);
}

工具组织模式

为了更好地组织,请分别定义工具模式和实现

typescript
// tools/definitions.ts
import { toolDefinition } from "@tanstack/ai";
import { z } from "zod";

export const getUserDataDef = toolDefinition({
  name: "get_user_data",
  description: "Get user information",
  inputSchema: z.object({
    userId: z.string(),
  }),
  outputSchema: z.object({
    name: z.string(),
    email: z.string(),
  }),
});

export const searchProductsDef = toolDefinition({
  name: "search_products",
  description: "Search products",
  inputSchema: z.object({
    query: z.string(),
  }),
});

// tools/server.ts
import { getUserDataDef, searchProductsDef } from "./definitions";
import { db } from "@/lib/db";

export const getUserData = getUserDataDef.server(async ({ userId }) => {
  const user = await db.users.findUnique({ where: { id: userId } });
  return { name: user.name, email: user.email };
});

export const searchProducts = searchProductsDef.server(async ({ query }) => {
  const products = await db.products.search(query);
  return products;
});

// api/chat/route.ts
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { getUserData, searchProducts } from "@/tools/server";

const stream = chat({
  adapter: openaiText("gpt-5.2"),
  messages,
  tools: [getUserData, searchProducts],
});

自动执行

当模型调用它们时,服务器工具会自动执行。SDK

  1. 从模型接收工具调用
  2. 执行工具的 execute 函数
  3. 将结果添加到对话中
  4. 使用工具结果继续聊天

您无需手动处理工具执行 - 它是自动的!

错误处理

工具应优雅地处理错误

typescript
const getUserDataDef = toolDefinition({
  name: "get_user_data",
  description: "Get user information",
  inputSchema: z.object({
    userId: z.string(),
  }),
  outputSchema: z.object({
    name: z.string().optional(),
    email: z.string().optional(),
    error: z.string().optional(),
  }),
});

const getUserData = getUserDataDef.server(async ({ userId }) => {
  try {
    const user = await db.users.findUnique({ where: { id: userId } });
    if (!user) {
      return { error: "User not found" };
    }
    return { name: user.name, email: user.email };
  } catch (error) {
    return { error: "Failed to fetch user data" };
  }
});

使用 JSON Schema

如果您有现有的 JSON Schema 定义或更喜欢不使用 Zod,则可以使用原始 JSON Schema 对象定义工具模式

typescript
import { toolDefinition } from "@tanstack/ai";
import type { JSONSchema } from "@tanstack/ai";

const inputSchema: JSONSchema = {
  type: "object",
  properties: {
    userId: {
      type: "string",
      description: "The user ID to look up",
    },
  },
  required: ["userId"],
};

const outputSchema: JSONSchema = {
  type: "object",
  properties: {
    name: { type: "string" },
    email: { type: "string" },
  },
  required: ["name", "email"],
};

const getUserDataDef = toolDefinition({
  name: "get_user_data",
  description: "Get user information from the database",
  inputSchema,
  outputSchema,
});

// When using JSON Schema, args is typed as `any`
const getUserData = getUserDataDef.server(async (args) => {
  const user = await db.users.findUnique({ where: { id: args.userId } });
  return { name: user.name, email: user.email };
});

注意:JSON Schema 工具会跳过运行时验证。建议使用 Zod 模式以实现完全的类型安全性和验证。

最佳实践

  1. 保持工具专注 - 每个工具应该做好一件事情
  2. 验证输入 - 使用 Zod 模式以确保类型安全(JSON Schema 跳过验证)
  3. 处理错误 - 返回有意义的错误消息
  4. 使用描述 - 清晰的描述有助于模型正确使用工具
  5. 保护敏感操作 - 切勿将 API 密钥或密码暴露给客户端

下一步