🤖

Agent Development Kit 1.11.0で修正された output_schema と tools の同時利用

に公開

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

2025/08/15にAgent Development Kit(以降ADK) 1.11.0がリリースされました。

https://github.com/google/adk-python/releases/tag/v1.11.0

最近は毎週金曜日にリリースされており、計画的に開発が進められていることがうかがえます。
今回のリリースで追加された主な機能は以下です。

[Tools] Support adding prefix to tool names returned by toolset (ebd726f)
[Eval] Expose print_detailed_results param to AgentEvaluator.evaluate (7e08808)
[Tools] Add Spanner toolset (breaking change to BigQueryTool, consolidating into generic GoogleTool) (1fc8d20)
[Core] Support both output_schema and tools at the same time in LlmAgent(sample) (af63567)

  • Toolsetのツールに対するprefixの設定
  • AgentEvaluator.evaluateに対するprint_detailed_resultsパラメータの追加
  • Spanner toolset の追加
  • output_schematoolsの同時利用のサポート

他にもバグフィックスや細々した機能追加やドキュメントの改善が行われています。
今回はこの中で待望されていた「output_schematoolsの同時利用のサポート」について書いていきたいと思います。

課題: output_schematoolsの同時利用ができなかった

ADKには、LLMの出力を指定の形式(プロパティや型)に整えるためのoutput_schema(構造化出力)と、エージェントに外部機能(Function Callingなど)を追加するためのtoolsという2つの設定項目があります。

Structured Outputとは

Structured OutputはLLMにJSON形式の決まったフォーマットで値を出力してもらい、その値をアプリケーションで利用する際に非常に有用な機能です。
例えば文章を渡して、その文章からタグを抽出するようなAgentを作成する際、後続処理でそのタグを利用したい場合は、ただの文字列で返却されるよりも、決まった形式のJSON(例えば {tags: ["タグの配列"]} の様な形式)の方がアプリケーションからは利用しやすいです。
ADKではLlmAgentのコンストラクタにて output_schema パラメータに pydantic.BaseModelを継承したクラスを渡すことでStructured Outputを利用できます。

Function Callingとは

Function Calling はLLMだけでは行えないリアルタイムの情報を取得したり、なにかしらのアクションを行うために、LLMに対して利用可能な機能群とその機能に必要なパラメータ、その機能が返却する値の情報を提供し、必要なタイミングでそれらの呼び出し要求を行ってもらう機能です。
なおLLMや利用する機能にもよりますが、基本的には機能の呼び出し自体はLLM側ではなくAgentフレームワーク内で行います。

例えばLLMに現在時刻を取得する機能を提供したりするために利用します。
ADKではLlmAgentのコンストラクタにて tools パラメータに利用するツール(python関数等)リストを渡すことでFunction Callingを利用できます。

これまでADKでは1.10.0まではLlmAgentを利用する際、このoutput_schematools とは同時利用することが不可能でした。以下のコードを実行すると ADK 1.10.0ではエラーとなります。

例: toolsoutput_schemaを併用したAgent

import datetime
import zoneinfo

from google.adk.agents.llm_agent import Agent
from google.adk.tools import ToolContext
from pydantic import BaseModel, Field

async def now_tool(tool_context: ToolContext):
    """
    現在時刻を返却します。返却する時刻はJSTです。
    """
    return datetime.datetime.now(tz=zoneinfo.ZoneInfo("Asia/Tokyo")).isoformat()

class TimeResponse(BaseModel):
    time: str = Field(description="日時 iso 8601 形式")

root_agent = Agent(
    model='gemini-2.5-flash',
    name='root_agent',
    description='時計エージェント',
    instruction="""
    あなたは現在時刻を教える時計エージェントです。 `now_tool` を 利用して、現在時刻を取得してユーザーの問いに答えてください。
    
    [出力フォーマット]
    JSON オブジェクト
    
    [出力スキーマ]
    time: string iso 8601 形式 
    例: {"time": "2022-09-04T16:07:48.53+0900"}
    """,
    tools=[now_tool],
    output_schema=TimeResponse
)

上記のAgentをADK1.10.0で実行するとエラーになります。

$ adk run tool_output_schema
....
pydantic_core._pydantic_core.ValidationError: 1 validation error for LlmAgent
  Value error, Invalid config for agent root_agent: if output_schema is set, tools must be empty [type=value_error, input_value={'model': 'gemini-2.5-fla...ma.agent.TimeResponse'>}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/value_error
ADK 1.10.0までのワークアラウンド

これまで課題を回避するためにはLlmAgentを2つに分けて、ツールを利用して結果を出力するLlmAgentと、その結果を受け取って output_schemaの形式に再出力するLlmAgentが必要でした。

例: ADK 1.10.0までの toolsoutput_schema の両方を行うためのワークアラウンド

import datetime
import zoneinfo

from google.adk.agents import SequentialAgent
from google.adk.agents.llm_agent import Agent
from google.adk.tools import ToolContext
from pydantic import BaseModel, Field

async def now_tool(tool_context: ToolContext):
    """
    現在時刻を返却します。返却する時刻はJSTです。
    """
    return datetime.datetime.now(tz=zoneinfo.ZoneInfo("Asia/Tokyo")).isoformat()

class TimeResponse(BaseModel):
    time: str = Field(description="日時 iso 8601 形式")

now_agent = Agent(
    model='gemini-2.5-flash',
    name='now_agent',
    description='時計エージェント',
    instruction="""
    あなたは現在時刻を教える時計エージェントです。 `now_tool` を 利用して、現在時刻を取得してユーザーの問いに答えてください。
    """,
    tools=[now_tool],
)

format_agent = Agent(
    model='gemini-2.5-flash',
    name='format_agent',
    description='フォーマットエージェント',
    instruction="""
    あなたは別エージェントによって取得された現在時刻を指定形式にフォーマットするエージェントです。

    [出力フォーマット]
    JSON オブジェクト

    [出力スキーマ]
    time: string iso 8601 形式 
    例: {"time": "2022-09-04T16:07:48.53+0900"}
    """,
    output_schema=TimeResponse,
)

root_agent = SequentialAgent(name="root_agent", sub_agents=[now_agent, format_agent])

❯ adk run tool_output_schema
Running agent root_agent, type exit to exit.
[user]: 今何時
[now_agent]: 現在時刻は2025年8月15日22時29分38秒です。
[format_agent]: {"time":"2025-08-15T22:29:38.087462+09:00"}
[user]:

少々コードが煩雑になりますね...

ADK 1.11.0 の output_schematoolsの同時利用のサポート

今回のリリースで上記の課題が修正されました。
実際に ADK 1.11.0 でエラーが発生していたコードを試してみましょう。
上記のAgentを ADK 1.11.0でコードを変更せずに実行してみます。

❯ adk run tool_output_schema
Running agent root_agent, type exit to exit.
[user]: 今何時?
[root_agent]: {"time": "2025-08-15T22:33:18.509335+09:00"}
[user]: 

エラーが発生せずに利用することができました

仕組み

興味がない方は、このセクションを読み飛ばしていただいて構いません。

上記のように、このStructured Output(output_schema)とFunction Calling(tools)が同時利用できない制約はADK由来ではなくLLM API由来のものです。
ではADKでは、どのようにしてこの課題に対応したのでしょうか?

ADKの開発UI(Dev UI)を利用すると、このケースでは set_model_response というツールが利用されていることがわかります。

また System Instructionにも以下のように追記されており、最終フォーマットを行うためにこのツールを呼び出す旨が記載されています。

IMPORTANT: You have access to other tools, but you must provide your final response using the set_model_response tool with the required structured format. After using any other tools needed to complete the task, always call set_model_response with your final answer in the specified schema format.
重要:他のツールもご利用いただけますが、最終的な回答は、必要な構造化形式でset_model_responseツールを使用して提供する必要があります。タスクを完了するために必要な他のツールを使用した後は、必ず指定されたスキーマ形式で最終的な回答を指定してset_model_responseを呼び出してください。

この set_model_response ツールは以下で定義されており、
簡単に言えば、output_schemaで指定されたスキーマ情報を基に、そのスキーマに合致した出力を生成するための特別なツール(set_model_response)を動的に作成します。そして、LLMにそのツールを呼び出させることで、結果的にスキーマ通りのアウトプットを実現しています。

https://github.com/google/adk-python/blob/main/src/google/adk/tools/set_model_response_tool.py

ツールの呼び出しを利用してスキーマを作成するのは面白い発想ですね!

まとめ

今回は 1.11.0で修正されたoutput_schematoolsの同時利用について解説しました。
小さな変更に見えますが、この問題はADKを利用する上で多くの開発者が直面するものだったので、今回の更新は非常に有用だと言えるでしょう。

1.11.0にはSpannerToolの追加など、(BigQueryに続き)SpannerというGoogle Cloudの主要データベースに対応した点は、エンタープライズ領域での活用を期待させますね。ぜひほかの更新も追っていきたいですね


お知らせ/宣伝

先日、ADKユーザー向けのイベント「ADK UG #0」が開催され、ADK開発者が集う日本語のDiscordコミュニティが誕生しました。ADKに関する情報交換や議論に興味がある方は、ぜひご参加ください!

https://discord.gg/BKpGRzjtqZ

また、ADKの最新のコミットログやリリースノートを分かりやすく解説するPodcastを、月・水・金に配信しています。ADKの動向を追いかけたい方は、ぜひ聴いてみてください。

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

Discussion