【第6部】AIエージェントの記憶を設計する

# 【第6部】AIエージェントの記憶を設計する
> 連載「Slack AIエージェント基盤を作る」全8部の第6部。
第5部で意図を読めるようになると、次に課題になるのは継続性だ。毎回ゼロから説明するAIエージェントは、業務ではすぐ疲れる。第6部では、短期文脈、長期ナレッジ、ユーザー設定を分けながら、覚えるべきことと覚えてはいけないことの境界を設計 する。
前後で読む
- 前回: 第5部 意図理解で振り分ける
- 次回: 第7部 定期実行で運用する
AIエージェントにSlackから仕事を頼むと、すぐに「前に言ったことを覚えていてほしい」という期待が出てくる。毎回プロジェクトの説明をするのは面倒だし、担当者の好みやチームのルールも引き継いでほしい。
一方で、何でも覚えるAIエージェントは危ない。トークン、個人情報、短期的な会話、未公開の顧客情報まで残してしまうと、便利さよりリスクが大きくなる。
この基盤の記憶設計は、AIエージェントに長期文脈を与えつつ、公開できない情報を本文や成果物に出さないための工夫がある。記憶は単なる履歴保存ではない。何を残し、何を捨て、次回の実行にどう注入するかを決める設計だ。
AIエージェントの記憶は3種類に分ける
記憶をひとまとめにすると扱いにくい。実務では、少なくとも3種類に分けると整理しやすい。
1つ目は短期文脈だ。現在のSlackスレッド、直前の依頼、添付ファイル、実行中ジョブの状態などが入る。これは1ターン、または数ターンだけ使う情報だ。
2つ目は長期ナレッジだ。プロジェクトの方針、開発ルール、記事の文体、成果物の保存方針、レビュー観点などが入る。次回以降も参照する。
3つ目はユーザー設定だ。返信の粒度、好む出力形式、確認を挟む条件などが入る。人によって違うため、全員共通の記憶とは分けて持つ。
この分類があると、AIエージェントの記憶を安全に運用しやすい。短期文脈を長期保存しない。長期ナレッジに秘密情報を混ぜない。ユーザー設定をチーム全体のルールとして扱わない。単純だが、運用では大きな差になる。
記憶をプロンプトへ入れる前に圧縮する
過去の情報を全部プロンプトに入れると、すぐに長くなる。長いだけならまだよいが、古い判断や関係ない会話が混ざると、AIエージェントの判断がぶれる。
記憶は、実行前に圧縮して入れる。たとえば「このプロジェクトではTypeScriptを使う」「記事では冒頭に定型句を置かない」「破壊的な変更は確認する」のように、短いルールへ整える。履歴そのものではなく、次の判断に使える形へ変換する。
OpenAIのコード生成ガイドでも、モデルに渡すコンテキストの質が結果を左右する。AIエージェントの記憶も同じで、量より選別が効く。
記憶更新のタイミングを決める
記憶は、いつ更新するかも設計する必要がある。おすすめは、実行前ではなく実行後に更新候補を作ることだ。
実行前は、ユーザーの依頼を解釈する段階だ。この時点で記憶を書き換えると、誤解した内容が残る可能性がある。実行後に「今回の依頼から次回も使うべき情報は何か」を抽出し、必要なら人間の確認を挟む。
たとえば「今後この形式で出して」と明示された場合はユーザー設定へ残す。「このプロジェクトはこの構成で進める」と決まった場合は長期ナレッジへ残す。
AIエージェントの記憶は、自動で増えるほど賢くなるとは限らない。むしろ、増えすぎると古い情報が残って事故につながる。更新、失効、削除のルールを持つことが欠かせない。
Slack連携で記憶を扱うときの注意点
Slackには、個人名、社内事情、商談、障害対応、未公開の企画などが流れる。AIエージェントがSlackを読むなら、記憶に残してよい情報を強く制限する必要がある。
公開できる設計としては、次の考え方が使いやすい。
- 個人情報は保存しない
- 認証情報らしき文字列は保存しない
- 顧客固有の情報は要約しても残さない
- ユーザーが明示した運用ルールだけ保存候補にする
- 保存する前にカテゴリを付ける
- 保存した記憶は後から削除できるようにする
Slack Bolt for JavaScriptでイベントを受けられるからといって、受けた内容をすべて記憶に回すべきではない。Slack AIエージェントでは、読める情報と覚えてよい情報を別物として扱う。
記憶と検索の違い
AIエージェントの記憶は、単なる検索インデックスではない。検索は「必要な情報を探す」ための仕組みで、記憶は「次の判断に使う前提」を持つための仕組みだ。
たとえば、過去の仕様書を探すなら検索が向いている。チームの開発方針を毎回守らせたいなら記憶が向いている。検索結果をそのまま長期記憶に入れると、情報の出どころや鮮度が分からなくなる。記憶には、誰が決めたか、いつから有効か、どの範囲に適用するかを持たせたい。
記憶設計で先に決める境界
AIエージェントの記憶を語るとき、保存先の名前だけでは設計にならない。重要なのは、常時注入する情報、検索して取り出す情報、後から圧縮する情報、そもそも残してはいけない情報を分けることだ。
Slackスレッド全文をそのまま長期記憶へ入れると、便利そうに見えて危ない。個人情報、顧客固有情報、一時的な判断、誤った発言が混ざる。だからretainでは、会話そのものではなく抽出結果を保存する。bank、TTL、redaction、source、confidenceを持たせ、あとから消せるようにする。
記憶の価値は「たくさん覚える」ことではない。必要な場面で、許された範囲の情報だけを、説明できる形で取り出せることにある。
記憶は「常時注入」と「検索呼び出し」に分ける
AIエージェントの記憶で失敗しやすいのは、全部をプロンプトへ入れることだ。長期運用では、記憶は増え続ける。増えた情報を毎回そのまま入れると、プロンプトは重くなり、古い情報が判断を汚す。
この基盤では、記憶を常時注入する軽い情報と、必要なときだけ検索する重い情報に分ける。
| 種類 | 置き場所の考え方 | 使い方 |
|---|---|---|
| working memory | Markdown / JSON | 毎回読む短い前提、現在の目標、最近の注意点 |
| profile memory | profile設定 | 誰として振る舞うか、読めるbank、書けるbank |
| long-term memory | DB / vector search | 会話から抽出した事実、日次・週次rollup |
| task memory | task registry | 未完了、保留、次回確認すべきこと |
ここで保存判定を挟むのが重要だ。Slackには個人情報、顧客情報、未公開企画、認証情報らしき文字列が混ざる。読める情報と覚えてよい情報は別物として扱う。
memory bankは一方向にする
複数profileを持つ場合、memory bankの読み取り方向を間違えると危ない。個人秘書AIは会社の公開ナレッジを読めてもよい場合があ る。一方、会社用AIが個人の記憶を読むべきではない。
そこで、bank_idとprofileを対応づける。personal profileはpersonalへ書き込み、必要に応じてcorporateを読む。corporate profileはcorporateだけを読む。具体的なDB名やテーブル名を共有しなくても、この一方向性はエンタープライズ導入で重要な設計になる。
書き込みは会話そのものではなく、抽出結果にする
Slackスレッド全文を保存すると、ノイズとリスクが増える。保存するのは会話そのものではなく、次回に使うための抽出結果にする。
{
"type": "project_rule",
"scope": "masked-project",
"source": "slack-thread-summary",
"confidence": 0.86,
"ttl": "90d",
"content": "このプロジェクトでは外部送信前に人間承認を必須にする",
"redaction": "pii-and-secret-checked"
}保存時には、種別、scope、信頼度、TTL、出典、redaction状態を持たせる。これがあると、古い記憶の失効、誤記憶の削除、監査時の追跡がやりやすい。AIエージェントの記憶は、ただの便利機能ではなく、データ管理の対象として扱うべきだ。
system promptとprompt bodyを分ける
CLI agentに渡すプロンプトは、全部を毎回1つの巨大文字列にしない。比較的安定 したルール、人格、利用できるスキル一覧はsystem prompt fileへ寄せる。Slackスレッド、添付ファイル要約、memory recall、今回の依頼はprompt bodyへ入れる。
この分割には理由がある。安定したsystem側はCLIやモデルのprompt cacheに乗りやすい。毎回変わるSlack文脈までsystemへ混ぜると、キャッシュ効率が落ちる。また、長い会話や添付ファイルをCLI引数へそのまま載せると、OSの引数長制限に当たる。そこで、大きい本文は一時ファイルや標準入力へ逃がす。
retain queueで返信体感を守る
会話後の記憶保存は、Slack返信の前に同期実行しない。返信を返したあと、retain queueへ投入する。保存に失敗した場合はfailure queueへ残し、次回のself-checkやheartbeatで拾えるようにする。
この設計にすると、記憶を持つAIでありながら、ユーザー体感を重くしにくい。さらに、memory writeの結果をeventとして残せるので、「どの発話が記憶に残ったのか」「保存に失敗したのか」を後から追える。
記憶は便利な機能ではなく、運用上のリスクでもある。だから、bank分離、TTL、redaction、failure queue、rollupを組み合わせる。覚えることより、どこへ覚えるか、いつ忘れるか、誰が読めるかのほうが難しい。
関連記事
連載「Slack AIエージェント基盤を作る」
- 第1部 Slackを業務OSにする
- 第2部 CLIをサーバーに上げる
- 第3部 並行実装を回す
- 第4部 Slack発言をジョブ化する
- 第5部 意図理解で振り分ける
- 第6部 記憶を設計する
- 第7部 定期実行で運用する
- 第8部 安全性と観測性を固める
- まとめ Slack AIエージェント基盤の全体設計



