Migrer de la version 0.9 vers la version 1.0

Genkit 1.0 introduit de nombreuses améliorations de fonctionnalités qui améliorent les fonctionnalités globales. Il comporte également des modifications non compatibles. Si vous avez développé des applications avec Genkit 0.9, vous devez mettre à jour le code de votre application lorsque vous passez à la dernière version de Genkit. Ce guide décrit les modifications les plus importantes et explique comment migrer vos applications existantes en douceur.

API bêta

Nous lançons un canal d'API bêta instable, et laissons les API client de session, de chat et de Genkit en version bêta pendant que nous continuons de les affiner. Plus précisément, les fonctions suivantes se trouvent actuellement dans l'espace de noms beta:

  • ai.chat
  • ai.createSession
  • ai.loadSession
  • ai.currentSession
  • ai.defineFormat
  • ai.defineInterrupt

Anciennement:

import { genkit } from 'genkit';
const ai = genkit({...})
const session = ai.createSession({ ... })

Nouveauté:

import { genkit } from 'genkit/beta';
const ai = genkit({...})
const session = ai.createSession({ ... })

Anciennement:

import { runFlow, streamFlow } from 'genkit/client';

Nouveauté:

import { runFlow, streamFlow } from 'genkit/beta/client';

Présentation du nouveau package @genkit-ai/express

Ce nouveau package contient des utilitaires qui facilitent la création d'un serveur Express.js avec Genkit. Pour en savoir plus, consultez cette page.

startFlowServer est passé d'une partie de l'objet genkit à ce nouveau package @genkit-ai/express. Pour utiliser startFlowServer, vous devez mettre à jour vos importations.

Anciennement:

const ai = genkit({ ... });
ai.startFlowServer({
  flows: [myFlow1, myFlow2],
});

Nouveauté:

import { startFlowServer } from '@genkit-ai/express';
startFlowServer({
  flows: [myFlow1, myFlow2],
});

Modifications apportées aux flux

Plusieurs modifications ont été apportées aux flux dans la version 1.0:

  • ai.defineStreamingFlow a été consolidé dans ai.defineFlow.
  • onFlow a été remplacé par onCallGenkit.
  • run a été déplacé vers ai.run.
  • Des modifications ont été apportées à l'utilisation de l'authentification.

La fonction run pour les blocs de trace personnalisés a été déplacée vers une partie de l'objet genkit. Utilisez plutôt ai.run pour l'appeler.

Anciennement:

ai.defineFlow({name: 'banana'}, async (input) => {
  const step = await run('myCode', async () => {
    return 'something'
  });
})

Nouveauté:

ai.defineFlow({name: 'banana'}, async (input) => {
  const step = await ai.run('myCode', async () => {
    return 'something'
  });
})

ai.defineStreamingFlow a été supprimé. Utilisez ai.defineFlow à la place. De plus, streamingCallback a été déplacé vers un champ dans le deuxième argument de la fonction de flux et est désormais appelé sendChunk.

Anciennement:

const flow = ai.defineStreamingFlow({name: 'banana'}, async (input, streamingCallback) => {
  streamingCallback({chunk: 1});
})

const {stream} = await flow()
for await (const chunk of stream) {
  // ...
}

Nouveauté:

const flow = ai.defineFlow({name: 'banana'}, async (input, {context, sendChunk}) => {
  sendChunk({chunk: 1});
})

const {stream, output} = flow.stream(input);
for await (const chunk of stream) {
  // ...
}

L'authentification FlowAuth s'appelle désormais "context". Vous pouvez accéder à l'authentification en tant que champ dans le contexte:

Anciennement:

ai.defineFlow({name: 'banana'}, async (input) => {
  const auth = getFlowAuth();
  // ...
})

Nouveauté:

ai.defineFlow({name: 'banana'}, async (input, { context }) => {
  const auth = context.auth;
})

onFlow a été déplacé vers le package firebase-functions/https et a été renommé onCallGenkit. L'extrait de code suivant montre comment l'utiliser.

Ancienne

import { onFlow } from "@genkit-ai/firebase/functions";

export const generatePoem = onFlow(
  ai,
  {
    name: "jokeTeller",
    inputSchema: z.string().nullable(),
    outputSchema: z.string(),
    streamSchema: z.string(),
  },
  async (type, streamingCallback) => {
    const { stream, response } = await ai.generateStream(
      `Tell me a longish ${type ?? "dad"} joke.`
    );
    for await (const chunk of stream) {
      streamingCallback(chunk.text);
    }
    return (await response).text;
  }
);

Nouveauté:

import { onCallGenkit } from "firebase-functions/https";
import { defineSecret } from "firebase-functions/params";
import { genkit, z } from "genkit";

const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

export const jokeTeller = ai.defineFlow(
  {
    name: "jokeTeller",
    inputSchema: z.string().nullable(),
    outputSchema: z.string(),
    streamSchema: z.string(),
  },
  async (type, { sendChunk }) => {
    const { stream, response } = ai.generateStream(
      `Tell me a longish ${type ?? "dad"} joke.`
    );
    for await (const chunk of stream) {
      sendChunk(chunk.text);
    }
    return (await response).text;
  }
);

export const tellJoke = onCallGenkit({ secrets: [apiKey] }, jokeTeller);

Les règles d'authentification ont été supprimées de defineFlow. La gestion des règles d'authentification dépend désormais du serveur.

Anciennement:

export const simpleFlow = ai.defineFlow(
  {
    name: 'simpleFlow',
    authPolicy: (auth, input) => {
      // auth policy
    },
  },
  async (input) => {
    // Flow logic here...
  }
);

L'extrait de code suivant montre un exemple de gestion de l'authentification dans Express.

Nouveauté:

import { UserFacingError } from 'genkit';
import { ContextProvider, RequestData } from 'genkit/context';
import { expressHandler, startFlowServer } from '@genkit-ai/express';

const context: ContextProvider<Context> = (req: RequestData) => {
  return {
    auth: parseAuthToken(req.headers['authorization']),
  };
};

export const simpleFlow = ai.defineFlow(
  {
    name: 'simpleFlow',
  },
  async (input, { context }) => {
    if (!context.auth) {
      throw new UserFacingError("UNAUTHORIZED", "Authorization required.");
    }
    if (input.uid !== context.auth.uid) {
      throw new UserFacingError("UNAUTHORIZED", "You may only summarize your own profile data.");
    }
    // Flow logic here...
  }
);

const app = express();
app.use(express.json());
app.post(
  '/simpleFlow',
  expressHandler(simpleFlow, { context })
);
app.listen(8080);

// or

startFlowServer(
  flows: [withContextProvider(simpleFlow, context)],
  port: 8080
);

Pour en savoir plus, consultez la documentation sur l'authentification.

L'extrait de code suivant montre un exemple de gestion de l'authentification dans Cloud Functions pour Firebase:

import { genkit } from 'genkit';
import { onCallGenkit } from 'firebase-functions/https';

const ai = genkit({ ... });;

const simpleFlow = ai.defineFlow({
  name: 'simpleFlow',
}, async (input) => {
  // Flow logic here...
});

export const selfSummary = onCallGenkit({
  authPolicy: (auth, data) => auth?.token?.['email_verified'] && auth?.token?.['admin'],
}, simpleFlow);

Requêtes

Nous avons apporté plusieurs modifications et améliorations aux requêtes.

Vous pouvez définir des modèles distincts pour les requêtes et les messages système:

const hello = ai.definePrompt({
  name: 'hello',
  system: 'talk like a pirate.',
  prompt: 'hello {{ name }}',
  input: {
    schema: z.object({
      name: z.string()
    })
  }
});
const { text } = await hello({name: 'Genkit'});

Vous pouvez également définir des invites multimessages dans le champ "messages" :

const hello = ai.definePrompt({
  name: 'hello',
  messages: '{{ role "system" }} talk like a pirate. {{ role "user" }} hello {{ name }}',
  input: {
    schema: z.object({
      name: z.string()
    })
  }
});

Au lieu de modèles d'invite, vous pouvez utiliser une fonction:

ai.definePrompt({
  name: 'hello',
  prompt: async (input, { context }) => {
    return `hello ${input.name}`
  },
  input: {
    schema: z.object({
      name: z.string()
    })
  }
});

Vous pouvez accéder au contexte (y compris aux informations d'authentification) depuis l'invite:

const hello = ai.definePrompt({
  name: 'hello',
  messages: 'hello {{ @auth.email }}',
});

Les fonctions de streaming ne nécessitent pas de await.

Anciennement:

const { stream, response } = await ai.generateStream(`hi`);
const { stream, output } = await myflow.stream(`hi`);

Nouveauté:

const { stream, response } = ai.generateStream(`hi`);
const { stream, output } = myflow.stream(`hi`);

Nouveau type de retour pour l'intégration

Nous avons ajouté la compatibilité avec les représentations vectorielles continues multimodales. Au lieu de renvoyer un seul vecteur d'embedding, Embed renvoie un tableau d'objets d'embedding, chacun contenant un vecteur d'embedding et des métadonnées.

Anciennement:

const response = await ai.embed({embedder, content, options});  // returns number[]

Nouveauté:

const response = await ai.embed({embedder, content, options}); // returns Embedding[]
const firstEmbeddingVector = response[0].embedding;  // is number[]