GASでClaude APIの拡張思考で
複雑な判定の精度を上げる方法

「規則に照らした可否判定」「条件が絡み合う分類」など、一発で答えを出しにくい処理は、thinking(拡張思考/Extended Thinking)を使うと精度が上がりやすくなります。GASからの有効化と、思考の深さ・コストの調整方法を解説します。

|対象: GAS / Claude API / 拡張思考

Table of Contents

拡張思考とは何か、なぜ精度が上がるのか

拡張思考(Extended Thinking)とは、AIが最終的な回答を出す前に、内部で段階的に考える時間を取る仕組みです。 人間が難しい問題を紙に書き出しながら解くのと同じで、途中の推論を挟むことで、複数の条件を順番に検討したり、計算を確かめたりできます。

効果が出やすいのは「一目で答えが決まらない処理」です。以下のようなケースでは、拡張思考なしより精度が上がりやすくなります。

規則に照らした可否判定

複数の社内ルールを順に当てはめて「承認/要確認/差し戻し」を決める

条件が絡み合う分類

金額・科目・相手先など複数の情報を突き合わせて分類する

計算を伴うチェック

上限額の超過や割合の計算をしてから可否を判断する

曖昧な入力の整理

表記ゆれや欠損を考慮しながら妥当な結論を導く

逆に、短い要約や単純な二値分類では効果が小さく、思考トークン分のコストと時間が増えるだけになりがちです。 「難しい処理にだけ使う」のが基本方針です。

GASからadaptive thinkingを有効にする

GASからはUrlFetchAppでClaude APIを呼び出します。拡張思考を使うには、リクエストのpayloadthinking: { type: "adaptive" }を1行足すだけです。adaptive(アダプティブ)は、モデルが「どれくらい考えるか」をタスクに応じて自動で決めるモードです。

// 拡張思考(adaptive thinking)を有効にした最小の呼び出し
function askWithThinking(prompt) {
  const apiKey = PropertiesService
    .getScriptProperties()
    .getProperty("CLAUDE_API_KEY");

  const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01",
    },
    payload: JSON.stringify({
      model: "claude-opus-4-8",
      max_tokens: 4096,
      thinking: { type: "adaptive" }, // ← これだけで拡張思考が有効になる
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  });

  const data = JSON.parse(res.getContentText());

  // content は複数ブロックの配列。回答本文は type: "text" のブロック
  const textBlock = data.content.find((b) => b.type === "text");
  return textBlock ? textBlock.text : "";
}

ポイントは、レスポンスのcontentが複数ブロックの配列になることです。思考ブロックと回答本文が別々に入るため、回答はtype === "text"のブロックから取り出します。なおthinkingを指定しないと思考なしで動くので、精度を上げたい処理では明示的に付けます。

APIキーはPropertiesServiceに保管し、コードに直接書かないのが安全です。保管方法は関連記事のClaude API入門で解説しています。

effortで思考の深さとコストを調整する

思考の深さはoutput_config.effort(努力レベル)で調整します。指定できるのはlow/medium/high/xhigh/maxの5段階で、省略時はhigh相当です。難しい判定はhigh以上、軽い処理はlowと使い分けると、精度とコストのバランスが取りやすくなります。

// effort(努力レベル)で思考の深さとコストを調整する
function askWithEffort(prompt, effort) {
  const apiKey = PropertiesService
    .getScriptProperties()
    .getProperty("CLAUDE_API_KEY");

  const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01",
    },
    payload: JSON.stringify({
      model: "claude-opus-4-8",
      max_tokens: 4096,
      thinking: { type: "adaptive" },
      // effort は output_config の中。low / medium / high / xhigh / max
      // 省略時は high 相当。難しい判定は high 以上、軽い処理は low
      output_config: { effort: effort || "high" },
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  });

  const data = JSON.parse(res.getContentText());
  const textBlock = data.content.find((b) => b.type === "text");
  return textBlock ? textBlock.text : "";
}

effortoutput_configの中に入れる点に注意してください(トップレベルではありません)。高い努力レベルほど思考トークンが増えて精度が上がる一方、 料金と応答時間も増えます。

思考の要約(display)を受け取る

判定の根拠を確認したいときは、思考の要約を受け取れます。新しいモデルの既定ではthinkingブロックは返るものの本文が空です。display: "summarized"を付けると、推論の要約がthinkingブロックに入ります。

// 思考の「要約」を受け取る(display: "summarized")
function askAndLogThinking(prompt) {
  const apiKey = PropertiesService
    .getScriptProperties()
    .getProperty("CLAUDE_API_KEY");

  const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01",
    },
    payload: JSON.stringify({
      model: "claude-opus-4-8",
      max_tokens: 4096,
      // display を付けないと thinking ブロックの本文は空のまま返る
      thinking: { type: "adaptive", display: "summarized" },
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  });

  const data = JSON.parse(res.getContentText());

  const thinkingBlock = data.content.find((b) => b.type === "thinking");
  const textBlock = data.content.find((b) => b.type === "text");

  Logger.log("思考の要約: " + (thinkingBlock ? thinkingBlock.thinking : "(なし)"));
  return textBlock ? textBlock.text : "";
}

返るのはあくまで「要約」で、生の思考そのものは取得できません。またdisplayは表示の有無を切り替えるだけで、思考自体は常に行われ、料金も同じようにかかります。ログや監査で「なぜその判定になったか」を残したいときに便利です。

実践:スプレッドシートの難しい判定を自動化する

拡張思考が活きるのは、単純な分類ではなく複数条件の突き合わせが必要な判定です。 例として、経費申請の各行を社内規則に照らして「承認/要確認/差し戻し」に振り分けます。 セクション03で作ったaskWithEffortを呼び出します。

// スプレッドシートの経費行を「規則に照らして」判定する
// 単純な分類ではなく、複数条件の突き合わせが必要なケースに向く
function judgeExpenseRows() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("経費申請");
  const values = sheet.getDataRange().getValues();
  const header = values[0];
  const rows = values.slice(1);

  const RULE = [
    "会議費は1人あたり5000円以下なら承認、超過は要確認。",
    "接待交際費は相手先名の記載が必須。無ければ差し戻し。",
    "領収書番号が空欄の行は金額に関わらず差し戻し。",
  ].join("\n");

  const results = [];
  rows.forEach((row, i) => {
    // 判定済み(結果列に値がある)行はスキップ
    if (row[4]) {
      results.push([row[4]]);
      return;
    }

    const prompt =
      "次の社内規則に厳密に従って、経費申請の1行を判定してください。\n" +
      "【規則】\n" + RULE + "\n\n" +
      "【申請内容】\n" +
      "科目: " + row[1] + " / 金額: " + row[2] + " / 相手先: " + row[3] + "\n\n" +
      "「承認」「要確認」「差し戻し」のいずれかと、その理由を1文で返してください。";

    const answer = askWithEffort(prompt, "high"); // 難しい判定なので high
    results.push([answer]);
    Utilities.sleep(500); // レート制限に配慮して少し待つ
  });

  // E列にまとめて書き戻す(一括書き込みで高速化)
  sheet.getRange(2, 5, results.length, 1).setValues(results);
}

判定済みの行はスキップし、結果はE列にまとめて書き戻すことで、再実行時の無駄なAPI呼び出しと処理時間を抑えています。 大量の行を回すときは、GASの6分実行時間制限に達しないよう分割実行を組み合わせると安定します。

トークン消費と料金の考え方

拡張思考で使われた思考トークンは、出力トークンとして課金されます。レスポンスのusage.output_tokensに思考分も含まれるため、拡張思考を使うと1回あたりの出力トークンが増えます。

// 思考トークンを含む消費量を確認する
function checkUsage(prompt) {
  const apiKey = PropertiesService
    .getScriptProperties()
    .getProperty("CLAUDE_API_KEY");

  const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01",
    },
    payload: JSON.stringify({
      model: "claude-opus-4-8",
      max_tokens: 4096,
      thinking: { type: "adaptive" },
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  });

  const data = JSON.parse(res.getContentText());
  const u = data.usage;

  // 思考トークンは output_tokens に含まれて課金される
  Logger.log("入力トークン: " + u.input_tokens);
  Logger.log("出力トークン(思考含む): " + u.output_tokens);
  Logger.log("stop_reason: " + data.stop_reason);
  return data;
}

コストを抑えるコツは3つです。1つ目はeffortを必要最小限にすること。2つ目はmax_tokensを適切に設定し、途中で切れないよう余裕を持たせつつ無駄に大きくしないこと。3つ目は、簡単な行は拡張思考なしで処理し、難しい行だけ拡張思考を使うことです。 消費量の記録は関連記事のコスト集計と組み合わせると、月次の料金が把握しやすくなります。

実務での注意点

1. budget_tokensは新しいモデルでは使えない

以前のthinking: { type: "enabled", budget_tokens: N }という書き方は、Claude Opus 4.8・4.7などの新しいモデルでは廃止され、送るとエラー(400)になります。{ type: "adaptive" }とeffortの組み合わせに置き換えてください。

2. temperatureは付けない

新しいモデルではtemperaturetop_pを送るとエラーになります。以前のコードを流用するときは、これらのパラメータを外しておきましょう。

3. 応答時間が伸びる前提で組む

思考する分だけ1回の応答が長くなります。多くの行を回すバッチ処理では、GASの実行時間制限やタイムアウトに達しやすくなるため、 分割実行やリトライ処理を併用すると安定します。

4. 会話を続けるときは思考ブロックをそのまま返す

同じモデルで会話を継続する場合は、返ってきたthinkingブロックを変更せずにそのまま次のリクエストのmessagesへ含めます。中身を書き換えたり削ったりすると、エラーの原因になります。

まとめ

GASからClaude APIの拡張思考を使うには、thinking: { type: "adaptive" }を足し、output_config.effortで深さを調整するだけです。規則に照らした判定や条件が絡み合う分類など「一発で決まらない処理」に絞って使えば、精度を上げつつコストの増加を抑えられます。 判定の根拠を残したいときはdisplay: "summarized"で思考の要約を受け取りましょう。

よくある質問

回答を出す前にモデルが内部で段階的に考える時間を取るため、多段の推論が必要な判断(規則に照らした可否判定、条件が絡み合う分類、計算を伴うチェックなど)で精度が上がりやすくなります。単純な要約や短い分類では効果が小さく、逆に思考トークン分のコストと時間が増えるため、難しい処理にだけ使うのがコツです。

UrlFetchAppでClaude APIを呼び出すとき、リクエストのpayloadに thinking: { type: 'adaptive' } を追加するだけです。Claude Opus 4.8などの新しいモデルでは、この adaptive(アダプティブ)指定でモデルが思考の量を自動調整します。thinkingを付けないと思考なしで動くので、精度を上げたい処理では明示的に指定します。

Claude Opus 4.8・4.7などの新しいモデルでは thinking: { type: 'enabled', budget_tokens: N } は廃止され、送るとエラー(400)になります。代わりに thinking: { type: 'adaptive' } を使い、思考の深さは output_config.effort(low〜max)で調整します。固定のトークン上限という考え方から、努力レベルという考え方に変わりました。

新しいモデルの既定では thinking ブロックは返りますが本文は空です。thinking に display: 'summarized' を付けると、推論の要約を受け取れます。生の思考そのものは返りません。displayは表示の有無を変えるだけで、思考自体は常に行われ、料金も同じようにかかります。

思考に使われたトークンは出力トークンとして課金されます。レスポンスの usage.output_tokens に思考分も含まれるため、拡張思考を使うと1回あたりの出力トークンが増えます。effortを下げる、max_tokensを適切に設定する、難しい行だけ拡張思考を使う、といった工夫でコストを抑えられます。

AI×GASの業務自動化を
相談する。

拡張思考を使った高精度な判定のほか、分類・要約・データ整形など、Claude APIとGASを組み合わせた業務自動化をご相談いただけます。