Tech0 阅读

De la fonction au Tool : ouvrir la porte de l'appel d'outil avec Vercel AI SDK

Si vous êtes déjà habitué à écrire des routes API dans Next.js et à appeler des API tierces, vous n'êtes plus qu'à un pas de créer un « assistant de grand modèle capable d'appeler ses propres API » : il suffit d'emballer ces fonctions en tant que Tool, et de laisser le modèle décider quand les utiliser.

Dans cet article, nous ne parlerons pas de MCP, des frameworks Agent ou de ces « grands mots », nous ne ferons qu'une chose :

Vous aider à passer de « écrire une fonction ordinaire » à « écrire un Tool qui peut être appelé par un grand modèle », tout en clarifiant le modèle mental sous-jacent.

Après avoir lu cet article, vous devriez être capable de :

1. Pourquoi avons-nous besoin de cette couche d'outil ?

Imaginez d'abord un besoin simple : vous voulez créer un « chatbot de météo ».

L'approche la plus naïve est :

  1. L'utilisateur saisit « Vérifie la météo à Pékin aujourd'hui ».

  2. Vous récupérez cette phrase en langage naturel sur le serveur.

  3. Vous écrivez vous-même un if/else ou une expression régulière pour extraire le nom de la ville.

  4. Vous appelez l'API météo et récupérez le résultat.

  5. Vous réinjectez le résultat dans le prompt, et laissez le modèle l'organiser en une réponse à envoyer à l'utilisateur.

Cette solution fonctionne, mais présente des problèmes évidents :

La couche Tool consiste à élever votre « if/else + appel d'API » en une capacité visible par le modèle.

Autrement dit :

Cette abstraction est exactement ce que le Tool du Vercel AI SDK fait pour vous.

2. Qu'est-ce que le Tool dans le Vercel AI SDK ?

Vous pouvez d'abord comprendre le Tool comme :

Une « fonction avec un mode d'emploi », le mode d'emploi est destiné au modèle, le corps de la fonction est destiné à votre propre code.

Dans le Vercel AI SDK, un Tool contient généralement trois parties d'informations :

  1. description : une phrase expliquant à quoi sert cet outil.

  2. parameters : décrit les paramètres d'entrée nécessaires à l'aide de JSON Schema (ou Zod).

  3. execute : la fonction qui s'exécute réellement, par exemple appeler une API HTTP, interroger une base de données.

Son apparence est à peu près celle-ci (pseudo-code, pour en saisir la définition) :

ts
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();
  },
});

Ensuite, lorsque vous appelez le modèle, vous passez ce getWeather au SDK AI :

Vous n'avez plus besoin d'écrire vous-même la logique d'« extraction du nom de la ville » ou de « décider quand appeler l'API », vous avez laissé l'initiative au modèle.

3. Un exemple minimal de Tool fonctionnel

Écrivons un exemple minimal qui fonctionne vraiment : obtenir l'heure actuelle.

3.1 Définir un Tool simple

Supposons que vous ayez déjà installé le package ai (Vercel AI SDK) dans votre projet Next.js. Sur le serveur, créons un Tool simple :

ts
// 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(),
    };
  },
});

Voici quelques points à noter :

3.2 Utiliser le Tool dans une Route API

Ensuite, écrivons une API de chat très simple qui permet au modèle d'appeler ce Tool dans la conversation. Les détails d'appel peuvent varier légèrement selon la version, ici nous insistons uniquement sur la « structure » et le « raisonnement », le pseudo-code ressemble à ceci :

ts
// 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();
}

Voici quelques points clés :

3.3 Une interface de chat frontend simple

Le frontend peut utiliser un Hook comme useChat pour créer une interface de chat minimale. Ce n'est pas le sujet central de cet article, donc nous ne nous y attardons pas. L'important est que du point de vue du frontend, il n'y a pas de différence avec une API de chat normale, sauf que le modèle est maintenant « capable de vérifier l'heure lui-même ».

4. Différence fondamentale entre un Tool et une fonction ordinaire

Vous pourriez demander : ne puis-je pas simplement écrire new Date().toISOString() directement dans la route pour obtenir l'heure ? Pourquoi passer par un Tool ?

La différence clé réside dans la question de savoir « qui prend la décision » :

Cela apporte plusieurs avantages pratiques :

  1. Moins de if/else

    • Vous n'avez pas besoin d'analyser le langage naturel, de faire correspondre des mots-clés ou de choisir des branches.

    • Le modèle décide lui-même, en fonction du contexte, s'il doit utiliser un Tool.

  2. Prise en charge de l'orchestration automatique de plusieurs Tools

    • Définissez plusieurs outils (vérifier l'heure, vérifier la météo, vérifier l'agenda), le modèle peut en appeler plusieurs au besoin dans une même conversation.

    • À mesure que le nombre d'outils augmente, vous n'avez pas besoin de maintenir une multitude de « tables de routage métier », le modèle se débrouille tout seul.

  3. Unification entre modèles

    • Les interfaces Tool / Function Calling des différents fournisseurs de modèles varient, mais le SDK AI unifie ces détails pour vous.

    • Vous n'avez besoin de maintenir qu'une seule définition de Tool pour basculer entre différents modèles.

Vous pouvez considérer le Tool comme :

Une couche de « fonction avec métadonnées structurées » ajoutée entre « le modèle ↔ votre code », rendant cette chaîne à la fois intelligente et contrôlable.

5. Concevoir un Tool efficace : paramètres et valeur de retour

Écrire un Tool ne se résume pas à « le faire fonctionner », une bonne conception des paramètres et de la valeur de retour permet au modèle de l'utiliser de manière plus stable et contrôlable.

5.1 Paramètres : aider le modèle à comprendre clairement

La définition des paramètres devrait suivre quelques petits principes :

Exemple :

ts
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 Valeur de retour : autant que possible structurée, plutôt qu'un tas de chaînes

Bien que vous puissiez directement retourner une phrase comme « Il fait 25 degrés et il fait beau à Pékin aujourd'hui » dans execute, cela perd beaucoup de flexibilité :

Une approche plus recommandée est de retourner un objet clair :

ts
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.
  };
}

Ainsi, le modèle peut à la fois organiser lui-même le langage pour répondre à l'utilisateur, et continuer à utiliser ces champs dans les étapes suivantes (par exemple pour appeler un autre Tool).

6. Connecter plusieurs Tools à la fois : laisser le modèle choisir

Précédemment, nous n'utilisions qu'un seul getCurrentTime, nous pouvons maintenant ajouter un getWeather et les donner tous au modèle.

ts
// app/api/chat/tools.ts
export const tools = {
  getCurrentTime,
  getWeather,
};

Lors de l'appel au modèle :

ts
const response = await streamText({
  model: openai('gpt-4o'),
  messages,
  tools,
});

À ce moment, si l'utilisateur dit :

« Vérifie la météo à Shanghai demain, et si c'est ensoleillé, rappelle-moi aussi l'heure actuelle. »

Le modèle a l'opportunité de faire ceci (au niveau logique) :

  1. Appeler d'abord getWeather, pour déterminer « si c'est ensoleillé ».

  2. Appeler ensuite getCurrentTime, pour obtenir l'heure actuelle.

  3. Générer une réponse finale en fusionnant les résultats des deux appels.

Vous n'avez pas besoin d'écrire de « diagramme de flux métier » pour cette logique, il suffit :

C'est là la véritable puissance de l'appel d'outils : vous passez de « écrire des flux » à « définir des capacités ».

7. Conclusion de cet article : maîtrisez d'abord les Tools, puis envisagez la couche de protocole

Dans cet article, nous n'avons fait que trois choses :

  1. Décomposer le Tool conceptuellement : c'est une « fonction avec un mode d'emploi », le mode d'emploi est destiné au modèle.

  2. Écrire un exemple minimal de Tool et montrer comment l'utiliser dans une Route API Next.js.

  3. Expliquer comment concevoir les paramètres et la valeur de retour pour que le modèle utilise mieux vos outils.

Avec seulement les Tools du Vercel AI SDK, vous pouvez déjà créer :

Et à ce stade, vous pouvez tout à fait ignorer les protocoles comme MCP – ils résolvent principalement le problème de « réutilisation des outils entre hôtes et projets », il est plus approprié de les introduire progressivement une fois que le nombre d'outils et l'environnement d'appel deviennent complexes.

Dans le prochain article, nous discuterons spécifiquement, sur la base de l'utilisation seule des Tools, des limites et des difficultés rencontrées lorsque le nombre d'outils augmente et que l'environnement d'appel devient plus complexe, ainsi que de la raison pour laquelle des protocoles comme MCP apparaissent.

Partager

Partager

Partager cet article.