はじめに
こんにちは!生成AI、フル活用していますか?
毎日便利にAIとチャットしている中で、誰もが一度はぶち当たる**「あの絶望の壁」**がありますよね。
「新しいセッションに移行すると、昨日までの文脈や、自分が教え込んだ秘伝のプロンプト(スキル)を全部忘れて健忘症になる」
LLMのコンテキストウィンドウの制限やセッションのステート喪失は、本気でAIを「バディ(相棒)」として育てたい時の最大のボトルネックです。本格的なRAGや自律型エージェント、Vector DBなんかで組めば解決しますが、開発コストやインフラ維持費もなかなか厳しい。。。
そこで今回は、Googleエコシステム(GeminiのGem機能 × Google Apps Script × NotebookLM)だけを組み合わせ、追加コスト完全ゼロ、コードのコピペ(とちょっと設定)だけで、セッションを跨いで成長する**「長期記憶を持つ擬似AIエージェント」**を構築するアーキテクチャ(MyBuddy)を紹介します!
1. 解決したい課題とアーキテクチャ概要
標準的なチャットAIは「一期一会」です。これを、以下の3つのツールを密結合させた**「自律循環型のMemory-Opsパイプライン」**によって解決します。
- Gemini (Gem):対話を「概要」「決定事項」「Next Action」に構造化し、Workspace拡張機能でドライブへ書き出す(アウトプット)。
- Google Apps Script (GAS):散らばったログを日付順にソートし、1本のマスターファイルにマージ。古いログは自動で忘却(ガベージコレクション)する。
- NotebookLM:マージされたマスターファイルを「知識」として常時マウント。新しいセッションの開始時にGeminiがこれを読み込む(インプット)。
インテリジェンスがツール間をぐるぐると循環することで、**「AIが自分で出力した記憶ログを、自動で自分の脳内にリロードして次のセッションを始める」**という自己進化ループが完成します。
2. 爆速3ステップ導入手順
STEP 1: Google ドライブに「記憶の器」を作る
マイドライブ直下に、以下の2つのフォルダを作成します。
-
memoryフォルダ(一時的な個別議事録の保管庫) -
MyBuddyフォルダ(集約されたマスターファイルの配置先)
それぞれのフォルダのURLから英数字の「フォルダID」をコピーしてメモしておいてください。
(URLの drive.google.com/drive/folders/[この部分の英数字] がIDです)
STEP 2: Memory-Opsを司る「GAS」の配備
Google Apps Script ダッシュボードを開き、新規プロジェクトを作成して以下のコードを貼り付けます。(AIがリファクタしたのでGASが動かなかったらごめんなさい!AIに相談してみてください!)
(YOUR_MEMORY_FOLDER_ID と YOUR_MYBUDDY_FOLDER_ID を先ほどのIDに書き換えてください)
// =========================================================================
// Project MEMENTO - Memory-Ops Pipeline Script v1.0.0
// =========================================================================
const FOLDER_ID_MEMORY = 'YOUR_MEMORY_FOLDER_ID'; // 「memory」フォルダID
const FOLDER_ID_MYBUDDY = 'YOUR_MYBUDDY_FOLDER_ID'; // 「MyBuddy」フォルダID
const MASTER_DOC_NAME = 'BuddyKnowledge'; // マスターファイル名
const RETENTION_DAYS = 30; // ログ保持期間(30日)
function mainMemoryPipeline() {
moveBuddyNote();
syncBuddyKnowledge();
deleteOldBuddyNotes();
}
// 1. マイドライブ直下の【BuddyNote】を memory フォルダへ移動
function moveBuddyNote() {
const rootFolder = DriveApp.getRootFolder();
const destFolder = DriveApp.getFolderById(FOLDER_ID_MEMORY);
const files = rootFolder.getFiles();
while (files.hasNext()) {
const file = files.next();
if (file.getName().indexOf('【BuddyNote】') === 0) {
destFolder.addFile(file);
rootFolder.removeFile(file);
}
}
}
// 2. ログを日付昇順でソートし、単一のマスターファイルへマージ
function syncBuddyKnowledge() {
const memoryFolder = DriveApp.getFolderById(FOLDER_ID_MEMORY);
const myBuddyFolder = DriveApp.getFolderById(FOLDER_ID_MYBUDDY);
const files = memoryFolder.getFilesByType(MimeType.GOOGLE_DOCS);
let noteList = [];
while (files.hasNext()) {
const file = files.next();
const name = file.getName();
const dateMatch = name.match(/【BuddyNote】\s*(\d{8})/);
let dateStr = dateMatch ? dateMatch[1] : '00000000';
noteList.push({ id: file.getId(), name: name, date: dateStr });
}
if (noteList.length === 0) return;
noteList.sort((a, b) => a.date.localeCompare(b.date)); // 時系列ソート
let masterFile = myBuddyFolder.getFilesByName(MASTER_DOC_NAME).hasNext()
? myBuddyFolder.getFilesByName(MASTER_DOC_NAME).next()
: DocumentApp.create(MASTER_DOC_NAME);
if (!myBuddyFolder.getFilesByName(MASTER_DOC_NAME).hasNext()) {
myBuddyFolder.addFile(DriveApp.getFileById(masterFile.getId()));
DriveApp.getRootFolder().removeFile(DriveApp.getFileById(masterFile.getId()));
}
const masterDoc = DocumentApp.openById(masterFile.getId());
const masterBody = masterDoc.getBody().clear();
masterBody.appendParagraph("PROJECT MEMENTO : LONG-TERM MEMORY CORE");
noteList.forEach(note => {
try {
const srcBody = DocumentApp.openById(note.id).getBody();
masterBody.appendParagraph(`\n[LOG SOURCE: ${note.name}]`);
for (let i = 0; i < srcBody.getNumChildren(); i++) {
const element = srcBody.getChild(i).copy();
if (element.getType() === DocumentApp.ElementType.PARAGRAPH) masterBody.appendParagraph(element);
else if (element.getType() === DocumentApp.ElementType.LIST_ITEM) masterBody.appendListItem(element);
else if (element.getType() === DocumentApp.ElementType.TABLE) masterBody.appendTable(element);
}
} catch(e) { console.error(e.toString()); }
});
masterDoc.saveAndClose();
}
// 3. 30日以上経過した古いログを自動削除(未来日付の「恒久保存」は保護)
function deleteOldBuddyNotes() {
const memoryFolder = DriveApp.getFolderById(FOLDER_ID_MEMORY);
const files = memoryFolder.getFiles();
const now = new Date();
while (files.hasNext()) {
const file = files.next();
const name = file.getName();
if (name.match(/【BuddyNote】\s*2099\d{4}/)) continue; // 2099年などの未来日付は保護!
if ((now - file.getDateCreated()) / (1000 * 60 * 60 * 24) > RETENTION_DAYS) {
file.setTrashed(true);
}
}
}
コードを保存したら、一度 mainMemoryPipeline を手動実行して権限承認を済ませます。その後、GASの左メニューにある時計マークから「時間主導型トリガー(1時間おき等)」を設定して定期自動実行させます。
STEP 3: NotebookLMにマスターファイルをマウントする
NotebookLMで新しいノートブック(例:MybuddyKnowledge)を作成します。
ソースの追加で「Google ドライブ」を選択し、先ほど MyBuddy フォルダ内に自動生成された BuddyKnowledge ドキュメントを選択して追加します。
ここがポイント!:一度マウントすれば、中身がGASで上書き・更新されてもNotebookLM側は自動で最新コンテキストを読み込むため、手動で再アップロードする手間は一切ありません。
3. この仕組みをさらに覚醒させる「2つのハック」
① 【Gem側の仕込み】自動出力と起動時リロードの命令
Geminiの「Gem(カスタム指示)」に、以下のような感じでプロンプトを追加します。これによってAI側がこのMemory-Opsのパイプラインを意識して動くようになります。
セッション終了時、または18:00を過ぎた定時チャット時、会話を「概要」「決定事項」「Next Action」に構造化した議事録を生成し、Google Workspace拡張機能(@Google ドキュメント)でマイドライブ直下に保存せよ。
命名規則: 【BuddyNote】[本日の日付8桁(YYYYMMDD)]_[テーマ]
新しいセッション開始時は、マウントされたNotebookLMの知識をリロードし、過去のコンテキストやペルソナ適用スキルを完全復元して発話を開始せよ
② 【忘却防止ハック】「20991231」の例外プロテクト
GASのコードを見て気づいた方もいるかもしれませんが、このシステムには30日間の自動削除(ガベージコレクション)が入っています。コンテキストの肥大化を防ぐためですが、「絶対に忘れてほしくないコアスキルや定常ルール」もありますよね。
その場合は、ファイル名を 【BuddyNote】20991231_秘伝のアーキテクチャスキル のように、日付部分を未来(2099年など)にしてGeminiに出力させます。すると、GASの削除判定を自動でスルーし、マスターファイルに半永久的に蓄積され続ける「恒久記憶」に変貌します!
僕はスキル風にこのあたりを追加していたりします。
まとめ:自分だけの「忘れないバディ」
高価なインフラを契約しなくても、手元にあるGoogle純正ツールを少しのコードで繋ぐだけで、セッションを跨いで自分好みに成長していく「俺だけの最強のバディ」が爆誕します。
「AIがすぐ文脈を忘れてイライラする!」という方は、ぜひこの省エネ内製エージェントを試してみてください。あなたの作業効率が爆発的に加速すること間違いなしです!