【GAS×Gemini API】契約書の期限管理を自動化|更新の通知漏れを防ぐ

この記事は約11分で読めます。

「解約するつもりだった契約が、自動更新されていた」。管理部門でよく聞く失敗です。契約書をPDFで保管していても、解約の通知期限まで一覧にできている会社は多くありません。

この記事では、GAS(Google Apps Script:Googleのサービスを自動化できるスクリプト環境)とGemini APIで、契約書の期限管理を自動化する方法を解説します。契約書PDFから期間や自動更新条項をAIで読み取って台帳を作り、期限が近づいたら担当者にメールで知らせます。契約管理をExcelや記憶に頼っている担当者の方が対象です。

スポンサーリンク

GASで契約書の期限管理を自動化するメリット

自動更新契約で管理すべきなのは、終了日ではなく「更新拒絶の通知期限」です。「期間満了の3か月前までに通知がなければ1年間自動更新」のように、期限は条文ごとに異なります。GASとGemini APIを使うと、次の作業を自動化できます。

  • 契約書PDFから契約期間・自動更新の有無・通知期限を読み取る
  • 読み取った内容を管理台帳(スプレッドシート)に追記する
  • 通知期限の90日前・30日前などに担当者へメールを送る

ただし、AIの読み取り結果をそのまま信じるのは危険です。AIが作った行は「要確認」で登録し、人が原本と照合して「確認済」にした行だけをリマインド対象にします。

契約書管理台帳の自動作成に必要な準備

  1. 契約書フォルダ:Googleドライブにフォルダを作り、契約書PDFを入れます。フォルダURL末尾の文字列がフォルダIDです。
  2. 管理台帳:「契約台帳」シートの1行目に、ファイルID、ファイル名、契約名、相手方、開始日、終了日、自動更新、更新期間、通知期間(値)、通知期間(単位)、通知期限日、担当者メール、ステータス、根拠条文、AIメモの15列を作ります。
  3. Gemini APIキー:Google AI Studioで発行します。業務データを扱うため、課金を有効にした有料利用を前提にしてください。
  4. キーの保存:「拡張機能」→「Apps Script」のプロジェクト設定で、スクリプトプロパティに GEMINI_API_KEY として保存します。

公式ドキュメントによると、Gemini APIはPDFを50MBまたは1,000ページまで直接読み込めます(執筆時点)。OCRを別に用意する必要はありません。

Gemini APIで契約書PDFを読み取るGASコード

処理の流れは次のとおりです。

  • ステップ1:フォルダからPDFを取得し、台帳にない未処理ファイルを選ぶ
  • ステップ2:PDFをGemini APIに送り、契約情報をJSONで受け取る
  • ステップ3:通知期限日をGASで計算し、台帳に「要確認」で追記する
const FOLDER_ID = '契約書フォルダのID';
const SHEET_NAME = '契約台帳';
const MODEL = 'gemini-3.5-flash-lite'; // 執筆時点の例。導入時に公式で確認
const PROMPT = `(次の章のプロンプトを貼り付け)`;

function extractContracts() {
  const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
  const done = new Set(sheet.getRange('A:A').getValues().flat());
  const files = DriveApp.getFolderById(FOLDER_ID).getFilesByType(MimeType.PDF);
  const start = Date.now();
  while (files.hasNext() && Date.now() - start < 270000) { // 4.5分で打ち切り
    const file = files.next();
    if (done.has(file.getId())) continue;
    const head = [file.getId(), file.getName()];
    try {
      const r = callGemini(file.getBlob());
      sheet.appendRow(head.concat([r.contract_title, r.counterparty,
        r.start_date, r.end_date, r.auto_renewal, r.renewal_term,
        r.notice_value, r.notice_unit, calcDeadline(r), '', '要確認',
        r.evidence, r.uncertain_points]));
    } catch (e) {
      sheet.appendRow(head.concat(Array(10).fill(''), ['抽出エラー', '', String(e)]));
    }
  }
}

function callGemini(blob) {
  const key = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  const url = 'https://generativelanguage.googleapis.com/v1beta/models/'
    + MODEL + ':generateContent';
  const body = {
    contents: [{ parts: [
      { inline_data: { mime_type: 'application/pdf',
        data: Utilities.base64Encode(blob.getBytes()) } },
      { text: PROMPT }
    ] }],
    generationConfig: { responseMimeType: 'application/json' }
  };
  const res = UrlFetchApp.fetch(url, {
    method: 'post', contentType: 'application/json',
    headers: { 'x-goog-api-key': key },
    payload: JSON.stringify(body), muteHttpExceptions: true
  });
  if (res.getResponseCode() !== 200) throw new Error(res.getContentText());
  const json = JSON.parse(res.getContentText());
  return JSON.parse(json.candidates[0].content.parts[0].text);
}

function calcDeadline(r) {
  if (!r.end_date || !r.notice_value) return '';
  const d = new Date(r.end_date);
  if (r.notice_unit === '月') d.setMonth(d.getMonth() - Number(r.notice_value));
  else d.setDate(d.getDate() - Number(r.notice_value));
  return Utilities.formatDate(d, 'Asia/Tokyo', 'yyyy-MM-dd');
}

ポイントは3つです。1つ目は、処理済みのファイルIDを台帳から読み、二重登録を防いでいる点です。2つ目は、GASの実行時間上限(1回6分)の手前で止め、残りは次回に回す点です。

3つ目は、通知期限日の計算をAIではなくGASで行う点です。生成AIは日付計算を誤ることがあるため、AIには条文の読み取りだけを任せます。モデル名は執筆時点(2026年11月)の公式ページに載っている一例のため、導入時に最新の一覧を確認してください。

契約書の読み取りに使うプロンプト例

コード内の PROMPT に、次の文章をそのまま貼り付けます。

添付の契約書PDFを読み、次のキーを持つJSONだけを出力してください。

- contract_title:契約書の表題
- counterparty:当社以外の契約当事者名
- start_date / end_date:契約開始日・当初の終了日(YYYY-MM-DD)
- auto_renewal:自動更新条項の有無(「あり」「なし」)
- renewal_term:自動更新時の更新期間(例:1年)
- notice_value / notice_unit:更新拒絶の通知期限の数値と単位(「日」か「月」)
- evidence:根拠となる条項番号と原文の抜粋
- uncertain_points:読み取れない点・解釈が分かれる点

ルール:
- 契約書に書かれていない項目は推測せず空文字にする
- 「締結日から1年間」のように日付が明記されていない場合は計算せず、
  原文をuncertain_pointsに書く
- 覚書などで期間が変わっている可能性があれば、その旨を書く

大切なのは「書かれていないことは推測しない」というルールです。日付が明記されていない契約でAIが日付を作ると、誤った期限で管理してしまいます。また根拠条文を出力させておくと、確認時は該当条項だけを原本と照合すれば済みます。

契約更新のリマインドを自動化する設定手順

台帳ができたら、同じプロジェクトに次のコードを追加します。

const ALERT_DAYS = [90, 60, 30, 14, 7];

function remindRenewals() {
  const rows = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME)
    .getDataRange().getValues().slice(1);
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  rows.forEach(r => {
    const [title, party] = [r[2], r[3]];
    const [deadline, owner, status] = [r[10], r[11], r[12]];
    if (status !== '確認済' || !deadline || !owner) return;
    const days = Math.round((new Date(deadline) - today) / 86400000);
    if (!ALERT_DAYS.includes(days)) return;
    MailApp.sendEmail(owner, '【契約更新】' + title + 'の通知期限まで残り' + days + '日',
      '相手方:' + party + '\n更新・条件変更・解約のどれにするか判断し、台帳に記録してください。');
  });
}

ステータスが「確認済」で担当者メールが入った行だけが対象です。通知期限までの残り日数が ALERT_DAYS に一致した日にメールを送ります。稟議にかかる日数に合わせて数字を調整してください。最後にトリガー(関数を決まった時刻に自動実行する設定)を登録します。

  1. Apps Scriptエディタ左側の時計アイコン「トリガー」を開く
  2. extractContracts を時間主導型・日付ベース(例:毎朝6〜7時)で登録する
  3. remindRenewals を毎朝8〜9時で登録する
  4. 初回の承認画面で、ドライブ・メール・外部接続の権限を確認して許可する

導入時の注意点とリスク

無料枠のAPIに契約書を送らない

Gemini APIの追加利用規約では、無料サービスに送った内容は製品改善に使われ、人間のレビュアーが読む場合があるとされています。機密情報や個人情報を無料サービスに送らないよう明記されています。有料サービスではプロンプトと回答を製品改善に使わないとされているため、契約書は有料利用で扱ってください。

AIの読み違いを前提に運用する

AIは条文を読み違えることがあります(ハルシネーション)。覚書で期間が変わっている場合や、基本契約と個別契約で条件が違う場合は特に注意が必要です。「確認済」への変更は、原本を見た人だけが行うルールにしましょう。

導入前チェックリスト

  • 有料プランでのAPI利用について社内承認を得たか
  • 契約書をAPIに送ることが情報管理規程に反しないか
  • フォルダと台帳の共有範囲を必要最小限にしたか
  • 「確認済」にできる担当者と、更新可否を決める人を決めたか

よくある質問(FAQ)

スキャンした紙の契約書PDFでも読み取れますか?

Gemini APIはPDFを画像としても解析するため、スキャンしたPDFでも読み取れる場合が多いです。ただし傾きや影、手書きの修正があると精度が下がります。読み取れない項目は空欄で返すよう指示しているので、空欄やAIメモが入った行から優先して確認すると効率的です。

契約書が何百件もある場合でも使えますか?

使えますが、GASには実行時間や1日あたりのURL Fetch回数に上限があります。本記事のコードは時間切れの手前で止まり、次回に続きを処理するため、初回は数日かけて登録する想定です。承認フローまで管理したい規模なら、契約管理SaaSも比較検討してください。

ChatGPTやClaudeのAPIでも同じことはできますか?

できます。どちらもPDFを入力できるAPIがあり、callGemini 関数を各社の仕様に合わせて書き換えれば同じ構成で動きます。Geminiの利点はGoogle Workspaceとそろえやすい点です。どのAPIでも、データの取り扱い条件の事前確認は欠かせません。

まとめ

契約書の期限管理で押さえるべきは、自動更新を止めるための通知期限です。GASとGemini APIを使えば、契約書PDFから管理台帳を自動で作り、期限前に担当者へ知らせられます。一方、AIの読み違いや情報漏えいのリスクはゼロではありません。有料プランでの利用、人による原本確認、権限の絞り込みをセットで運用しましょう。

次のアクションとして、更新時期が近い契約書を10件ほどフォルダに入れて試してみてください。手入力の台帳と見比べると、任せられる範囲が見えてきます。

関連記事

参考リンク

タイトルとURLをコピーしました