0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Autonomous AI Database の A2A Server を DB の中から見てみた

0
Posted at

1. はじめに

2026 年 7 月、Oracle Autonomous AI Database Serverless(以下 ADB)に、Select AI Agent のチームを A2A(Agent2Agent)プロトコルで外部に公開する A2A Server が追加されました1。A2A は、別々に作られた AI エージェントの間で、HTTP でタスクを依頼して結果を受け取るための公開仕様です2。

外から呼ぶ手順そのものは、curl で呼ぶ記事3や、A2A の Python SDK と OpenAI Agents SDK から呼ぶ記事4がすでに日本語で出ています。本記事で確かめたいのは、呼ばれた側の DB で何が起きるかです。公式ドキュメントには、呼び出し側の認証について次の一文があります。

データベース資格証明はアクセス・トークンの取得に使用され、後続のすべてのリクエストは直接データベース接続のかわりにトークンを使用します。

Agent2Agentプロトコルについて5

外部のエージェントは DB に接続せず、トークンだけで DB の中のエージェントを動かす、という説明です。では、DB に接続していない呼び出しは、DB の中では誰のセッションとして動き、何が記録されるのか。前回の記事6で作った Supervisor 付きのチーム構成を Always Free の ADB に作り直し、A2A で公開して確かめます。呼び出し自体は、タグを 1 つ付け、コメントと空行を除いて 24 行の Python を書くだけでできました。

1.1. 結論(先出し)

  • A2A 経由の実行は、トークンを取った DB ユーザーではなく、ADB の内部ユーザー C##CLOUD$SERVICE のセッション(module RUN_A2A_AGENT、action は A2A のタスク ID)として動いた
  • そのため、DB ユーザー名でセッションを探しても A2A の実行は見つからず、デフォルトの統一監査にも記録されなかった。追える手がかりは module・action と、チームの持ち主の実行履歴(CONVERSATION_ID = A2A の contextId)である
  • Supervisor がユーザーに聞き返して DB 側の履歴が WAITING_FOR_HUMAN のままでも、A2A の応答は completed だった
  • Supervisor 付きチームを別スキーマへ移すと、EXPORT_TEAM/IMPORT_TEAM では Supervisor が含まれなかった。GET_DEFINITION の出力なら、実行順を並べ替えれば Supervisor ごと作り直せた

1.2. 検証ゴール

# 確かめること 確認できれば OK の条件
1 A2A 経由の実行が DB からどう見えるか 実行中のセッションのユーザー・接続元・スキーマと、エージェントの履歴・統一監査に記録されるものを、PL/SQL で直接実行した場合と並べて比べられる
2 A2A の状態と DB の状態が一致するか 完了・聞き返しのそれぞれで、A2A の応答と DB の履歴の状態を並べられる
3 Supervisor 付きチームを別のスキーマへ移せるか 定義を書き出して別スキーマで作り直したチームが、Supervisor を含めて A2A から呼べる

2. 検証環境

項目 内容
ADB Oracle Autonomous AI Database Serverless 26ai、Always Free(1 OCPU)、ap-tokyo-1
AI プロファイル OCI_OSAKA(OCI Generative AI 大阪リージョンの meta.llama-3.3-70b-instruct を、リソースプリンシパルで呼ぶ)
チーム OPS_SUPERVISOR_TEAM(Supervisor 1 つ+ワーカー 2 つ。Top SQL 解析と統計確認)。前回の記事6と同じ構成を、この ADB に作り直したもの
チームの持ち主 DB ユーザー DBA_COPILOT
クライアント Windows 11 の Python 3.12.0、requests 2.33.0、a2a-sdk 0.3.26 と 1.1.4

A2A のクライアントは、最初は requests で JSON をそのまま組み立てて送りました。公式ドキュメントが挙げる外部クライアントの例は Google Gemini Enterprise だけで、Python などのコード例が無く7、何を送れば動くかを 1 つずつ確かめたかったためです。そのあとで、A2A の公式 Python SDK でも同じことができるかを試しています。


3. 構成

本記事の A2A のクライアントは PC の Python です。Python は ADB のリスナーに SQL*Net で接続するのではなく、ADB の HTTPS の API(https://dataaccess.adb.ap-tokyo-1.oraclecloudapps.com/adb/...)を呼びます。図中の Agent Card は、チームの名前・説明・使えるツール・呼び出し先の URL を記述した JSON で、A2A Server がチームの定義から自動で作ります8(中身は 4.3 章)。流れは次のとおりです。

図 1: A2A で ADB のチームを呼ぶ流れ

呼び出しは非同期です。message/send はすぐにタスク ID を返し、クライアントは tasks/get で完了を待ちます。

「A2A Server」は、1 台のサーバーというより、この HTTPS の API と、自分の ADB の中で動く処理の 2 つで構成されています。

API のホスト名 dataaccess.adb.ap-tokyo-1.oraclecloudapps.com は、DNS で名前解決すると、Database Actions(ブラウザの SQL 画面)や OML と同じ 3 つの IP アドレスになりました。ウォレットで接続するリスナーとは別のアドレスです。トークン発行・一覧・Agent Card、それに Managed MCP Server も、このホストの配下にあります。

処理は、自分の ADB の中の C##CLOUD$SERVICE のセッションで動きます。このセッションは ADB 自身のホストから共有サーバー経由で接続され、クライアントのドライバ名とバージョンの列は空でした。接続直後の接続サービスは SYS$USERS です。実行が始まると _low に切り替わります。そのあとスキーマをチームの持ち主(今回は DBA_COPILOT)に切り替えてから、DBMS_CLOUD_AI_AGENT.RUN_TEAM を呼んでいました。中身は、持ち主に代わって PL/SQL でチームを実行しています。公式ドキュメントにも、A2A を有効にしても追加のコンピュートは割り当てられず、ADB の割り当てを使うと書かれています9。


4. 外から呼んでみる

4.1. A2A Server を有効にする

有効化は PL/SQL ではなく、ADB に付ける freeform タグで行います10。

# 既存の freeform タグを全部置き換えるので、他のタグがあれば同じ JSON に含める
oci db autonomous-database update \
  --autonomous-database-id <ADB の OCID> \
  --freeform-tags '{"adb$feature": "{\"name\":\"a2a_server\",\"enable\":true}"}' \
  --force --wait-for-state AVAILABLE

図 2: ADB のタグ。freeform タグの adb$feature に A2A の値が入っている

図 2: ADB のタグ。freeform タグの adb$feature に A2A の値が入っている

--wait-for-state AVAILABLE で待つ更新は、あとで付け直した 3 回で 9.5〜17.6 秒でした。認証なしで一覧の URL にリクエストを送ると、更新前は HTTP 403(The tool you are trying to access is disabled by your administrator.)でした。更新のあと 1 分おきに確認すると、2 回目で HTTP 401(ADB-00015 Invalid credential.)に変わりました。401 は「A2A Server は動いているが、トークンが無い」という応答です。

なお、2026 年 9 月 18 日時点のコンソールでは、ADB の詳細(「ツール構成」タブと一般情報)に A2A の URL を表示する欄は見当たりませんでした。URL は公式ドキュメントの形式から組み立てるか、4.3 章の一覧 API で取得します。

この ADB には、前に Managed MCP Server を有効にするため、同じキー adb$feature で MCP の値を付けていました11。キーは 1 つなので、A2A の値で上書きしたことになります。公式ドキュメントには「MCP Server と A2A Server は独立して有効化する」と書かれており10、上書き後も MCP のエンドポイントは 401 と WWW-Authenticate を返していました。無効なら 403 になるはずなので、MCP は有効なままだと判断しました。

4.2. トークンを取得する

公式の手順は、ADMIN で OAuth クライアントを登録し12、DB ユーザーのパスワードでベアラートークンを取得する13、の 2 段階です。

# DB ユーザー(ここではチームの持ち主 DBA_COPILOT)のパスワードでトークンを取得する
BASE = "https://dataaccess.adb.ap-tokyo-1.oraclecloudapps.com/adb"
r = requests.post(
    f"{BASE}/auth/v1/databases/{ocid}/token",
    json={"grant_type": "password", "username": "DBA_COPILOT", "password": password},
    timeout=30,
)
token = r.json()["access_token"]   # expires_in は 3600 秒

今回は OAuth クライアントを登録してからトークンを取得しましたが、トークン取得のリクエストに、登録で得た client_id と client_secret は不要でした(公式の例も同じです)。

4.3. 一覧と Agent Card

トークンで agents/ を呼ぶと、そのユーザーが持つチームの一覧が返ります。ADMIN のトークンでは空でした。見えるのは自分が持つチームだけです。同じ ADB の Managed MCP Server でも、ログインしたユーザーが持つツールだけが見えたので、同じ仕様と考えられます。

一覧には、Supervisor の無い NL2SQL_DATA_RETRIEVAL_TEAM だけが出て、OPS_SUPERVISOR_TEAM は出ませんでした。18 分後に取り直しても同じです。一方、URL を組み立てて Agent Card を取得すると HTTP 200 で返り、呼び出しもできました。

取得した Agent Card の抜粋を載せます。

{
  "name": "OPS_SUPERVISOR_TEAM",
  "description": "Supervisor-led ops support team: top SQL analysis + statistics freshness",
  "url": "https://dataaccess.adb.ap-tokyo-1.oraclecloudapps.com/adb/a2a/v1/databases/<ADB の OCID>/agents/OPS_SUPERVISOR_TEAM",
  "capabilities": {"streaming": false, "pushNotifications": false, "stateTransitionHistory": false},
  "skills": [
    {"id": "28", "name": "SQL_TOOL", "description": "This tool can access the data in database. ..."},
    {"id": "31", "name": "CHECK_TABLE_STATS_TOOL", "description": "Returns optimizer statistics freshness for one table as JSON: ..."}
  ],
  "preferredTransport": "JSONRPC",
  "protocolVersion": "0.3.0"
}

skills には、チームのワーカーが使うツールが 5 つ並びました(上は 2 つに省略)。Supervisor 自身もワーカーのエージェントも skills には出ません。

4.4. 質問を送って答えを受け取る

A2A v0.3.0 の JSON-RPC で message/send を送り、tasks/get で完了を待ちます2。

# 質問を送る(すぐに submitted とタスク ID が返る)
body = {
    "jsonrpc": "2.0", "id": "1", "method": "message/send",
    "params": {"message": {
        "kind": "message", "messageId": str(uuid.uuid4()), "role": "user",
        "parts": [{"kind": "text", "text": "いま一番重いSQLはどれ?"}],
    }},
}
headers = {"Authorization": f"Bearer {token}"}
task = requests.post(card["url"], json=body, headers=headers, timeout=60).json()["result"]

# 3 秒ごとに状態を確認する
while task["status"]["state"] in ("submitted", "working"):
    time.sleep(3)
    poll = {"jsonrpc": "2.0", "id": "2", "method": "tasks/get", "params": {"id": task["id"]}}
    task = requests.post(card["url"], json=poll, headers=headers, timeout=30).json()["result"]

print(task["artifacts"][0]["parts"][0]["text"])   # 答えの本文

A2A の公式 Python SDK(a2a-sdk)でも試しました。2026 年 9 月 18 日時点で PyPI の最新は 1.1.4 で、A2A 仕様 1.0 の実装に 0.3 との互換モードが付いたものです。ADB は 0.3.0 準拠なので、0.3 系の最終版 0.3.26 も並べて試したところ、どちらも 1 回目で呼べました。1.1.4 は Agent Card の protocolVersion を見て 0.3 用の通信方式を自動で選ぶため、互換モードを指定するコードは不要でした。

4.5. 答えが返った

記事用に 1 本にまとめたスクリプト(コメントと空行を除いて 24 行)を実行すると、次のように出ます。

> python a2a_ask.py "いま一番重いSQLはどれ?"
チーム: OPS_SUPERVISOR_TEAM  skills: ['SQL_TOOL', 'DISTINCT_VALUES_CHECK', 'RANGE_VALUES_CHECK', 'GENERATE_CHART', 'CHECK_TABLE_STATS_TOOL']
  0.0 秒  submitted
  3.6 秒  working
  7.1 秒  working
...(中略)...
 70.2 秒  working
 73.7 秒  completed

現在最も重いSQLクエリは、SQL_IDが「7ukk8uw1539mm」で、ELAPSED_PER_EXEC_SECが41.173秒です。

最初に requests で JSON を組み立てて送ったときは、message/send は 0.97 秒で submitted を返し、tasks/get で working が続いたあと、送信から 19.1 秒の確認で completed になりました。

{"id": "de62c18f-...", "contextId": "5AB5B432-C6AF-...", "status": {"state": "submitted"}}
{"id": "de62c18f-...", "status": {"state": "working"}}
{"id": "de62c18f-...", "status": {"state": "completed"},
 "artifacts": [{"name": "select_ai_agent_result",
   "parts": [{"kind": "text", "text": "現在最も重いSQLクエリは、SQL_IDが「gyuu22b55z3g0」です。..."}]}]}

DB 側の履歴では、Supervisor のタスクのあとに Top SQL ワーカーのタスクが続いており、前回の記事6と同じ委譲の流れでした。LLM は Llama 3.3 70B のままです。

答えの「一番重い SQL」は、1 回目がこの ADB に常時接続している監視ツールの SQL、上の実行例では直前の A2A 実行で動いた RUN_TEAM の呼び出しでした。どちらも A2A とは別の、エージェントがどの SQL を答えに選ぶかの話なので、本記事では扱いません。


5. DB から見た A2A

5.1. 誰のセッションで動くか

A2A で呼んでいる最中に、ADMIN で V$SESSION を module で絞ると、次の 1 行が見えます。

図 3: A2A 実行中の V$SESSION(Database Actions)。ユーザーは C##CLOUD$SERVICE、module は RUN_A2A_AGENT、action は A2A のタスク ID

図 3: A2A 実行中の V$SESSION(Database Actions)。ユーザーは C##CLOUD$SERVICE、module は RUN_A2A_AGENT、action は A2A のタスク ID

A2A で呼んだ実行と、同じ質問を DBA_COPILOT で接続して PL/SQL(DBMS_CLOUD_AI_AGENT.RUN_TEAM)で直接実行した場合を並べます。

項目 PL/SQL で直接実行 A2A 経由
セッションのユーザー DBA_COPILOT C##CLOUD$SERVICE
実行中のスキーマ DBA_COPILOT C##CLOUD$SERVICE から DBA_COPILOT に切り替わる
接続元(machine) 手元の PC ADB 自身のホスト
module 接続したクライアント(Python) RUN_A2A_AGENT
action 空 A2A のタスク ID(de62c18f-...)
接続サービス _high(接続時に選んだもの) SYS$USERS から _low に切り替わる
client_identifier 空 空
エージェントの履歴 DBA_COPILOT の USER_AI_AGENT_TEAM_HISTORY ほか DBA_COPILOT の USER_AI_AGENT_TEAM_HISTORY ほか
履歴の時刻 日本時間(セッションのタイムゾーン) UTC
統一監査(デフォルトのまま) 確認していない 0 件

A2A 経由の実行は、トークンを取った DBA_COPILOT ではなく、ADB の内部ユーザー C##CLOUD$SERVICE のセッションとして動きました。V$SESSION を DB ユーザー名で絞っても、A2A の実行は出てきません。手がかりは module の RUN_A2A_AGENT と、action に入る A2A のタスク ID です。

それでも、エージェントの履歴は DBA_COPILOT の USER_AI_AGENT_TEAM_HISTORY に記録されました。CONVERSATION_ID は A2A 応答の contextId と同じ値です。「誰のチームが、どの会話で動いたか」は、履歴から追えます。「どのセッションで動いたか」は、action のタスク ID から A2A の応答を経由してたどることになります。

履歴の時刻は、直接実行の行は日本時間、A2A 経由の行は UTC で入っていました。列はタイムゾーンを持たない型なので、START_DATE の降順で並べると A2A の行が 9 時間古く見えます。行の特定は時刻ではなく、TEAM_EXEC_ID と CONVERSATION_ID で行うのが確実です。

統一監査は、ADMIN から見て、A2A を呼んだ時間帯に DBA_COPILOT と C##CLOUD$SERVICE のどちらの行もありませんでした。監査ポリシーはデフォルトのままで、追加していません。公式ドキュメントのセキュリティの章には、SYS_CONTEXT('A2A_AGENT_ACCESS_CONTEXT$', 'USER_IDENTITY') などで呼び出し元を取得できると書かれています9。

5.2. 聞き返しても A2A は completed を返す

Supervisor 付きチームは、情報が足りないとユーザーに聞き返します。前回の記事6では、その間チームの状態が WAITING_FOR_HUMAN(人の入力待ち)になり、同じ会話で答えると再開しました。

A2A で「統計が古い表はある?」と送ると、答えは「Which table would you like to check for stale statistics?」という聞き返しでした。範囲外の「明日の東京の天気は?」も、3.8 秒で completed になりました。こちらの答えは、質問を英訳した 1 文だけでした。どちらも DB 側の履歴は WAITING_FOR_HUMAN のままで、終了時刻は空です。

質問 A2A の応答(tasks/get) DB のチームの履歴
統計が古い表はある?(答えは聞き返し) completed WAITING_FOR_HUMAN(終了時刻なし)
明日の東京の天気は?(答えは質問の英訳) completed WAITING_FOR_HUMAN(終了時刻なし)

A2A の仕様には、入力待ちを表す input-required という状態があります2。今回の ADB は、この状態を返しませんでした。呼び出す側のエージェントは、聞き返しを「完了した答え」として受け取ることになります。

5.3. 別のスキーマへ移す

開発用のスキーマで作ったチームを別のスキーマへ移す手段として、8 月に EXPORT_TEAM / IMPORT_TEAM と GET_DEFINITION が追加されました14。前回の記事6では EXPORT_TEAM の出力に Supervisor が含まれないことを見ていたので、今回は取り込む側まで試しました。

方法 Supervisor 結果
EXPORT_TEAM → 新しいユーザーのスキーマで IMPORT_TEAM 含まれない 取り込みは成功し、Supervisor の無い順番実行("process":"sequential")のチームになった。エラーも警告も出ない
EXPORT_TEAM → 同じスキーマで IMPORT_TEAM(チーム名だけ変更) 取り込めず ORA-20050: Tool SQL_TOOL already exists. で失敗。変えられるのはチーム名だけで、中のツール名は元のまま
GET_DEFINITION('TEAM', ..., '{"dependent_objects":true}') の PL/SQL を、同じスキーマで名前だけ変えて実行 含まれる 出力の先頭が CREATE_TEAM のため、そのまま先頭から実行すると参照先のエージェントが無く失敗。ツール → エージェント → タスク → チームの順に並べ替えると成功し、A2A からも Supervisor 経由で呼べた(ツールが使う関数は同じスキーマにあるもの)

新しいユーザーのスキーマに取り込んだチームは、A2A から呼べませんでした。Agent Card が HTTP 400(-32603 Failed to get agent card)、message/send が -32602 Agent not found です。原因は、取り込んだツールが元のスキーマ(DBA_COPILOT)の関数を指したままだったことでした。公式ドキュメントにも、ツールが使う自作の PL/SQL は移送されないと書かれています14。

これは、別の新しいユーザーに「自分の関数を呼ぶツール」と「見えない関数を指すツール」のチームを並べて作ると再現しました。前者は Agent Card が HTTP 200 で返り、5.8 秒で答えが返りました。後者は同じ 2 つのエラーになりました。どちらのチームも agents/ の一覧には出ています。今回、CREATE_TOOL は参照先の関数が見えない状態でもエラーを返さず、参照先の関数を呼べないことは A2A で Agent Card を取得するまで分かりませんでした。


6. 考察

6.1. A2A で呼ばれた実行を DB から追う

A2A 経由の実行は C##CLOUD$SERVICE のセッションで動き、デフォルトの統一監査には記録されませんでした(5.1 章)。DB ユーザー名でセッションや監査を絞る普段のやり方では、A2A からの利用が見えません。

実行中なら V$SESSION の module RUN_A2A_AGENT と action(A2A のタスク ID)から、終わったあとならチームの持ち主の USER_AI_AGENT_TEAM_HISTORY から追えます。後者の CONVERSATION_ID は A2A の contextId と一致するので、呼び出し側のログと突き合わせられます。

「どの外部エージェント・どの利用者から呼ばれたか」を DB 側に記録したい場合は、公式の A2A_AGENT_ACCESS_CONTEXT$9 をツールの中で読んで書き込むか、統一監査のポリシーを追加する必要があると考えられます(どちらも未検証)。

6.2. 完了の判定は DB 側の状態も見る

聞き返しでも A2A の応答は completed でした(5.2 章)。呼び出す側が A2A の状態だけで分岐すると、聞き返しを答えとして扱ってしまいます。

必要な入力をタスクの指示文(instruction)に書いておくと、聞き返しを減らせると考えられます。DB 側では WAITING_FOR_HUMAN の実行が増え続ける可能性があるため、件数を定期的に数えると、聞き返しの頻度を把握できると考えられます。

6.3. 移したあとは Agent Card で確かめる

IMPORT_TEAM はエラーも警告も出ないまま Supervisor の無いチームとして取り込み、ツールの参照先の関数を呼べなくてもエラーを出しませんでした(5.3 章)。GET_DEFINITION は Supervisor を含めて書き出しますが、実行順の並べ替えと、ツールが使う PL/SQL の移送は自分で行う必要があります。

移したあとは、A2A で Agent Card を取得して HTTP 200 が返ることを確かめるのが、今回試した中で最も手早い確認でした。一覧に出ることは確認になりません。参照先の関数を呼べないツールを持つチームも一覧に出て、逆に Supervisor 付きのチームは正常でも一覧に出ませんでした。


7. まとめ

確かめたこと 結果
外から呼べるか Always Free でもタグ 1 つで有効になり、Python(requests・a2a-sdk 0.3.26 / 1.1.4)から呼べた。所要時間は 19.1〜73.7 秒
DB からどう見えるか C##CLOUD$SERVICE のセッション(module RUN_A2A_AGENT、action はタスク ID)。履歴はチームの持ち主に記録され、CONVERSATION_ID = contextId。デフォルトの統一監査には記録されない
聞き返したとき A2A は completed、DB は WAITING_FOR_HUMAN
別スキーマへ移せるか EXPORT_TEAM/IMPORT_TEAM では Supervisor が含まれない。GET_DEFINITION は並べ替えれば Supervisor ごと作り直せる。ツールが使う PL/SQL は別に移す

外部のエージェントから ADB の中のエージェントを呼ぶことは、Always Free でもタグの付与とトークンの取得だけでできました。一方で、DB から見ると「誰が呼んだか」はデフォルトでは追いにくく、「完了したか」は A2A と DB で一致しません。A2A で公開するなら、この 2 点を DB 側でどう記録するかを先に決めておく必要があると考えられます。

参考

  1. Oracle Autonomous AI Database Serverlessの新機能(2026 年 7 月の、Select AI Agent のチームを A2A プロトコルで公開する項目) ↩

  2. A2A Protocol Specification v0.3.0(message/send・tasks/get・タスクの状態・AgentCard) ↩ ↩2 ↩3

  3. Getting Started with Oracle AutonomousDB Managed A2A Server: From Obtaining an Agent Card to Running curl Locally(Zenn・日本語。curl で message/send・tasks/get まで) ↩

  4. Google A2AをサポートしたOCI Autonomous Databaseでマルチエージェントを実装してみる(Qiita。A2A の Python SDK と OpenAI Agents SDK から呼ぶ) ↩

  5. Agent2Agentプロトコルについて ↩

  6. Oracle Autonomous AI Database の Select AI Supervisor Agent を試してみた(前回の記事。同じチーム構成) ↩ ↩2 ↩3 ↩4 ↩5

  7. エージェントのコール(外部クライアントの例は Google Gemini Enterprise のみ) ↩

  8. エージェント・カードの取得(name はチーム名、skills は CREATE_TOOL のツール) ↩

  9. A2A エージェントのセキュリティ(ページ名は「セキュリティ」。A2A_AGENT_ACCESS_CONTEXT$ の USER_IDENTITY・TEAM_NAME、追加のコンピュートを割り当てないこと) ↩ ↩2 ↩3

  10. A2Aサーバーの有効化(freeform タグ adb$feature。MCP Server と A2A Server は独立) ↩ ↩2

  11. Oracle Autonomous AI Database の MCPサーバを Claude Desktop につないで「いま重いSQL」を聞けるようにしてみた(Managed MCP Server もタグ adb$feature で有効にする) ↩

  12. OAuthクライアントを登録します(OAuth)(登録できるのは ADMIN のみ) ↩

  13. Bearerトークンの生成(grant_type: password) ↩

  14. DBMS_CLOUD_AI_AGENTパッケージ(EXPORT_TEAM・IMPORT_TEAM・GET_DEFINITION。移送されない依存物の一覧) ↩ ↩2

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?