Przekazywanie informacji w kontekście

Istnieją różne kategorie informacji, którymi deweloper pracujący z LLM może zajmować się jednocześnie:

  • Dane wejściowe: informacje, które bezpośrednio wpływają na odpowiedź LLM w przypadku konkretnego wywołania. Przykładem może być tekst, który należy streścić.
  • Kontekst generowania: informacje, które są istotne dla LLM, ale nie są specyficzne dla tego wywołania. Przykładem może być aktualna godzina lub nazwa użytkownika.
  • Kontekst wykonania: informacje, które są ważne dla kodu otaczającego wywołanie LLM, ale nie dla samego LLM. Przykładem jest bieżący token uwierzytelniający użytkownika.

Genkit udostępnia spójny obiekt context, który może propagować kontekst generowania i wykonania w całym procesie. Ten kontekst jest udostępniany wszystkim działaniom, w tym obrotom, narzędziom i promptom.

Kontekst jest automatycznie propagowany do wszystkich działań wywoływanych w ramach wykonania: kontekst przekazany do przepływu jest udostępniany promptom wykonywanym w ramach przepływu. Kontekst przekazany metodzie generate() jest dostępny dla narzędzi wywoływanych w ramach pętli generowania.

Dlaczego kontekst jest ważny?

Sprawdzoną metodą jest przekazywanie LLM tylko minimalnej ilości informacji potrzebnych do wykonania zadania. Jest to ważne z kilku powodów:

  • Im mniej zbędnych informacji ma LLM, tym większe jest prawdopodobieństwo, że dobrze wykona swoje zadanie.
  • Jeśli LLM musi przekazywać narzędziom informacje, takie jak identyfikatory użytkowników lub kont, może zostać oszukany i wyciekną z niego dane.

Kontekst zapewnia kanał boczny z informacjami, z których może korzystać każdy kod, ale nie muszą one być przesyłane do LLM. Możesz na przykład ograniczyć zapytania narzędzia do zakresu dostępnego dla bieżącego użytkownika.

Struktura kontekstu

Kontekst musi być obiektem, ale jego właściwości są zależne od Ciebie. W niektórych sytuacjach Genkit automatycznie wypełnia kontekst. Jeśli np. używasz sesji trwałych, właściwość state jest automatycznie dodawana do kontekstu.

Jednym z najczęstszych zastosowań kontekstu jest przechowywanie informacji o bieżącym użytkowniku. Zalecamy dodanie kontekstu uwierzytelniania w takim formacie:

{
  auth: {
    uid: "...", // the user's unique identifier
    token: {...}, // the decoded claims of a user's id token
    rawToken: "...", // the user's raw encoded id token
    // ...any other fields
  }
}

Obiekt kontekstu może przechowywać wszystkie informacje, które mogą być Ci potrzebne w innym miejscu w przebiegu wykonywania kodu.

Używanie kontekstu w działaniu

Aby używać kontekstu w działaniu, możesz uzyskać dostęp do pomocnika kontekstowego, który jest automatycznie dostarczany do definicji funkcji:

Płynięcie

const summarizeHistory = ai.defineFlow({
  name: 'summarizeMessages',
  inputSchema: z.object({friendUid: z.string()}),
  outputSchema: z.string();
}, async ({friendUid}, {context}) => {
  if (!context.auth?.uid) throw new Error("Must supply auth context.");
  const messages = await listMessagesBetween(friendUid, context.auth.uid);
  const {text} = await ai.generate({
    prompt:
      `Summarize the content of these messages: ${JSON.stringify(messages)}`,
  });
  return text;
});

Narzędzie

const searchNotes = ai.defineTool({
  name: 'searchNotes',
  description: "search the current user's notes for info",
  inputSchema: z.object({query: z.string()}),
  outputSchmea: z.array(NoteSchema);
}, async ({query}, {context}) => {
  if (!context.auth?.uid) throw new Error("Must be called by a signed-in user.");
  return searchUserNotes(context.auth.uid, query);
});

Plik z promptami

Jeśli używasz szablonów Dotprompt, kontekst jest udostępniany za pomocą prefiksu zmiennej @. Na przykład obiekt kontekstu {auth: {name: 'Michael'}} można uzyskać w szablonie prompta w ten sposób:

---
input:
  schema:
    pirateStyle?: boolean
---

{{#if pirateStyle}}
Avast, {{@auth.name}}, how be ye today?
{{else}}
Hello, {{@auth.name}}, how are you today?
{{/if}}

Podawanie kontekstu w czasie wykonywania

Aby podać kontekst działania, podczas wywołania działania przekazujesz obiekt kontekstu jako opcję.

Przepływy

const summarizeHistory = ai.defineFlow(/* ... */);

const summary = await summarizeHistory(friend.uid, {context: {auth: currentUser}});

Generacja

const {text} = await ai.generate({
  prompt: "Find references to ocelots in my notes.",
  // the context will propagate to tool calls
  tools: [searchNotes],
  context: {auth: currentUser},
});

Prompty

const helloPrompt = ai.prompt('sayHello');
helloPrompt({pirateStyle: true}, {context: {auth: currentUser}});

Rozprzestrzenianie kontekstu i zastąpienia

Gdy podasz kontekst, zostanie on domyślnie rozpowszechniony do wszystkich działań wywołanych przez pierwotne wywołanie. Jeśli Twój przepływ wywołuje inne przepływy lub narzędzia do generowania, ten sam kontekst jest przekazywany.

Jeśli chcesz zastąpić kontekst w działaniu, możesz przekazać inny obiekt kontekstu, aby zastąpić istniejący:

const otherFlow = ai.defineFlow(/* ... */);

const myFlow = ai.defineFlow({
  // ...
}, (input, {context}) => {
  // override the existing context completely
  otherFlow({/*...*/}, {context: {newContext: true}});
  // or selectively override
  otherFlow({/*...*/}, {context: {...context, updatedContext: true}});
}); 

Gdy kontekst zostanie zastąpiony, rozprzestrzenia się w taki sam sposób. W tym przykładzie wszystkie czynności wywołane przez otherFlow podczas jego wykonywania odziedziczą zastąpiony kontekst.