生成 AI 機能開発を高速化する Genkit を用いて Function Calling を実装してみた
この記事について
Google I/O 2024 にて Genkit が発表されました。Genkit を使って Function Calling を実装してみたので紹介しようと思います。
Genkit とは
Genkit は生成 AI 機能を搭載したアプリケーションの開発を支援するオープンソースのフレームワークです。LangChain を使ったことがある方は、LangChain のように単一のインターフェースで複数の生成 AI モデルに対応できるフレームワークだとイメージしてもらえると分かりやすいかと思います。
Genkit は Firebase チームが開発しており、フレームワークのインターフェースは Firebase ユーザーにとってはとっつきやすいものになっています。
プログラミング言語は JavaScript, TypeScript, Go がサポートされています。
Genkit を使うと何が嬉しい?
Genkit を使って個人的に一番嬉しいのは Developer tools をローカルで起動できることです。以下のようにコマンドを叩くと、
npx genkit start -- npx tsx --watch src/index.ts
localhost で Developer tools が立ち上がります。
生成 AI 機能を開発する上で現状人間が一番注力して開発するのは AI オーケストレーション部分の開発ではないかと思います。 Developer tools を使うと、この AI オーケストレーション部分の開発が非常に効率的に進められます。
また、Firebase チームが開発していることもあって、 Firebase との統合が簡単にできます。 Firebase Authentication を用いた認証や、先日発表された Firestore のベクトル検索機能を用いた RAG の構築も簡単に行うことができます。
Function Calling を実装してみた
今回は Function Calling を用いて Web スクレイピングした結果を、日本語要約する機能を実装しました。以下に全文を貼りましたが、 50 行程度で簡単に実装することができます。特徴的な部分について以下に 1 つずつ説明していきます。
実装ファイルのソースコード全文
import { genkit, z } from 'genkit'
import { googleAI, gemini15Flash } from '@genkit-ai/googleai'
import * as cheerio from 'cheerio'
import { logger } from 'genkit/logging'
logger.setLogLevel('debug')
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
})
const webLoader = ai.defineTool(
{
name: "webLoader",
description:
"When a URL is received, it accesses the URL and retrieves the content inside.",
inputSchema: z.object({ url: z.string() }),
outputSchema: z.string(),
},
async ({ url }) => {
const res = await fetch(url)
const html = await res.text()
const $ = cheerio.load(html)
$("script, style, noscript").remove()
if ($("article")) {
return $("article").text()
}
return $("body").text()
},
)
const mainFlow = ai.defineFlow({
name: 'mainFlow',
inputSchema: z.string(),
}, async (input) => {
const { text } = await ai.generate({
prompt: `First fetch the content of the URL: ${input}. Next, summarize the content in under 200 words.`,
tools: [webLoader],
})
return text
})
ai.startFlowServer({ flows: [mainFlow] })
configure Genkit
Genkit では genkit
関数で初期設定をします。 Firebase でいう initializeApp
のようなものです。
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
})
defineTool
Function Calling で呼び出す関数を defineTool
で定義します。こちらの入出力値も zod で型指定できます。今回は cheerio
を用いて URL にアクセスして中身のコンテンツを取得します。
const webLoader = ai.defineTool(
{
name: "webLoader",
description:
"When a URL is received, it accesses the URL and retrieves the content inside.",
inputSchema: z.object({ url: z.string() }),
outputSchema: z.string(),
},
async ({ url }) => {
const res = await fetch(url);
const html = await res.text();
const $ = cheerio.load(html);
$("script, style, noscript").remove();
if ($("article")) {
return $("article").text();
}
return $("body").text();
},
);
defineTool
で実装した関数は以下のスクリーンショットのように Tools
メニューからアクセスできるようになり、ツール単体の動作検証ができるようになります。
defineFlow
Genkit の開発では Flow
というタイプの関数を実装することになります。これをローカル環境で形にして本番環境(Firebase 等)にデプロイする流れです。Genkit では zod を用いて入力値(inputSchema) と出力値 (outputSchema)の型指定ができます。
generate
関数に先ほど追加した webLoader
tool を渡します。
const mainFlow = ai.defineFlow({
name: 'mainFlow',
inputSchema: z.string(),
}, async (input) => {
const { text } = await ai.generate({
prompt: `First fetch the content of the URL: ${input}. Next, summarize the content in under 200 words.`,
tools: [webLoader],
})
return text
})
defineFlow
で実装した関数は以下のスクリーンショットのように Flows
メニューからアクセスできるようになり、動作検証することができます。
実際の挙動
実際の挙動を以下に貼っておきます。
Flow の実行プロセスは inspect タブから詳しく追うことができます。これにより、Function Calling が実際に実行されたのかなど、詳しくデバッグすることができます。
まとめ
Genkit を使って簡単に Function Calling が実現できました。これが 50 行ほどで実装でき、 Cloud Functions for Firebase などに簡単にデプロイできるのは非常に魅力的だと思います。
ソースコードは以下からアクセスできますので参考にしてください。
Discussion