Migrazione dalla versione 0.9 a 1.0

Genkit 1.0 introduce molti miglioramenti delle funzionalità che migliorano la funzionalità complessiva. Inoltre, presenta alcune modifiche che comportano interruzioni. Se hai sviluppato applicazioni con Genkit 0.9, devi aggiornare il codice dell'applicazione quando esegui l'upgrade all'ultima versione di Genkit. Questa guida illustra le modifiche più significative e spiega come eseguire la migrazione delle applicazioni esistenti senza problemi.

API beta

Stiamo introducendo un canale API beta instabile e lasciamo le API client di sessione, chat e Genkit in versione beta mentre continuiamo a perfezionarle. Nello spazio dei nomi beta sono attualmente presenti le seguenti funzioni:

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

Precedente:

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

Novità:

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

Precedente:

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

Novità:

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

Introduzione del nuovo pacchetto @genkit-ai/express

Questo nuovo pacchetto contiene utilità per semplificare la creazione di un server Express.js con Genkit. Puoi trovare maggiori dettagli su questo argomento in questa pagina.

startFlowServer è passato da parte dell'oggetto genkit a questo nuovo @genkit-ai/express pacchetto; per utilizzare startFlowServer, devi aggiornare le importazioni.

Precedente:

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

Novità:

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

Modifiche ai flussi

Nella versione 1.0 sono state apportate diverse modifiche ai flussi:

  • ai.defineStreamingFlow è stato consolidato in ai.defineFlow,
  • onFlow è stato sostituito da onCallGenkit,
  • run si è trasferito in ai.run,
  • Sono state apportate modifiche al lavoro con l'autenticazione.

La funzione run per i blocchi di traccia personalizzati è stata spostata all'interno dell'oggetto genkit. Utilizza ai.run per invocarla.

Precedente:

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

Novità:

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

ai.defineStreamingFlow è stato rimosso; utilizza ai.defineFlow. Inoltre, streamingCallback è stato spostato in un campo all'interno del secondo argomento della funzione flussi ed ora si chiama sendChunk.

Precedente:

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

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

Novità:

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'autenticazione FlowAuth ora si chiama context. Puoi accedere all'autenticazione come campo all'interno del contesto:

Precedente:

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

Novità:

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

onFlow è stato spostato nel pacchetto firebase-functions/https e rinominato in onCallGenkit. Il seguente snippet mostra un esempio di utilizzo.

Vecchia

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;
  }
);

Novità:

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);

I criteri di autenticazione sono stati rimossi da defineFlow. La gestione dei criteri di autenticazione ora dipende dal server.

Precedente:

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

Il seguente snippet mostra un esempio di gestione dell'autenticazione in Express.

Novità:

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
);

Per ulteriori dettagli, consulta la documentazione sull'autenticazione.

Lo snippet seguente mostra un esempio di gestione dell'autenticazione in Cloud Functions for 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);

Prompt

Abbiamo apportato diverse modifiche e miglioramenti ai prompt.

Puoi definire modelli separati per i prompt e i messaggi di sistema:

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'});

In alternativa, puoi definire prompt con più messaggi nel campo messaggi:

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

Anziché i modelli di prompt, puoi utilizzare una funzione:

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

Puoi accedere al contesto (incluse le informazioni di autenticazione) dal prompt:

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

Le funzioni di streaming non richiedono un await

Precedente:

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

Novità:

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

Embed ha un nuovo tipo di ritorno

Abbiamo aggiunto il supporto per gli embedding multimodali. Anziché restituire solo un singolo vettore di incorporamento, Embed restituisce un array di oggetti di incorporamento, ciascuno contenente un vettore di incorporamento e i metadati.

Precedente:

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

Novità:

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