GASのライブラリで共通処理を
複数プロジェクトに使い回す方法

同じClaude API呼び出しのコードを、プロジェクトごとにコピペしていませんか。GASのライブラリ(別のスクリプトプロジェクトを部品として読み込む仕組み)を使えば、共通処理を1か所にまとめて全社のスクリプトから呼び出せます。作り方・公開手順・呼び出し方と、トリガーや速度の落とし穴までまとめます。

|対象: GAS / ライブラリ / コード共通化

Table of Contents

GASのライブラリとは何か

GASのライブラリは、別のスクリプトプロジェクトを部品として読み込み、その関数を自分のスクリプトから呼び出せる仕組みです。読み込む側はAiLib.callClaude()のように「識別子.関数名」で呼びます。コピペで増殖した共通コードを1か所に集約したいときに効きます。

AI呼び出しの共通化

Claude APIのリクエスト組み立て・エラー処理・リトライを全プロジェクトで統一できる

修正が1か所で済む

モデル名やAPIバージョンの変更を、ライブラリのバージョンを上げるだけで各プロジェクトに反映できる

社内標準の部品化

ログ記録・Slack通知・営業日計算など、どの案件でも使う処理を共通資産にできる

品質のばらつきを防ぐ

担当者ごとに書き方が違う状態をなくし、テスト済みの実装だけを使わせられる

一方で、ライブラリは万能ではありません。呼び出しのオーバーヘッドで実行が少し遅くなり、バージョン管理を怠ると「どのプロジェクトがどの版を使っているか分からない」状態になります。共通化の効果が大きい処理に絞って使うのが現実的です。

ライブラリ側のコードを書く(公開関数と非公開関数)

ライブラリ側は普通のGASプロジェクトです。特別な書き方は要りません。ポイントは2つで、外に見せたくない関数は名前の末尾にアンダースコアを付けること、公開する関数にはJSDoc(関数の上に書く説明コメント)を書くことです。アンダースコアで終わる関数は参照側から呼び出せず、JSDocは参照側のエディタで入力補完として表示されます。

// === ライブラリ側プロジェクト(プロジェクト名: AiLib)===

/**
 * Claude APIにテキストを送り、回答本文だけを返す。
 * @param {string} apiKey Anthropic APIキー
 * @param {string} prompt AIに渡す指示文
 * @param {number} maxTokens 出力トークンの上限(省略時1024)
 * @return {string} AIの回答テキスト
 */
function callClaude(apiKey, prompt, maxTokens) {
  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-sonnet-4-5",
      max_tokens: maxTokens || 1024,
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  });

  return parseMessage_(res);
}

/**
 * 末尾がアンダースコアの関数は参照側から呼び出せない(内部処理用)。
 */
function parseMessage_(res) {
  const code = res.getResponseCode();
  const body = res.getContentText();
  if (code !== 200) {
    throw new Error("Claude APIエラー: " + code + " " + body);
  }
  const json = JSON.parse(body);
  return json.content
    .filter((block) => block.type === "text")
    .map((block) => block.text)
    .join("");
}

APIキーを引数で受け取っている点に注目してください。ライブラリは複数のプロジェクトから共有されるため、キーをライブラリ側に埋め込むと誰がどの権限で使っているのか追えなくなります。呼び出し側から渡す形にしておくと、プロジェクトごとにキーを分けられます。

バージョンを作って公開する手順

ライブラリはコードを保存しただけでは配れません。「バージョン」というスナップショットを作る必要があります。手順は次のとおりです。

1. バージョンを作成する

ライブラリ側のエディタ右上「デプロイ」→「デプロイを管理」または「新しいデプロイ」から、種類に「ライブラリ」を選んでバージョンを作成します。説明欄には変更内容を1行書いておくと後で助かります。

2. スクリプトIDを控える

左メニューの「プロジェクトの設定」に表示される長い文字列がスクリプトIDです。参照側はこのIDでライブラリを探します。

3. 参照者に閲覧権限を渡す

ライブラリを使う人は、そのスクリプトプロジェクトに対する閲覧権限が必要です。社内で広く使うなら、共有設定でドメイン内の閲覧可にしておくと運用が楽になります。

4. 更新時は新バージョンを作る

コードを直しても既存の参照側には影響しません。新しいバージョンを作成し、参照側でバージョン番号を上げてもらって初めて反映されます。

開発中はバージョンの代わりにHEAD(開発モード)を選ぶと、ライブラリの保存内容がそのまま反映されます。手早く試せる反面、保存したそばから全プロジェクトの挙動が変わるため、本番運用ではバージョン固定にしてください。

参照側から呼び出す(スクリプトIDと識別子)

参照側のエディタで左メニュー「ライブラリ」の+を押し、控えておいたスクリプトIDを貼り付けて検索します。追加時に決めるのが識別子(コード内でライブラリを指す名前)です。既定ではライブラリのプロジェクト名が入りますが、短い名前に変えても構いません。ここではAiLibとしています。

// === 参照側プロジェクト(各業務のスクリプト)===

function summarizeInquiries() {
  // APIキーは参照側のスクリプトプロパティに置き、引数で渡す
  const apiKey = PropertiesService.getScriptProperties().getProperty("ANTHROPIC_API_KEY");
  const sheet = SpreadsheetApp.getActive().getSheetByName("問い合わせ");
  const rows = sheet.getDataRange().getValues().slice(1);

  const results = rows.map((row) => {
    const body = String(row[2]);
    // 識別子(AiLib)+ ドット + 関数名 で呼び出す
    return [AiLib.callClaude(apiKey, "次の問い合わせを1行で要約してください。\n\n" + body, 200)];
  });

  if (results.length > 0) {
    sheet.getRange(2, 4, results.length, 1).setValues(results);
  }
}

参照側のコードからClaude APIのリクエスト組み立てが消え、業務ロジックだけが残ります。モデル名を新しいものへ差し替えるときも、直すのはライブラリ1か所だけです。

トリガーからはライブラリを直接呼べない

ライブラリ導入で最初につまずくのがここです。トリガー(決まった時間やイベントで自動実行する仕組み)が指定できるのは、自分のプロジェクト内にある関数だけです。AiLib.runNightlyをそのままトリガーに登録することはできません。参照側に1行のラッパー関数を用意して、そちらを登録します。

// === 参照側プロジェクト ===
// トリガーに登録できるのは自分のプロジェクトの関数だけ。
// ライブラリの関数はラッパー経由で呼ぶ。

function nightlyAiJob() {
  const apiKey = PropertiesService.getScriptProperties().getProperty("ANTHROPIC_API_KEY");
  AiLib.runDailySummary(apiKey, "問い合わせ");
}

function createNightlyTrigger() {
  // 二重登録を防ぐため、同名トリガーを消してから作る
  ScriptApp.getProjectTriggers()
    .filter((t) => t.getHandlerFunction() === "nightlyAiJob")
    .forEach((t) => ScriptApp.deleteTrigger(t));

  ScriptApp.newTrigger("nightlyAiJob")
    .timeBased()
    .everyDays(1)
    .atHour(2)
    .create();
}

// onOpen などのシンプルトリガーも同じくラッパーが必要
function onOpen() {
  AiLib.addAiMenu();
}

onOpenonEditといったシンプルトリガーも同じです。関数そのものは参照側に定義し、中身の処理をライブラリに委ねる形にします。カスタムメニューの組み立てをライブラリ側に置いておけば、全プロジェクトで同じメニューを出せます。

呼び出し回数を減らして速度を守る

ライブラリの呼び出しには読み込みのオーバーヘッドがあり、多用するとスクリプト全体が遅くなります。対策はシンプルで、「1件ずつ呼ぶ」のではなく「まとめて渡して、まとめて返す」設計にすることです。ループ自体をライブラリ側に持たせれば、参照側からの呼び出しは1回で済みます。

// === ライブラリ側 ===
// 呼び出し回数を減らすため、ループごとライブラリに任せる設計にする。

/**
 * 複数のプロンプトをまとめて処理し、結果の配列を返す。
 * @param {string} apiKey Anthropic APIキー
 * @param {string[]} prompts 指示文の配列
 * @return {string[]} 回答テキストの配列(失敗した要素は空文字)
 */
function callClaudeBatch(apiKey, prompts) {
  const requests = prompts.map((prompt) => ({
    url: "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-sonnet-4-5",
      max_tokens: 300,
      messages: [{ role: "user", content: prompt }],
    }),
    muteHttpExceptions: true,
  }));

  // fetchAllで並列実行。1回のライブラリ呼び出しで全件処理する
  return UrlFetchApp.fetchAll(requests).map((res) => {
    try {
      return parseMessage_(res);
    } catch (e) {
      console.error(e);
      return "";
    }
  });
}

この例ではUrlFetchApp.fetchAll(複数のHTTPリクエストを並列実行するメソッド)と組み合わせ、API通信そのものも高速化しています。ライブラリ化と並列化は相性が良く、共通部品にしておけば全プロジェクトが同じ速度改善の恩恵を受けられます。

実務での注意点

1. 権限(スコープ)は参照側にも要求される

ライブラリがGmailや外部通信を使うなら、その権限は参照側スクリプトの承認画面にも現れます。「シートを読むだけのつもりが、なぜかGmailの許可を求められた」という混乱を招かないよう、ライブラリには用途の近い機能だけをまとめましょう。使う機能が違うなら、AI用・通知用のようにライブラリを分けるのが無難です。

2. 破壊的な変更は影響範囲が全社に及ぶ

引数の順番を変える、戻り値の形を変えるといった修正は、参照している全プロジェクトを壊す可能性があります。既存の関数は残したまま新しい関数を追加し、移行が済んでから古い方を消す進め方が安全です。

3. どのバージョンが使われているか分からなくなる

参照側が古いバージョンのまま放置される事故はよく起きます。バージョン文字列を返す関数を用意しておくと、参照側で1行実行するだけで確認でき、調査が一気に楽になります。

// === ライブラリ側 ===
// 参照側がどのバージョンを使っているか分からなくなりがちなので、
// バージョン情報を返す関数を1つ用意しておくと調査が楽になる。

const LIB_VERSION = "1.4.0";

/**
 * ライブラリのバージョン文字列を返す。
 * @return {string} バージョン
 */
function getVersion() {
  return LIB_VERSION;
}

// === 参照側 ===
function checkLibVersion() {
  console.log("AiLib version: " + AiLib.getVersion());
}

4. ソースはGitで管理する

共通ライブラリはブラウザのエディタだけで育てると履歴が追えません。clasp(GASの公式CLI)で手元に落とし、Gitで管理したうえでClaude Codeなどのエージェントに書かせると、変更の理由をコミットログとして残せます。

5. 迷ったらまず共有スプレッドシート方式で足りないか考える

共通化したいものが「処理」ではなく「設定値」なら、ライブラリではなく設定用シートやスクリプトプロパティで足ります。ライブラリはコードを共有する仕組みであり、データの共有には向きません。

まとめ

GASのライブラリを使えば、Claude API呼び出しやログ記録といった共通処理を1か所に集約し、複数プロジェクトから同じ品質で呼び出せます。外に見せない関数は末尾アンダースコア、公開する関数にはJSDoc、更新はバージョン作成、という3点を押さえれば運用は難しくありません。

つまずきやすいのは、トリガーにライブラリ関数を直接指定できない点と、呼び出し回数が多いと遅くなる点です。ラッパー関数を1つ挟み、処理はまとめて渡す設計にすれば、どちらも回避できます。社内でGASの案件が増えてきたタイミングが、共通ライブラリを整える良い機会です。

よくある質問

参照する側のスクリプトエディタで、左メニューの「ライブラリ」の+を押し、ライブラリ側プロジェクトのスクリプトIDを貼り付けて検索します。バージョンと識別子(呼び出すときの名前)を選んで追加すれば、AiLib.callClaude() のように呼び出せます。スクリプトIDはライブラリ側の「プロジェクトの設定」で確認できます。

関数名の末尾にアンダースコアを付けます。buildPayload_() のようにアンダースコアで終わる関数は、ライブラリを参照している側からは呼び出せません。内部処理はアンダースコア付きにして、外から使ってほしい関数だけ通常の名前にするのが基本の設計です。

参照側は追加したときのバージョンに固定されているためです。ライブラリ側で「デプロイを管理」から新しいバージョンを作成し、参照側のライブラリ設定でバージョン番号を上げ直してください。開発中はバージョンの代わりに HEAD(開発モード)を選ぶと保存内容がすぐ反映されますが、本番運用ではバージョン固定を推奨します。

できません。トリガーが指定できるのは自分のプロジェクト内の関数だけです。参照側に function nightlyJob() { AiLib.runNightly(); } のような1行のラッパー関数を作り、そのラッパーをトリガーに登録します。onOpen や onEdit などのシンプルトリガーも同じくラッパーが必要です。

多少遅くなります。ライブラリの呼び出しには読み込みのオーバーヘッドがあり、ループの中で何万回も呼ぶような使い方では差が出ます。共通化のメリットが上回るケースが多いものの、速度が重要な処理はライブラリ側でループごと引き受け、参照側からの呼び出し回数を減らす設計にしてください。

参照側のスクリプトプロパティに置き、ライブラリの関数には引数で渡す設計が安全で分かりやすいです。ライブラリは複数プロジェクトから共有されるため、キーをライブラリ側に埋め込むと利用範囲の管理が難しくなります。呼び出し側ごとにキーを差し替えられる形にしておきましょう。

GAS開発・AI業務自動化を
相談する。

増えすぎたGASスクリプトの整理・共通ライブラリ化から、Claude APIを組み込んだ業務自動化まで、設計段階からご相談いただけます。

AI×GAS業務自動化を見る