はじめに
2026年4月上旬からElastic Cloud Serverlessでは使えるようになったAgent Skills機能の動きを検証してみました。参考になれば幸いです。
(現時点はServerless版のみに入ってます。セルフマネージドやElastic Cloud Hostedの場合は今後出てくるリリースに入ってくると思われます。)
今回の検証内容としてはAgent Skillsを利用することで、AIエージェントが回答するES|QLクエリー文や報告方法を制御できるか、です。
テストデータとしてElastic製品付属のKibana Sample Flight Dataを使っています。
テストパターン
このようにAIエージェントへの指示の方式が異なるものをいくつか作成しました。エージェントのプロンプト(Custom Instructions欄)への指示だったり、Skillsを使ったり。
テスト1: デフォルト状態のエージェントが回答したクエリー
まずは何も指示していない場合にエージェントが生成したESQLクエリーを確認します。

テスト2: プロンプトにクエリー例を指示したエージェントが回答したクエリー
次に、エージェントのプロンプトに利用するクエリーを指示しました。テスト1とは違い、FlightDelayTypeも表示するように指示していますので、その通りになることが期待値です。

- 実は何度かテストしているうちに私のミスでテスト1にあるクエリーとは異なる関数
DATE_EXTRACTを使うクエリー例をここで書いてしまったのですが、一旦そこに関しては無視してください。最後の補足検証の部分で補足してます。
期待通り、プロンプトで指示したFlightDelayTypeも表示するクエリー文になりました。

テスト3: Skillsにクエリー例を指示したエージェントが回答したクエリー
ここからSkillsを活用します。まずは先程のエージェントプロンプト内での指示は外しました。

1つ目のSkillは、さきほどと同じようにFlightDelayTypeも表示せよという指示です。

2つ目のSkillは、シドニー便を検索するときは、天気としてOriginWeatherのフィールドも表示せよという指示です。

まずは東京発のフライトの検索をします。Reasoningでfilestore.readとあり、Skillが読み込まれているのがわかります。また、期待通りFlightDelayTypeも表示するクエリーになっています。

次にシドニーの便の検索です。こちらも、期待通りSkillを読み込み、OriginWeatherを取得し、またサマリーでは天気についてコメントしてくれてます。

テスト4: 該当するSkillsが複数あったら?
シドニー便に関して、もう一つのSkillを作ったらそれも使ってくれるのでしょうか?DestWeatherもクエリーするSkillを追加しました。

シドニー便を検索すると、DestWeatherも表示されたので複数のSkillも読み込まれますね!

テスト5: 一度のチャットで複数の条件がある場合は?
ロンドンの場合は、天気についてクエリーに含めないようなSkillを追加しました。

チャットには、シドニー便とロンドン便を一緒に質問しました。結果、Skill定義の期待通りにシドニー便の検索ではOrigintWeatherを表示し、ロンドン便の検索ではOriginWeatherは表示されませんでした。
Skillsによる場合分け成功です。

テスト6: Skillsで異なる役割を追加
Skillsを使って異なる役割を同じエージェントに複数持たせるテストです。
今回はシンプルなものですが、Skillsがなかったら複数のエージェントを作りたくなるような状況でも、Skillsを使って一つのエージェントで色々な役割を持たせられるか、を想定したテストです。
フライト情報の更新というダミーのElastic Workflowsを作りました。受け取ったメッセージを表示するだけの処理です。

Workflowをエージェントが利用するためのTools化がこちら。

そしてフライトデータ更新のSkillを作成します。Skillには個別要件(管制塔システムへの連携)を埋め込んでみました。また、Associated tools として先程のWorkflowを実行するToolを関連付けます。

今まではToolをエージェントが使うには、そのエージェント自身のTools設定でそれを有効にする必要がありましたが、今回それは行わず、Skillをエージェントに対して設定しています。

フライトデータ更新に関する指示をすると、期待通りにWorkflowを呼び出すTool update_fligh_infoが実行され、メッセージにもSkillsに定義した通りに管制塔システムへの連携が含まれていました。

テスト7: パターン別にもっと多くのSkillsを登録してみた。報告文章を変えてみる。
検索対象の日本の都市別で報告パターンの指示を分けてみました。

各都市には、その都市の観光名所を付け加えて報告するようにするSkillです。(ここでは、観光名所の情報はLLMの知識を使っており、Elasticsearchにデータを入れているわけではありません)

福岡のフライトを検索したら、期待通り福岡の観光名所も教えてくれました。

該当の都市のSkillがない場合として、その都市の最も高いビルを報告するようなSkillも追加しました。

期待通り、個別にSkill登録していない函館のフライト検索では、その都市での最も高いビルを教えてくれました。

テスト8: どの項目の情報がSkillsの選択に使われているのか?
まずはNameを見ているかのテスト。沖縄を検索するときに、Nameに含まれるokinawaを見るかです。

結果を見ると、NameはSkillの選択に使われているようです。

次にDescriptionを見ているかのテストです。長野を検索するときに、Descriptionに書いてある長野を見ているかをテストします。
結果を見ると、Descriptionは参考にしているようです。

次にInstructionsを見ているかのテストです。広島を検索するときに、Insutrcutionsに書いてある広島を見ているかをテストします。

この場合は該当のSkillsが使われていないので、Instructionsの情報はSkillsの選択には使われないようです。

Instructionsにたくさんの情報を書いても、Skillsとして選定される前まではエージェントとして読み込まれず、トークンもその分は消費されないと考えられます。
補足の検証 (Agent Skillsとは直接は関係ない検証)
プロンプトの指示にて、クエリーの例を与えると同じ目的を達成する前提で異なる関数を使ったクエリーを作るケースが見られましたので、必ず指示したクエリー関数を使うようにプロンプト指示してみました。

興味深いことに、platform.core.search ツールには期待通りのクエリーが渡りましたが、そのツールが異なる関数に変換してました。得られる結果はどちらも同じです。(DATE_EXTRACTではなくDATE_TRUNCを利用する方式)

platform.core.searchではなく、platform.core.execute_esqlを使わせると設定にした場合、変換はされませんでした。素直にプロンプト/Skills指示通りのクエリーとなりました。

おわり
Skillsを使うと、従来はエージェントのプロンプトに全部の指示を詰め込まないといけなかったのが、Skillsですっきりと場合分けできるようになりました。
従来のやり方でプロンプトが巨大になりすぎる場合は、複数のエージェントに分割することも手として考えてましたが、Skillsを使うと一つのエージェントで複数の役割を持たせられそうです。
このようにSkillsによって大幅にエージェント構築の複雑さが軽減されると思います。
従来のプログラミング言語(Javaなど)に例えると、一つのJavaプロセス内で一つのクラスに全部詰め込むのではなく、クラスを分けられる様になった感じでしょうか。そう思うとSkillsの利用はAIエージェント構築において、もはや必須技術だなと思います。

