本チュートリアルでは、Letta を使ってステートフルなエンジニアリング・コパイロットを構築し、エージェント型メモリ(agentic memory)が従来のプロンプトベースの会話をどう超えていくかを示します。まず、エージェント自身が自律的に更新できる検査可能なコアメモリブロックを作成し、それらのブロックを公開してプログラムによる状態同期や複数エージェント間での共有アクセスを可能にします。さらに、セマンティック検索のためのアーカイバル・ベクトルメモリ、決定論的なリスク推定を行うカスタムのサーバーサイドツール、エージェントの実行を観察するためのストリーミング、永続的な会話のためのサーバーサイドメッセージ履歴、そしてポータビリティのための .af エクスポートでアーキテクチャを拡張します。これらのコンポーネントを組み合わせることで、永続状態・検索・ツール・マルチエージェント協調・実行トレースが統合されたエージェント型システムとして機能する、実用的なメモリアーキテクチャを示します。
最初に Letta クライアントをインストールして初期化し、Letta のバージョン間の API 差異に対応するための互換性ヘルパーを追加します。flex ヘルパーは複数の呼び出し形式を順に試し、すべて失敗した場合には明確なエラーを送出します。利用可能なモデルの動的選択では、openai/gpt-4.1、openai/gpt-4o-mini、anthropic/claude-sonnet-4-20250514 の順に優先し、いずれも利用できなければモデル一覧の最初のハンドルにフォールバックします。次に、構造化されたコアメモリブロックを備えたステートフルなエンジニアリング・コパイロットを作成します。ブロックは次のとおりです。persona(私は Mnemo というエンジニアリング・コパイロットであり、簡潔で具体的、事実を決して捏造せず、分からないことは分からないと言ってから調べる)、human(協働するエンジニアに関する永続的な事実:名前、役割、スタック、好み、作業スタイル。安定した情報を学ぶたびに更新する)、project_state(出荷中のプロジェクトのライブ状態:マイルストーン、ブロッカー、決定とその根拠。密で最新に保ち、古い行は削除する)、lessons(苦労して得た教訓と二度と繰り返さない誤り。追記のみ、1 行ずつ)。作成後はエージェント ID を出力し、初期のコアメモリをダンプしてエージェントの永続コンテキストの基準を確立します。
次に自己編集メモリを示します。コパイロットに「私は Priya、Northwind のスタッフエンジニア。11 月 14 日に Rust の取り込みサービス『Halo』を出荷する。長い説明は嫌い——箇条書きかコードだけにして、エッセイは不要。現在のブロッカーは、Kafka コンシューマが負荷時に約 4 分ごとにリバランスすること」と伝えます。続けて「更新:リバランスは 5 秒の max.poll.interval.ms と遅いバッチコミットに起因すると突き止めた。決定:コミットをポーリングループの外に移す。また、session.timeout.ms を増やすのは既に試して効果がなかった——二度と提案しないで」と補足します。2 ターン後に再びコアメモリをダンプし、どの情報がどのブロックへ移動したかを観察します。これにより、エージェントが永続的な事実を human に、決定を project_state に、失敗の教訓を lessons に自律的に振り分ける様子が分かります。
第 3 段階では、アプリケーションコードがコンテキストウィンドウへ直接書き込めることを示します。ブロックから現在の project_state を読み取り、「[CI 09:41Z] main が赤:integration/kafka_rebalance_test が失敗(3 回フレーク再現)」という行を追記します。その後「今日の作業を始める前に知っておくべきことは?」と尋ね、外部から注入した状態を活用できることを検証します。
第 4 段階では 2 つのエージェント間の共有メモリを示します。読み取り専用の policies ブロック(交渉不可のエンジニアリングポリシー:1. main への直接プッシュ禁止、2. すべての修正には回帰テストを付ける、3. 顧客データは EU リージョン外に出さない)と、コパイロットとレビュアーエージェントが共有する読み書き可能な team_scratchpad ブロック(双方が読み書きし、エントリには自分の名前を前置する)を作成します。この 2 つのブロックをコパイロットにアタッチし、次に reviewer エージェント(ペルソナは Argus、他の誰もが見落とした失敗モードを探し、チームポリシーを番号で引用する偏執的なスタッフレビュアー)を作成して同じ 2 つのブロックを共有させます。コパイロットにリバランス問題の修正案を team_scratchpad に書かせ(4 行以内)、レビュアーが見る共有ブロックの内容を出力したうえで、reviewer に team_scratchpad を読んで修正案をレビューさせ、違反するポリシーを引用し、判定を同じブロックに追記させます。最後にレビュアー返信後の共有ブロック内容と、そのブロックにアタッチされたエージェント一覧を出力し、マルチエージェント間の永続的な作業コンテキストの交換を検証します。
第 5 段階はアーカイバルメモリです。タグ付きのエンジニアリング知識を一括ロードし、完全一致のキーワードに依存せずセマンティック検索で関連情報を取得します。知識項目には、2024-08-02 のポストモーテム(Halo がデプロイ中のコンシューマグループのリバランスで 120 万イベントを失った。根本原因はポーリングループ内のコミットが max.poll.interval.ms を超えてブロックしたこと)、ADR-017(Halo は少なくとも 1 回配信を用い、(tenant_id, event_id) をキーとする冪等書き込みを行う。スループット上の理由から Kafka トランザクションによる exactly-once は却下された)、そして Halo ノードをドレインする手順のランブックが含まれます。その後、エージェントが運用上の質問に答える際にこのアーカイバル知識を自律的に照会できるようにします。
最後に、決定論的なリスク推定のためのカスタムサーバーサイドツール estimate_release_risk を作成してアタッチします。この関数は open_bugs(未解決の P0/P1 バグ数)、days_to_deadline(出荷日までの残り日数)、test_coverage(0.0〜1.0 のカバレッジ)を受け取り、pressure = open_bugs / max(days_to_deadline, 1)、score = max(0.0, min(100.0, 100 * (1 - exp(-1.4 * pressure)) * (1.3 - test_coverage))) を計算し、判定を返します。35 未満は SHIP、70 未満は SLIP ONE WEEK、それ以上は DO NOT SHIP で、risk_score=… verdict=… の形式で返します。このツールを upsert してコパイロットにアタッチし、アタッチ済みツールとエージェントのツール一覧を出力したうえで、「未解決の P0/P1 バグが 9 件、11 月 14 日まで残り 12 日、カバレッジ 0.61」という条件でツールを呼び出してスコアリングさせ、判定を project_state に記録させます。
以上のように、本チュートリアルは永続状態・検索・ツール・マルチエージェント協調・実行トレースが統合されたエージェント型システムとして連携する様子を示します。さらに、ストリーミングによるエージェント実行の観察、サーバーサイドメッセージ履歴による永続会話、.af エクスポートによるポータブルなエージェントワークフローも扱います。なお、チュートリアル内のヘルパー関数は複数の API バリアントに対応するよう作られているため、実際に実行する際は使用する Letta クライアントのバージョンに応じて呼び出し形式を調整する必要がある場合があります。また、例示されたモデルハンドルや埋め込みモデル(openai/text-embedding-3-small)はアカウントの利用可否に依存します。