Como escrever plug-ins do Genkit

Os recursos do Firebase Genkit foram projetados para serem estendidos por plug-ins. Os plug-ins do Genkit são módulos configuráveis que podem fornecer modelos, recuperadores, indexadores, armazenamentos de rastros e muito mais. Você já viu os plug-ins em ação usando apenas o Genkit:

import { genkit } from 'genkit';
import { vertexAI } from '@genkit-ai/vertexai';

const ai = genkit({
  plugins: [vertexAI({ projectId: 'my-project' })],
});

O plug-in da Vertex AI usa a configuração (como o arquivo ID do projeto) e registra uma variedade de novos modelos, incorporadores e muito mais com o Genkit. O registro capacita a interface de usuário local do Genkit para executar e inspecionar modelos, comandos e muito mais, além de servir como um serviço de pesquisa para ações nomeadas no momento da execução.

Como criar um plug-in

Para criar um plug-in, geralmente é necessário criar um novo pacote NPM:

mkdir genkitx-my-plugin
cd genkitx-my-plugin
npm init -y
npm i --save genkit
npm i --save-dev typescript
npx tsc --init

Em seguida, defina e exporte o plug-in do ponto de entrada principal:

import { Genkit, z } from 'genkit';
import { GenkitPlugin, genkitPlugin } from 'genkit/plugin';

interface MyPluginOptions {
  // add any plugin configuration here
}

export function myPlugin(options?: MyPluginOptions) {
  return genkitPlugin('myPlugin', async (ai: Genkit) => {
    ai.defineModel(...);
    ai.defineEmbedder(...)
    // ....
  });
};

Orientações sobre as opções de plug-ins

Em geral, o plug-in precisa ter um único argumento options que inclua qualquer configuração em todo o plug-in necessária para funcionar. Para qualquer opção de plug-in que exija um valor secreto, como chaves de API, ofereça uma opção e uma variável de ambiente padrão para configurá-la:

import { Genkit, z } from 'genkit';
import { GenkitPlugin, genkitPlugin } from 'genkit/plugin';
import { GenkitError } from '@genkit-ai/core';

interface MyPluginOptions {
  apiKey?: string;
}

export function myPlugin(options?: MyPluginOptions) {
  return genkitPlugin('myPlugin', async (ai: Genkit) => {
    if (!apiKey)
      throw new GenkitError({
        source: 'my-plugin',
        status: 'INVALID_ARGUMENT',
        message:
          'Must supply either `options.apiKey` or set `MY_PLUGIN_API_KEY` environment variable.',
      });

    ai.defineModel(...);
    ai.defineEmbedder(...)
    
    // ....
  });
};

Como criar seu plug-in

Um único plug-in pode ativar muitas coisas novas no Genkit. Por exemplo, o plug-in da Vertex AI ativa vários modelos novos, bem como um incorporador.

Plug-ins de modelos

Os plug-ins de modelo do Genkit adicionam um ou mais modelos de IA generativa ao registro do Genkit. Um modelo representa qualquer modelo generativo capaz de receber um comando como entrada e gerar texto, mídia ou dados como saída. Geralmente, um plug-in de modelo faz uma ou mais chamadas defineModel na função de inicialização.

Um modelo personalizado geralmente consiste em três componentes:

  1. Metadados que definem os recursos do modelo.
  2. Um esquema de configuração com quaisquer parâmetros específicos aceitos pelo modelo.
  3. Uma função que implementa o modelo aceitando GenerateRequest e retornando GenerateResponse.

Para criar um plug-in de modelo, use o pacote @genkit-ai/ai:

npm i --save @genkit-ai/ai

De modo geral, um plug-in de modelo pode ter esta aparência:

import { genkitPlugin, GenkitPlugin } from 'genkit/plugin';
import { GenkitError } from '@genkit-ai/core';
import { GenerationCommonConfigSchema } from '@genkit-ai/ai/model';
import { simulateSystemPrompt } from '@genkit-ai/ai/model/middleware';
import { z } from 'genkit';


export function myPlugin(options?: MyPluginOptions) {
  return genkitPlugin('my-plugin', async (ai: Genkit) => {
    ai.defineModel({
      // be sure to include your plugin as a provider prefix
      name: 'my-plugin/my-model',
      // label for your model as shown in Genkit Developer UI
      label: 'My Awesome Model',
      // optional list of supported versions of your model
      versions: ['my-model-001', 'my-model-001'],
      // model support attributes
      supports: {
        multiturn: true, // true if your model supports conversations
        media: true, // true if your model supports multimodal input
        tools: true, // true if your model supports tool/function calling
        systemRole: true, // true if your model supports the system role
        output: ['text', 'media', 'json'], // types of output your model supports
      },
      // Zod schema for your model's custom configuration
      configSchema: GenerationCommonConfigSchema.extend({
        safetySettings: z.object({...}),
      }),
      // list of middleware for your model to use
      use: [simulateSystemPrompt()]
    }, async request => {
      const myModelRequest = toMyModelRequest(request);
      const myModelResponse = await myModelApi(myModelRequest);
      return toGenerateResponse(myModelResponse);
    });
  });
};


Como transformar solicitações e respostas

O trabalho principal de um plug-in de modelo do Genkit é transformar o GenerateRequest do formato comum do Genkit em um formato reconhecido e compatível com a API do modelo e, em seguida, transformar a resposta do modelo no formato GenerateResponseData usado pelo Genkit.

Às vezes, isso pode exigir massagens ou manipulação de dados para contornar o modelo limitações. Por exemplo, se o modelo não oferecer suporte nativo a uma mensagem system, talvez seja necessário transformar uma mensagem do sistema de um comando em um par de mensagens de usuário/modelo.

Referências de modelos

Depois que um modelo é registrado usando defineModel, ele fica sempre disponível quando solicitado por nome. No entanto, para melhorar a digitação e a autopreenchimento do ambiente de desenvolvimento integrado, é possível exportar uma referência de modelo do pacote que inclui apenas os metadados de um modelo, mas não a implementação dele:

import { modelRef } from "@genkit-ai/ai/model";

export myModelRef = modelRef({
  name: "my-plugin/my-model",
  configSchema: MyConfigSchema,
  info: {
    // ... model-specific info
  },
})

Ao chamar generate(), as referências de modelo e os nomes de modelo de string podem ser usados de forma intercambiável:

import { myModelRef } from 'genkitx-my-plugin';
import { generate } from '@genkit-ai/ai';

generate({ model: myModelRef });
// is equivalent to
generate({ model: 'my-plugin/my-model' });

Publicar um plug-in

Os plug-ins do Genkit podem ser publicados como pacotes NPM normais. Para aumentar a detecção e maximizar a consistência, seu pacote precisa ser nomeado genkitx-{name} para indicar que é um plug-in do Genkit. Inclua o maior número possível dos seguintes keywords no package.json que sejam relevantes para o plug-in:

  • genkit-plugin: sempre inclua essa palavra-chave no pacote para indicar que ele é um plug-in do Genkit.
  • genkit-model: inclua essa palavra-chave se o pacote definir modelos.
  • genkit-retriever: inclua essa palavra-chave se o pacote definir algum retriever.
  • genkit-indexer: inclua essa palavra-chave se o pacote definir indexadores.
  • genkit-embedder: inclua essa palavra-chave se o pacote definir indexadores.
  • genkit-tracestore: inclua essa palavra-chave se o pacote definir lojas de rastreamento.
  • genkit-statestore: inclua essa palavra-chave se o pacote definir lojas de estado.
  • genkit-telemetry: inclua essa palavra-chave se o pacote definir um provedor de telemetria.
  • genkit-deploy: inclua essa palavra-chave se o pacote incluir helpers para implantar apps do Genkit em provedores de nuvem.
  • genkit-flow: inclua essa palavra-chave se o pacote melhorar os fluxos do Genkit.

Um plug-in que forneceu um recuperador, um incorporador e um modelo pode ter um package.json parecido com este:

{
  "name": "genkitx-my-plugin",
  "keywords": ["genkit-plugin", "genkit-retriever", "genkit-embedder", "genkit-model"],
  // ... dependencies etc.
}