Migrazione dalla versione 0.5

Genkit 0.9 introduce una serie di modifiche che comportano interruzioni, oltre a miglioramenti delle funzionalità che migliorano la funzionalità complessiva. Se hai sviluppato applicazioni con Genkit 0.5, dovrai aggiornare il codice dell'applicazione quando esegui l'upgrade alla versione più recente. Questa guida illustra le modifiche più significative e offre i passaggi per eseguire la migrazione delle applicazioni esistenti senza problemi.

Guida rapida

I passaggi che seguono ti aiuteranno a eseguire rapidamente la migrazione da Genkit 0.5 a Genkit 0.9. Scopri di più su queste modifiche nel log delle modifiche dettagliato di seguito.

1. Installa la nuova interfaccia a riga di comando

  • Disinstalla la vecchia CLI

    npm uninstall -g genkit && npm uninstall genkit
    
  • Installa la nuova interfaccia a riga di comando

    npm i -D genkit-cli
    

2. Aggiorna le dipendenze

  • Rimuovere i singoli pacchetti di Genkit principali

    npm uninstall @genkit-ai/ai @genkit-ai/core @genkit-ai/dotprompt @genkit-ai/flow
    
  • Installa il nuovo pacchetto consolidato genkit

    npm i --save genkit
    
  • Esegui l'upgrade di tutte le versioni dei plug-in (esempio di seguito)

    npm upgrade @genkit-ai/firebase
    

3. Modificare le importazioni

  • Rimuovi le importazioni per i singoli pacchetti principali di Genkit

    import { … } from '@genkit-ai/ai';
    import { … } from '@genkit-ai/core';
    import { … } from '@genkit-ai/flow';
    
  • Rimuovi le importazioni zod

    import * as z from 'zod';
    
  • Importa genkit e zod da genkit

    import { z, genkit } from 'genkit';
    

4. Aggiorna il codice

Rimuovi i blocchi configureGenkit

La configurazione di Genkit viene ora eseguita per istanza. La telemetria e la registrazione vengono configurate a livello globale e separatamente dall'istanza Genkit.

  • Sostituisci configureGenkit con blocchi ai = genkit({...}). Mantieni solo la configurazione del plug-in.

    import { genkit } from 'genkit';
    
    const ai = genkit({ plugins: [...]});
    
  • Configura la telemetria utilizzando enableFirebaseTelemetry o enableGoogleCloudTelemetry

    Per Firebase:

    import { enableFirebaseTelemetry } from '@genkit-ai/firebase';
    
    enableFirebaseTelemetry({...});
    

    Per Google Cloud:

    import { enableGoogleCloudTelemetry } from '@genkit-ai/google-cloud';
    
    enableGoogleCloudTelemetry({...});
    
  • Imposta il livello di logging in modo indipendente ```js import { logger } from 'genkit/logging';

    logger.setLogLevel('debug'); ```

Per ulteriori dettagli su come configurare la telemetria e il logging, consulta la documentazione relativa a Monitoraggio e logging.

Per maggiori dettagli su come configurare un'istanza Genkit, consulta la documentazione Guida introduttiva.

Esegui la migrazione delle azioni Genkit da chiamare dall'istanza genkit

Le azioni (flussi, strumenti, retriever, indicizzatori e così via) sono definite per istanza. Leggi il log delle modifiche per tutte le funzionalità che dovrai modificare, ma di seguito è riportato un esempio di alcune comuni.

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

const ai = genkit({ plugins: [...]});

// Flows and tools are defined on the specific genkit instance
// and are directly callable.
const sampleFlow = ai.defineFlow(...);
const sampleTool = ai.defineTool(...);

async function callMyFlow() {
  // Previously, text output could accessed via .text()
  // Now it is either .output() or .text
  return await sampleFlow().output();
}

// onFlow now takes the Genkit instance as first argument
// This registers the flow as a callable firebase function
onFlow(ai, ...);
const flows = [ sampleFlow, ... ];
// Start the flow server to make the registered flows callable over HTTP
ai.startFlowServer({flows});

5. Eseguilo

# run the DevUI and your js code
genkit start -- <command to run node>
# run a defined flow
genkit flow:run <flowName>

Log delle modifiche

1. Modifiche all'interfaccia a riga di comando

L'interfaccia a riga di comando (CLI) ha subito aggiornamenti significativi in Genkit 0.9. Il comando per avviare Genkit è cambiato e la CLI è stata separata in un proprio pacchetto autonomo, che ora devi installare separatamente.

Per installare l'interfaccia a riga di comando:

npm i -g genkit-cli

Sono state apportate alcune modifiche al comando genkit start:

Avvia il codice dell'applicazione Genkit e l'interfaccia utente di sviluppo contemporaneamente:

genkit start -- [start command]
genkit start -- tsx src/index.ts
genkit start -- go run main.go

È supportata anche la modalità Orologio:

genkit start -- tsx --watch src/index.ts

Avvia SOLO il codice dell'applicazione in modalità di sviluppo Genkit:

genkit start --noui -- <start command>
genkit start --noui -- tsx src/index.ts

Avvia SOLO l'interfaccia utente di sviluppo:

genkit start

In precedenza, il comando genkit start avviava contemporaneamente l'interfaccia utente di sviluppo e il codice dell'applicazione. Se hai pipeline CI/CD che si basano su questo comando, potresti doverle aggiornare.

L'interfaccia utente per sviluppatori interagisce direttamente con il server di flusso per capire quali flussi sono registrati e ti consente di invocarli direttamente con input di esempio.

2. Pacchetti e importazioni semplificati

In precedenza, le librerie Genkit erano suddivise in diversi moduli che dovevano essere installati e importati singolarmente. Questi moduli sono stati ora raggruppati in un'unica importazione. Inoltre, il modulo Zod viene ora esportato di nuovo da Genkit.

Precedente:

npm i @genkit-ai/core @genkit-ai/ai @genkit-ai/flow @genkit-ai/dotprompt

Novità:

npm i genkit

Precedente:

import { … } from '@genkit-ai/ai';
import { … } from '@genkit-ai/core';
import { … } from '@genkit-ai/flow';
import * as z from 'zod';

Novità:

import { genkit, z } from 'genkit';

I plug-in Genkit devono comunque essere installati e importati singolarmente.

3. Configurazione di Genkit

In precedenza, l'inizializzazione di Genkit veniva eseguita una volta a livello globale chiamando la funzione configureGenkit. Le risorse di Genkit (flussi, strumenti, prompt e così via) verranno collegate automaticamente a questa configurazione globale.

Genkit 0.9 introduce le istanze Genkit, ognuna delle quali incapsula una configurazione. Vedi i seguenti esempi:

Precedente:

import { configureGenkit } from '@genkit-ai/core';

configureGenkit({
  telemetry: {
    instrumentation: ...,
    logger: ...
  }
});

Novità:

import { genkit } from 'genkit';
import { logger } from 'genkit/logging';
import { enableFirebaseTelemetry } from '@genkit-ai/firebase';

logger.setLogLevel('debug');
enableFirebaseTelemetry({...});

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

Analizziamo la questione nel dettaglio:

  • configureGenkit() è stato sostituito con genkit() e restituisce un'istanza Genkit configurata anziché configurare le configurazioni a livello globale.
  • La funzione di inizializzazione di Genkit ora si trova nel pacchetto genkit.
  • La registrazione e la telemetria vengono comunque configurate a livello globale utilizzando i relativi metodi espliciti. Queste configurazioni si applicano in modo uniforme a tutte le istanze di Genkit.

4. Definire i flussi e avviare il server di flusso in modo esplicito

Ora che hai configurato un'istanza Genkit, devi definire i flussi. Tutti i metodi API principali rivolti agli sviluppatori, come defineFlow, defineTool e onFlow, vengono ora invocati tramite questa istanza.

Questo approccio è diverso da quello precedente, in cui i flussi e gli strumenti venivano registrati a livello globale.

Precedente:

import { defineFlow, defineTool, onFlow } from '@genkit-ai/core';

defineFlow(...);
defineTool(...);

onFlow(...);

Novità:

// Define tools and flows
const sampleFlow = ai.defineFlow(...);
const sampleTool = ai.defineTool(...);

// onFlow now takes the Genkit instance as first argument
// This registers the flow as a callable firebase function
onFlow(ai, ...);  

const flows = [ sampleFlow, ... ];
// Start the flow server to make the registered flows callable over HTTP
ai.startFlowServer({flows});

Al momento, tutti i flussi che vuoi rendere disponibili devono essere registrati esplicitamente nell'array flows riportato sopra.

5. Gli strumenti e i prompt devono essere definiti in modo statico

Nelle versioni precedenti di Genkit, era possibile definire dinamicamente strumenti e prompt in fase di esecuzione, direttamente all'interno di un flusso.

In Genkit 0.9, questo comportamento non è più consentito. Devi invece definire tutte le azioni e i flussi al di fuori dell'esecuzione del flusso (ovvero in modo statico).

Questa modifica impone una separazione più rigida delle definizioni delle azioni dall'esecuzione.

Se parte del codice è definito in modo dinamico, deve essere sottoposto a refactoring. In caso contrario, verrà generato un errore durante l'esecuzione del flusso.

❌ NON:

const flow = defineFlow({...}, async (input) => {
  const tool = defineTool({...});
  await tool(...);
});

✅ DA FARE:

const tool = ai.defineTool({...});

const flow = ai.defineFlow({...}, async (input) => {
  await tool(...);
});

6. Nuova API per i flussi di streaming

In Genkit 0.9 abbiamo semplificato la sintassi per definire e richiamare un flusso di streaming.

Innanzitutto, defineFlow e defineStreamingFlow sono stati separati. Se hai un flusso destinato a essere trasmesso in streaming, dovrai aggiornare il codice per definirlo tramite defineStreamingFlow.

In secondo luogo, anziché chiamare funzioni stream() e response() separate, ora sia stream che response sono valori restituiti direttamente dal flusso. Questa modifica semplifica lo streaming in sequenza.

Precedente:

import { defineFlow, streamFlow } from '@genkit-ai/flow';

const myStreamingFlow = defineFlow(...);
const { stream, output } = await streamFlow(myStreamingFlow, ...);

for await (const chunk of stream()) {
  console.log(chunk);
}

console.log(await output());

Novità:

const myStreamingFlow = ai.defineStreamingFlow(...);
const { stream, response } = await myStreamingFlow(...);

for await (const chunk of stream) {
  console.log(chunk);
}

console.log(await response);

7. I metodi della classe GenerateResponse sono stati sostituiti con proprietà getter

In precedenza, per accedere all'output strutturato o al testo della risposta utilizzavi i metodi di classe, come output() o text().

In Genkit 0.9, questi metodi sono stati sostituiti dalle proprietà getter. In questo modo, la gestione delle risposte è più semplice.

Precedente:

const response = await generate({ prompt: 'hi' });
console.log(response.text());

Novità:

const response = await ai.generate('hi');
console.log(response.text);

Lo stesso vale per output:

Precedente:

console.log(response.output());

Novità:

console.log(response.output);

8. Generazione di candidati eliminata

Genkit 0.9 semplifica la gestione delle risposte rimuovendo l'attributo candidates. In precedenza, le risposte potevano contenere più candidati, che dovevano essere gestiti esplicitamente. Ora, solo il primo candidato viene restituito direttamente in una risposta piatta.

Qualsiasi codice che acceda direttamente ai candidati non funzionerà più.

Precedente:

const response = await generate({
 messages: [ { role: 'user', content: ...} ]
});
console.log(response.candidates); // previously you could access candidates directly

Novità:

const response = await ai.generate({
 messages: [ { role: 'user', content: ...} ]
});
console.log(response.message); // single candidate is returned directly in a flat response

9. API Generate - Miglioramenti per più passaggi

Per le conversazioni multi-turno, il vecchio metodo toHistory() è stato sostituito da messages, semplificando ulteriormente la gestione della cronologia delle conversazioni.

Precedente:

const history = response.toHistory();

Novità:

const response = await ai.generate({
 messages: [ { role: 'user', content: ...} ]
});
const history = response.messages;

10. API Chat semplificata

In Genkit 0.9, l'API Chat è stata riprogettata per semplificare la gestione e l'interazione con le sessioni. Ecco come puoi utilizzarla per esperienze di chat sia sincrone che in streaming:

import { genkit } from 'genkit';
import { gemini15Flash, googleAI } from '@genkit-ai/googleai';

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

const session = ai.createSession({ store: firestoreSessionStore() });
const chat = await session.chat({ system: 'talk like a pirate' });

let response = await chat.send('hi, my name is Pavel');
console.log(response.text()); // "hi Pavel, I'm llm"

// continue the conversation
response = await chat.send("what's my name");
console.log(response.text()); // "Pavel"

// can stream
const { response, stream } = await chat.sendStream('bye');
for await (const chunk of stream) {
 console.log(chunk.text());
}
console.log((await response).text());

// can load session from the store
const prevSession = await ai.loadSession(session.id, { store });
const prevChat = await prevSession.chat();
await prevChat.send('bye');