Wywołania narzędzi

Wywoływanie narzędzia, czyli wywoływanie funkcji, to uporządkowany sposób na umożliwienie LLM przesyłania żądań do aplikacji, która je wywołała. Ty określasz narzędzia, które chcesz udostępnić modelowi, a model będzie wysyłać do Twojej aplikacji żądania użycia narzędzia w miarę potrzeby, aby zrealizować prompty.

Przypadki użycia wywoływania narzędzi można ogólnie podzielić na kilka tematów:

Udzielanie LLM dostępu do informacji, na których nie był on trenowany

  • często zmieniające się informacje, takie jak cena akcji lub aktualna pogoda;
  • informacje dotyczące Twojej domeny aplikacji, takie jak informacje o produkcie lub profilach użytkowników;

Zwróć uwagę na pokrywanie się z generowaniem rozszerzonym przez wyszukiwanie w zapisanych informacjach (RAG), które jest też sposobem na to, aby model LLM integrował informacje oparte na faktach w generowanych przez siebie treściach. RAG to bardziej zaawansowane rozwiązanie, które najlepiej sprawdza się, gdy masz dużą ilość informacji lub informacje, które są najbardziej trafne w przypadku prompta, są niejednoznaczne. Jeśli jednak do pobrania informacji, których potrzebuje LLM, wystarczy wywołanie funkcji lub sprawdzenie w bazie danych, odpowiedniejsze będzie wywołanie narzędzia.

Wprowadzanie pewnego stopnia determinizmu w przepływie pracy LLM

  • wykonywanie obliczeń, których LLM nie może wykonać samodzielnie;
  • wymuszanie generowania przez LLM dosłownego tekstu w określonych okolicznościach, np. podczas udzielania odpowiedzi na pytanie dotyczące warunków korzystania z aplikacji;

Wykonywanie działania po jego zainicjowaniu przez LLM

  • Włączanie i wyłączanie światła za pomocą asystenta domowego opartego na LLM
  • Rezerwowanie stolików w usługach opartych na LLM

Zanim zaczniesz

Jeśli chcesz uruchomić przykłady kodu na tej stronie, najpierw wykonaj czynności opisane w przewodniku dla początkujących. Wszystkie przykłady zakładają, że masz już skonfigurowany projekt z zainstalowanymi zależnościami Genkit.

Na tej stronie omawiamy jedną z zaawansowanych funkcji abstrakcji modelu w Genkit, dlatego zanim zaczniesz się zagłębiać w tą tematykę, zapoznaj się z treścią na stronie Generowanie treści za pomocą modeli AI. Musisz też znać system Genkit do definiowania schematów danych wejściowych i wyjściowych, który opisany jest na stronie Przepływy.

Omówienie wywoływania narzędzi

Ogólnie rzecz biorąc, typowa interakcja z LLM polegająca na wywołaniu narzędzia wygląda tak:

  1. Aplikacja wywołująca przesyła do LLM żądanie, a także zawiera w promptzie listę narzędzi, których LLM może użyć do wygenerowania odpowiedzi.
  2. LLM generuje pełną odpowiedź lub żądanie wywołania narzędzia w określonym formacie.
  3. Jeśli rozmówca otrzyma pełną odpowiedź, żądanie zostanie spełnione, a interakcja zakończy się. Jeśli jednak otrzyma wywołanie narzędzia, wykona odpowiednią logikę i wyśle nowe żądanie do LLM, zawierające pierwotne prompty lub ich odmianę, a także wynik wywołania narzędzia.
  4. LLM obsługuje nowy prompt w sposób opisany w kroku 2.

Aby to działało, musisz spełnić kilka wymagań:

  • Model musi być wytrenowany, aby wysyłać żądania do narzędzia, gdy jest to potrzebne do wykonania promptu. Większość większych modeli udostępnianych przez interfejsy API, takie jak Gemini, może to zrobić, ale mniejsze i bardziej wyspecjalizowane modele często nie są w stanie tego zrobić. Jeśli spróbujesz udostępnić narzędzia modelowi, który ich nie obsługuje, Genkit wyświetli błąd.
  • Aplikacja wywołująca musi przekazać model definicje narzędzi w oczekiwanym formacie.
  • Aplikacja wywołująca musi poprosić model o wygenerowanie żądań wywołania narzędzia w oczekiwanym przez aplikację formacie.

Narzędzie do dzwonienia w Genkit

Genkit udostępnia jeden interfejs wywoływania narzędzia w przypadku modeli, które go obsługują. Każdy wtyczka modelu zapewnia spełnienie 2 ostatnich kryteriów wymienionych w poprzedniej sekcji, a funkcja genkit.Generate() automatycznie wykonuje pętlę wywoływania narzędzia opisaną wcześniej.

Obsługa modelu

Obsługa wywoływania narzędzi zależy od modelu, interfejsu API modelu i wtyczki Genkit. Aby dowiedzieć się, czy narzędzie obsługuje wywoływanie, zapoznaj się z odpowiednią dokumentacją. Oprócz tego:

  • Jeśli spróbujesz udostępnić narzędzia modelowi, który ich nie obsługuje, Genkit wyświetli błąd.
  • Jeśli wtyczka eksportuje odwołania do modelu, właściwość ModelInfo.Supports.Tools wskazuje, czy obsługuje wywoływanie narzędzia.

Definiowanie narzędzi

Aby zapisać definicje narzędzi, użyj funkcji genkit.DefineTool():

import (
    "context"
    "log"

    "github.com/firebase/genkit/go/ai"
    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
    ctx := context.Background()

    g, err := genkit.Init(ctx,
        genkit.WithPlugins(&googlegenai.GoogleAI{}),
        genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
    )
    if err != nil {
      log.Fatal(err)
    }

    getWeatherTool := genkit.DefineTool(
        g, "getWeather", "Gets the current weather in a given location",
        func(ctx *ai.ToolContext, location string) (string, error) {
            // Here, we would typically make an API call or database query. For this
            // example, we just return a fixed value.
            return fmt.Sprintf("The current weather in %s is 63°F and sunny.", location);
        })
}

Składnia jest podobna do genkit.DefineFlow(), ale musisz napisać opis. Zwróć szczególną uwagę na treść i opis, ponieważ są one kluczowe dla prawidłowego użycia LLM.

Korzystanie z narzędzi

Uwzględnij zdefiniowane narzędzia w promptach, aby generować treści.

Wygeneruj

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("What is the weather in San Francisco?"),
    ai.WithTools(getWeatherTool),
)

DefinePrompt

weatherPrompt, err := genkit.DefinePrompt(g, "weatherPrompt",
    ai.WithPrompt("What is the weather in {{location}}?"),
    ai.WithTools(getWeatherTool),
)
if err != nil {
    log.Fatal(err)
}

resp, err := weatherPrompt.Execute(ctx,
    with.Input(map[string]any{"location": "San Francisco"}),
)

Plik z promptami

---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

Następnie możesz uruchomić prompt w kodzie w ten sposób:

// Assuming prompt file named weatherPrompt.prompt exists in ./prompts dir.
weatherPrompt := genkit.LookupPrompt("weatherPrompt")
if weatherPrompt == nil {
    log.Fatal("no prompt named 'weatherPrompt' found")
}

resp, err := weatherPrompt.Execute(ctx,
    ai.WithInput(map[string]any{"location": "San Francisco"}),
)

Genkit automatycznie obsłuży wywołanie narzędzia, jeśli LLM musi użyć narzędzia getWeather, aby odpowiedzieć na prompt.

Wyraźne obsługiwanie wywołań narzędzia

Jeśli chcesz mieć pełną kontrolę nad pętlą wywoływania narzędzia, np. aby zastosować bardziej skomplikowaną logikę, ustaw opcję WithReturnToolRequests() na true. Teraz Twoim zadaniem jest spełnienie wszystkich żądań dotyczących narzędzi:

getWeatherTool := genkit.DefineTool(
    g, "getWeather", "Gets the current weather in a given location",
    func(ctx *ai.ToolContext, location string) (string, error) {
        // Tool implementation...
    })

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("What is the weather in San Francisco?"),
    ai.WithTools(getWeatherTool),
    ai.WithReturnToolRequests(true),
)
if err != nil {
    log.Fatal(err)
}

parts := []*Part{}
for _, req := range resp.ToolRequests() {
    tool := genkit.LookupTool(g, req.Name)
    if tool == nil {
        log.Fatalf("tool %q not found", req.Name)
    }

    output, err := tool.RunRaw(ctx, req.Input)
    if err != nil {
        log.Fatalf("tool %q execution failed: %v", err)
    }

    parts = append(parts,
        ai.NewToolResponsePart(&ai.ToolResponse{
            Name:   req.Name,
            Ref:    req.Ref,
            Output: output,
        }))
}

resp, err = genkit.Generate(ctx, g,
    ai.WithMessages(resp.History()..., NewMessage(ai.RoleTool, nil, parts...)),
)
if err != nil {
    log.Fatal(err)
}