先に結論
AIエージェントは、同じ検索や失敗したAPI呼び出しを繰り返してしまうことがあります。
そこで使えるのが、**呼び出しを識別する「指紋化」と、履歴から繰り返しを見つける「循環検出」**です。
ここでは、この2つの設計を Tool-Call Fingerprinting と Repetition Cycle Detection と呼びます。
1. まず、呼び出しに「指紋」を付ける
例えば、同じ検索ツールに同じ引数を渡しているなら、同じ呼び出しとして扱いたいです。
そのために、ツール名と引数を一定の形式に揃えてハッシュ化します。
import hashlib
import json
def fingerprint(tool, args):
payload = json.dumps(
{"tool": tool, "args": args},
sort_keys=True,
ensure_ascii=False,
separators=(",", ":"),
)
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
これはJSONで表現できる引数を想定した最小例です。キーの順序が違っても、同じ指紋になります。
ただし、表現の違う検索文が同じ意味かどうかまでは判定しません。
2. 指紋だけでは、ループは分からない
指紋化は「同じ呼び出しか」を調べる仕組みです。
循環検出では、さらに直近の呼び出し履歴を見ます。
| パターン | 確認すること |
|---|---|
| A → A → A | 同じ呼び出しが連続していないか |
| A → B → A → B | 同じ呼び出し列が繰り返されていないか |
| 同じ呼び出し・同じ結果 | 処理が進んでいるか |
例えば、検索して、ページを読んで、また同じ検索に戻る。
1回ずつは正常でも、履歴全体を見ると循環していることがあります。
3. 「繰り返し」と「進展なし」を分ける
同じツールを使うこと自体は問題ではありません。
ジョブの完了待ちや、一時的なエラーへの再試行でも、同じ呼び出しは発生します。
だから、入力だけでなく、結果やタスクの状態も確認する必要があります。
OpenClawの公式資料でも、同じツール・入力・結果の繰り返しや、進展のないポーリングを検出対象にしています。
結果を比較するときは、時刻やリクエストIDなど、毎回変わる項目だけで「進展あり」と判断しない設計が大事です。
4. 検出した後の動きも決めておく
実装するなら、次のような段階を設けると扱いやすいと思います。
- 繰り返しを検出したら、理由を添えて警告する
- 続く場合は、別の検索条件や手段への変更を促す
- 改善しなければ停止し、未解決の内容を返す
回数のしきい値は、ツールごとに調整します。ポーリングには、間隔と制限時間も必要です。
まずは呼び出し履歴を記録し、どこで同じ処理に戻っているかを見る。
そこから始めると、止める条件も決めやすくなります。
