🎄

[ADK] 今更 LlmAgentの各種プロパティを詳しく説明する ~ ADK LlmAgent Property Maniax ~

に公開

こんにちは、サントリーこと大橋です。

本記事は ADK Advent Calendar 2025 の初日 2025/12/01 の記事です。
ADK Advent Calendar 2025 はまだまだ参加者を募集中ですので、興味のある方はぜひ参加してください!

https://qiita.com/advent-calendar/2025/adk

今回は初日なので初心に帰って、GoogleのAgent Development Kit(ADK) の LlmAgent の普段あまり使われない各種プロパティについて、実際に設定しながら挙動を確認してみたいと思います。
初日なのであまりマニアックな内容にならないように気をつけますね。

対象

  • ADK を触ったことがある Python ユーザー
  • LlmAgent の動きがよくわからない ADK ユーザー

なお本記事中では ADK の Agent をAgent、それ以外の AI エージェントをエージェントと表記します。

LlmAgent のあまり使わない各種プロパティについて

LlmAgent では namemodeldescriptioninstruction や各種 Callback などはよく使いますが、それ以外にもたくさんのプロパティが存在します。
設定によってはトークン消費量を軽減できたり、LLM の挙動が大きく変わるものもあるため、いくつかピックアップして説明していきます。

LlmAgent の各種プロパティ

1. name

Agent 名です。名前が同じでもエラーにならないケースがあり、その場合、正しい Agent が選ばれないときもあるので、名前付けには注意が必要です。
また、LLM に対する System Instruction にもこの名称が渡されているので、少なからず名称が出力結果に影響を与えていると考えられます。

Your internal name is "AgentName".

なお AgentTool や AgentTransfer のようなマルチエージェントシステムでも、この名称がツール名やサブエージェントとしても利用されます。つまり親エージェントの System Instruction 内でも記述する必要があるため、わかりやすい名前をつけることを心がけると良いでしょう。

2. model

LLM のモデル名です。文字列か、BaseLlm を継承したオブジェクトを渡します。

文字列の場合は google.adk.models.registry.LLMRegistry に登録されたパターン(正規表現)にマッチしている必要があります。
例えば Gemini 系のモデルであれば、google.adk.models.google_llm.Geminisupported_models メソッドに設定されている以下の正規表現にマッチしていれば、Gemini のモデルとして認識されます。

  • gemini-.*
  • model-optimizer-.*
  • projects\/.+\/locations\/.+\/endpoints\/.+
  • projects\/.+\/locations\/.+\/publishers\/google\/models\/gemini.+

自分で BaseLlm を継承したモデルクラスを作成し、LLMRegistry に登録すれば、自前のモデルを文字列だけで利用することもできるようになります(普通に BaseLlmmodel に渡せば動くので、あえてやらないとは思いますが)

登録済みのモデルとしては Gemini, Gemma, ApigeeLlm などが登録されています。またライブラリをインストールしていれば ClaudeLiteLlm も使えます。
LiteLlm は世の中にあるありとあらゆる LLM をラップして使えるようにするライブラリなので、大抵のモデルは LiteLlm 経由で利用することができます。
接頭辞などは各モデルクラスの supported_models メソッドに設定されている正規表現を確認して利用してください。

https://github.com/google/adk-python/blob/main/src/google/adk/models/lite_llm.py#L1399

また、BaseLlm を継承したクラスを渡せばカスタム LLM モデルを作成できます。つまりテストなどで毎回同じ返答をするモデルなども簡単に作成できます。
例えば ADK の testing_utils.py にある MockModel は LLM Response を受け取って固定のレスポンスを返すだけのモデルで、テストなどで便利です。

https://github.com/google/adk-python/blob/main/tests/unittests/testing_utils.py#L14

3. description

Agent の説明です。
instruction があるので、結構簡単に書いてしまいがちですが、LLM に System Instruction として渡されているので結果に影響を与えています。
また親 Agent が AgentTool やサブエージェントとして子 Agent を利用する場合もこの description を参照しているので実は非常に重要です。

System Instruction に追加されるテキスト
The description about you is "A helpful assistant for user questions."

A2A などでも Agent Card などにも利用されるので、しっかりと書いたほうが良いでしょう。

4. instruction, global_instruction, static_instruction

LLM の System Instruction を設定するプロパティです。

instruction が最も基本となる LLM に対するシステム指示で、基本的に「ユーザーが更新することができない指示を記載する場所」です。
GitHub とかでたまに callback の引数である llm_requestappend_instructions があるので、ユーザのクエリを含むデータを整形して、append_instructions 経由で LLM に渡すというコードを書いているものを見たことがありますが、これは NG です。
System Instruction をユーザーが上書きできてしまうことになるので、プロンプトインジェクションが容易にできてしまうことになります。

instruction では基本機能として動的に instruction を生成するためのテンプレート機能があります。
このテンプレート機能は instruction 中に {var} の形式を書くと、statevar の値を埋め込むことができます。
例えば The date is {date} と書くと、statedate の値を埋め込むことができます。

例:この場合{user:user_id}がstateに保存された値に置換される
from google.adk.agents.llm_agent import Agent

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction="""
    Answer user questions to the best of your knowledge.
    UserID: {user:user_id}
    """
)

初期の頃にハマったのが、この変数名 var にはいくつか設定してしまうと、うまく置換できない文字列が存在する点です。
具体的には source code_is_valid_state_name を満たす必要があります。
例えば state のキーを管理するために自前でプレフィックスなどをつけて org:org_id みたいなキーを設定すると、{org:org_id} は置換できません。
これは {prefix:key} の形式では prefix の部分は ADK であらかじめ定義されている app:, temp:, user: 以外は設定できないためです。
また Python の isidentifier メソッドを満たす必要があり、例えば先頭が数字だったり、ハイフンが含まれると置換ができません。
あまりしっかりドキュメントに記載がないのでちょっとハマると辛いです。

例:この場合{org:org_id}は仮にstateにあっても置換されない
from google.adk.agents.llm_agent import Agent

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction="""
    Answer user questions to the best of your knowledge.
    Organization ID: {org:org_id}
    """
)

また instruction では InstructionProvider を利用することで動的に instruction を生成することもできます。
ADK 内部では InstructionProvider を継承したクラスは現在は McpInstructionProvider のみです。
これを利用することで例えばファイルや GCS などから instruction を読み込むことも可能となります。
サンプルコードは 以下を参照してください。

https://github.com/soundTricker/personalized-podcast-platform/blob/main/apps/radio-station/radio_station/utils/instruction_provider.py#L29

global_instruction は元々全 Agent に対して設定する Instruction で、例えば実行日や実行ユーザの ID 等を渡すために利用できる Instruction でした。
しかしこの global_instruction は現在非推奨になっていて将来削除される予定です。代わりに GlobalInstructionPlugin を利用することが推奨されています。

static_instruction は ADK 1.15.0 で追加された Context Caching を利用するための設定です。

https://zenn.dev/soundtricker/articles/6891fed2de91b0

この設定を利用すると、Context Caching が利用できるので、長文の固定文やファイル、画像などはこちらに設定しつつ動的な部分は instruction に設定するなどの使い分けができます。

5. tools

Tool を設定するための設定です。
大きく分けて Callable (関数)、BaseToolBaseToolset の 3 つの値を設定可能です。

  • Callable はそのまま Python 関数です。少し前から非同期(Async)関数にも対応したので、基本的には Async にしておいてもいいと思います。
  • BaseTool はツールの基底クラスです。LLM へのツール情報の受け渡しと、LLM からツールの呼び出し命令を受けたときにツールの実行を担います。上記の Callable を渡した場合も ADK 内部では BaseTool を継承した FunctionTool クラスへ Python 関数を渡しています。
  • BaseToolsetBaseTool をまとめたツールセットです。ADK で複数のツールをまとめて提供する場合などに利用されています。

現状 ADK では以下のビルトインツールセットが存在します。

  • ToolboxToolset (google.adk.tools.toolbox_toolset)
  • SpannerToolset (google.adk.tools.spanner.spanner_toolset)
  • BigQueryToolset (google.adk.tools.bigquery.bigquery_toolset)
  • BigtableToolset (google.adk.tools.bigtable.bigtable_toolset)
  • McpToolset (google.adk.tools.mcp_tool.mcp_toolset)
  • APIHubToolset (google.adk.tools.apihub_tool.apihub_toolset)
  • ComputerUseToolset (google.adk.tools.computer_use.computer_use_toolset)
  • GoogleApiToolset (google.adk.tools.google_api_tool.google_api_toolset)
    • BigQueryToolset, CalendarToolset, GmailToolset, YoutubeToolset, SlidesToolset, SheetsToolset, DocsToolset など
  • ApplicationIntegrationToolset (google.adk.tools.application_integration_tool.application_integration_toolset)
  • OpenAPIToolset (google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset)

特段マニアックな裏技は思いつきません、ごめんなさい。

6. generate_content_config

Temperature 等の LLM API に渡すパラメータを設定するためのパラメータです。
これに設定したからと言ってすべてのパラメータが LLM に渡されるわけではないのでたまにハマります。
例えば thinking_config などは generate_content_config に設定できますが、thinking_config は Planner へ設定するべきパラメータのため設定すると ValueError が発生します。
これは ADK の仕様なのでしょうが、ADK の仕様を理解していないと辛いです。

個人的によく使うのは frequency_penaltysafety_settings あたりです。

  • frequency_penalty: 頻繁に同じ文章を繰り返さないようにするためのパラメータ。タグ付けなどをすると、同じ文章を繰り返してレスポンスサイズをオーバーする場合があるので設定する時があります。
  • safety_settings: LLM の安全性を保つためのパラメータ。例えば、不適切な文章を生成するのを防ぐために設定します。詳しくは 以下の Safety settings のドキュメントを参照してください。

https://ai.google.dev/gemini-api/docs/safety-settings

generate_content_config のサンプルコード
root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction='Answer user questions to the best of your knowledge',
    generate_content_config=types.GenerateContentConfig(
        safety_settings=[
            types.SafetySetting(
                category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
                threshold=types.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,
            ),
        ]
    )
)

上記の場合ヘイトスピーチを含むようなコンテンツは生成されません。

7. disallow_transfer_to_parent

LlmAgent のプロパティの中で最も名前と動きが合っていない気がするプロパティです。Issue もあります。

https://github.com/google/adk-docs/issues/823

マルチエージェントシステムの LlmAgentsub_agents を指定するパターン(Agent Transfer パターン)で、サブエージェントに処理が移譲されたあと、サブエージェントが後続クエリを処理できるかできないかを指定するフラグです。

実際に動きを見てもらったほうが早いので、以下の「こんにちは/さようならエージェントシステム」を題材に説明します。

「こんにちは/さようならエージェントシステム」は、ユーザのクエリを最初に処理しサブエージェントへ振り分ける root_agent(ルートエージェント)、ユーザの挨拶を処理する disallow_transfer_to_parent_false(こんにちはエージェント)、ユーザのさようならの挨拶を処理する disallow_transfer_to_parent_true(さようならエージェント)の 3 種類のエージェントで構成します。

from google.adk.agents.llm_agent import Agent

disallow_transfer_to_parent_false = Agent(
    model='gemini-2.5-flash',
    name='disallow_transfer_to_parent_false',
    description='A helpful assistant for user greeting.',
    instruction='ユーザーの挨拶に回答してください。常に語尾にデスをつけてユーザーに返答を返してください。',
    disallow_transfer_to_parent=False
)

disallow_transfer_to_parent_true = Agent(
    model='gemini-2.5-flash',
    name='disallow_transfer_to_parent_true',
    description='A helpful assistant for user good bye.',
    instruction='ユーザーのさよならに回答してください。常に語尾にデースをつけてユーザーに返答を返してください。',
    disallow_transfer_to_parent=True
)

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction='ユーザーからの挨拶は`disallow_transfer_to_parent_false`を呼び出してください。ユーザーからのさよならの挨拶は、`disallow_transfer_to_parent_true`を呼び出してください。 それ以外はあなたが返してください。',
    sub_agents=[disallow_transfer_to_parent_false, disallow_transfer_to_parent_true]
)

名前の通り「こんにちはエージェント」は disallow_transfer_to_parent=False、「さようならエージェント」は disallow_transfer_to_parent=True を設定します。

  1. ユーザーが「こんにちは」と言うと、「ルートエージェント」は「こんにちはエージェント」に処理を移譲(Agent Transfer)します。その後もユーザーが「こんにちは」と言い続けると、「こんにちはエージェント」は disallow_transfer_to_parent=False を指定しているので、そのまま処理を行い続けます。
  2. ユーザーが「こんにちは」以外のクエリを行うと、「こんにちはエージェント」はルートエージェントへ処理を移譲します。
  3. ユーザーが「さようなら」と言うと、「ルートエージェント」は「さようならエージェント」に処理を移譲します。その後もユーザーが「さようなら」と言い続けても、「こんにちはエージェント」とは異なり、「さようならエージェント」は disallow_transfer_to_parent=True を指定しているので、処理をし続けず、ルートエージェントに処理を戻します。


「こんにちは」->「なにができる」と話したあとは、transfer_to_agentが走るが、「こんばんが」->「なにができる」のあとは移譲処理が行われていない

ちょっと分かりづらいですが、disallow_transfer_to_parent の有無でサブエージェントに設定される System Instruction が変わります。

disallow_transfer_to_parent=False の場合は、以下のようにサブエージェントから親エージェントへの移譲を許可する System Instruction が設定されます。

**NOTE**: the only available agents for `transfer_to_agent` function are `disallow_transfer_to_parent_true`, `root_agent`. If neither you nor the other agents are best for the question, transfer to your parent agent root_agent.

disallow_transfer_to_parent=True の場合は、以下のようにサブエージェントから親エージェントへの移譲に関する System Instruction は設定されません。

**NOTE**: the only available agents for `transfer_to_agent` function are `disallow_transfer_to_parent_false`.

サブエージェントでの処理後に常に親エージェントへ処理を戻したい場合は、disallow_transfer_to_parent=True を設定すると覚えておくと良いと思います。

ちなみに、v1.19.0 までは output_schema を指定している場合は、LLM の仕組みで output_schema を設定していた為、様々な制約により自動的に disallow_transfer_to_parent と、このあと説明する disallow_transfer_to_peers は警告とともに True が設定されていました。
しかし、途中で追加された set_model_response ツールシステムにより output_schema のような処理を同一リクエストではなく、別処理でツールとして処理するようになったため、この制約が取り払われ、この設定はなくなりました。

https://github.com/google/adk-python/issues/3318

8. disallow_transfer_to_peers

前述の disallow_transfer_to_parent と似たような仕組みで、親エージェントではなく兄弟エージェントへの処理の移譲を制限します。
上述の「こんにちは/さようならエージェントシステム」で言えば、「こんにちはエージェント」と「さよならエージェント」間の遷移を制限します。


「さようなら」のあとはtransfer_to_agentが行われているが、その後の「こんにちは」ではtransfer_to_agentが行われず、親エージェントに処理が戻っている

disallow_transfer_to_parent と同様に disallow_transfer_to_peers の設定によって System Instruction が変わります。

disallow_transfer_to_peers=False の場合は、以下のようにサブエージェントからサブエージェントへの移譲を許可する System Instruction が設定されます。

**NOTE**: the only available agents for `transfer_to_agent` function are `disallow_transfer_to_peers_true`, `root_agent`. If neither you nor the other agents are best for the question, transfer to your parent agent root_agent.

disallow_transfer_to_peers=True の場合は、以下のようにサブエージェントからサブエージェントへの移譲に関する System Instruction は設定されません。

**NOTE**: the only available agents for `transfer_to_agent` function are `root_agent`. If neither you nor the other agents are best for the question, transfer to your parent agent root_agent

9. include_contents

Agent に対して、過去の会話履歴や State などを含む(default)か含まない(=instruction とユーザのクエリのみ None)かを設定します。
例えばサブエージェントに処理を移譲する際に、過去の会話履歴が不要な処理の場合にコンテキストウィンドウを抑えることができます。

実際の挙動を見てみましょう。

以下のような include_contents='default'を指定した Agent を作成して adk webで動かしてみます。

from google.adk.agents.llm_agent import Agent

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction='Answer user questions to the best of your knowledge',
    include_contents='default'
)

「私の好きな色は赤です」と伝えてから、改めて好きな色を聞いてみると、ちゃんとその色が返ってきます。


include_contents='default'の動作

ここで include_contents='none'を指定してみましょう。

from google.adk.agents.llm_agent import Agent

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='A helpful assistant for user questions.',
    instruction='Answer user questions to the best of your knowledge',
    include_contents='none'
)

そして同じように好きな色を伝えてから、再度その好きな色を聞いてみると、先程の会話履歴が残っていないような返答がされます。


include_contents='none'の動作

これは左のリクエストを見てみるとわかるように、include_contents='none'を指定することで、過去の会話履歴が LLM に渡されていないことがわかります。

10. input_schema/output_schema

Agent に対して、入力と出力を定義します。
LLM に対しても LLM API のパラメータがあれば渡されますが、Agent as a Tool (AgentTool) を利用する場合は、ツールを利用する Agent に対して、ツールのパラメータと出力形式の情報を渡す目的でも利用されます。

11. output_key

Agent の処理結果(生成されたコンテンツ)を state に直接設定する場合に設定します。
Agent 間で結果を共有したり、ツールやコールバックなどで、結果を抽出したい場合に利用します。

12. planner

Agent に対して、処理の実行計画を知らせるために利用します。

通常は BuiltInPlanner と呼ばれる特に何もしない Planner が設定されます。
Thinking が無いモデルの場合は、PlanReActPlanner を利用することで、System Instruction に Thinking のように以下の処理を追記します。

  1. 一度ユーザーのクエリに対して答えるためのプランを作成
  2. ツールを使用して計画を実行し、ツールのコードスニペット間の推論を記述して、現状と次のステップをまとめ
  3. 最後に、最終的な回答を 1 つ返します。

PlanReActPlanner は Thinking モデルでなくても Thinking モデルのような振る舞いを行い、またツールの利用率を上げる効果があります。System Instruction の書き方としても参考になるので一度コードを見てみるのをおすすめします。

https://github.com/google/adk-python/blob/0094eea3cadf5fe2e960cc558e467dd2131de1b7/src/google/adk/planners/plan_re_act_planner.py#L33

ただ最近はかなり Thinking モデルが普及し、モデル自体も賢くなったのであまり使わなくても問題がない気がします。

現在はこの目的よりも、BuiltInPlanner に対して thinking_config を設定することで、思考バジェットの設定する目的で利用されることが多い気がします。

13. *_callback

Agent に対してコールバックを指定します。
よく出るし、説明も多いので割愛します。

14. code_executor

Agent に対してコードを実行するためのツールを指定します。
名前の通りだし、動きもみんなが想定する感じなので割愛します。

まとめ

今回は ADK の LlmAgent のプロパティについて、あまり使われないものも含めて解説しました。
ADK は非常に多機能で、プロパティ一つで挙動が大きく変わることもあります。
特に設定によって、System Instructionが変わる点が、AI Agent Frameworkたる所以かもしれません。
ぜひ皆さんも色々な設定を試して見てください。


お知らせ/宣伝

ADK 開発者が集う日本語の Discord コミュニティがあります。ADK に関する情報交換や議論に興味がある方は、ぜひご参加ください!

https://discord.gg/BKpGRzjtqZ

また、ADK の最新のコミットログやリリースノートを分かりやすく解説する Podcast を、月・水・金に配信しています。ADK の動向を追いかけたい方は、ぜひ聴いてみてください。
この12月は25日までAdvent Calendarを追いかける目的で、毎日放送予定です。

https://www.youtube.com/playlist?list=PL0Zc2RFDZsM_MkHOzWNJpaT4EH5fQxA8n

Discussion