Галоўная / Артыкулы

Выклік функцыі OpenAI у маршрутах API Next.js

Выклік функцыі OpenAI у маршрутах API Next.js: пад’язычыце інструменты з сервернымі апрацоўшчыкамі, напісайце тачныя апісаціі інструментаў і выклекайце автарызацыю для разрушальных выклікаў.

Выдавец: REACTAPP.TOP3 хв чытання797 слоў

Крыніцы: Function Calling with Next.js and OpenAI: Letting AI Actually Do Things

Звычныя завершэння чату можаюць выдаваць толькі тэкст. Выклік функцый — які таксама называецца вікорыстаннем інструментоў — дазволяе модэлю запрашваць рэальныя дзеяння ў прыкладнай програме, такія як пошук рэкорда, адправка пашты чы выконанне актуалізаціі, на адной засадзе запіту корыстніка. Наведзены ніжэй практычны прыклад паўтарае гэту схему ў маршруце API Next.js з вікорыстаннем OpenAI.

Основная схема

Апісваюце модэлю інструменты. Модэль выбірае, чы хацець выклікнуць адзін з іх і якія аргументы адправіць. Код прыкладнай програмы запускае апрацоўшчык і вяртае рэзультат, які модэль можа перэтворыць у адпаведны адказ.

// app/api/chat/route.js
import OpenAI from 'openai';
const openai = new OpenAI();
const tools = [
  {
    type: 'function',
    function: {
      name: 'get_order_status',
      description: "Get the status of a customer's order",
      parameters: {
        type: 'object',
        properties: {
          orderId: { type: 'string', description: 'The order ID' },
        },
        required: ['orderId'],
      },
    },
  },
];export async function POST(request) {
  const { messages } = await request.json();  const response = await openai.chat.completions.create({
    model: 'gpt-4o-mini',
    messages,
    tools,
  });  const toolCall = response.choices[0].message.tool_calls?.[0];  if (toolCall) {
    const args = JSON.parse(toolCall.function.arguments);
    const result = await getOrderStatus(args.orderId); // your real function    // Send the result back so the model can respond in natural language
    const followUp = await openai.chat.completions.create({
      model: 'gpt-4o-mini',
      messages: [
        ...messages,
        response.choices[0].message,
        { role: 'tool', tool_call_id: toolCall.id, content: JSON.stringify(result) },
      ],
    });    return Response.json({ reply: followUp.choices[0].message.content });
  }  return Response.json({ reply: response.choices[0].message.content });
}

Рэальная функцыя за інструментам

async function getOrderStatus(orderId) {
  const order = await db.order.findUnique({ where: { id: orderId } });
  return order ? { status: order.status, eta: order.estimatedDelivery } : { error: 'Order not found' };
}

Этот апрацоўшчык — гэта звычны код сэрвера. Вікорыстанне інструментоў сама по сабе не выконвае чаго-небудзь чародзяскага; яно толькі дае модэлю структураваны спосаб прасіць сэрвера запустыць функцыю.

Апрацоўка калькі інструментоў

const tools = [
  { type: 'function', function: { name: 'get_order_status', /* ... */ } },
  { type: 'function', function: { name: 'cancel_order', /* ... */ } },
  { type: 'function', function: { name: 'get_account_balance', /* ... */ } },
];
const toolHandlers = {
  get_order_status: (args) => getOrderStatus(args.orderId),
  cancel_order: (args) => cancelOrder(args.orderId),
  get_account_balance: (args) => getAccountBalance(args.userId),
};// In your handler:
const handler = toolHandlers[toolCall.function.name];
const result = await handler(JSON.parse(toolCall.function.arguments));

Карта адаптараў дозволяе лепша кераваць сітуацыяю, чым зрастаючы ланец if/else, калі расшырваецца спіс інструментаў.

Крытычнае правіла: ніколі не дазволяйце модэлю выканаць разрушальныя дзеянні без падтверджэння

async function cancelOrder(orderId, userId) {
  // Always verify the action against the actual authenticated user server-side —
  // never trust that the model's tool call alone represents authorized intent
  const order = await db.order.findUnique({ where: { id: orderId } });
  if (order.userId !== userId) throw new Error('Unauthorized');
  await db.order.update({ where: { id: orderId }, data: { status: 'cancelled' } });
}

Тое, што модэль выбірае вызванне cancel_order, не ўсуняе падазрэння, што аўтэнтыфікованы корыстувач можа анулюваць гэты замовленне. Адаптар павінен парадзейнаць правы на выкананне кожнага вызову, так сама як і звычны API-эндпоінт.

Частая памылка: нечысткія апісанні функцый

// Too vague — model may call this incorrectly or miss when it should
{ name: 'update', description: 'Updates something' }
// Specific enough for the model to use reliably
{ name: 'update_shipping_address', description: "Updates the shipping address for the customer's most recent unshipped order" }

Якасць выбору інструментаў залежыць ад тое, насколькі точныя ў іх апісанні. Неодназначныя назвы і расплывчатыя апісанні прыводзяць да неправільных чы або вовсе не выкананых вызоў; конкрэтныя назвы і дэталізаваныя апісанні спамагаюць забезпечыць надзеяны роутынг.

Спрытваць аргументы інструменту як ненадзеяны вхідны даны. Пераканаць ідэнтыфікаторы, адхроніць нечаканыя поля, а таксама трэба зберагаць пасяродны эфекты ў межах транзакцый, калі зменяецца калькольна табелей. Журналіраванне назвы інструменту, фармату аргументаў (не секрэтных даных) і рэзультата автарызаціі дапамагае легчэй восстанавіць сітуацыю ў працэсе вырабніцтва, калі мадэль паўтараючыся выбірае некарэктны інструмент.

Асновная мысль

Выклік функцыі ператварае інтэрфейс чата на ўсталяванне, якое можа дзеяць, але намер модэлі — толькі палова сістэмы. Адпаведальныя за апрацоўку на серверэ яшчэ патрабуюць автарызацію на рэвэле канцачнай точкі, а тачныя апісанні інструментаў дапамагаюць пераканаць, што ўсі дзеяння будуць спрамованы на правільную працу, а не на помылкі. Неабходна задаць таймауты і павторныя спробы падчас раунд-трыпамоў модэлі, каб цыклы інструментаў, якія застраглі, не моглі выкарыстаць усе рэсурсы апрацоўшчыка маршрутаў.