В основе генеративного ИИ лежат модели ИИ. В настоящее время двумя наиболее яркими примерами генеративных моделей являются модели большого языка (LLM) и модели генерации изображений. Эти модели принимают входные данные, называемые подсказками (чаще всего текст, изображение или их комбинацию), и на выходе выдают текст, изображение или даже аудио или видео.
Результаты этих моделей могут быть на удивление убедительными: LLM генерируют текст, который выглядит так, как если бы он был написан человеком, а модели генерации изображений могут создавать изображения, очень близкие к реальным фотографиям или произведениям искусства, созданным людьми.
Кроме того, LLM доказали свою способность решать задачи, выходящие за рамки простой генерации текста:
- Написание компьютерных программ
- Планирование подзадач, необходимых для выполнения более крупной задачи.
- Организация неорганизованных данных
- Понимание и извлечение информационных данных из корпуса текста
- Отслеживание и выполнение автоматизированных действий на основе текстового описания действия.
Вам доступно множество моделей от разных поставщиков. У каждой модели есть свои сильные и слабые стороны, и одна модель может превосходить одни задачи, но хуже справляться с другими. Приложения, использующие генеративный искусственный интеллект, часто могут получить выгоду от использования нескольких различных моделей в зависимости от поставленной задачи.
Как разработчик приложений, вы обычно не взаимодействуете с генеративными моделями ИИ напрямую, а скорее через сервисы, доступные в виде веб-API. Хотя эти службы часто имеют схожие функциональные возможности, все они предоставляют их через разные и несовместимые API. Если вы хотите использовать несколько сервисов моделей, вам придется использовать каждый из их собственных SDK, потенциально несовместимых друг с другом. И если вы хотите перейти с одной модели на новейшую и наиболее функциональную, вам, возможно, придется создавать эту интеграцию заново.
Genkit решает эту проблему, предоставляя единый интерфейс, который абстрагирует детали доступа к потенциально любому сервису генеративной модели ИИ, при этом уже доступно несколько готовых реализаций. Создание приложения на основе искусственного интеллекта на основе Genkit упрощает процесс первого вызова генеративного искусственного интеллекта и позволяет одинаково легко комбинировать несколько моделей или заменять одну модель на другую по мере появления новых моделей.
Прежде чем начать
Если вы хотите запустить примеры кода на этой странице, сначала выполните действия, описанные в руководстве по началу работы . Во всех примерах предполагается, что вы уже установили Genkit в качестве зависимости в своем проекте.
Модели, поддерживаемые Genkit
Genkit спроектирован так, чтобы быть достаточно гибким, чтобы потенциально использовать любой сервис генеративных моделей искусственного интеллекта. Его основные библиотеки определяют общий интерфейс для работы с моделями, а плагины моделей определяют детали реализации для работы с конкретной моделью и ее API.
Команда Genkit поддерживает плагины для работы с моделями, предоставляемыми Vertex AI, Google Generative AI и Ollama:
- Семейство LLM Gemini через плагин Google Cloud Vertex AI.
- Семейство LLM Gemini через плагин Google AI
- Модели генерации изображений Imagen2 и Imagen3 с помощью Google Cloud Vertex AI
- Семейство LLM Claude 3 от Anthropic в модельном саду Google Cloud Vertex AI
- Gemma 2, Llama 3 и многие другие открытые модели через плагин Ollama (вы должны самостоятельно разместить сервер Ollama)
Кроме того, существует несколько поддерживаемых сообществом плагинов, которые предоставляют интерфейсы для этих моделей:
- Семейство LLM Claude 3 через плагин Anthropic.
- Семейство LLM GPT через плагин OpenAI
- Семейство LLM GPT через плагин Azure OpenAI
- Семейство LLM Command R через плагин Cohere
- Семейство LLM Mistral через плагин Mistral
- Gemma 2, Llama 3 и многие другие открытые модели, размещенные на Groq через плагин Groq .
Вы можете узнать больше, выполнив поиск пакетов с тегом genkit-model
на npmjs.org .
Загрузка и настройка плагинов модели
Прежде чем вы сможете использовать Genkit для создания контента, вам необходимо загрузить и настроить плагин модели. Если вы пришли из руководства «Приступая к работе», вы уже это сделали. В противном случае обратитесь к руководству по началу работы или к документации отдельного плагина и следуйте инструкциям, прежде чем продолжить.
Метод генерации()
В Genkit основным интерфейсом, через который вы взаимодействуете с генеративными моделями ИИ, является generate()
.
Самый простой вызов generate()
указывает модель, которую вы хотите использовать, и текстовое приглашение:
import { gemini15Flash, googleAI } from '@genkit-ai/googleai';
import { genkit } from 'genkit';
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
});
(async () => {
const { text } = await ai.generate(
'Invent a menu item for a pirate themed restaurant.'
);
console.log(text);
})();
Когда вы запустите этот краткий пример, он распечатает некоторую отладочную информацию, за которой последует вывод вызова метода generate()
, который обычно представляет собой текст Markdown, как в следующем примере:
## The Blackheart's Bounty
**A hearty stew of slow-cooked beef, spiced with rum and molasses, served in a
hollowed-out cannonball with a side of crusty bread and a dollop of tangy
pineapple salsa.**
**Description:** This dish is a tribute to the hearty meals enjoyed by pirates
on the high seas. The beef is tender and flavorful, infused with the warm spices
of rum and molasses. The pineapple salsa adds a touch of sweetness and acidity,
balancing the richness of the stew. The cannonball serving vessel adds a fun and
thematic touch, making this dish a perfect choice for any pirate-themed
adventure.
Запустите сценарий еще раз, и вы получите другой результат.
В предыдущем примере кода запрос на создание был отправлен в модель по умолчанию, которую вы указали при настройке экземпляра Genkit.
Вы также можете указать модель для одного вызова метода generate()
:
const { text } = await ai.generate({
model: gemini15Pro,
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
В этом примере используется ссылка на модель, экспортированная плагином модели. Другой вариант — указать модель с помощью строкового идентификатора:
const { text } = await ai.generate({
model: 'googleai/gemini-1.5-pro-latest',
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
Идентификатор строки модели выглядит как providerid/modelid
, где идентификатор поставщика (в данном случае googleai
) идентифицирует плагин, а идентификатор модели — это строковый идентификатор, специфичный для плагина, для конкретной версии модели.
Некоторые плагины моделей, такие как плагин Ollama, предоставляют доступ потенциально к десяткам различных моделей и поэтому не экспортируют отдельные ссылки на модели. В этих случаях вы можете указать модель для generate()
только с помощью ее строкового идентификатора.
Эти примеры также иллюстрируют важный момент: когда вы используете generate()
для вызова генеративной модели ИИ, изменение модели, которую вы хотите использовать, — это просто вопрос передачи другого значения в параметр модели. Используя generate()
вместо собственных SDK моделей, вы получаете возможность более легко использовать несколько разных моделей в своем приложении и изменять модели в будущем.
До сих пор вы видели только примеры простейших вызовов generate()
. Однако generate()
также предоставляет интерфейс для более сложного взаимодействия с генеративными моделями, который вы увидите в следующих разделах.
Системные подсказки
Некоторые модели поддерживают предоставление системного приглашения , которое дает модели инструкции о том, как она должна реагировать на сообщения пользователя. Вы можете использовать системную подсказку, чтобы указать личность, которую вы хотите, чтобы модель приняла, тон ее ответов, формат ее ответов и т. д.
Если используемая вами модель поддерживает системные подсказки, вы можете предоставить ее с system
параметром:
const { text } = await ai.generate({
system: 'You are a food industry marketing consultant.',
prompt: 'Invent a menu item for a pirate themed restaurant.',
});
Параметры модели
generate()
принимает параметр config
, с помощью которого вы можете указать дополнительные настройки, управляющие тем, как модель генерирует контент:
const { text } = await ai.generate({
prompt: 'Invent a menu item for a pirate themed restaurant.',
config: {
maxOutputTokens: 400,
stopSequences: ['<end>', '<fin>'],
temperature: 1.2,
topP: 0.4,
topK: 50,
},
});
Точные поддерживаемые параметры зависят от конкретной модели и API модели. Однако параметры в предыдущем примере являются общими практически для каждой модели. Ниже приводится объяснение этих параметров:
Параметры, управляющие длиной вывода
Максаутпуттокенс
LLM работают с единицами, называемыми токенами . Токен обычно (но не обязательно) соответствует определенной последовательности символов. Когда вы передаете приглашение модели, одним из первых шагов является преобразование строки приглашения в последовательность токенов. Затем LLM генерирует последовательность токенов из токенизированных входных данных. Наконец, последовательность токенов преобразуется обратно в текст, который и является вашим результатом.
Параметр максимального количества токенов просто устанавливает ограничение на количество токенов, которые можно сгенерировать с помощью LLM. В каждой модели потенциально используется свой токенизатор, но хорошее практическое правило — считать, что одно английское слово состоит из 2–4 токенов.
Как говорилось ранее, некоторые токены могут не соответствовать последовательностям символов. Одним из таких примеров является то, что часто существует токен, указывающий конец последовательности: когда LLM генерирует этот токен, он перестает генерировать новые. Следовательно, возможно и часто бывает так, что LLM генерирует меньше токенов, чем максимальное, потому что он сгенерировал «стоповый» токен.
стоп-последовательности
Этот параметр можно использовать для установки токенов или последовательностей токенов, которые при создании указывают на конец вывода LLM. Правильные значения, которые следует использовать здесь, обычно зависят от того, как была обучена модель, и обычно устанавливаются плагином модели. Однако если вы предложили модели создать другую последовательность остановок, вы можете указать ее здесь.
Обратите внимание, что вы указываете последовательности символов, а не токены как таковые. В большинстве случаев вы указываете последовательность символов, которую токенизатор модели сопоставляет одному токену.
Параметры, управляющие «креативностью»
Параметры температуры , top-p и top-k вместе определяют, насколько «креативной» должна быть модель. Ниже приведены очень краткие объяснения того, что означают эти параметры, но более важный момент, который следует отметить, заключается в следующем: эти параметры используются для настройки характера выходного сигнала LLM. Оптимальные значения для них зависят от ваших целей и предпочтений и, скорее всего, будут найдены только экспериментальным путем.
температура
LLM — это, по сути, машины прогнозирования токенов. Для заданной последовательности токенов (например, приглашения) LLM прогнозирует для каждого токена в своем словаре вероятность того, что этот токен будет следующим в последовательности. Температура — это коэффициент масштабирования, на который эти прогнозы делятся перед нормализацией на вероятность от 0 до 1.
Низкие значения температуры — от 0,0 до 1,0 — усиливают разницу в вероятности между токенами, в результате чего модель с еще меньшей вероятностью создаст токен, который она уже оценила как маловероятный. Это часто воспринимается как менее творческий результат. Хотя 0,0 технически не является допустимым значением, многие модели рассматривают его как указание на то, что модель должна вести себя детерминировано и учитывать только один наиболее вероятный токен.
Значения высокой температуры — те, которые больше 1,0 — сжимают различия в вероятности между токенами, в результате чего модель с большей вероятностью будет производить токены, которые она ранее считала маловероятными. Это часто воспринимается как более творческий результат. API некоторых моделей устанавливают максимальную температуру, часто 2,0.
топП
Top-p — это значение от 0,0 до 1,0, которое контролирует количество возможных токенов, которые должна учитывать модель, путем указания совокупной вероятности токенов. Например, значение 1,0 означает, что нужно учитывать все возможные токены (но при этом учитывать вероятность каждого токена). Значение 0,4 означает, что следует учитывать только наиболее вероятные токены, сумма вероятностей которых равна 0,4, и исключать из рассмотрения остальные токены.
топК
Top-k — это целочисленное значение, которое также контролирует количество возможных токенов, которые должна учитывать модель, но на этот раз путем явного указания максимального количества токенов. Указание значения 1 означает, что модель должна вести себя детерминировано.
Экспериментируйте с параметрами модели
Вы можете поэкспериментировать с влиянием этих параметров на выходные данные, генерируемые различными комбинациями моделей и подсказок, с помощью пользовательского интерфейса разработчика. Запустите пользовательский интерфейс разработчика с помощью команды genkit start
, и он автоматически загрузит все модели, определенные плагинами, настроенными в вашем проекте. Вы можете быстро попробовать различные запросы и значения конфигурации без необходимости многократного внесения этих изменений в код.
Структурированный вывод
При использовании генеративного ИИ в качестве компонента вашего приложения часто требуется вывод в формате, отличном от обычного текста. Даже если вы просто создаете контент для отображения пользователю, вы можете извлечь выгоду из структурированного вывода просто с целью представить его более привлекательно для пользователя. Но для более продвинутых приложений генеративного ИИ, таких как программное использование результатов модели или передача результатов одной модели в другую, структурированный вывод просто необходим.
В Genkit вы можете запросить структурированный вывод из модели, указав схему при вызове generate()
:
import { z } from 'genkit'; // Import Zod, which is re-exported by Genkit.
const MenuItemSchema = z.object({
name: z.string(),
description: z.string(),
calories: z.number(),
allergens: z.array(z.string()),
});
const { output } = await ai.generate({
prompt: 'Invent a menu item for a pirate themed restaurant.',
output: { schema: MenuItemSchema },
});
Схемы вывода модели задаются с использованием библиотеки Zod . В дополнение к языку определения схемы Zod также обеспечивает проверку типов во время выполнения, которая устраняет разрыв между статическими типами TypeScript и непредсказуемыми результатами генеративных моделей ИИ. Zod позволяет вам писать код, который может полагаться на тот факт, что успешный вызов генерации всегда будет возвращать выходные данные, соответствующие вашим типам TypeScript.
Когда вы указываете схему в generate()
, Genkit незаметно делает несколько вещей:
- Дополняет подсказку дополнительными указаниями о желаемом формате вывода. Это также имеет побочный эффект: вы указываете модели, какой именно контент вы хотите сгенерировать (например, не только предложить пункт меню, но и сгенерировать описание, список аллергенов и т. д.).
- Анализирует выходные данные модели в объект JavaScript.
- Проверяет соответствие вывода схеме.
Чтобы получить структурированный вывод в результате успешного вызова генерации, используйте свойство output
объекта ответа:
if (output) {
const { name, description, calories, allergens } = output;
}
Обработка ошибок
Обратите внимание, что в предыдущем примере свойство output
может иметь значение null
. Это может произойти, если модель не может генерировать выходные данные, соответствующие схеме. Лучшая стратегия борьбы с такими ошибками будет зависеть от вашего конкретного варианта использования, но вот несколько общих советов:
Попробуйте другую модель . Для успешного структурированного вывода модель должна иметь возможность генерировать выходные данные в формате JSON. Самые мощные LLM, такие как Gemini и Claude, достаточно универсальны, чтобы сделать это; однако модели меньшего размера, такие как некоторые из локальных моделей, которые вы могли бы использовать с Ollama, возможно, не смогут надежно генерировать структурированные выходные данные, если они не были специально обучены этому.
Используйте возможности Зода по принуждению : в своих схемах вы можете указать, что Зод должен попытаться привести несоответствующие типы к типу, указанному в схеме. Если ваша схема включает в себя примитивные типы, отличные от строк, использование приведения Zod может уменьшить количество сбоев
generate()
с которыми вы сталкиваетесь. Следующая версияMenuItemSchema
использует приведение типов для автоматического исправления ситуаций, когда модель генерирует информацию о калориях в виде строки, а не числа:const MenuItemSchema = z.object({ name: z.string(), description: z.string(), calories: z.coerce.number(), allergens: z.array(z.string()), });
Повторите вызов метода Generate() . Если выбранная вами модель лишь изредка не генерирует соответствующий вывод, вы можете обработать ошибку так же, как если бы вы обрабатывали сетевую ошибку, и просто повторить запрос, используя какую-то стратегию постепенной отсрочки.
Потоковое вещание
При создании больших объемов текста вы можете улучшить взаимодействие с пользователями, представляя выходные данные в том виде, в котором они сгенерированы, — потоковую передачу результатов. Знакомый пример потоковой передачи в действии можно увидеть в большинстве чат-приложений LLM: пользователи могут читать ответ модели на свое сообщение по мере его создания, что улучшает восприятие реакции приложения и усиливает иллюзию общения с умным собеседником.
В Genkit вы можете осуществлять потоковую передачу вывода с помощью generateStream()
. Его синтаксис аналогичен generate()
:
const { response, stream } = await ai.generateStream(
'Suggest a complete menu for a pirate themed restaurant.'
);
Объект ответа имеет свойство stream
, которое можно использовать для перебора потокового вывода запроса по мере его создания:
for await (const chunk of stream) {
console.log(chunk.text);
}
Вы также можете получить полный вывод запроса, как и в случае с непотоковым запросом:
const completeText = (await response).text;
Потоковая передача также работает со структурированным выводом:
const MenuSchema = z.object({
starters: z.array(MenuItemSchema),
mains: z.array(MenuItemSchema),
desserts: z.array(MenuItemSchema),
});
const { response, stream } = await ai.generateStream({
prompt: 'Suggest a complete menu for a pirate themed restaurant.',
output: { schema: MenuSchema },
});
for await (const chunk of stream) {
// `output` is an object representing the entire output so far.
console.log(chunk.output);
}
// Get the completed output.
const { output } = await response;
Потоковый структурированный вывод работает немного иначе, чем потоковый текст: свойство output
фрагмента ответа представляет собой объект, созданный на основе накопления фрагментов, которые были созданы на данный момент, а не объект, представляющий один фрагмент (который может быть недействителен на свое собственное). Каждый фрагмент структурированного вывода в некотором смысле заменяет предыдущий фрагмент .
Например, вот как могут выглядеть первые пять результатов предыдущего примера:
null
{ starters: [ {} ] }
{
starters: [ { name: "Captain's Treasure Chest", description: 'A' } ]
}
{
starters: [
{
name: "Captain's Treasure Chest",
description: 'A mix of spiced nuts, olives, and marinated cheese served in a treasure chest.',
calories: 350
}
]
}
{
starters: [
{
name: "Captain's Treasure Chest",
description: 'A mix of spiced nuts, olives, and marinated cheese served in a treasure chest.',
calories: 350,
allergens: [Array]
},
{ name: 'Shipwreck Salad', description: 'Fresh' }
]
}
Мультимодальный ввод
В примерах, которые вы видели до сих пор, в качестве подсказок модели использовались текстовые строки. Хотя это остается наиболее распространенным способом подсказки генеративным моделям ИИ, многие модели также могут принимать в качестве подсказок другие носители. Медиа-подсказки чаще всего используются вместе с текстовыми подсказками, которые инструктируют модель выполнить некоторую операцию с мультимедиа, например добавить подпись к изображению или расшифровать аудиозапись.
Возможность принимать медиа-вход и типы мультимедиа, которые вы можете использовать, полностью зависят от модели и ее API. Например, модели серии Gemini 1.5 могут принимать изображения, видео и аудио в качестве подсказок.
Чтобы предоставить мультимедийное приглашение модели, которая его поддерживает, вместо передачи простого текстового приглашения в generate
передайте массив, состоящий из медиа-части и текстовой части:
const { text } = await ai.generate([
{ media: { url: 'https://example.com/photo.jpg' } },
{ text: 'Compose a poem about this image.' },
]);
В приведенном выше примере вы указали изображение, используя общедоступный URL-адрес HTTPS. Вы также можете передавать медиаданные напрямую, закодировав их как URL-адрес данных. Например:
import { readFile } from 'node:fs/promises';
const b64Data = await readFile('photo.jpg', { encoding: 'base64url' });
const dataUrl = `data:image/jpeg;base64,${b64Data}`;
const { text } = await ai.generate([
{ media: { url: dataUrl } },
{ text: 'Compose a poem about this image.' },
]);
Все модели, поддерживающие ввод мультимедиа, поддерживают как URL-адреса данных, так и URL-адреса HTTPS. Некоторые плагины модели добавляют поддержку других источников мультимедиа. Например, плагин Vertex AI также позволяет использовать URL-адреса облачного хранилища ( gs://
).
Создание медиа
До сих пор большинство примеров на этой странице касались генерации текста с использованием LLM. Однако Genkit также можно использовать с моделями генерации изображений. Использование generate()
с моделью генерации изображений аналогично использованию LLM. Например, чтобы сгенерировать изображение с использованием модели Imagen2 через Vertex AI:
Genkit использует
data:
URL-адреса в качестве стандартного формата вывода для сгенерированных мультимедиа. Это стандартный формат, для которого доступно множество библиотек. В этом примере используется пакетdata-urls
изjsdom
:npm i --save data-urls
npm i --save-dev @types/data-urls
Чтобы сгенерировать изображение и сохранить его в файл, вызовите
generate()
, указав модель создания изображения и тип носителя выходного формата:import { imagen3Fast, vertexAI } from '@genkit-ai/vertexai'; import parseDataURL from 'data-urls'; import { genkit } from 'genkit'; import { writeFile } from 'node:fs/promises'; const ai = genkit({ plugins: [vertexAI({ location: 'us-central1' })], }); (async () => { const { media } = await ai.generate({ model: imagen3Fast, prompt: 'photo of a meal fit for a pirate', output: { format: 'media' }, }); if (media === null) throw new Error('No media generated.'); const data = parseDataURL(media.url); if (data === null) throw new Error('Invalid "data:" URL.'); await writeFile(`output.${data.mimeType.subtype}`, data.body); })();
Следующие шаги
Узнайте больше о Генките
- Для разработчика приложений основной способ повлиять на результаты генеративных моделей ИИ — это подсказки. Прочтите «Управление подсказками» , чтобы узнать, как Genkit помогает разрабатывать эффективные подсказки и управлять ими в базе кода.
- Хотя
generate()
является ядром каждого приложения, работающего на основе генеративного ИИ, реальные приложения обычно требуют дополнительной работы до и после вызова генеративной модели ИИ. Чтобы отразить это, Genkit вводит концепцию потоков , которые определяются как функции, но добавляют дополнительные функции, такие как наблюдаемость и упрощенное развертывание. Дополнительные сведения см. в разделе Определение рабочих процессов .
Продвинутое использование LLM
- Один из способов расширить возможности LLM — предложить им список способов, которыми они могут запросить у вас дополнительную информацию или попросить вас выполнить какое-либо действие. Это известно как вызов инструмента или вызов функции . Модели, обученные поддерживать эту возможность, могут отвечать на приглашение специально отформатированным ответом, который указывает вызывающему приложению, что оно должно выполнить какое-то действие и отправить результат обратно в LLM вместе с исходным приглашением. В Genkit есть библиотечные функции, которые автоматизируют как генерацию подсказок, так и элементы цикла вызов-ответ в реализации вызова инструмента. См. раздел Вызов инструмента , чтобы узнать больше.
- Генерация с расширенным поиском (RAG) — это метод, используемый для введения специфичной для предметной области информации в выходные данные модели. Это достигается путем вставки соответствующей информации в подсказку перед ее передачей в языковую модель. Полная реализация RAG требует объединения нескольких технологий: моделей генерации встраивания текста, векторных баз данных и больших языковых моделей. См. раздел Генерация с расширенным поиском (RAG), чтобы узнать, как Genkit упрощает процесс координации этих различных элементов.
Тестирование выходных данных модели
Как инженер-программист, вы привыкли к детерминированным системам, в которых одни и те же входные данные всегда дают один и тот же результат. Однако, поскольку модели ИИ являются вероятностными, выходные данные могут варьироваться в зависимости от тонких нюансов входных данных, данных обучения модели и даже случайности, намеренно введенной такими параметрами, как температура.
Оценщики Genkit — это структурированные способы оценки качества ответов вашего LLM с использованием различных стратегий. Подробнее читайте на странице оценки .