ツール呼び出し(別名: 関数呼び出し)は、呼び出したアプリケーションにリクエストを返す機能を LLM に提供する構造化された方法です。モデルで使用できるようにするツールを定義すると、モデルは指定したプロンプトを実行するために必要に応じてアプリにツール リクエストを送信します。
ツール呼び出しのユースケースは、一般的に次のテーマに分類されます。
LLM にトレーニングに使用しなかった情報へのアクセス権を付与する
- 株価や現在の天気など、頻繁に変更される情報。
- 商品情報やユーザー プロフィールなど、アプリのドメインに固有の情報。
検索拡張生成(RAG)との重複に注意してください。これは、LLM が事実情報を生成に統合できるようにする方法でもあります。RAG はより負荷の高いソリューションであり、大量の情報がある場合や、プロンプトに最も関連性の高い情報があいまいな場合に最適です。一方、LLM に必要な情報を取得するために必要なのが関数呼び出しまたはデータベース検索のみの場合は、ツール呼び出しの方が適しています。
LLM ワークフローに一定の確定性を導入する
- LLM が確実に完了できない計算を実行する。
- アプリの利用規約に関する質問に回答する場合など、特定の状況下で LLM に文字どおりのテキストを生成させる。
LLM によって開始されたときにアクションを実行する
- LLM を搭載したスマートホーム アシスタントで照明をオンまたはオフにする
- LLM を搭載したレストラン エージェントでテーブルを予約する
始める前に
このページのコードサンプルを実行する場合は、まずスタートガイドの手順を完了してください。すべての例では、Genkit の依存関係がインストールされたプロジェクトがすでに設定されていることを前提としています。
このページでは、Genkit モデルの抽象化の高度な機能の一つについて説明します。詳しく説明する前に、AI モデルを使用してコンテンツを生成するページの内容を確認してください。また、入力スキーマと出力スキーマを定義する Genkit のシステムについても理解している必要があります。これは、フローのページで説明しています。
ツール呼び出しの概要
LLM との一般的なツール呼び出しのインタラクションの概要は次のとおりです。
- 呼び出し元のアプリケーションは、LLM にリクエストをプロンプトします。また、LLM がレスポンスの生成に使用できるツールのリストをプロンプトに含めます。
- LLM は、完全なレスポンスを生成するか、特定の形式でツール呼び出しリクエストを生成します。
- 呼び出し元が完全なレスポンスを受信した場合、リクエストは処理され、インタラクションは終了します。呼び出し元がツール呼び出しを受信した場合は、適切なロジックを実行し、元のプロンプトまたはそのバリエーションとツール呼び出しの結果を含む新しいリクエストを LLM に送信します。
- LLM は、ステップ 2 と同様に新しいプロンプトを処理します。
そのためには、いくつかの要件を満たす必要があります。
- プロンプトの完了に必要なときにツール リクエストを行うようにモデルをトレーニングする必要があります。Gemini などのウェブ API で提供される大規模なモデルのほとんどはこれを実行できますが、小規模でより特殊なモデルではできないことがよくあります。ツールをサポートしていないモデルにツールを提供しようとすると、Genkit はエラーをスローします。
- 呼び出し元のアプリケーションは、モデルが想定する形式でツール定義をモデルに提供する必要があります。
- 呼び出し元のアプリケーションは、アプリケーションが想定する形式でツール呼び出しリクエストを生成するようにモデルにプロンプトを送信する必要があります。
Genkit によるツール呼び出し
Genkit は、サポートするモデルでツールを呼び出すための単一のインターフェースを提供します。
各モデル プラグインは、前のセクションで説明した最後の 2 つの条件が満たされることを確認し、genkit.Generate()
関数は前述のツール呼び出しループを自動的に実行します。
モデルサポート
ツール呼び出しのサポートは、モデル、モデル API、Genkit プラグインによって異なります。 ツール呼び出しがサポートされる可能性が高いかどうかを判断するには、関連するドキュメントをご覧ください。さらに、以下のことにご留意ください。
- ツールをサポートしていないモデルにツールを提供しようとすると、Genkit はエラーをスローします。
- プラグインがモデル参照をエクスポートする場合、
ModelInfo.Supports.Tools
プロパティはツール呼び出しをサポートしているかどうかを示します。
ツールの定義
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);
})
}
この構文は genkit.DefineFlow()
構文とよく似ていますが、説明を記述する必要があります。LLM が適切に使用することを決定するために不可欠であるため、説明の文言と説明内容に特に注意してください。
ツールの使用
定義済みのツールをプロンプトに含めてコンテンツを生成します。
生成
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"}),
)
プロンプト ファイル
---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
schema:
location: string
---
What is the weather in {{location}}?
次に、コードでプロンプトを次のように実行します。
// 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"}),
)
LLM が getWeather
ツールを使用してプロンプトに回答する必要がある場合、Genkit はツール呼び出しを自動的に処理します。
ツール呼び出しを明示的に処理する
より複雑なロジックを適用するなど、このツール呼び出しループを完全に制御する場合は、WithReturnToolRequests()
オプションを true
に設定します。これで、すべてのツール リクエストが確実に処理されるようにするのは、ユーザーの責任となります。
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)
}