> ## Documentation Index
> Fetch the complete documentation index at: https://wb-21fd5541-docs-sandboxes-integrations-placement.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# チュートリアル: サンドボックスでエージェントを呼び出す

> Serverless サンドボックス 環境内で OpenAI エージェントを呼び出す方法を学びます

<Warning>
  Serverless Sandboxes は現在パブリックプレビュー中です。
</Warning>

このチュートリアルでは、W\&B Serverless サンドボックスでエージェントを呼び出します。必須の環境変数を設定してサンドボックスを起動し、必要な依存関係をインストールしたうえで、シンプルな OpenAI エージェントを作成して呼び出す Python スクリプトを実行します。このエージェントは、ツール呼び出しを使用して特定の場所の天気を取得し、しゃれの効いた予報を返します。

<Note>
  このチュートリアルでは、エージェントの言語モデルとして OpenAI を使用します。これには OpenAI APIキーが必要です。
</Note>

<div id="prerequisites">
  ## 前提条件
</div>

開始する前に、W\&B Python SDK をインストールし、W\&B に認証し、サンドボックスで使用できるように OpenAI APIキー をシークレットとして保存してください。

<div id="install-wb-python-sdk">
  ### W\&B Python SDK をインストールする
</div>

`pip` を使用して W\&B Python SDK をインストールします:

```bash theme={null}
pip install wandb
```

<div id="log-in-and-authenticate-with-wb">
  ### W\&B にログインして認証する
</div>

[`wandb login`](/ja/models/ref/cli/wandb-login) コマンドを実行し、表示されるプロンプトに従って W\&B のアカウントにログインします。

```bash theme={null}
wandb login
```

<div id="store-api-keys-in-secret-manager">
  ### Secret Manager に APIキーを保存する
</div>

OpenAI APIキーを `OPENAI_API_KEY` として [W\&B Secret Manager](/ja/platform/secrets) に保存します。サンドボックスでシークレットを使用する方法について詳しくは、[Secrets](/ja/sandboxes/secrets) を参照してください。

これにより、コードやサンドボックスの設定にハードコードすることなく、サンドボックス内から APIキーへ安全にアクセスできます。

<div id="copy-agent-code">
  ## エージェントのコードをコピーする
</div>

前提条件が整ったら、サンドボックス内で実行できるように、エージェントのコードをローカルに保存します。このスクリプトでは、2 つのツールと構造化された応答形式を備えた OpenAI エージェントを定義します。

<Accordion title="OpenAI エージェントのコード">
  以下のコードをコピーして、このチュートリアルと同じディレクトリに `demo.py` という名前のファイルとして保存してください。その後、前のコードスニペットを実行して、サンドボックス内でOpenAIエージェントを呼び出してください。

  ```python title="demo.py" theme={null}
  import json
  import os
  import urllib.request
  import urllib.parse

  from openai import OpenAI

  api_key = os.getenv("OPENAI_API_KEY")
  if not api_key:
      raise ValueError("OPENAI_API_KEY environment variable not set")

  client = OpenAI(api_key=api_key)

  SYSTEM_PROMPT = """You are an expert weather forecaster, who speaks in puns.

  You have access to two tools:

  - get_weather_for_location: use this to get the weather for a specific location
  - get_user_location: use this to get the user's location

  If a user asks you for the weather, make sure you know the location. If you can tell from the question that they mean wherever they are, use the get_user_location tool to find their location.
  """

  TOOLS = [
      {
          "type": "function",
          "function": {
              "name": "get_weather_for_location",
              "description": "Get weather for a given location name.",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "location": {
                          "type": "string",
                          "description": "The location to get weather for.",
                      }
                  },
                  "required": ["location"],
              },
          },
      },
      {
          "type": "function",
          "function": {
              "name": "get_user_location",
              "description": "Retrieve the user's current location from application context.",
              "parameters": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": False,
              },
          },
      },
  ]

  RESPONSE_FORMAT = {
      "type": "json_schema",
      "json_schema": {
          "name": "weather_response",
          "strict": True,
          "schema": {
              "type": "object",
              "properties": {
                  "punny_response": {"type": "string"},
                  "weather_conditions": {"type": ["string", "null"]},
              },
              "required": ["punny_response", "weather_conditions"],
              "additionalProperties": False,
          },
      },
  }

  _WMO_CODES = {
      0: "clear sky", 1: "mainly clear", 2: "partly cloudy", 3: "overcast",
      45: "foggy", 48: "depositing rime fog",
      51: "light drizzle", 53: "moderate drizzle", 55: "dense drizzle",
      61: "slight rain", 63: "moderate rain", 65: "heavy rain",
      71: "slight snowfall", 73: "moderate snowfall", 75: "heavy snowfall",
      80: "slight rain showers", 81: "moderate rain showers", 82: "violent rain showers",
      95: "thunderstorm", 96: "thunderstorm with slight hail", 99: "thunderstorm with heavy hail",
  }


  def get_weather_for_location(location: str) -> str:
      geo_url = "https://geocoding-api.open-meteo.com/v1/search?" + urllib.parse.urlencode(
          {"name": location, "count": 1}
      )
      with urllib.request.urlopen(geo_url) as resp:
          geo = json.loads(resp.read())

      if not geo.get("results"):
          return f"Could not find a location named '{location}'."

      loc = geo["results"][0]
      lat, lon = loc["latitude"], loc["longitude"]
      name = loc.get("name", location)

      weather_url = "https://api.open-meteo.com/v1/forecast?" + urllib.parse.urlencode({
          "latitude": lat,
          "longitude": lon,
          "current": "temperature_2m,weather_code,wind_speed_10m",
          "temperature_unit": "fahrenheit",
          "wind_speed_unit": "mph",
      })
      with urllib.request.urlopen(weather_url) as resp:
          weather = json.loads(resp.read())

      cur = weather["current"]
      condition = _WMO_CODES.get(cur["weather_code"], "unknown conditions")
      temp = cur["temperature_2m"]
      wind = cur["wind_speed_10m"]

      return f"{name}: {condition}, {temp}°F, wind {wind} mph"


  def get_user_location(user_id: str) -> str:
      return "Miami" if user_id == "1" else "San Francisco"


  TOOL_DISPATCH = {
      "get_weather_for_location": lambda args, _ctx: get_weather_for_location(args["location"]),
      "get_user_location": lambda _args, ctx: get_user_location(ctx["user_id"]),
  }


  def run_agent(messages: list[dict], context: dict) -> dict:
      while True:
          response = client.chat.completions.create(
              model="gpt-4o",
              temperature=0,
              messages=messages,
              tools=TOOLS,
              response_format=RESPONSE_FORMAT,
          )

          message = response.choices[0].message

          if message.tool_calls:
              messages.append({
                  "role": "assistant",
                  "content": message.content,
                  "tool_calls": [
                      {
                          "id": tc.id,
                          "type": "function",
                          "function": {
                              "name": tc.function.name,
                              "arguments": tc.function.arguments,
                          },
                      }
                      for tc in message.tool_calls
                  ],
              })

              for tool_call in message.tool_calls:
                  fn_name = tool_call.function.name
                  fn_args = json.loads(tool_call.function.arguments)

                  tool_fn = TOOL_DISPATCH.get(fn_name)
                  if tool_fn is None:
                      raise ValueError(f"Unknown tool: {fn_name}")

                  result = tool_fn(fn_args, context)
                  messages.append({
                      "role": "tool",
                      "tool_call_id": tool_call.id,
                      "content": result,
                  })
              continue

          messages.append({
              "role": "assistant",
              "content": message.content,
          })
          return json.loads(message.content)


  # --- エージェントを実行する ---

  conversation: list[dict] = [{"role": "system", "content": SYSTEM_PROMPT}]
  context = {"user_id": "1"}

  # 最初のターン
  conversation.append({"role": "user", "content": "what is the weather outside?"})
  result = run_agent(conversation, context)
  print(result)
  # {'punny_response': "Florida is still having a 'sun-derful' day! ...", 'weather_conditions': "It's always sunny in Florida!"}

  # 2回目のターン（会話履歴は保持されます）
  conversation.append({"role": "user", "content": "thank you!"})
  result = run_agent(conversation, context)
  print(json.dumps(result, indent=2))
  ```
</Accordion>
