太陽がまぶしかったから

C'etait a cause du soleil.

DDDの「境界づけられたコンテキスト」をヒントにプロジェクトに寄り添う Coding Agent の記憶と忘却をコンテキストンジニアリングする

エリック・エヴァンスのドメイン駆動設計

/compact という小さな死

Claude Codeの開発設計において丁寧にコンテキストを積み上げて「この方向でいこう」と合意した直後にcompactionが走ると、次のターンでは合意のニュアンスが失われている。遊園地のキャラクターの「中の人」が変わっているのに、「去年の夏にも来ていて、〜をしてもらった」と子供が言って仕方なしに前回の続きのフリをしてもらっているかのような感覚に近い。

Claude Codeの /compact コマンドはコンテキストウィンドウを自動的に圧縮して、新しい会話が始まる。この振る舞いは連続しているように見えるが記憶は断絶していて小さな死さえ感じる感覚に共感する。3人目の綾波レイだ。

即興演劇において蓄積を放棄する技術は、蓄積を前提にするために苦労するAIエージェントとは真逆のベクトルだ。人間がリセットを強いられ機械が記憶のアップデートを志向するという倒錯に価値があり、それぞれが苦手なことをするからこそ、なんらかの運動量が発生するという構造がある。

「これはゲームなのか?展3」のアフタートークで面白い対比があった。イマーシブシアターの演者は客が入れ替わるたびに蓄積をゼロにリセットするのが技術だという。前の客の反応を引きずったまま初体験である次の客に対応すると、文脈が汚染されて体験の質が落ちるということだ。

/compact はまさにイマーシブシアターの演者が行う蓄積のリセットに近い。前セッションの文脈を引きずらないことで、次のタスクに対してバイアスなく対応できるという利点がある。しかしながらソフトウェア開発においては議論の蓄積こそがドメイン知識であり、蓄積を捨てる技術と蓄積を保つ技術の両方が必要で、どちらをいつ適用するかの判断に技術が宿る。

自分をとりまく空間と時間のすべてが編集対象になる。「良さそうなもの」を無限に足し算していくだけの編集指針ではなく、「これはキャンセル」「これは任せて忘れる」という明示的な引き算の宣言も大切になってくる。

/compact の実行は校正者が紙幅の都合で勝手にカットしていく挙動に近いが、それで編集者が当初に考えたニュアンスが失われることは避けなければならない。コンテキストエンジニアリングとは「何を前提として共有するか」を意図的に設計する技術であるからこそ、「何を捨てて良いか」にこだわり抜いて明示化するのが大事なのだろう。

「何を捨てて良いか」をDDDで設計する

僕自身は個人開発しかしてなくて、あまり意識してこなかったのだけど、業務メンバーと開発メンバー同士の会話の難しさについて改善しようとするとDDD(ドメイン駆動設計)が基本になると改めて感じている。DDDとはエリック・エヴァンスが提唱した設計思想で、ソフトウェアの構造をビジネスの問題領域(ドメイン)に合わせてモデリングすることを核とする。技術的に正しいコードを書くことよりも、業務の言葉でシステムを語れることを優先する考え方だ。

DDDの中心的な概念の一つに「ユビキタス言語」がある。開発者とビジネス側が同じ言葉を使って会話し、その言葉がそのままコードに反映されるべきだという原則だ。「顧客」「注文」「出荷」といった業務用語をそのままクラス名やメソッド名にする。逆に言えば、技術者だけが理解できる命名や抽象化はプロジェクトにとっては不要な知識となる。

この「同じ言葉で話す」という当たり前のことが、実際のプロジェクトでは驚くほど難しい。業務側は「案件」と呼んでいるものを開発側は「プロジェクト」と呼び、同じ「ステータス」という言葉が部署によって違う状態遷移を指している。こうした認知の不一致がバグや手戻りの温床になっていて、会議ですり合ったと思った諸々の概念が開発作業中に失われてしまうリスクへの対応策としてプロジェクト用語集の更新がドメイン知識として必要となる。

境界づけられたコンテキストのエンジニアリング

だからといって全ての用語を網羅した辞書を作りきって意味がないし、暗黙的な言葉の意味づけが界隈によって異なってしまうことは避けられない。このため、DDDのもう一つの要となるのが「境界づけられたコンテキスト」だ。問題領域(ドメイン)たる巨大なシステムを単一のモデルで理解することを諦め、意味が通じる範囲に境界を引いてその中でだけ一貫性を保つ設計思想である。

すでに「営業部門では案件、開発部門ではプロジェクトと呼ぶ」といったように境界ごとに異なるルールが適用されている現状がある場合においては、用語の統一作業に消耗するのではなく、「腐敗防止層(Anticorruption Layer)」と呼ばれる隔離された変換層を準備することで互いの汚染を防ぐのが現実的であり、そこにはウィトゲンシュタインの「言語ゲーム」の概念との接続がある。

言語ゲームとは"言葉の意味は、辞書的な定義にあるのではなく、特定のコミュニティや活動の中でどのように使われているかに依存する"といった前提で論じられる記号論であり、まさに境界付けられたコンテキスト同士の差異のことを指している。同じ境界内にいるからこそ通じる圧縮された会話と、境界の外にも向けた統一された言語に差異が生まれることは前提として、だからこそ境界内の言葉をそのまま外に出さない態度が必要となるということだ。

LLMのコンテキストウィンドウやLLM自体が利用する言葉もまた有限の境界内に存在するものであり、その境界内に有用となるルールや知識をコンテキストに載せ、不要な情報を捨てるエンジニアリングが最終的な出力の質を左右する。LLMにおいても、MoE(Mixture of Experts)というアーキテクチャがあり、どのエキスパートパラメータを活性させるかによって計算資源を削減しながら結果の質を上げるアプローチが採用されることがある。

まず必要な戦略は不要な情報を LLM に読み込ませず、必要な情報だけを必要なタイミングでロードする Lazy Loading の原則だ。

Claude Codeのコンテキスト管理で痛感したLazy Loadingの原則は、境界づけられたコンテキストの設計思想と通底している。CLAUDE.mdやSKILL.mdの設計は、どの境界を活性化するかというDDD的な意思決定であり、Coding Agentがプロジェクトに寄り添い続けるためにcompactionされた際にも生き残る境界を設定しておく操作となる。具体的にはClaude Codeのファイル構成がそのまま境界づけられたコンテキストの実装になっている。

.claude/
├── CLAUDE.md           # 共有カーネル: 全セッションで常にロード
├── rules/
│   └── blog.md         # パス特定ルール: blog/ 配下でのみ活性化
├── skills/
│   └── blog-article-manager/
│       └── SKILL.md    # スキル境界: /blog-article-manager 発動時のみロード
└── settings.json
DDD概念 Claude Code実装 役割
共有カーネル CLAUDE.md 全セッションで常にロードされる最小限の共通理解
コンテキストマップ .claude/rules/ (paths指定) パスに応じて異なるルールを条件付きで活性化
ドメイン層 SKILL.md スキル発動時のみロードされる専門知識の境界
腐敗防止層 .claudeignore、Sub Agents 不要な知識の流入を明示的に遮断する境界
ユビキタス言語 用語辞書、文体ルール 境界内で一貫した語彙を維持する仕組み

Claude Codeでは .claude/rules/blog.mdpaths: blog/** と指定すれば、ブログ記事の編集時にだけ文体ルールが活性化され、コード開発時には一切ロードされない。.claudeignore は明示的に境界の外に追い出すファイルの指定となる。LLM自体にスキルや言葉を教え直すファインチューニングを実施するのは高コストであるため、界隈独特の作法や言葉を変換する辞書を用意してインコンテキストラーニングをしたり入出力における変換層を用意して必要に応じて活性化させることが現実的になる。

多層的なスイッチ機構という解決策

コーディングエージェントにおいて cd でプロジェクトディレクトリを切り替えればプロジェクトという境界内のコンテキストが切り替わり明文化されたルールが適用されるが、汎用的なエージェントで毎回毎回利用すべきコンテキスト指定するのは煩雑だ。かといって「すべての情報にアクセス可能」にすると、セキュリティリスクやコンテキストウィンドウの浪費につながる。

この延長線上には、OAuth における認可と似た構造が見えてくる。AI エージェントに対して「この境界内のコンテキストだったらこのコンテキストセットへのアクセスを許可する」という仕組み、いわば「Bounded Context of Context」の制御なのではないか。

「埋め込みモデル」自体の表現力が、RAGの検索精度向上において、キモの一つになっています。

コンテキストセットだけでなく、精製手法のスイッチも必要だ。メルカリの研究チームは、検索語「coach」を例に挙げている。汎用モデルは「指導者」と解釈するが、EC サイトでは「COACH」ブランドを求めるケースが大半だ。500万件のデータで埋め込みモデルを再学習し、検索精度が向上した。同じテキストでも、どのドメインの文脈で解釈するかによって意味が変わる。Corrective RAG(CRAG)のような動的なコンテキスト調整も重要で、検索結果の信頼度に応じて内部コーパスと外部 Web 検索を切り替える仕組みが求められる。

retrieverが不適切な文書を返した場合、LLMがそれを「根拠」と信じ込み、より自信満々の誤答を生成する危険性がある。

界隈スイッチとしてのペルソナ設定も必要だ。用語集を一から定義するのは現実的ではない。医療、法律、金融、マーケティング、それぞれの界隈には固有の語彙体系があり、同じ言葉でも意味が異なる。「このエージェントは医療従事者として振る舞う」という設定は、単なるキャラクター付けではなく、どの語彙辞書を参照するかという実質的な機能を持つ。

つまり汎用エージェントには、コンテキストセット(参照範囲)、埋め込みモデル(精製手法)、ペルソナ(界隈の語彙辞書)という3層のスイッチ機構が必要になる。しかしこれらを個別にスイッチするのは煩雑すぎる。必要なのは、これらを一括でパッケージ化した「スキルとメモリのコンテナ」だ。

Docker コンテナがアプリケーションと依存関係をまとめるように、エージェントのスキルとメモリをパッケージ化し、タスクに応じてコンテナごとスイッチする。コーディングエージェントではプロジェクトディレクトリ、プログラミング言語用の検索手法、コーディング界隈の語彙辞書のすべてが「ソフトウェア開発コンテナ」として暗黙に提供されていた。真に有用な汎用エージェントが目指すべきは、このようなコンテナを複数持ち、タスクに応じて切り替えられる仕組みなのだろう。コーディングエージェントはそのショーケースの one of them に過ぎない。

プロジェクトに寄り添うCoding Agentの記憶と忘却をエンジニアリングする

しかしどれだけ精巧な境界設計やスイッチ機構を用意しても、ロードする原液の品質が悪ければ意味がない。だからこそ、AI議事録にAI要約機能はいらないと確信を持つようになった。人と固有名詞をちゃんと判別した文字起こしの全文をAI Agentに入れてコンテキストを再生成するのが有用であって、AI要約をコンテキストにしても無駄になることが多い。テキスト全文保存なんてたいした容量ではないのだから、綺麗な要約よりもドメイン知識の自動学習の材料になることが大事だ。

これはCDをマスターにすると永遠に失われる音域がある問題に近い。人間の可聴域の外にも意味がある音が存在するように、AI要約で切り落とされた「些末な」発言の中にこそ、後からドメイン知識として有用になる情報が眠っている。全文と言わず音声だってS3のGlacierにでもぶっこんでおけばストレージコストは誤差の範囲だ。

そもそもマスタリング前の音源を残しておく理由は、機材が進歩する未来があるからだ。同じ音源でも10年後のマスタリング技術で処理すれば、当時は引き出せなかった音が聴こえるようになる。AI Agentもまた進歩していくのだから、2026年の最高地点で要約して残してしまうのは勿体無い。

全文が残っていれば、より賢くなった未来のAIで再度の要約ができる。これはMCPにおいてLLMを内包しない設計思想とも通底している。MCPはプロトコルとしてツールやデータの接続規格だけを定め、どのLLMで処理するかは問わない。データを特定のモデルの解釈に固定しないからこそ、モデルが進化するたびにデータの価値も一緒に上がっていくからこそ、全文を Lazy Loading できる余地を残しておきたいのだ。

プロンプトエンジニアリングとは、AI という新たな他者に対する理解の訓練の末に生まれるものである。

ジョン・ベリーマンの『LLMのプロンプトエンジニアリング』が提起していたのは、AIの動作原理への「共感」だった。AIに「なぜこの情報が必要なのか」「どの文脈で解釈すべきか」を明示しなければ意図通りに動かないという経験は、人間に対しても「よしなに」で済ませてきたコミュニケーションの杜撰さへの反省を促す。

DDDの「境界づけられたコンテキスト」をヒントにプロジェクトに寄り添うCoding Agentの記憶と忘却をエンジニアリングする過程で見えてきたのは、コンテキストを共有せずに「分かるだろう」と期待していた人間同士のコミュニケーションの甘さへの処方箋だった。DDDやスクラムなど人間同士の問題に対するエンジニアリングを再考するサンドボックスとして、Coding Agentとの対話が機能しているという点で、イネーブルメントされているのは自分なのかもしれない。