AIエージェントが存在しないツールを呼び出す原因|Tool Callingのハルシネーション対策

AIエージェントが存在しないツールを呼び出す原因|Tool Callingのハルシネーション対策 AI開発

AIエージェントにFunction CallingやTool Callingを実装していると、登録していないツール名をモデルが返したり、現在は利用できないツールを呼び出そうとしたりすることがあります。

たとえばアプリ側ではsearch_productsしか登録していないのに、モデルから次のような呼び出しが返ってくるケースです。

モデルが返すfunction_call
{
  "type": "function_call",
  "name": "search_database",
  "arguments": "{\"query\":\"gaming pc\"}"
}

search_databaseというツールが存在しなければ、そのまま実行することはできません。

こうした現象は「Tool Callingのハルシネーション」と呼ばれることがありますが、必ずしもモデルだけが原因とは限りません。

プロンプトに削除済みのツール名が残っている、似た役割のツールが多すぎる、実行時に利用できるツールとモデルへ見せているツールが異なる、過去の会話履歴に古いFunction Callが含まれている、といったアプリ側の問題でも発生します。

すでに発生している「tool not found」エラーを1件ずつ切り分けてデバッグする手順はFunction Callingで「tool not found」になる原因|ツール名・登録漏れ・スキーマを確認で解説しています。この記事では逆の視点から、ハルシネーションやツール解決の失敗をそもそも起こしにくくするための設計を中心に解説します。ツール名やRegistry構成の実行時チェック自体は前の記事の設計をそのまま使う前提で進めます。

スポンサーリンク

AIエージェントはコード内の関数を直接探しているわけではない

最初に理解しておきたいのは、LLMがアプリケーション内のJavaScriptやPythonコードを直接検索して、利用可能な関数を判断しているわけではないという点です。

Function Callingでは、アプリ側からモデルへツール定義を渡します。

たとえばOpenAI Responses APIでは、リクエストのtoolsにFunction Toolを指定できます。モデルは渡された情報をもとに、どのツールを使うべきか判断します。現在のAPIではtool_choiceによって使用可能なツールや選択方法を制御することもできます。

概念的には次のような構造です。

src/tools.js
const tools = [
  {
    type: "function",
    name: "search_products",
    description: "商品データベースから商品を検索する",
    parameters: {
      type: "object",
      properties: {
        query: {
          type: "string"
        }
      },
      required: ["query"],
      additionalProperties: false
    },
    strict: true
  }
];

モデルが返すのは、あくまで「このツールを呼びたい」という要求です。

function_call
{
  "type": "function_call",
  "name": "search_products",
  "arguments": "{\"query\":\"RTX 5070\"}"
}

その後、アプリ側がsearch_productsという名前を実際の関数へ対応付けます。

src/registry.js
const toolRegistry = {
  search_products: searchProducts
};

つまりTool Callingでは、モデルの判断とアプリ側の実行処理が分離されています。

このため「存在しないツールを呼んだ」という現象も、モデルだけを見るのではなく、モデルへ何を見せたか、プロンプトに何を書いたか、実行時に何が登録されていたかまで確認する必要があります。個々の原因を1つずつ切り分ける手順はFunction Callingで「tool not found」になる原因にまとめているため、この記事ではこうした不整合自体を起こしにくくする設計へ進みます。

Few-shot例に古いTool Callが残っている

Tool Callingの精度を上げるために、過去のTool Callを例としてプロンプトへ含めている場合にも注意が必要です。

たとえば次のような例です。

古いFew-shot例
ユーザー:
商品を検索してください。

Assistant:
search_databaseを使用します。

現在のツール名がsearch_productsに変更されていても、この例が残っていればモデルが古い名称へ引っ張られる可能性があります。

特にFew-shot例は、「こういう状況ではこう行動する」という強い手掛かりとしてモデルへ渡されます。

ツール構成を変更するときは、Function定義だけを更新するのではなく、Tool Callingを含むサンプル会話も同時に更新したほうが安全です。プロンプト本文や会話履歴に古いツール名が残っていないかを網羅的に確認する方法は前の記事で解説しています。

似た名前のツールが多すぎる

存在しない完全に架空のツールだけでなく、「既存ツールを混ぜたような名前」が生成される場合もあります。

たとえば次のようなツールを大量に登録しているケースです。

区別しづらい例
search_user
find_user
get_user
get_user_profile
search_user_profile
find_customer
get_customer

人間でも使い分けが分かりにくい構成です。

このようなツールセットでは、モデルが名前や役割を混同しやすくなります。

OpenAIの公式ガイダンスでも、タスクに関連するツールだけを公開し、説明を簡潔かつ正確にすることが推奨されています。

名前についても役割が分かるようにします。

役割が分かる名前
search_customer_by_name
get_customer_by_id
update_customer_email

このようにすれば、「検索」「取得」「更新」の用途を区別しやすくなります。

descriptionが曖昧だと間違ったツールを選びやすい

Tool Callingではツール名だけでなくdescriptionも重要です。

次のような説明では情報が不足しています。

情報不足
{
  name: "search_products",
  description: "検索します"
}

何を検索するのか、いつ使うのか分かりません。

もう少し具体的にします。

具体的な例
{
  name: "search_products",
  description:
    "商品カタログから商品名・型番を検索する。ユーザー情報や注文情報の検索には使用しない。"
}

ツール同士の用途が近い場合は、「何に使うか」だけでなく「何には使わないか」を書くのも有効です。

たとえば注文検索と商品検索があるなら、

境界を明示する例
商品そのものを探す場合に使用する。購入済み注文の検索には使用しない。

のように境界を明示できます。

OpenAI公式ドキュメントでも、ツールのdescriptionには返り値のフィールド・型・エラー時の挙動を明記することが案内されています。Tool Callingで重要なのは、モデルへツールの存在を知らせるだけではなく、どの状況でどのツールを選択し、成功・失敗時に何が返るかまで判断できる情報を与えることです。

1つのツールに役割を詰め込みすぎない

逆に、ツール数を減らそうとして1つのFunctionにあらゆる処理を持たせるのも問題になります。

たとえば次のようなツールです。

汎用ツール
manage_data

descriptionには、

曖昧な説明
ユーザー検索、商品検索、注文更新、メール送信、データ削除などを行います。

と書かれているとします。

これでは入力Schemaも複雑になり、モデルが何を指定すればよいのか分かりにくくなります。

Tool Callingでは「ツールを細かくしすぎる」と選択肢が増えすぎますが、「巨大な万能ツールにする」と入力の意味が曖昧になります。

適切な粒度で役割を分けることが重要です。

たとえば読み取り系なら、

読み取り系
search_products
get_order
get_customer

変更系なら、

変更系
update_order_status
update_customer_email

といった形です。

名前だけを見ても副作用の有無を判断できるようにすると、人間によるログ確認もしやすくなります。

モデルへ毎回すべてのツールを渡さない

Agentが大規模になると、50個、100個とツールが増えることがあります。

しかし、ユーザーが天気を聞いているだけなのに、支払い処理、メール送信、ユーザー削除、商品登録、データベース更新などのツールまでモデルへ渡す必要はありません。

OpenAIの公式ガイダンスでも、タスクに関連するツールだけを公開することが推奨されています。

たとえば処理前にタスクを分類し、天気関連なら、

src/tools-weather.js
const tools = [
  getWeatherTool,
  getForecastTool
];

だけを渡します。

商品検索なら、

src/tools-products.js
const tools = [
  searchProductsTool,
  getProductTool
];

だけにします。

選択肢が少なくなれば、モデルが誤ったツールを選ぶ余地も減ります。

これは精度だけでなく、意図しない副作用を持つツールを呼ばせないというセキュリティ面でも重要です。

ツールが30〜50個を超えたあたりから選択精度が落ち始める

前のセクションのように処理内容でツールを絞り込む工夫をしても、Agentが扱う機能自体が増え続ければ、いずれツール数の絶対的な多さが問題になります。

Anthropicの公式ドキュメントでは、登録するツールがおよそ30〜50個を超えたあたりから、モデルのツール選択精度が低下し始めると案内されています。

公式ドキュメントは、次のような状況をTool Search導入の検討基準として挙げています。

導入を検討する基準
登録ツールが10個を超えている

ツール定義だけで10,000トークンを超えている

ツール数が増えるにつれて選択精度が落ちている

MCP経由でツールを集約し200個を超える規模になっている

今後もツールライブラリが増え続ける見込みがある

たとえばGitHub・Slack・Sentry・Grafana・Splunkのような複数のMCPサーバーを1つのAgentへまとめて接続すると、ツール定義だけで55,000トークン前後を消費することがあります。公式ドキュメントでは、Tool Searchを使うことでこの消費を85%以上削減し、実際にロードされるツールを3〜5個程度まで絞り込めると案内されています。

ただし、すべてのツールを検索対象にする必要はありません。最もよく使う3〜5個程度のツールは検索を経由させず、常にモデルへ見せておいたほうが応答が速く安定します。

ツールが多い場合はRouter Agentとカテゴリ分けで絞り込む

前のセクションのように、「天気関連ならこの2つだけ」「商品検索ならこの2つだけ」という形で先に処理を分類してから必要なツールだけを渡す構成は、Router Agentと呼ばれることがあります。

Router Agent自体は追加のツールを持たず、ユーザーの入力がどのカテゴリに属するかだけを判断し、該当カテゴリのツール一式を後続のAgentへ引き継ぎます。

カテゴリが2〜3種類ならこの分岐を自前で書いても管理できますが、カテゴリ数が増えるとルーティングロジック自体が複雑になります。

OpenAI Agents SDKには、このグループ化を仕組みとして提供するtool_namespaceがあります。公式ドキュメントの例では、CRM・請求(billing)・配送(shipping)のようにツールをまとめて登録できます。

src/tool_namespace_example.py
from agents import tool_namespace

crm_tools = tool_namespace(
    name="crm",
    description="顧客情報の検索・更新を行うツール群",
    tools=[search_customer, update_customer_email],
)

billing_tools = tool_namespace(
    name="billing",
    description="請求・支払い状況を確認するツール群",
    tools=[get_invoice, get_payment_status],
)

shipping_tools = tool_namespace(
    name="shipping",
    description="配送状況を確認するツール群",
    tools=[get_shipment_status, get_tracking_number],
)

Namespaceごとに名前とdescriptionを持たせることで、モデルはまず「どのNamespaceに関係する要求か」を判断してから、そのNamespace配下のツールだけを詳しく検討できます。個別のFunctionを1つずつ見比べるより、カテゴリ単位で絞り込んだほうが、似た名前のツールを取り違えるリスクも下がります。

Tool Searchで必要なツールだけを動的にロードする

Namespaceによるグループ化は人間が事前にカテゴリを設計する方法ですが、Tool Search機能を使うと、ツール自体の検索をモデルに任せることができます。

OpenAI Agents SDKでは、個々のツールにdefer_loading=Trueを指定すると、そのツールは名前だけが登録された状態になります。AgentへToolSearchTool()を追加すると、モデルが必要に応じてツールを検索してから呼び出せるようになります。

src/tool_search_openai.py
from agents import Agent, function_tool, ToolSearchTool

@function_tool(defer_loading=True)
def search_customer_by_name(name: str) -> dict:
    """顧客名から顧客情報を検索する"""
    ...

agent = Agent(
    name="support-agent",
    tools=[search_customer_by_name, ToolSearchTool()],
)

Anthropicのツール定義でも同様に、個々のツールへ"defer_loading": trueを指定し、あわせてtool_search_tool_regex_20251119またはtool_search_tool_bm25_20251119のいずれかのTool Searchツールを登録します。

tools.json
{
  "tools": [
    {
      "type": "tool_search_tool_bm25_20251119",
      "name": "tool_search"
    },
    {
      "name": "search_customer_by_name",
      "description": "顧客名から顧客情報を検索する",
      "defer_loading": true,
      "input_schema": {
        "type": "object",
        "properties": {
          "name": { "type": "string" }
        },
        "required": ["name"]
      }
    }
  ]
}

公式ドキュメントでは、1リクエストあたり最大10,000個までのツールを遅延ロード対象にでき、Tool Search自体もデフォルトで5件、limit指定で最大10,000件まで検索結果を返せるとされています。

allowed_toolsで利用可能なツールを制限する

OpenAI APIでは、すべてのツール定義を維持しながら、そのターンでモデルが使用できるツールだけを制限する方法もあります。

現在はtool_choiceallowed_toolsを利用できます。

たとえば多数のツールを登録していても、その処理では天気取得とドキュメント検索しか許可したくない場合、次のように制限できます。

allowed_toolsの例
{
  "tool_choice": {
    "type": "allowed_tools",
    "mode": "auto",
    "tools": [
      {
        "type": "function",
        "name": "get_weather"
      },
      {
        "type": "function",
        "name": "search_docs"
      }
    ]
  }
}

OpenAIのドキュメントでは、allowed_toolsを使うことでモデルが利用できるツールをサブセットへ制限でき、渡すツール定義自体は変更しないためPrompt Cachingを維持したまま安全性や予測可能性を高められると説明されています。

特に「読み取り処理中は更新系ツールを使わせたくない」といったケースで有効です。

tool_choice=”required”を安易に使わない

Tool Callingを確実に利用させるため、

安易な設定
tool_choice = required

にしているケースがあります。

OpenAI APIではautoならモデルがツールを使うかどうかを判断し、requiredなら少なくとも1つのツールを呼ぶ必要があります。またnoneならツールを呼ばせず、特定のツール名を指定して強制することもできます。

しかし、ユーザーの要求に適切なツールが存在しない状態でrequiredにすると問題になります。

モデルには「必ず何か使え」と指示しているのに、適切な選択肢がありません。

たとえばツールが、

登録されているツール
get_weather
search_products

しかない状態で、

ツール不要な質問
2+2はいくつ?

と聞かれ、それでもツール利用を必須にすれば、不自然なツール選択を誘発します。

ツールが不要な質問にも対応するAgentなら、基本的にはautoを検討したほうが自然です。

逆に「必ずデータベースから最新データを取得して回答する」など、ツール利用が業務要件になっている処理ではrequiredが適しています。ツール名を変更したときにtool_choice側の指定が古いまま残っていないかを確認する方法は前の記事で解説しています。

動的にツールを切り替える場合はモデルと実行側を同じ条件から生成する

AIエージェントでは、ユーザー権限や契約プランによって利用可能なツールを変更することがあります。

この仕組み自体は問題ありませんが、モデルへ渡すツール一覧と実行側Registryの生成条件が別々になっているとズレが発生し、モデル側には見えているのに実行側には存在しないツールが生まれます。

これをモデルのTool Callingハルシネーションだと判断してしまうと、原因を見誤ります。

モデルへ公開するツールと実際に実行できるツールは、可能であれば同じRegistryから生成したほうが安全です。このズレが起きたときの発見・切り分け手順(会話履歴やtool_choiceの古い指定を含む)は前の記事にまとめています。

モデルが返したツール名をそのまま実行してはいけない

Tool Callingのハルシネーション対策で最も重要な実装の1つが、ツール名のallowlistです。

モデルが、

危険な名前
delete_all_users

という名前を返したからといって、その名前をそのまま動的に実行してはいけません。

危険なのは、次のような発想です。

危険な実装
await globalThis[toolCall.name](args);

あるいは文字列から任意のモジュールやコマンドを解決するような実装です。

モデル出力は必ず信頼できない入力として扱い、事前登録したRegistryに存在するものだけを実行します。

安全な実装
const tool = toolRegistry[toolCall.name];

if (!tool) {
  return {
    success: false,
    error: "UNKNOWN_TOOL"
  };
}

return await tool.handler(args);

つまり、モデルが存在しないツールを生成すること自体を完全にゼロにできなくても、存在しないツールを実際に実行できない設計にしておくことが重要です。この実行時チェックの基本パターン自体は前の記事で解説したRegistry設計と同じものを使います。

引数についてもモデル出力を信用しない

ツール名だけ正しければ安全というわけではありません。

たとえば、

delete_user
delete_user

という正規のツールが存在していても、モデルが意図しないユーザーIDを渡す可能性があります。

そのためTool Callingでは、ツール名の検証に加えて引数Schemaも重要になります。

OpenAI Function ToolではstrictなSchemaを利用でき、型や必須フィールドなどを制約できます。

ただしSchemaを通過したからといって、業務上その操作を許可してよいとは限りません。

たとえば、

引数の例
{
  "user_id": "123"
}

が型として正しくても、現在ログインしているユーザーにID 123を削除する権限があるとは限りません。

認可処理はLLMに任せず、ツール実行側でも必ず確認する必要があります。

読み取りツールと変更ツールを分ける

ハルシネーションが特に危険なのは、副作用を持つツールです。

検索ツールを間違えても、多くの場合は検索に失敗するだけです。

しかし、

副作用のあるツール
delete_user
send_email
refund_payment
deploy_production

のようなツールを誤って呼ぶと、実際のデータや外部システムへ影響します。

そのため、読み取り処理と書き込み処理を明確に分ける設計が重要です。

たとえば、

get_order
get_order

update_order
update_order

を別Functionにします。

さらに変更系のツールについては、Tool Callingが返っただけで即実行せず、アプリ側で追加確認を挟む設計も有効です。

AIエージェントでは「モデルに選ばせること」と「実行を許可すること」を同じ意味にしないことが重要です。

Tool Callを実行する前にサーバー側で検証する

安全なTool Callingでは、モデルの出力を最終決定として扱いません。

たとえば実行前に、

実行前の検証
const allowedTools = new Set([
  "search_products",
  "get_product"
]);

if (!allowedTools.has(toolCall.name)) {
  return {
    error: "Tool is not available"
  };
}

のように検証します。

その後に引数をSchemaで検証し、さらにユーザー権限や現在の状態を確認してから実際の処理を行います。

この層を設けておけば、モデルが架空のツール名を返したとしても、その時点で止められます。

再試行回数には上限を設ける

存在しないツールを呼ぶたびにモデルへ再試行させると、別の問題が発生します。

たとえば、

search_database
search_database

が存在しないためエラーを返します。

モデルが次に、

database_search
database_search

を生成します。

それも存在しないので再びエラーを返します。

さらに、

find_database
find_database

を生成する、といったループに入る可能性があります。

この状態を無制限に続けると、APIコストとレイテンシだけが増えます。

そのためAgent Runner側で最大ターン数やツールエラーの最大再試行回数を決めておくことが重要です。

一定回数失敗したら、

終了メッセージ
利用可能なツールでは要求を処理できませんでした。

として終了する設計のほうが安全です。ステップ数・料金・時間などを複数の上限で組み合わせて止める設計は、AIエージェント全般の無限ループ対策として扱っています。

遅延ロードするツールでは「まだ読み込まれていない」ケースもある

前述のTool Searchやdefer_loadingを導入すると、ツールは「システムに存在するかどうか」と「そのターンでモデルが利用できるかどうか」が別問題になります。

このような構成では、

存在する
ツール自体はシステムに存在する

のと、

利用できる
現在のターンでモデルが利用できる

のは別問題です。

ツール検索や遅延ロードを導入してから「tool not found」が増えた場合は、ツールが存在するかだけでなく、呼び出し時点で正しくロードされているかも確認してください。

descriptionを変更したら評価用テストを作る

Tool Callingの精度を上げるためにdescriptionを書き換えても、本当に改善したかは数回試しただけでは分かりません。

実運用では、代表的なユーザー入力を保存しておき、Tool Callingの回帰テストを作ると効果的です。

たとえば、

入力例1
RTX 5070の商品を探して

なら、

期待する選択
search_products

が選ばれることを期待します。

一方、

入力例2
注文番号12345の状態を確認して

なら、

期待する選択
get_order

が選ばれるべきです。

さらに、

入力例3
こんにちは

のように、本来ツールを必要としない入力もテストします。

ツールを追加するたびにこれらを再実行すれば、新しいFunctionによって既存のTool Routingが悪化していないか確認できます。

OpenAIの公式ガイダンスでも、Tool Callingを含む構成変更では代表的なタスクで評価し、成功率や最終回答品質などを比較することが推奨されています。

モデル変更時にもTool Callingを再テストする

同じプロンプト、同じツール定義でも、モデルを変更するとツール選択の傾向が変わる可能性があります。

そのため、

変更内容
モデルをアップグレードした

直後にTool Callingエラーが増えた場合は、コードだけを見るのではなく、既存のTool Routingテストも再実行してください。

特にツール数が多いAgentでは、

確認項目
どのFunctionを選んだか

不要なTool Callが増えていないか

ツールなしで回答すべき質問にTool Callしていないか

存在しない名前を生成していないか

を評価することが重要です。

Tool Callingは単に「Function CallがJSONとして成功したか」だけではなく、「正しいFunctionを選択したか」まで評価する必要があります。

プロンプトだけで完全に防ごうとしない

存在しないツールを呼ばせないために、

強い指示例
絶対に存在しないツールを使用しないでください。
利用可能なツールだけを使ってください。

と強く書きたくなるかもしれません。

こうした指示が補助になることはあります。

しかし、安全性をプロンプトだけへ依存するべきではありません。

モデル出力は確率的です。

プロンプトが正しくても、履歴、ツール数、モデル変更、複雑なタスクなどによって予想外の出力が発生する可能性があります。

そのためTool Callingでは、

モデル側
モデル側では正しいツールを選びやすくする

のと同時に、

アプリ側
アプリ側では間違ったツールを実行できないようにする

という二重の対策が重要です。

Tool Callingのハルシネーション対策に関するよくある質問

Qtool not foundエラーが出たらまずこの記事から読むべきですか

Aすでにエラーが発生している場合は、名前の不一致・登録漏れ・古い会話履歴などを1つずつ切り分けるFunction Callingで「tool not found」になる原因を先に確認することをおすすめします。この記事は同じ問題を未然に防ぐための設計・予防の視点です。

Qツール名は何個まで登録して大丈夫ですか

A上限は仕組み上決まっていませんが、数が増えるほどモデルが似た名前を混同しやすくなります。タスクに関連するツールだけをそのターンへ渡す、allowed_toolsで絞り込む、必要なら遅延ロードを使うといった方法で、モデルへ見せる選択肢自体を減らすほうが安全です。

Qallowed_toolsと特定のFunction名を指定するtool_choiceの違いは何ですか

A特定のFunction名を指定するtool_choiceはそのツールを必ず1つ呼ばせる強制です。allowed_toolsはツール定義全体は維持したまま、そのリクエストで選べる候補をサブセットへ絞り込みます。定義自体を書き換えないためキャッシュを維持しやすい利点があります。

Qtool_choice=”required”はいつ使うべきですか

Aツール利用が業務要件になっている処理、たとえば必ず最新データを取得して回答する必要がある場合に向いています。ツールが不要な質問にも対応する汎用的なAgentでrequiredを使うと、無理なツール選択を誘発しやすくなります。

Qモデルが返したツール名は絶対に信用してはいけませんか

Aはい。モデル出力は確率的であり、プロンプトを工夫しても予期しない名前が返る可能性を完全にはなくせません。事前登録したRegistryに存在する名前だけを実行し、存在しない名前はエラーとして扱う設計を必ず用意します。

Q遅延ロードしたツールでtool not foundが増えた場合はどうすればよいですか

Aツールがシステム上に存在することと、そのターンでモデルが利用できる状態にあることは別問題です。defer_loadingやtool searchを導入している場合は、呼び出し時点でそのツールが正しくロードされているかを確認してください。

QTool Callingの精度はどうやって評価すればよいですか

A代表的なユーザー入力と期待するツール選択の組み合わせをテストケースとして保存し、descriptionの変更やモデルのアップグレードのたびに再実行します。正しいFunctionが選ばれているか、不要なTool Callが増えていないかを継続的に確認します。

まとめ

AIエージェントが存在しないツールを呼び出す場合、単純にモデルの性能不足と考えるのではなく、ツールをどのように見せているかを確認する必要があります。

似た名前のツールが増えすぎていないか、descriptionが曖昧になっていないか、1つのツールへ役割を詰め込みすぎていないかを見直してください。

さらに、毎回すべてのFunctionを公開するのではなく、タスクに必要なツールだけを渡したり、OpenAI APIのallowed_toolsなどで利用可能な範囲を絞ったりする方法も有効です。ツール数が30〜50個を超えるような規模になってきた場合は、Router AgentやNamespaceによるカテゴリ分け、Tool Searchによる遅延ロードも検討してください。

それでも存在しないTool Callが返る可能性を前提として、アプリ側では必ずallowlistやRegistryを使ってツール名を検証し、引数の権限確認、読み取り/変更の分離、実行前のサーバー側検証まで含めた多層防御にします。

すでに発生しているエラーを1件ずつ切り分ける具体的な手順や、Registry設計・tool_not_found_behaviortool_name_collision_policyといった実行時の仕組みはFunction Callingで「tool not found」になる原因で解説しています。

Tool Callingのハルシネーションを完全にモデル側だけでなくすのではなく、正しいツールを選びやすい設計にし、それでも存在しないツールが返ってきたときに実行できないようにすることが、安定したAIエージェントを作るうえで重要です。