Взаимодействие с API
Почти все веб-приложения основываются на RESTful API. Разрешая LLM взаимодействовать с ними, расширяется его практическая полезность.
Этот урок демонстрирует, как LLM можно использовать для выполнения вызовов API через вызов интеграций.
Требование — пример сервера управления событиями
Мы будем использовать простую серверную систему управления событиями и показать, как с ней взаимодействовать.
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const app = express();
const PORT = process.env.PORT || 5566;
// Middleware
app.use(express.json());
// Fake database - in-memory storage
let events = [
{
id: '1',
name: 'Tech Conference 2024',
date: '2024-06-15T09:00:00Z',
location: 'San Francisco, CA'
},
{
id: '2',
name: 'Music Festival',
date: '2024-07-20T18:00:00Z',
location: 'Austin, TX'
},
{
id: '3',
name: 'Art Exhibition Opening',
date: '2024-05-10T14:00:00Z',
location: 'New York, NY'
},
{
id: '4',
name: 'Startup Networking Event',
date: '2024-08-05T17:30:00Z',
location: 'Seattle, WA'
},
{
id: '5',
name: 'Food & Wine Tasting',
date: '2024-09-12T19:00:00Z',
location: 'Napa Valley, CA'
}
];
// Helper function to validate event data
const validateEvent = (eventData) => {
const required = ['name', 'date', 'location'];
const missing = required.filter(field => !eventData[field]);
if (missing.length > 0) {
return { valid: false, message: `Missing required fields: ${missing.join(', ')}` };
}
// Basic date validation
const dateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
if (!dateRegex.test(eventData.date)) {
return { valid: false, message: 'Date must be in ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ)' };
}
return { valid: true };
};
// GET /events - List all events
app.get('/events', (req, res) => {
res.status(200).json(events);
});
// POST /events - Create a new event
app.post('/events', (req, res) => {
const validation = validateEvent(req.body);
if (!validation.valid) {
return res.status(400).json({ error: validation.message });
}
const newEvent = {
id: req.body.id || uuidv4(),
name: req.body.name,
date: req.body.date,
location: req.body.location
};
events.push(newEvent);
res.status(201).json(newEvent);
});
// GET /events/{id} - Retrieve an event by ID
app.get('/events/:id', (req, res) => {
const event = events.find(e => e.id === req.params.id);
if (!event) {
return res.status(404).json({ error: 'Event not found' });
}
res.status(200).json(event);
});
// DELETE /events/{id} - Delete an event by ID
app.delete('/events/:id', (req, res) => {
const eventIndex = events.findIndex(e => e.id === req.params.id);
if (eventIndex === -1) {
return res.status(404).json({ error: 'Event not found' });
}
events.splice(eventIndex, 1);
res.status(204).send();
});
// PATCH /events/{id} - Update an event's details by ID
app.patch('/events/:id', (req, res) => {
const eventIndex = events.findIndex(e => e.id === req.params.id);
if (eventIndex === -1) {
return res.status(404).json({ error: 'Event not found' });
}
const validation = validateEvent(req.body);
if (!validation.valid) {
return res.status(400).json({ error: validation.message });
}
// Update the event
events[eventIndex] = {
...events[eventIndex],
name: req.body.name,
date: req.body.date,
location: req.body.location
};
res.status(200).json(events[eventIndex]);
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Endpoint not found' });
});
// Start the server
app.listen(PORT, () => {
console.log(`Event Management API server is running on port ${PORT}`);
console.log(`Available endpoints:`);
console.log(` GET /events - List all events`);
console.log(` POST /events - Create a new event`);
console.log(` GET /events/{id} - Get event by ID`);
console.log(` PATCH /events/{id} - Update event by ID`);
console.log(` DELETE /events/{id} - Delete event by ID`);
});
module.exports = app;
Интеграции для запросов
Доступно 4 интеграции запросов, которые можно использовать. Это позволяет LLM вызывать интеграции GET, POST, PUT и DELETE по мере необходимости.
Шаг 1: Добавьте стартовый узел
Стартовый узел — это входная точка вашего сценария.
Шаг 2: Добавьте узел агент
Затем добавьте узел Agent. В этой настройке агент настроен с четырьмя основными интеграциями: GET, POST, PUT и DELETE. Каждая интеграция предназначена для выполнения конкретного типа API-запроса.
Интеграция 1: GET (Получение событий)
- Цель: получить список событий или конкретное событие из API.
- Настройки::
- URL:
http://localhost:5566/events - Имя:
get_events - Описание: Опишите, когда использовать этот интеграцию. Например:
Use this when you need to get events - Headers (Заголовки): (по желанию) добавьте необходимые HTTP-заголовки.
- Schema параметров запроса: JSON-схема API, которая позволяет LLM знать структуру URL, а также какие параметры пути и запроса нужно генерировать.Например:
{ "id": { "type": "string", "in": "path", "description": "ID of the item to get. /:id" }, "limit": { "type": "string", "in": "query", "description": "Limit the number of items to get. ?limit=10" } }
- URL:
Интеграция 2: POST (Создание события)
- Цель: создать новое событие в системе.
- Настройки:
- URL:
http://localhost:5566/events - Имя:
create_event - Описание: Используйте, когда нужно создать новое событие.
- Headers: (по желанию) Добавьте необходимые HTTP-заголовки.
- Body (Тело запроса): Жестко заданный объект тела, который переопределит сгенерированный LLM.
- Schema тела: JSON-схема запроса, которая показывает, как нужно автоматически генерировать правильный JSON. Например:
{ "name": { "type": "string", "required": true, "description": "Name of the event" }, "date": { "type": "string", "required": true, "description": "Date of the event" }, "location": { "type": "string", "required": true, "description": "Location of the event" } }
- URL:
Интеграция 3: PUT (Обновление события)
- Цель: обновить данные существующего события.
- Настройки:
- URL:
http://localhost:5566/events - Имя:
update_event - Описание: Используйте, когда нужно обновить событие.
- Headers: (по желанию) добавьте необходимые HTTP-заголовки.
- Body: Жестко заданный объект тела, который переопределит тело, генерируемое LLM.
- Schema тела: JSON-схема, поясняющая, как автоматически генерировать JSON. Например:
{ "name": { "type": "string", "required": true, "description": "Name of the event" }, "date": { "type": "string", "required": true, "description": "Date of the event" }, "location": { "type": "string", "required": true, "description": "Location of the event" } }
- URL:
Интеграция 4: DELETE (Удаление события)
- Цель: удалить событие из системы.
- Настройки:
- URL:
http://localhost:5566/events - Имя:
delete_event - Описание: Используйте, когда нужно удалить событие.
- Headers: (по желанию) добавьте необходимые HTTP-заголовки.
- Schema параметров запроса: JSON-схема API, чтобы LLM знало структуру URL и какие параметры нужны. Например:
{ "id": { "type": "string", "required": true, "in": "path", "description": "ID of the item to delete. /:id" } }
- URL:
Как агент использует эти интеграции
- Агент может динамически выбрать, какую интеграцию использовать, исходя из запроса пользователя или логики сценария.
- Каждая интеграция сопоставлена с конкретным HTTP-методом и конечной точкой, с четко определенными схемами ввода.
- Агент использует LLM для интерпретации пользовательского ввода, заполнения необходимых параметров и выполнения соответствующего API-вызова.
Вот несколько примеров взаимодействий для вашего потока, включая примеры пользовательских запросов и ожидаемое поведение для каждого из них, сопоставленное с соответствующей интеграцией (GET, POST, PUT, DELETE):
Пример взаимодействий
1. Получение событий (GET)
Пример запроса:
"Покажи все предстоящие события"
Ожидаемое поведение:
- Агент выбирает интеграцию GET.
- Отправляет запрос GET по адресу
http://localhost:5566/events. - Возвращает список всех событий пользователю.
Другой пример:
"Получить детали события с ID 12345."
Поведение:
- Агент выбирает GET.
- Отправляет GET по адресу
http://localhost:5566/events/12345. - Возвращает детали этого события.
2. Создание нового события (POST)
Пример запроса:
"Создай новое событие 'AI Conference' на 15.07.2024 в Tech Hall."
Ожидаемое поведение:
- Выбирает POST.
- Отправляет POST по адресу
http://localhost:5566/eventsс телом:"name": "AI Conference", "date": "2024-07-15", "location": "Tech Hall"
Подтверждает, что событие создано, и возвращает его детали.
3. Обновление события (PUT)
Пример запроса:
"Измени место проведения события 'AI Conference' на 15.07.2024 на 'Main Auditorium'."
Ожидаемое поведение:
- Выбирает PUT.
- Отправляет PUT с обновленными данными:
{ "name": "AI Conference", "date": "2024-07-15", "location": "Main Auditorium" } - Подтверждает обновление.
4. Удаление события (DELETE)
Пример запроса:
"Удалить событие с ID 12345."
Ожидаемое поведение:
- Выбирает DELETE.
- Отправляет DELETE по адресу
http://localhost:5566/events/12345. - Подтверждает, что событие удалено.
OpenAPI Toolkit
Интеграции Requests из 4-х работают отлично, если у вас всего несколько API, но представьте, что у вас десятки или сотни API — это может стать трудно поддерживать. Чтобы решить эту проблему, OSMI-AI предоставляет набор интеграций OpenAPI, который способен взять YAML-файл OpenAPI и преобразовать каждый API в отдельную интеграцию. Спецификация OpenAPI (OAS) — это универсальный стандарт для описания деталей RESTful API в формате, который может читать и интерпретировать машина.
Используя API управления событиями, мы можем сгенерировать YAML-файл OpenAPI:
openapi: 3.0.0
info:
version: 1.0.0
title: Event Management API
description: An API for managing event data
servers:
- url: http://localhost:5566
description: Local development server
paths:
/events:
get:
summary: List all events
operationId: listEvents
responses:
'200':
description: A list of events
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Event'
post:
summary: Create a new event
operationId: createEvent
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EventInput'
responses:
'201':
description: The event was created
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/events/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
description: The event ID
get:
summary: Retrieve an event by ID
operationId: getEventById
responses:
'200':
description: The event
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
'404':
description: Event not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
summary: Update an event's details by ID
operationId: updateEventDetails
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EventInput'
responses:
'200':
description: The event's details were updated
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Event not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
summary: Delete an event by ID
operationId: deleteEvent
responses:
'204':
description: The event was deleted
'404':
description: Event not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Event:
type: object
properties:
id:
type: string
description: The unique identifier for the event
name:
type: string
description: The name of the event
date:
type: string
format: date-time
description: The date and time of the event in ISO 8601 format
location:
type: string
description: The location of the event
required:
- name
- date
- location
EventInput:
type: object
properties:
name:
type: string
description: The name of the event
date:
type: string
format: date-time
description: The date and time of the event in ISO 8601 format
location:
type: string
description: The location of the event
required:
- name
- date
- location
Error:
type: object
properties:
error:
type: string
description: Error message
Шаг 1: Добавьте узел Старт.
Шаг 2: Добавьте узел Агент.
Далее добавьте узел Агент. В этой конфигурации агент настроен только с одной интеграции — OpenAPI Toolkit.
Интеграция: OpenAPI Toolkit
- Цель: Получить список API из YAML-файла и преобразовать каждый API в список интеграций.
- Входные параметры конфигурации:
- YAML File: YAML-файл OpenAPI
- Return Direct: Возвращать ответ API напрямую или нет
- Headers (опционально): Добавить необходимые HTTP-заголовки
- Remove null parameters: Удалять все ключи с null-значениями из разобранных данных
- Custom Code: Настроить, как возвращается ответ
Примеры взаимодействия:
Можно использовать те же пример запросов из предыдущего примера для тестирования.
Последовательный вызов API
Из приведённых выше примеров мы увидели, как агент может динамически вызывать интеграцию и взаимодействовать с API. В некоторых случаях может потребоваться последовательный вызов API до или после определённых действий. Например, вы можете получить список клиентов из CRM и передать его агенту. В таких случаях можно использовать узел HTTP.
Лучшие практики
- Взаимодействие с API обычно используется, когда вы хотите, чтобы агент получил наиболее актуальную информацию. Например, агент может получить вашу доступность в календаре, статус проекта или другие данные в реальном времени.
- Часто бывает полезно явно включать текущую дату и время в системный запрос. OSMI-AI предоставляет параметр
{{ current_date_time }}, которая получает текущую дату и время. Это позволяет модели быть осведомлённой о настоящем моменте, поэтому, если вы спросите о своей доступности на сегодня, модель сможет использовать правильную дату. В противном случае она может опираться на дату окончания своего последнего обучения, что приведет к устаревшей информации. Например:
Вы полезный помощник..
Сегодняшняя дата и время: {{current_date_time }}
Человек в цепочке
В предыдущих уроках мы рассмотрели, как агент может динамично использовать инструменты для ответа на запросы или выполнения поставленных задач. Human-in-the-loop (человек в цикле) добавляет уровень контроля, позволяя агенту запрашивать у человека ввод, одобрение или обратную связь перед дальнейшими действиями.
RAG
Модели крупного языка (LLM) открыли возможность создания продвинутых чат-ботов с вопросами и ответами, которые способны давать точные ответы на основе конкретных данных. Эти системы используют метод под названием Retrieval-Augmented Generation (RAG), который улучшает их ответы, опираясь на релевантные исходные материалы.

