Google ADKのSkillsを試してみた
こんにちは。ビデオリサーチのキクチです。
タイトルの通り、今回はGoogle ADK(Agent Development Kit)に新しく追加されたSkills機能をPoCで試してみた話を書きます。
はじめに
Google ADK(Agent Development Kit)に、Claude CodeのSkillsのような仕組みのサポートについて、以前からGitHub Issueで要望が上がっていました。
(自分も微力ながら賛同コメントをしていました(笑))

そしてついに、公式ドキュメントにSkillsのページが登場しました。
※ Skills機能は記事投稿時点の最新版(v1.27.2)ではExperimentalです。
待ち望んでいた機能だったので、早速試してみることにしました。
これまでの課題
ADKでエージェントに複雑なドメイン知識を持たせたい場合、これまでの選択肢は主に2つでした。
1. プロンプトに全部入れる
- システムプロンプトにルールや手順をすべて定義する。当たり前ですが、promptが肥大すればLLMが重要な制約を落としやすくなります。
2. Toolsに寄せる
- ドメイン知識をtoolのdescriptionなどに埋め込む。ただしtoolはあくまで「何ができるか」を定義するものなので「ドメイン知識」の箱として使うのは不自然。
また、どちらのアプローチも、ドメイン知識の管理・選択・注入を自前で実装する必要がありました。
どの知識をいつLLMに渡すかの判断ロジックを自作することになります。
今回の取り組み
PoCとして開発していた、TV視聴率分析用のエージェントでSkills(SkillToolset)を導入し効果を検証しました。
放送業界には独特のドメインルールがあります。
例えば、深夜番組の放送時間は当日として扱う方が都合が良いため、所謂「30時間制」で管理されており、翌日の午前2時30分は「26:30」と表現します。
こうしたドメイン知識にSkillsはうってつけです。早速スキルを定義し、SkillToolset経由でエージェントに持たせる構成を試しました。
Skillsの使い方
スキルの定義
各スキルはディレクトリにSKILL.mdを置くだけです。名前と説明を簡潔に記載し、ドメイン知識を記述します。
skills/
└── broadcast-time-30hour-rule/
└── SKILL.md
--- name: broadcast-time-30hour-rule description: 放送時間の30時間表記ルール。日跨ぎ番組や深夜帯の時刻解釈が必要なクエリで使用。 --- ## 必須手順 - 30時間表記の `hhmm` を維持して扱う(`2400`–`2859` を保持)。 - 時刻比較は4桁ゼロ埋めで行う。 ## 禁止事項 - 下流が要求しない限り `00xx` へ変換しない。 ## ルール - 時刻は `hhmm` の文字列で、以下の範囲を取る: - `0500`–`2359`(当日) - `2400`–`2859`(翌日の 00:00–04:59 を 24xx–28xx として表現)
エージェントへの組み込み
最小構成ではこれだけです。SkillToolsetをエージェントのtoolsに渡します。
from google.adk import Agent from google.adk.skills import load_skill_from_dir from google.adk.tools.skill_toolset import SkillToolset skill = load_skill_from_dir("skills/broadcast-time-30hour-rule") agent = Agent( name="my_agent", model="gemini-3.1-flash-lite-preview", instruction="あなたはリサーチアシスタントです。", tools=[SkillToolset(skills=[skill])], )
これでLLMは以下のツールを使えるようになります。
| ツール | 役割 |
|---|---|
load_skill |
スキルの全文(SKILL.md の本文)を読み込む |
load_skill_resource |
スキルに付随する参照ファイルを読む |
スキル一覧(name + description)は自動的に LLM に注入されます。
LLM 自身が「このユーザーの質問にはこのドメイン知識が必要だ」と判断して、スキルを選択・読み込みします。
ADKの実装を見てみると
これは蛇足ですが、ADKのSkills実装を読んでみるとアプローチは段階的ローディングです。
スキル一覧の自動注入
- 毎ターンスキルの name と description が LLM に渡される
スキルの読み込み
- LLM が
load_skillツールで必要なスキルの全文を取得する
リソースの参照
- 必要に応じて
load_skill_resourceで補助ファイルを読む
のようなフローで行われているようです。 IssueでもClaude CodeのSkillsが参照されていますが、この段階的ローディングはClaude CodeのSkillsを踏襲しているようです。
試してみてわかったこと
実際にSkillToolsetで運用してみると、いくつかの発見がありました。
まず動作の様子を紹介します。「深夜1時〜5時の時間帯で視聴率ランキングを出して」というクエリを投げると、LLMが自律的に load_skill を呼び出し、30時間表記ルールのスキルを読み込んでいることがトレースから確認できます。



※ 業務データのため局名・番組名はマスクしています。
うまくいった点
- スキルの選択は概ね正確
- LLMはdescriptionを見て適切なスキルを
load_skillできている
- LLMはdescriptionを見て適切なスキルを
- スキルの追加・修正がSKILL.mdの編集だけで済む
課題として残った点
スキルの内容は部分的にしか反映されない
- load_skill した本文の全てを忠実に守るわけではなく、重要な制約を取りこぼすことがある。特に SKILL.md の後半に書かれた制約ほど落ちやすい。
対策として、最も重要な制約は「必須手順」セクションの先頭に置くようにしたところ、反映率が改善した。 LLM はスキル本文を全文均等に扱うわけではなく、冒頭の記述ほど強く効く傾向がある。
- load_skill した本文の全てを忠実に守るわけではなく、重要な制約を取りこぼすことがある。特に SKILL.md の後半に書かれた制約ほど落ちやすい。
会話が進むとスキル本文が落ちる
- ADK 側で毎ターン再注入されるのはスキル一覧(name + description)のみで、load_skill で取得した本文は会話履歴に依存する。
今回の実装では会話ウィンドウを制限しているため、数ターン後にはスキル本文が参照外に出る。LLM が再度 load_skill を呼ぶかどうかは保証されないため、長いセッションでは注意が必要。
- ADK 側で毎ターン再注入されるのはスキル一覧(name + description)のみで、load_skill で取得した本文は会話履歴に依存する。
LLM が勝手にスコープを広げることがある
- スキルに書いていない集計や要約を LLM が自分で追加してしまうケースがあった。
例えば、スキルが「分単位の時系列で表示する」と定義しているのに、「行数が多くなるため番組全体のサマリーも出します」と LLM が勝手に判断するケース。
これにはシステムプロンプトに「ユーザー要求、active skill、またはシステム指示で明示されていない合計/平均/要約/派生指標を勝手に追加しない」という汎用ルールを足すことで一定の効果があった。
- スキルに書いていない集計や要約を LLM が自分で追加してしまうケースがあった。
まとめ
ADKのSkills機能は、エージェントへのドメイン知識の組み込みを簡素化してくれます。これをフレームワークが標準機能として提供してくれる価値は大きいと考えます。
一方で、LLMがスキルの内容をどこまで忠実に守るかは、まだスキルの書き方やプロンプト設計に依存する部分が残っています。「スキルを書けば解決」ではなく、スキルの内容をどうLLMに伝え、どう守らせるかというエンジニアリングは引き続き必要そうです。 現時点では、ドメイン知識の管理をSkillToolsetに寄せつつ、出力品質の制御は処理フェーズの分離やモデル選択で補強するという組み合わせが、現実的なアプローチだと感じました。