От функции к Tool: как Vercel AI SDK открывает дверь к вызову инструментов

Если вы уже привыкли писать API Route и вызывать сторонние API в Next.js, то до создания «помощника с большой языковой моделью, который может сам вызывать интерфейсы» остался всего полшага: обернуть эти функции в Tool и передать модели решение, когда их использовать.Tool, и передать модели решение, когда их использовать.
В этой статье мы сначала не будем обсуждать «большие слова» вроде MCP, Agent frameworks, а сделаем только одно:
помочь вам перейти от «написания обычной функции» к «написанию Tool, который может вызываться большой языковой моделью», заодно объяснив ментальную модель, стоящую за этим.
После прочтения вы сможете:
знать, что такое Tool в Vercel AI SDK и чем он отличается от обычной функции.
написать минимально рабочий Tool и запустить его в Next.js.
понять, как проектировать параметры/возвращаемые значения Tool, чтобы модель лучше использовала ваш код.
приблизительно знать: сегодня можно обойтись только Tool для многих приложений, а протоколы вроде MCP можно оставить на потом.
1. Зачем нужен слой «инструментов»?
Сначала представьте простую задачу: вы хотите сделать чат-бота для проверки погоды.
Самый наивный подход:
Пользователь вводит: «Проверь погоду в Пекине на сегодня».
Вы получаете на сервере эту фразу на естественном языке.
Пишете свой if/else или регулярное выражение, чтобы извлечь название города.
Вызываете API погоды, получаете результат.
Вставляете результат обратно в prompt, даёте модели сформировать ответ пользователю.
Этот подход работает, но есть очевидные проблемы:
Логика жёстко зашита в коде, модель — просто «продвинутый шаблонизатор».
Каждый раз при добавлении новой функции (проверка курса валют, проверка расписания) нужно писать ещё один парсер + логику вызова.
Модель совершенно не знает, «какими возможностями обладает», и вам приходится вручную «прокладывать путь».
Слой Tool поднимает ваш «if/else + вызов API» до уровня способности, видимой модели.
Другими словами:
Вы пишете функцию, определяя «что я могу сделать», «какие параметры нужны», «что будет возвращено».
Вы говорите модели: это инструменты, которые вы можете вызывать.
Модель на основе ввода пользователя сама решает, нужно ли вызывать какой-либо инструмент и какие параметры передать.
Это абстракция, которую делает Tool в Vercel AI SDK.
2. Что такое Tool в Vercel AI SDK?
Можно сначала понять Tool как:
функция с инструкцией — инструкция для модели, а тело функции для вашего кода.
В Vercel AI SDK Tool обычно содержит три части информации:
description: одно предложение, объясняющее, что делает этот инструмент.parameters: описание необходимых входных параметров с помощью JSON Schema (или Zod).execute: функция, которая фактически выполняется, например, вызов HTTP API или запрос к базе данных.
Выглядит это примерно так (псевдокод, чтобы почувствовать определение):
import { tool } from 'ai';
const getWeather = tool({
description: '查询指定城市的实时天气',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '城市名称,比如 Beijing' },
},
required: ['city'],
},
execute: async ({ city }) => {
// 这里就是你平时会写的业务代码
const res = await fetch(`https://api.example.com/weather?city=${city}`);
return await res.json();
},
});После этого при вызове модели вы передаёте этот getWeather в AI SDK:
SDK отвечает за преобразование
descriptionиparametersв «список инструментов», понятный модели.При понимании намерения пользователя модель будет думать: «Стоит ли использовать getWeather? Если да, какой
cityпередать?»Как только модель решает вызвать, SDK передаёт параметры в
execute, получает результат и затем позволяет модели сгенерировать окончательный ответ.
Вам больше не нужно писать логику «извлечения названия города» и «решения, когда вызывать API» — вы передаёте «инициативу» модели.
3. Пример минимально рабочего Tool
Давайте напишем минимальный реально работающий пример: получение текущего времени.
3.1 Определяем простой Tool
Предположим, вы уже установили пакет ai (Vercel AI SDK) в проект Next.js. На сервере создадим простой Tool:
// app/api/chat/tools.ts
import { tool } from 'ai';
export const getCurrentTime = tool({
description: '获取当前服务器时间(ISO 字符串)',
parameters: {
type: 'object',
properties: {},
},
async execute() {
return {
now: new Date().toISOString(),
};
},
});Здесь стоит обратить внимание на несколько моментов:
parameters— это пустой объект: означает, что инструменту не нужны входные параметры.executeвозвращает объект{ now: string }, а не просто строку, что удобно для последующей структурированной обработки (например, отображение на фронтенде, дальнейшие вычисления).
3.2 Используем Tool в API Route
Далее напишем простейший чат API, позволяющий модели вызывать этот Tool. Конкретные детали вызова могут немного различаться в зависимости от версии, здесь мы акцентируем только «структуру» и «идею», псевдокод выглядит примерно так:
// app/api/chat/route.ts
import { NextRequest } from 'next/server';
import { streamText } from 'ai'; // 假设使用 AI SDK 的某个调用方法
import { getCurrentTime } from './tools';
import { openai } from '@ai-sdk/openai';
export async function POST(req: NextRequest) {
const { messages } = await req.json();
const response = await streamText({
model: openai('gpt-4o'), // 你选的模型
messages,
tools: {
getCurrentTime,
},
});
return response.toAIStreamResponse();
}Вот несколько ключевых моментов:
Поле
toolsоткрывает определённый вами Tool для модели.После получения сообщения от пользователя, если модель решает, что нужно текущее время, она «инициирует вызов getCurrentTime», и SDK автоматически выполнит
execute.Результат вызова Tool передаётся обратно модели, чтобы она могла сгенерировать окончательный ответ с учётом времени.
3.3 Простой чат-интерфейс на фронтенде
На фронтенде можно использовать Hook типа useChat для создания минимального чат-интерфейса. Эта часть не является фокусом статьи, поэтому подробно останавливаться не будем. Важно: с точки зрения фронтенда нет отличий от обычного Chat API, только модель теперь «сама может проверять время».
4. Принципиальное различие между Tool и обычной функцией
Здесь вы можете спросить: разве я не могу просто написать new Date().toISOString() в роуте и получить время? Зачем оборачивать в Tool?
Ключевое различие в том, кто отвечает за «принятие решения»:
Обычная функция: вы явно вызываете её в бизнес-логике, и только вы решаете, «когда её вызвать».
Tool: вы просто выставляете «эту способность» и объясняете модели, «как её использовать», а вопрос «использовать или нет» и «как именно» оставляете на решение модели.
Это даёт несколько практических преимуществ:
Меньше if/else
Вам не нужно разбирать естественный язык, сопоставлять ключевые слова, выбирать ветви.
Модель сама на основе контекста решает, стоит ли использовать какой-либо Tool.
Поддержка автоматической оркестровки нескольких Tool
Определить несколько инструментов (получение времени, погоды, расписания), и модель может вызывать их по необходимости в одном диалоге.
По мере увеличения количества инструментов вам не нужно поддерживать кучу «таблиц маршрутизации бизнес-логики» — модель сама «разбирается».
Единообразие между моделями
У разных провайдеров моделей интерфейсы Tool / Function Calling различаются, а AI SDK унифицирует эти детали.
Вам нужно поддерживать только один набор определений Tool для переключения между разными моделями.
Можно рассматривать Tool как:
добавление слоя «функции со структурированными метаданными» между «моделью и вашим кодом», делая этот канал одновременно умным и управляемым.
5. Проектирование удобного Tool: параметры и возвращаемые значения
Написать Tool — это не просто «чтобы работало». Правильно спроектированные параметры и возвращаемые значения позволяют модели использовать его более стабильно и управляемо.
5.1 Параметры: помогаем модели чётко формулировать
Рекомендуется следовать нескольким принципам при определении параметров:
Перечисляйте, где возможно: например,
unit: 'celsius' | 'fahrenheit'.Разбивайте на поля, если можно: не объединяйте «город+дату» в одну строку, заставляя модель разбирать.
Используйте
description, чтобы дать модели примеры: она действительно их учитывает (или, по крайней мере, во время обучения видела похожие шаблоны).
Пример:
const getWeather = tool({
description: '查询指定城市在指定日期的天气',
parameters: {
type: 'object',
properties: {
city: {
type: 'string',
description: '城市名称,比如 Beijing、Shanghai',
},
date: {
type: 'string',
description: '日期,格式为 YYYY-MM-DD,比如 2025-05-17',
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit'],
description: '温度单位,默认 celsius',
},
},
required: ['city', 'date'],
},
async execute({ city, date, unit = 'celsius' }) {
// ...
},
});5.2 Возвращаемые значения: предпочитайте структурированные, а не строки
Хотя вы можете напрямую вернуть из execute строку вроде «В Пекине сегодня 25 градусов, ясно», это потеряет много гибкости:
Фронтенд не сможет напрямую использовать этот результат для отображения или вычислений.
Модель также не сможет удобно повторно использовать структурированную информацию в последующих вызовах.
Более предпочтительный подход — возвращать чёткий объект:
async execute({ city, date, unit = 'celsius' }) {
const data = await fetchWeather(city, date, unit);
return {
city,
date,
unit,
temperature: data.temp,
condition: data.condition, // sunny, cloudy, etc.
};
}Так модель сможет как самостоятельно сформулировать ответ пользователю, так и использовать эти поля в последующих шагах (например, вызывать другой Tool).
6. Подключение нескольких Tool сразу: пусть модель выбирает сама
Ранее мы использовали только getCurrentTime, теперь можно добавить getWeather и передать их модели вместе.
// app/api/chat/tools.ts
export const tools = {
getCurrentTime,
getWeather,
};При вызове модели:
const response = await streamText({
model: openai('gpt-4o'),
messages,
tools,
});Теперь, если пользователь скажет:
«Проверь погоду в Шанхае на завтра, если солнечно, заодно напомни текущее время.»
У модели будет возможность сделать следующее (на логическом уровне):
Сначала вызвать
getWeather, определить, «солнечно ли».Затем вызвать
getCurrentTime, получить текущее время.Сгенерировать окончательный ответ, объединив результаты двух вызовов.
Вам не нужно писать никакую «бизнес-блок-схему» для этой логики, достаточно:
Перечислить инструменты, чётко определить параметры.
В системном Prompt примерно объяснить модели «при таких запросах используйте инструменты».
В этом и заключается истинная сила «вызова инструментов»: вы переходите от «написания процессов» к «определению возможностей».
7. Завершение этой статьи: сначала освойте Tool, затем думайте об уровне протоколов
В этой статье мы сделали три вещи:
Разобрали Tool концептуально: это «функция с инструкцией», инструкция предназначена для модели.
Написали минимальный пример Tool и показали, как использовать его в API Route Next.js.
Рассказали, как проектировать параметры и возвращаемые значения, чтобы модель лучше использовала ваш инструмент.
Только с помощью Tool от Vercel AI SDK вы уже можете создавать:
Внутреннего помощника поддержки / помощника по заявкам.
Интеллектуальные запросы / генерацию в SaaS-продуктах.
Различные бизнес-помощники: «проверь», «посчитай», «запомни».
Причём на этом этапе вы совершенно можете не беспокоиться о протокольных уровнях вроде MCP — они в основном решают проблемы «повторного использования инструментов между хостами и проектами» и лучше внедрять их постепенно, когда количество инструментов и среда вызова станут сложнее.
В следующей статье мы на основе «только Tool» отдельно обсудим: с какими границами и болями сталкивается один только Tool, когда инструментов становится больше и среда вызова сложнее, и почему появляются такие протоколы, как MCP.
Следить в Google
Добавить HeyBinyang как предпочтительный источник в Google
Если вы хотите чаще находить мои обновления через Google, можно отметить этот сайт как предпочтительный источник.
Поделиться
Поделиться
Поделиться этой статьей.