Claude Media
Computer Useの座標ズレを直すスケーリング計算式とmacOS Retinaの罠

Computer Useの座標ズレを直すスケーリング計算式とmacOS Retinaの罠

Computer Useのクリックが外れる最大の原因は座標のスケール不一致です。画面サイズとスクリーンショットサイズの比率計算式、モデル世代ごとの上限差、macOS Retinaの2倍問題を実装コード付きで解説します。

Computer Useのクリックがずれる原因は座標スケール不一致

Computer Useツールで最初につまずくのは、たいてい「クリックした位置が微妙にずれる」現象です。原因の大半は座標のスケール不一致にあります。

Claudeが返すcoordinateは、直前に返したスクリーンショット画像のピクセル空間で表現されます。実際のディスプレイがそのスクリーンショットより大きければ、Claudeの座標をそのまま実画面へ適用するとずれます。

新しいComputer Useツールセット(computer_toolset_20260801)は、表示解像度をリクエストに含みません。旧バージョンにあったdisplay_width_pxのようなパラメータは廃止されています。つまり、スケーリングの計算とその後の座標変換は、すべてアプリケーション側のコードで担う設計です。

ツールセット自体は画像を縮小してくれません。上限を超えた画像をtool_resultに含めると、APIはバリデーションエラーでリクエストごと拒否します。エラーの原因が「単に画像が大きすぎるだけ」なのか「スケーリング計算そのものが間違っている」のかは切り分けにくく、実装初期にまとめて混乱しやすいポイントです。

zoomアクションを使った場合も座標系は変わりません。Claudeはzoomで切り出した拡大画像を見た後も、常にフルスクリーンショットのピクセル空間で座標を返します。拡大画像上の相対位置に変換されるわけではないので、zoomの実装有無にかかわらず、座標のスケーリング処理は1本化しておけます。

スケーリング計算式 — 長辺基準と総ピクセル基準の小さい方を使う

スクリーンショットは、モデルの画像サイズ上限を超えないように縮小してから返す必要があります。縮小率は「長辺の上限に対する比率」と「ビジュアルトークン数の上限に対する比率」のうち小さい方を採用します。以下はComputer Useツールセット(computer_toolset_20260801)に対応するOpus 4.7以降のモデル向けの実装です。長辺2,576px、ビジュアルトークン4,784(⌈幅 / 28⌉ × ⌈高さ / 28⌉)が上限になります。

import math
 
def get_scale_factor(width, height):
    long_edge = max(width, height)
    total_pixels = width * height
 
    long_edge_scale = 2576 / long_edge
    visual_token_scale = math.sqrt((4784 * 28 * 28) / total_pixels)
 
    return min(1.0, long_edge_scale, visual_token_scale)
 
scale = get_scale_factor(screen_width, screen_height)
scaled_width = int(screen_width * scale)
scaled_height = int(screen_height * scale)
 
# Claudeの座標を実画面へ戻すときはスケールで割り戻す
def execute_click(x, y):
    perform_click(x / scale, y / scale)

visual_token_scaleはビジュアルトークン上限からの近似値です。ビジュアルトークン数自体は⌈幅 / 28⌉ × ⌈高さ / 28⌉という切り上げ計算で決まるため、境界に近い解像度ではスケール後の幅・高さをそれぞれ28で割って切り上げ、4,784を超えていないか最後に確認すると安全です。

縮小はスクリーンショット取得時に一度だけ行い、Claudeから返ってきた座標は/ scaleで実画面のピクセルへ戻します。このscaleの値を毎回同じ計算式で再現できる状態にしておくことが、往復の一貫性を保つ条件です。値をどこかにキャッシュし忘れて再計算がずれると、その回だけクリックが外れるという再現しにくい不具合になります。

Opus 4.7以降のモデルは上限そのものが変わる

上のコード例に出てくる2576(長辺の上限ピクセル数)と4784(ビジュアルトークンの上限)は、Computer Useツールセットに対応するOpus 4.7以降のモデル向けの値です。この記事の読者が使うモデルは、基本的にすべてこちらに該当します。それ以前のモデルは、より厳しい上限を持っています。

モデル世代長辺の上限総量の上限
Opus 4.7以降(ツールセット対応モデル全て)長辺の上限2,576px総量の上限ビジュアルトークン4,784(約3.75メガピクセル相当)
それ以前のモデル長辺の上限1,568px総量の上限約1.15メガピクセル

「昔のサンプルコードをコピーしたら妙に画質が粗い」という症状が出たときは、この表のどちらの上限で計算しているかをまず疑います。旧モデル(Opus 4.7より前)を使う場合は、get_scale_factorの上限値を差し替えれば同じ関数構成のまま使えます。

def get_scale_factor_legacy(width, height):
    long_edge = max(width, height)
    total_pixels = width * height
 
    long_edge_scale = 1568 / long_edge
    total_pixels_scale = math.sqrt(1_150_000 / total_pixels)
 
    return min(1.0, long_edge_scale, total_pixels_scale)

macOS Retinaは2倍でスクリーンショットを撮る

macOSのRetinaディスプレイは、デバイスピクセル比2でスクリーンショットをキャプチャします。つまり、論理的な画面座標の2倍の解像度で画像が生成されます。これをそのままClaudeに渡すと、Claudeが認識する座標系と実際にクリックを送る座標系が2倍ズレます。

対処は2通りです。スクリーンショットを送る前に2分の1へ縮小するか、Claudeから返ってきた座標を実行前に2で割るかのどちらかです。どちらか一方だけを行い、両方を同時に行わないようにします。二重に補正すると、今度は逆方向にずれてしまいます。開発機がRetinaで本番環境がRetinaでない、という構成もあり得るため、環境ごとにデバイスピクセル比を検出してから補正を分岐させるのが安全です。

解像度はどう選ぶか

スクリーンショットの解像度は、大きければ良いというものではありません。公式ドキュメントが挙げる用途別の目安は次のとおりです。

用途解像度の目安
一般的なデスクトップ操作解像度の目安1024x768または1280x720
Webアプリケーションの操作解像度の目安1280x800または1366x768
避けるべき範囲解像度の目安1920x1080超(パフォーマンス低下を招きやすい)

スクリーンショットはbase64のPNGかJPEGでエンコードし、大きな画像は圧縮を検討します。タイムスタンプや表示状態のようなメタデータを添えておくと、後からログを追うときに役立ちます。

高い解像度を使う場合は、座標が正しくスケーリングされているかを重点的に確認します。

zoomメンバーツールで小さい対象の精度を上げる

解像度を上げずに精度を確保する手段として、zoomメンバーツールがあります。regionパラメータで[x0, y0, x1, y1]の矩形を指定すると、その範囲だけをフル解像度で切り出し、アスペクト比を保ったまま通常のスクリーンショットと同じ寸法に収めて返します。ファイル名やタブのタイトル、ステータスバーの文字、行番号、ボタンのラベルのように、縮小したフルスクリーンショットでは読み取れない小さな文字を確認したいときに使います。

Claudeが期待通りにzoomを呼ばない場合、画面全体について聞くのではなく、対象の領域や要素を名指しして質問すると呼び出されやすくなります。zoomが実装できない環境では、有効なまま放置してエラーを返し続けるのではなく、configsで明示的に無効化しておきます。

スクリーンショット履歴が増えるとキャッシュも壊れる

長時間のエージェントループは、スクリーンショットを1枚あたりおよそ1,000〜1,800入力トークン消費しながら蓄積していきます。1リクエストに含まれる画像が20枚を超えると、すべての画像がより厳しいサイズ制限の対象になります。対策は、各スクリーンショットの長辺を2000px以下に抑えるか、20枚以下になるよう古いものを間引くかのどちらかです。

間引き方にもコツがあります。毎ターン1枚ずつ削除すると、プロンプトキャッシュの接頭辞が毎回変わってしまい、キャッシュが効かなくなります。直近3枚を残して25ターンごとにまとめて間引く、といった「間引きをバッチで行う」運用にすると、間引きが起きないターンの間はキャッシュの接頭辞がバイト単位で同一に保たれます。

Claude Fable 5.1を使う場合はさらに注意が必要です。クライアント側で古いスクリーンショットを削除すると、それ以降のすべてのthinkingブロックが無効になります。Fable 5.1では削除ではなく、スクリーンショットを2000px以下にリサイズしたうえで、サーバー側のtool result clearingで古いものをコンテキストから落とす方法が推奨されています。

実行前に座標をバリデーションする

スケーリングを正しく実装しても、Claudeが画面外の座標を返すことはあり得ます。実際にクリックへ渡す前に、座標がディスプレイの範囲内に収まっているかを確認しておくと、範囲外クリックによる不可解な挙動を未然に防げます。

display_width, display_height = 1024, 768
 
def validate_action(action_type, params):
    if action_type == "left_click" and "coordinate" in params:
        x, y = params["coordinate"]
        if not (0 <= x < display_width and 0 <= y < display_height):
            return False, "Coordinates out of bounds"
    return True, None

バリデーションで弾いた場合は、実行をスキップしてis_error: trueのツール結果を返します。スケーリングの計算式やRetina補正にバグが残っていると、この範囲外エラーが高頻度で出るようになるため、実装初期の動作確認にも使える簡易的な検知手段になります。あわせて、実行したアクションと結果をログに残しておくと、後から「どのターンでスケールがずれ始めたか」を追いやすくなります。

スクリーンショット取得が失敗したときの返し方

画面ロックやディスプレイの一時的な不可用性で、スクリーンショットの取得自体が失敗することもあります。この場合もtool_resultの形式は変えず、is_error: trueと失敗理由を短いテキストで返します。

{
  "type": "tool_result",
  "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
  "toolset_name": "computer",
  "content": "Error: Failed to capture screenshot. Display may be locked or unavailable.",
  "is_error": true
}

画面外座標や範囲外クリックも同じ形式で返します。バッチアクションの途中でこのエラーが発生した場合は、残りのブロックを実行せず、決まった文言でスキップした旨を返す必要があります。座標のスケーリングそのものとは別問題ですが、スケーリングのバグはこの経路でエラーとして表面化することが多いため、実装を分けて考えるより一体でログを見る方が原因特定は早くなります。

症状から原因を切り分ける早見表

座標のスケーリングに関連する不具合は、症状ごとに疑うべき箇所が異なります。実装を見直す前に、次の対応関係で当たりを付けておくと遠回りを避けられます。

症状まず疑う箇所
クリックが一定方向にずれ続けるまず疑う箇所スクリーンショットと実画面のサイズ比を計算していない
macOSでだけクリックが2倍近くずれるまず疑う箇所Retinaのデバイスピクセル比2を補正していない
Opus 4.7以降で画質が妙に粗いまず疑う箇所旧モデル向けの上限(1568px / 1.15MP)をそのまま使っている
長時間のループで途中から挙動が不安定になるまず疑う箇所スクリーンショット履歴が20枚を超え、より厳しい制限の対象になっている

いずれも「Claudeが見ている画像の座標系」と「実際にクリックを送る座標系」がどこかでずれているという点は共通しています。実装を分けて考えるより、スケーリング処理を1箇所にまとめてログを仕込んでおく方が、後から原因を追いやすくなります。

まとめ

Computer Useのクリックがずれる最大の原因は座標のスケール不一致です。スクリーンショットを縮小したら、その縮小率をアプリケーション側で保持し、Claudeが返す座標を実画面へ戻すときに使います。計算式に使う上限値(長辺・総量)はモデル世代で変わるため、Opus 4.7以降のツールセット対応モデルを使うなら新しい上限(2,576px / ビジュアルトークン4,784)に合わせます。macOS Retinaは2倍のデバイスピクセル比が原因なので、縮小か座標補正のどちらか一方で対処します。小さい対象を正確に読ませたいなら解像度全体を上げるよりzoomを使う方が実装コストも低くなります。実装の骨格自体はComputer Useツールを自前実装する最小構成で扱っているので、エージェントループ全体を組む前にあわせて確認してください。スケーリングを直してもクリックが外れる場合は、クリックが外れる4パターンの診断表に他の原因がまとまっています。

この記事を共有:XはてブLinkedIn