GASからClaude APIを呼び出して
問い合わせを自動分類する方法

スプレッドシートに溜まった問い合わせを、UrlFetchApp(GASからHTTPリクエストを送る標準機能)とClaude API(Anthropic社の生成AI)を組み合わせ、 「見積依頼」「クレーム」などに自動で振り分ける方法を、そのまま動くコードで解説します。

|対象: GAS / Claude API / 業務自動化

Table of Contents

GAS×AIで何ができるのか

結論から言うと、GAS(Google Apps Script。Googleサービスを操作する無料のプログラム実行環境)から AIのAPIを呼べば、「人が読んで判断していた作業」をそのまま自動化できます。 APIとは、外部のサービスをプログラムから呼び出すための窓口のことです。

なかでも相性が良いのが、フォーム受付やメールから溜まっていく問い合わせの仕分けです。 例えば次のような処理を、担当者の手を介さずに回せます。

問い合わせの自動分類

本文を読んで「見積依頼」「クレーム」などのカテゴリに振り分ける

長文の要約

長い問い合わせ本文を1〜2行に要約して一覧を見やすくする

優先度の判定

緊急度を推定し、至急対応が必要な行に印をつける

返信の下書き生成

内容に沿った返信文のたたき台を自動で作成する

この記事では、もっとも需要の多い「問い合わせの自動分類」を題材に、実装の全体像をたどります。 使うAIは、Anthropic社のClaude APIです。

準備:APIキーを安全に保管する

APIを使うには、AnthropicのコンソールでAPIキー(サービスを使う権利を示す秘密の文字列)を発行します。 このキーは料金が発生する権限そのものなので、コードに直書きしてはいけません。GASの「スクリプトプロパティ」(PropertiesServiceで読み書きする、スクリプト単位の設定保存領域)に入れておき、コードからはキー名で読み出します。

// 一度だけ実行してAPIキーを安全に保存する
function saveApiKey() {
  // 実行後、この関数のキー文字列は削除しておく
  PropertiesService.getScriptProperties()
    .setProperty("ANTHROPIC_API_KEY", "sk-ant-xxxxxxxx");
}

// コードからはキー名で読み出す(直書きしない)
function getApiKey() {
  const key = PropertiesService.getScriptProperties()
    .getProperty("ANTHROPIC_API_KEY");
  if (!key) throw new Error("APIキーが未設定です。saveApiKeyを実行してください。");
  return key;
}

saveApiKeyを一度だけ実行したら、キー文字列はコードから消しておきましょう。以降はどの関数からもgetApiKey()で安全に取り出せます。

Claude APIを1回呼び出す基本コード

Claude APIはhttps://api.anthropic.com/v1/messagesにPOSTリクエストを送るだけで使えます。GAS標準のUrlFetchApp.fetch()でリクエストを送り、返ってきたJSONから返答テキストを取り出します。

// Claude APIに1回問い合わせて、返答テキストを取得する
function askClaude(userText) {
  const url = "https://api.anthropic.com/v1/messages";

  const payload = {
    model: "claude-opus-4-8",
    max_tokens: 20,
    messages: [
      { role: "user", content: userText }
    ]
  };

  const options = {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": getApiKey(),
      "anthropic-version": "2023-06-01"
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // エラー時も例外にせずレスポンスを受け取る
  };

  const res = UrlFetchApp.fetch(url, options);
  const code = res.getResponseCode();
  if (code !== 200) {
    throw new Error("API エラー (" + code + "): " + res.getContentText());
  }

  const json = JSON.parse(res.getContentText());
  // 返答は content 配列の先頭 text ブロックに入る
  return json.content[0].text.trim();
}

ポイントは3つです。ヘッダーにx-api-keyとバージョン指定anthropic-versionを必ず入れること。リクエストにはmodelmax_tokens(返答の最大の長さ)・messagesが必要なこと。そして返答はcontent配列の先頭textに入ること。muteHttpExceptions: trueを付けると、エラー時も例外で止まらずステータスコードを自分で確認できます。

モデル名は用途に応じて選べます。分類のような短い判定は高性能なclaude-opus-4-8で精度を確認し、コスト重視なら軽量なclaude-haiku-4-5に差し替えるだけで切り替えられます。

問い合わせを決められたカテゴリに分類する

分類を安定させるコツは、AIに自由記述させず「候補の中から1つだけ選ばせる」ことです。 プロンプト(AIへの指示文)で候補リストとルールを渡し、返ってきた文字列を候補と照合して、 想定外の値は「その他」に寄せる後処理を入れます。

const CATEGORIES = ["見積依頼", "サポート", "クレーム", "採用応募", "その他"];

// 問い合わせ本文を、決められたカテゴリのどれか1つに分類する
function classifyInquiry(text) {
  const prompt =
    "あなたは問い合わせ内容の分類担当です。\n" +
    "次の本文を、以下の候補から最も近いもの1つに分類してください。\n" +
    "候補: " + CATEGORIES.join("、") + "\n" +
    "カテゴリ名だけを、余計な説明なしで返してください。\n\n" +
    "本文:\n" + text;

  const answer = askClaude(prompt);

  // 想定外の値が返ってきたら「その他」に寄せる(後処理でぶれを防ぐ)
  return CATEGORIES.includes(answer) ? answer : "その他";
}

このように「カテゴリ名だけを返して」と明示し、max_tokensも小さく設定すると、余計な説明文が混ざらず、後続の処理が扱いやすくなります。 候補を後から増やしたいときはCATEGORIESの配列に追記するだけです。

スプレッドシートを一括で自動分類する

あとはシートの未分類行をまとめて処理するだけです。 A列に受付日時、B列に問い合わせ本文、C列に分類結果を書き込む構成を例に、 まだ分類されていない行だけを走査して結果を書き込みます。

// スプレッドシートの未分類行を読み、分類結果をC列に書き込む
// 前提: A列=受付日時, B列=問い合わせ本文, C列=分類結果
function classifySheet() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("問い合わせ");
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return; // ヘッダーのみ

  const values = sheet.getRange(2, 2, lastRow - 1, 2).getValues(); // B・C列

  values.forEach((row, i) => {
    const body = row[0];      // B列: 本文
    const current = row[1];   // C列: 既存の分類

    if (!body || current) return; // 空行・分類済みはスキップ

    const category = classifyInquiry(body);
    sheet.getRange(i + 2, 3).setValue(category); // C列に書き込み
    Utilities.sleep(300); // 連続呼び出しの間隔をあける
  });
}

すでにC列が埋まっている行はスキップするので、同じ行を二重に処理しません。Utilities.sleep(300)でAPIを呼ぶ間隔を少しあけているのは、短時間に大量のリクエストを送りすぎないためです。

エラー処理とレート制限への対応

APIは常に成功するとは限りません。とくに短時間にリクエストが集中すると、 「レート制限」(一定時間あたりの呼び出し回数の上限)にかかり、ステータスコード429が返ります。この場合は少し待ってから再試行すれば回復します。

// 429(レート制限)や 529(過負荷)は少し待って再試行する
function askClaudeWithRetry(userText, maxRetries) {
  maxRetries = maxRetries || 3;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = fetchClaude(userText); // UrlFetchApp.fetch を実行する関数
    const code = res.getResponseCode();

    if (code === 200) {
      return JSON.parse(res.getContentText()).content[0].text.trim();
    }

    // リトライで回復が見込めるステータスだけ待って再挑戦
    if (code === 429 || code >= 500) {
      Utilities.sleep(Math.pow(2, attempt) * 1000); // 1s, 2s, 4s...
      continue;
    }

    // 400・401など、待っても直らないエラーは即中断
    throw new Error("API エラー (" + code + "): " + res.getContentText());
  }
  throw new Error("リトライ上限に達しました");
}

待ち時間を1秒→2秒→4秒と伸ばす「指数バックオフ」で再試行するのがコツです。 一方、401(認証エラー=キーが誤り)や400(リクエストの不備)は待っても直らないので、再試行せず即座に止めて原因を確認します。 サーバー側の一時的な不調を示す500番台も再試行の対象です。

トリガーで定期実行を自動化する

最後に、時間主導トリガー(決まった間隔で関数を自動実行するGASの仕組み)を設定すれば、 人が手を動かさなくても分類が回り続けます。フォーム回答が随時追加されるシートと相性が良い構成です。

// 5分おきに自動分類を回す時間主導トリガーを設定する
function createClassifyTrigger() {
  ScriptApp.newTrigger("classifySheet")
    .timeBased()
    .everyMinutes(5)
    .create();
}

なお、1回の実行で扱う行数が多いと、GASの実行時間制限(無料枠で6分)に達することがあります。 その場合は処理する行数を区切り、続きを次のトリガーで再開する分割実行にすると安定します。 実装の詳細は関連記事で解説しています。

まとめ

GASからClaude APIを呼び出す仕組みは、UrlFetchAppでリクエストを送り、返ってきたJSONを読むだけとシンプルです。 APIキーはスクリプトプロパティで安全に保管し、分類は候補リスト+後処理でぶれを抑え、 エラーは再試行で受け止め、最後にトリガーで自動化する——この流れを押さえれば、 問い合わせ分類に限らず、要約・優先度判定・下書き生成といったAI活用にも同じ型で応用できます。

よくある質問

不要です。GASに標準で組み込まれているUrlFetchApp.fetch()でHTTPリクエストを送れるため、外部ライブラリを追加せずにClaude APIを呼び出せます。APIキーと送信するJSONを用意するだけで動きます。

書かないでください。APIキーをソースコードに直書きすると、共有時やバージョン管理で漏洩する危険があります。GASの「スクリプトプロパティ」(PropertiesService)に保存し、コードからはキー名で読み出す方法が安全です。本文で手順を解説しています。

分類のような短い判定タスクなら、まずは高性能な claude-opus-4-8 で精度を確認し、コストを抑えたい場合は軽量な claude-haiku-4-5 に切り替えるのがおすすめです。モデルはリクエストのmodelフィールドの文字列を差し替えるだけで変更できます。

プロンプトで「次の候補から必ず1つだけ選び、カテゴリ名だけを返す」と明示し、候補リストを渡すのが有効です。max_tokensを小さめ(例: 20)にし、返ってきた文字列を候補リストと照合して想定外の値をはじく後処理を入れると、より安定します。

引っかかる可能性があります。GASには1回の実行あたり6分(Workspaceは30分)の制限があります。1回で処理する行数を区切り、続きは時間主導トリガーで再開する分割実行にすると安定します。関連記事で分割実行の実装を解説しています。

料金は入力・出力のトークン数に応じた従量課金です。問い合わせ分類のように入力も出力も短い用途では、1件あたりの費用はごくわずかです。正確な単価はAnthropicの公式料金ページで最新の値を確認してください。

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

問い合わせ分類のほかにも、要約・優先度判定・返信下書きの自動生成など、 AI APIとGASを組み合わせた自動化をご相談いただけます。既存のスプレッドシート運用にも組み込めます。

AI×GAS自動化の対応範囲を見る