/note/tech

Enable on-demand expertise with Agent Skills in Genkit Go

要約:

■ 1. 背景と課題

  • コンテキスト肥大化の問題:
    • LLMベースのエージェントの責務が拡大するにつれ、プロンプトコンテキストのサイズ管理が課題となる
    • 標準業務手順、参照ガイド、ドキュメントをすべて永続的なコンテキストウィンドウへ読み込む方式は持続可能でない
  • 常時ロードの弊害:
    • 貴重なトークンを消費する
    • モデルの集中を散漫にする
    • 誤った応答が生じる可能性を高める
  • Genkitでのサポート追加:
    • TypeScript、Go、Dart、PythonのGenkitにAgent Skillsのサポートを追加した
    • 本稿ではGenkit GoでのAgent Skillsの利用方法を示す
  • スキルの位置づけ:
    • 専門知識を発見可能な能力としてパッケージ化し、必要なときだけエージェントが読み込む標準
    • 必要になる瞬間まで背景に控える専門知識パックとして機能する

■ 2. Agent Skillsの仕組み

  • Progressive disclosure:
    • 必要になったときにのみ情報をモデルへ開示するという原則で動作する
  • SKILL.mdの構成:
    • frontmatterとbodyの2つのセクションでスキルを定義する
    • frontmatterにはスキルの説明と追加のメタデータを記述する
    • bodyにはモデルへの実際の指示を記述する
    • 参照ドキュメントやスクリプトなどの補助ファイルを追加できる
  • ディスク上の構成:
    • skill-name/配下に必須のSKILL.md(メタデータと指示)を置く
    • 任意でscripts/(実行可能コード)、references/(ドキュメント)、assets/(テンプレート、リソース)を置く
    • その他の任意のファイルやディレクトリも配置できる
  • frontmatterの記述例:
    • name、description、license、metadata(author、version)を記述する
    • descriptionにはスキルを有効化すべき状況と用途を明示する
  • 段階的な開示の流れ:
    • エージェントハーネスはSKILL.mdからスキル定義を読み込み、システムプロンプトにはfrontmatterのみを露出する
    • frontmatterはスキルを有効化すべきか判断するために必要な情報
    • 会話が進みスキルが必要な状況に至ると有効化処理が始まり、bodyの全文が読み込まれる
    • bodyの内容に応じて追加の参照ファイル読み込みや同梱スクリプトの実行が判断され、開示サイクルが完了する

■ 3. Progressive disclosureの利点

  • トークン効率:
    • Genkitは初期にはスキルのメタデータのみを読み込む
    • 詳細な指示はスキルが有効化された時点で注入する
  • 軽量な実装:
    • スキルはMarkdownファイルの束であり、コードと同じ方法で配布できる
    • 追加のインフラを構成せずに利点を得られる
  • リソースの同梱:
    • スキルはPython、Node.js、Bashのスクリプトを内包でき、エージェントがそれを実行できる
    • その仕事に必要な正しいツールを確実に備えられる

■ 4. Genkitのミドルウェア構造

  • ミドルウェアの役割:
    • モデルのライフサイクルの重要な局面を横取りしラップするフックのパイプラインとして機能する
  • Model Wrapper(WrapModel):
    • イテレーション内のモデルAPI呼び出しごとに1回発火する
    • リトライ、フォールバック、キャッシュなどモデル呼び出し自体に関するロジックを扱う
  • Tool Wrapper(WrapTool):
    • ツール実行ごとに1回発火する
    • 同一イテレーション内の並列ツール呼び出しでは並行して実行されうる
  • Generate Wrapper(WrapGenerate):
    • ツールループのイテレーションごとに1回発火し、N回のツールターンならN+1回呼び出される
    • リライト、システムプロンプト注入、メッセージ蓄積など会話全体を見る必要のあるロジックを扱う
  • スキルの実現方式:
    • Agent Skillsはこのフック機構の上に構築される
    • ミドルウェアが入力プロンプトを監視し、説明に合致するものを検出してスキルを動的に有効化する
  • 呼び出し方:
    • genkit.Generateにai.WithUseで&middleware.Skills{SkillPaths: []string{"./skills"}}を渡す

■ 5. 動作の3段階

  • Discovery:
    • スキルミドルウェアを伴うGenkit初期化時に、設定されたSkillPathsを走査しSKILL.mdを探す
    • 見つけたメタデータをシステムプロンプトへ注入する
  • Activation:
    • ユーザーのリクエストがスキルのdescriptionに合致すると、Genkitはuse_skillツールを呼び出す
    • 現在のタスクに必要な具体的な指示を取得する
  • Execution:
    • SKILL.mdの全文と、スクリプトや参照などの同梱リソースへのアクセスがアクティブなコンテキストへ読み込まれる
    • それにより厳密なワークフローに沿ってモデルを導く

■ 6. 環境の準備

  • SDKの導入:
    • go get github.com/firebase/genkit/go で最新のGenkit Go SDKを取得する
  • CLIの導入:
    • 任意の手順だが導入を推奨する
    • macOSとLinuxではcurl -sL cli.genkit.dev | bash を実行する
    • Windowsではcli.genkit.devからバイナリをダウンロードする

■ 7. 基本フローへの適用例

  • レシピ生成CLI:
    • 料理名または食材を引数に取り、Genkitフローでレシピを生成するコマンドラインツールを定義する
    • genkit.InitでgooglegenaiのGoogleAIプラグインとmiddleware.Middlewareを登録する
  • モデル設定:
    • googleai/gemini-flash-latestを指定し、ThinkingLevelをLowに設定する
  • システムプロンプト:
    • レシピに関する広範な知識を持つプロのシェフ助手として振る舞わせる
    • 可能な限り専門知識(スキル)を用いるよう指示する
    • Markdownを使わず、ターミナル出力に最適化したASCII整形で応答させる
  • スキルの登録:
    • genkit.GenerateText内でai.WithUseの関数オプションによりSkillsミドルウェアを設定する
    • SkillPathsで./skillsフォルダを指定し、そこにbanana-breadとcheese-breadの2つのスキルを配置する
  • 実行結果:
    • go run main.go cheese の実行でcheese-breadスキルが有効化される
    • ブラジル伝統のチーズパン(Pao de Queijo)のレシピがASCII整形で出力される
    • 出力されたレシピはGeminiによる生成物であり、試す場合は自己責任とする

■ 8. 実運用に近い応用例

  • より現実的な題材の必要性:
    • レシピフローは基本的なオンデマンド読み込みの実演にとどまる
    • 本番システムでは、非決定的なタスクに対し専門的な指示を統率して適用する必要がある
  • 美術品修復アプリケーション:
    • Genkit GoとGemini 3.1 Flash Image(Nano Banana 2)で構築したマルチモーダルな美術修復アプリを示す
    • 画像ファイルのパスを引数に受け取り、Base64のデータURIへ変換して入力する
  • 入出力スキーマ:
    • InputはBase64画像データURIを保持するURLフィールドを持つ
    • Outputはテキスト説明のTextと画像データのImageを持つ
  • フロー実装:
    • googleai/gemini-3.1-flash-imageを指定し、ResponseModalitiesにTEXTとIMAGEを設定する
    • システムプロンプトで画像の種類を分析させ、対応する修復スキルを適宜呼び出させる
    • 高精度な修復を実行し、修復後のIMAGEと、処理の概要および使用スキル名を含むテキストを返させる
    • ai.WithUseで./skillsディレクトリからスキルを動的に読み込む
  • 後処理:
    • 返却テキストが生の画像データでない場合のみ修復プランを表示する
    • データURIをbase64デコードし、元のファイル名に_restoredを付したPNGとして保存する
  • ログ設定:
    • slogの出力レベルをErrorに設定し、標準出力への冗長なトレースログと情報ログを抑制する

■ 9. 修復スキルの内容

  • 3種類のスキルの同梱:
    • drawings、paintings、photographyの3つのスキルを同梱する
    • 美術様式ごとに固有の修復指示が必要となるため分割する
  • paintingsスキルの方針:
    • 直接的かつ最小限の介入による絵画修復を行う
    • 化粧的な現代化よりも歴史的一貫性、原顔料の深み、表面の質感を優先する
    • 原作に存在しない要素や技法は一切導入しない
  • 保存の基本原則:
    • 新たな主題、人物、風景、細部、物語的要素の追加を厳格に禁止する
    • 原筆致の特性を保持し、支持体の質感を平板化しない
    • 亀裂網(craquelure)を作品の歴史の一部として尊重する
    • 剥落の危険が現に存在しない限り、亀裂を埋めたり消したりしない
  • 修復の手順:
    • 黄変した天然ニスを穏やかに調整し、過度な高コントラスト化を避けつつ本来の顔料の色度を回復する
    • 薄い下層のグレーズを保護しながら、表面の煤と汚れを分離して除去する
    • 絵具層の欠損部は現存部分を参照し、筆の方向、速度、盛り、透明度、光源を再現して補筆する

■ 10. 実行結果と留意点

  • 対象画像:
    • Elías García Martínezの「Ecce Homo」の、悪名高い修復の試みが行われる前の画像を入力とする
    • ecce_homo.pngとして保存し、環境にGEMINI_API_KEYを設定したうえで実行する
  • モデルの判断:
    • 画像を悲しみの人(Ecce Homo)を描いた古い宗教的な献身画像と識別する
    • 使用スキルとしてpaintingsを出力する
  • 修復内容の説明:
    • 表面清掃を模して汚れと黄変したニスの層を除去し、本来の鮮やかな深紅と豊かな暗い肌色を回復する
    • 顔と上衣を中心に非芸術的な亀裂とカンヴァスの織り目を抑え、経年感を残しつつ肖像を明瞭にする
    • 特徴的な質感のある紫の衣は保持し、最も目立つ表面の汚点のみを除去する
    • 淡く不明瞭だった背景の巻物構造を精緻化し、古びた羊皮紙の質感と局所的な経年変化を加える
  • 留意点:
    • LLMは非決定的であるため、良好な結果を得るには数回の試行が必要な場合がある
    • 提示した修復スキルは初期の試みであり、専門家による調整の余地がある
    • 写真や素描など他種の画像を与え、対応するスキルの有効化を試せる

■ 11. スキルのベストプラクティス

  • 詳細な説明の記述:
    • YAML frontmatterのdescriptionがミドルウェアの主要なトリガーとして機能する
    • モデルがuse_skillを呼ぶべき時点を判断できるよう、明確で命令的な言葉を用いる
  • 焦点の限定:
    • 1つのスキルは1つのことを適切に行うべきものとする
    • 何でもこなす一枚岩のスキルの作成を避ける
  • 決定的なツールの同梱:
    • 軽量なスクリプトをスキル内に同梱する
    • エージェントに真実の情報源を与え、内部の訓練上の限界を回避させる
  • リソースのモジュール化:
    • references/フォルダを用いてSKILL.mdを簡潔に保つ
    • エージェントは必要に応じてこれらのファイルを読み込める

■ 12. まとめと次の一歩

  • Agent Skillsの意義:
    • Genkit Goにおいて開発者の専門知識を管理するための、モジュラーで拡張可能な枠組みを提供する
    • スキルミドルウェアの統合により、複雑な複数手順のタスクをより高い信頼性で実行できる
  • 参照先:
    • Getting Started with Genkitのページを読む
    • ミドルウェアのドキュメントで詳細を確認する
    • オープン標準を理解するためAgent Skillsの仕様を参照する