Skip to content

Integrate REST APIs with OpenAPI

使用 OpenAPI 集成 REST API

Supported in ADKPython v0.1.0

ADK simplifies interacting with external REST APIs by automatically generating callable tools directly from an OpenAPI Specification (v3.x). This eliminates the need to manually define individual function tools for each API endpoint.

ADK 通过直接从 OpenAPI 规范(v3.x) 自动生成可调用工具,简化了与外部 REST API 的交互。这消除了为每个 API 端点手动定义单个函数工具的需要。

Core Benefit

提示:核心优势

Use OpenAPIToolset to instantly create agent tools (RestApiTool) from your existing API documentation (OpenAPI spec), enabling agents to seamlessly call your web services.

使用 OpenAPIToolset 从您现有的 API 文档(OpenAPI 规范)即时创建智能体工具(RestApiTool),使智能体能够无缝调用您的 Web 服务。

Key Components

关键组件

  • OpenAPIToolset: This is the primary class you'll use. You initialize it with your OpenAPI specification, and it handles the parsing and generation of tools.

    OpenAPIToolset: 这是您将使用的主要类。您使用 OpenAPI 规范初始化它,它处理工具的解析和生成。

  • RestApiTool: This class represents a single, callable API operation (like GET /pets/{petId} or POST /pets). OpenAPIToolset creates one RestApiTool instance for each operation defined in your spec.

    RestApiTool: 此类表示单个可调用的 API 操作(如 GET /pets/{petId}POST /pets)。OpenAPIToolset 为您的规范中定义的每个操作创建一个 RestApiTool 实例。

How it Works

工作原理

The process involves these main steps when you use OpenAPIToolset:

当您使用 OpenAPIToolset 时,该过程涉及以下主要步骤:

  1. Initialization & Parsing:

    初始化和解析:

    • You provide the OpenAPI specification to OpenAPIToolset either as a Python dictionary, a JSON string, or a YAML string.

      您以 Python 字典、JSON 字符串或 YAML 字符串的形式向 OpenAPIToolset 提供 OpenAPI 规范。

    • The toolset internally parses the spec, resolving any internal references ($ref) to understand the complete API structure.

      工具集在内部解析规范,解析任何内部引用($ref)以理解完整的 API 结构。

  2. Operation Discovery:

    操作发现:

    • It identifies all valid API operations (e.g., GET, POST, PUT, DELETE) defined within the paths object of your specification.

      它识别您的规范的 paths 对象中定义的所有有效 API 操作(例如,GETPOSTPUTDELETE)。

  3. Tool Generation:

    工具生成:

    • For each discovered operation, OpenAPIToolset automatically creates a corresponding RestApiTool instance.

      对于每个发现的操作,OpenAPIToolset 会自动创建一个相应的 RestApiTool 实例。

    • Tool Name: Derived from the operationId in the spec (converted to snake_case, max 60 chars). If operationId is missing, a name is generated from the method and path.

      工具名称: 派生自规范中的 operationId(转换为 snake_case,最多 60 个字符)。如果缺少 operationId,则从方法和路径生成名称。

    • Tool Description: Uses the summary or description from the operation for the LLM.

      工具描述: 使用操作的 summarydescription 供 LLM 使用。

    • API Details: Stores the required HTTP method, path, server base URL, parameters (path, query, header, cookie), and request body schema internally.

      API 详细信息: 在内部存储所需的 HTTP 方法、路径、服务器基本 URL、参数(path、query、header、cookie)和请求正文模式。

  4. RestApiTool Functionality: Each generated RestApiTool:

    RestApiTool 功能: 每个生成的 RestApiTool:

    • Schema Generation: Dynamically creates a FunctionDeclaration based on the operation's parameters and request body. This schema tells the LLM how to call the tool (what arguments are expected).

      模式生成: 根据操作的参数和请求正文动态创建 FunctionDeclaration。此模式告诉 LLM 如何调用工具(预期什么参数)。

    • Execution: When called by the LLM, it constructs the correct HTTP request (URL, headers, query params, body) using the arguments provided by the LLM and the details from the OpenAPI spec. It handles authentication (if configured) and executes the API call using the requests library.

      执行: 当被 LLM 调用时,它使用 LLM 提供的参数和 OpenAPI 规范中的详细信息构造正确的 HTTP 请求(URL、标头、查询参数、正文)。它处理身份验证(如果已配置)并使用 requests 库执行 API 调用。

    • Response Handling: Returns the API response (typically JSON) back to the agent flow.

      响应处理: 将 API 响应(通常为 JSON)返回到智能体流程。

  5. Authentication: You can configure global authentication (like API keys or OAuth - see Authentication for details) when initializing OpenAPIToolset. This authentication configuration is automatically applied to all generated RestApiTool instances.

    身份验证: 您可以在初始化 OpenAPIToolset 时配置全局身份验证(如 API 密钥或 OAuth - 有关详细信息,请参阅身份验证)。此身份验证配置会自动应用于所有生成的 RestApiTool 实例。

Usage Workflow

使用流程

Follow these steps to integrate an OpenAPI spec into your agent:

按照以下步骤将 OpenAPI 规范集成到您的智能体中:

  1. Obtain Spec: Get your OpenAPI specification document (e.g., load from a .json or .yaml file, fetch from a URL).

    获取规范: 获取您的 OpenAPI 规范文档(例如,从 .json.yaml 文件加载,从 URL 获取)。

  2. Instantiate Toolset: Create an OpenAPIToolset instance, passing the spec content and type (spec_str/spec_dict, spec_str_type). Provide authentication details (auth_scheme, auth_credential) if required by the API.

    实例化工具集: 创建一个 OpenAPIToolset 实例,传递规范内容和类型(spec_str/spec_dictspec_str_type)。如果 API 需要身份验证详细信息(auth_schemeauth_credential)。

    from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
    
    # Example with a JSON string
    # JSON 字符串示例
    openapi_spec_json = '...' # Your OpenAPI JSON string
    # 您的 OpenAPI JSON 字符串
    toolset = OpenAPIToolset(spec_str=openapi_spec_json, spec_str_type="json")
    
    # Example with a dictionary
    # 字典示例
    # openapi_spec_dict = {...} # Your OpenAPI spec as a dict
    # 您的 OpenAPI 规范作为字典
    # toolset = OpenAPIToolset(spec_dict=openapi_spec_dict)
    
  3. Add to Agent: Include the retrieved tools in your LlmAgent's tools list.

    添加到智能体: 将检索到的工具包含在您的 LlmAgenttools 列表中。

    from google.adk.agents import LlmAgent
    
    my_agent = LlmAgent(
        name="api_interacting_agent",
        model="gemini-2.0-flash", # Or your preferred model
        # 或您偏好的模型
        tools=[toolset], # Pass the toolset
        # 传递工具集
        # ... other agent config ...
        # ...其他智能体配置...
    )
    
  4. Instruct Agent: Update your agent's instructions to inform it about the new API capabilities and the names of the tools it can use (e.g., list_pets, create_pet). The tool descriptions generated from the spec will also help the LLM.

    指示智能体: 更新您的智能体指令,使其了解新的 API 功能以及它可以使用的工具名称(例如,list_petscreate_pet)。从规范生成的工具描述也将帮助 LLM。

  5. Run Agent: Execute your agent using the Runner. When the LLM determines it needs to call one of the APIs, it will generate a function call targeting the appropriate RestApiTool, which will then handle the HTTP request automatically.

    运行智能体: 使用 Runner 执行您的智能体。当 LLM 确定需要调用其中一个 API 时,它将生成一个针对适当 RestApiTool 的函数调用,该调用随后将自动处理 HTTP 请求。

Example

示例

This example demonstrates generating tools from a simple Pet Store OpenAPI spec (using httpbin.org for mock responses) and interacting with them via an agent.

此示例演示了从简单的 Pet Store OpenAPI 规范(使用 httpbin.org 进行模拟响应)生成工具并通过智能体与它们交互。

Code: Pet Store API

代码:Pet Store API

openapi_example.py
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import asyncio
import uuid # For unique session IDs
from dotenv import load_dotenv

from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types

# --- OpenAPI Tool Imports ---
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset

# --- Load Environment Variables (If ADK tools need them, e.g., API keys) ---
load_dotenv() # Create a .env file in the same directory if needed

# --- Constants ---
APP_NAME_OPENAPI = "openapi_petstore_app"
USER_ID_OPENAPI = "user_openapi_1"
SESSION_ID_OPENAPI = f"session_openapi_{uuid.uuid4()}" # Unique session ID
AGENT_NAME_OPENAPI = "petstore_manager_agent"
GEMINI_MODEL = "gemini-2.0-flash"

# --- Sample OpenAPI Specification (JSON String) ---
# A basic Pet Store API example using httpbin.org as a mock server
openapi_spec_string = """
{
  "openapi": "3.0.0",
  "info": {
    "title": "Simple Pet Store API (Mock)",
    "version": "1.0.1",
    "description": "An API to manage pets in a store, using httpbin for responses."
  },
  "servers": [
    {
      "url": "https://httpbin.org",
      "description": "Mock server (httpbin.org)"
    }
  ],
  "paths": {
    "/get": {
      "get": {
        "summary": "List all pets (Simulated)",
        "operationId": "listPets",
        "description": "Simulates returning a list of pets. Uses httpbin's /get endpoint which echoes query parameters.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of pets to return",
            "required": false,
            "schema": { "type": "integer", "format": "int32" }
          },
          {
             "name": "status",
             "in": "query",
             "description": "Filter pets by status",
             "required": false,
             "schema": { "type": "string", "enum": ["available", "pending", "sold"] }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of pets (echoed query params).",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/post": {
      "post": {
        "summary": "Create a pet (Simulated)",
        "operationId": "createPet",
        "description": "Simulates adding a new pet. Uses httpbin's /post endpoint which echoes the request body.",
        "requestBody": {
          "description": "Pet object to add",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": {"type": "string", "description": "Name of the pet"},
                  "tag": {"type": "string", "description": "Optional tag for the pet"}
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pet created successfully (echoed request body).",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/get?petId={petId}": {
      "get": {
        "summary": "Info for a specific pet (Simulated)",
        "operationId": "showPetById",
        "description": "Simulates returning info for a pet ID. Uses httpbin's /get endpoint.",
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "description": "This is actually passed as a query param to httpbin /get",
            "required": true,
            "schema": { "type": "integer", "format": "int64" }
          }
        ],
        "responses": {
          "200": {
            "description": "Information about the pet (echoed query params)",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "404": { "description": "Pet not found (simulated)" }
        }
      }
    }
  }
}
"""

# --- Create OpenAPIToolset ---
petstore_toolset = OpenAPIToolset(
    spec_str=openapi_spec_string,
    spec_str_type='json',
    # No authentication needed for httpbin.org
)

# --- Agent Definition ---
root_agent = LlmAgent(
    name=AGENT_NAME_OPENAPI,
    model=GEMINI_MODEL,
    tools=[petstore_toolset], # Pass the list of RestApiTool objects
    instruction="""You are a Pet Store assistant managing pets via an API.
    Use the available tools to fulfill user requests.
    When creating a pet, confirm the details echoed back by the API.
    When listing pets, mention any filters used (like limit or status).
    When showing a pet by ID, state the ID you requested.
    """,
    description="Manages a Pet Store using tools generated from an OpenAPI spec."
)

# --- Session and Runner Setup ---
async def setup_session_and_runner():
    session_service_openapi = InMemorySessionService()
    runner_openapi = Runner(
        agent=root_agent,
        app_name=APP_NAME_OPENAPI,
        session_service=session_service_openapi,
    )
    await session_service_openapi.create_session(
        app_name=APP_NAME_OPENAPI,
        user_id=USER_ID_OPENAPI,
        session_id=SESSION_ID_OPENAPI,
    )
    return runner_openapi

# --- Agent Interaction Function ---
async def call_openapi_agent_async(query, runner_openapi):
    print("\n--- Running OpenAPI Pet Store Agent ---")
    print(f"Query: {query}")

    content = types.Content(role='user', parts=[types.Part(text=query)])
    final_response_text = "Agent did not provide a final text response."
    try:
        async for event in runner_openapi.run_async(
            user_id=USER_ID_OPENAPI, session_id=SESSION_ID_OPENAPI, new_message=content
            ):
            # Optional: Detailed event logging for debugging
            # print(f"  DEBUG Event: Author={event.author}, Type={'Final' if event.is_final_response() else 'Intermediate'}, Content={str(event.content)[:100]}...")
            if event.get_function_calls():
                call = event.get_function_calls()[0]
                print(f"  Agent Action: Called function '{call.name}' with args {call.args}")
            elif event.get_function_responses():
                response = event.get_function_responses()[0]
                print(f"  Agent Action: Received response for '{response.name}'")
                # print(f"  Tool Response Snippet: {str(response.response)[:200]}...") # Uncomment for response details
            elif event.is_final_response() and event.content and event.content.parts:
                # Capture the last final text response
                final_response_text = event.content.parts[0].text.strip()

        print(f"Agent Final Response: {final_response_text}")

    except Exception as e:
        print(f"An error occurred during agent run: {e}")
        import traceback
        traceback.print_exc() # Print full traceback for errors
    print("-" * 30)

# --- Run Examples ---
async def run_openapi_example():
    runner_openapi = await setup_session_and_runner()

    # Trigger listPets
    await call_openapi_agent_async("Show me the pets available.", runner_openapi)
    # Trigger createPet
    await call_openapi_agent_async("Please add a new dog named 'Dukey'.", runner_openapi)
    # Trigger showPetById
    await call_openapi_agent_async("Get info for pet with ID 123.", runner_openapi)

# --- Execute ---
if __name__ == "__main__":
    print("Executing OpenAPI example...")
    # Use asyncio.run() for top-level execution
    try:
        asyncio.run(run_openapi_example())
    except RuntimeError as e:
        if "cannot be called from a running event loop" in str(e):
            print("Info: Cannot run asyncio.run from a running event loop (e.g., Jupyter/Colab).")
            # If in Jupyter/Colab, you might need to run like this:
            # await run_openapi_example()
        else:
            raise e
    print("OpenAPI example finished.")