日本時間2025年5月14日から15日にかけて、サンフランシスコにてAIエージェント開発に特化したテックイベント「LangChain Interrupt」が開催中されています。
ジェネラティブエージェンツはLangChainアンバサダーとして本イベントに現地参加しています。
本記事では、現地参加して得られたDay 1の模様をダイジェストでお届けします。Day 1は、メールエージェントを題材に、LangChainエコシステムの各コンポーネント(LangGraph, LangSmithなど)を駆使して、アイデアから本番稼働可能なエージェントを構築していく過程を体験する、ハンズオン中心の一日となりました。
本日のハンズオンは、公開されている次のリポジトリの内容にのっとったものとなっています。ぜひリポジトリとあわせて記事をご覧ください。
セッション1: Introduction to LangGraph
Lance Martin氏 (LangChain ソフトウェアエンジニア)
最初のセッションでは、LangChainのLance氏が登壇し、イベントのテーマである「アンビエントエージェント」の概念を紹介。チャットインターフェースを超え、バックグラウンドで継続的に動作し、複数のリクエストを処理できるエージェントの可能性を示唆しました。
ダイジェスト
本日のゴールとして、メールエージェントをLangGraphで構築し、テスト、Human-in-the-Loopの導入、記憶(メモリ)の実装までを行うロードマップが提示されました。
エージェントの中心となる概念として「ツール呼び出し」が解説され、LLMが外部API(ツール)を利用して具体的なアクションを実行する仕組みが説明されました。LangChainでは@tool
デコレータで簡単にツールを定義できます。
LangGraphは、ワークフローとエージェントを柔軟に組み合わせるためのオーケストレーションフレームワークとして紹介されました。その主要な構成要素は以下の3つです。
- 状態 (State): アプリケーションの実行過程で追跡する情報。通常はDict(TypedDict)やPydanticオブジェクトで定義される。
- ノード (Nodes): 状態を変更する作業単位。Python関数などで実装される。
- エッジ (Edges): ノード間の遷移を定義し、条件分岐も可能。
MessagesState
のような事前定義された状態オブジェクトや、グラフを一時停止してユーザーのフィードバックを待つ「割り込み (Interrupt)」機能、そして各ステップの状態を保存・復元する「永続化 (Persistence)」機能(チェックポインター)が紹介されました。
余談ですが、今回のイベント名である「Interrupt」は、この割り込みの機能に由来しています。LangGraphでHuman-in-the-Loopを実現するための中核機能なので、その想いも込められているんですね。
最後に、LangGraph Studioを用いたローカルでのエージェント開発・デバッグがデモされました。Studioを使うことで、グラフの実行フローや各ノードでの状態変化を視覚的に確認できます。LangChain(共通コンポーネントの標準インターフェース)、LangGraph(オーケストレーション)、LangSmith(オブザーバビリティとテスト・評価)の連携についても触れ、これらがシームレスに機能することがLangChainのエコシステムなのだと強調されました。
セッション2: Cisco CXにおけるLangChain活用事例
Aman Sardana氏 (Cisco CX シニアプロダクトアーキテクト), Vince Motto氏 (Cisco CX プリンシパルエンジニア)
続いて、Ciscoのカスタマーエクスペリエンス(CX)部門でLangChainがどのように活用されているか、具体的な事例が紹介されました。150億ドル規模のCX部門で、顧客の成功を支援するためのAIアシスタント開発の裏側が語られました。
ダイジェスト
Cisco CXでは、LAER (Land, Adopt, Expand, Renew) モデルに基づき顧客のエンゲージメントを高めるための活動を行っていますが、カスタマーサクセス担当者やリニューアル担当者は情報過多に悩まされていました。この課題に対し、AIを活用してデータアクセスを容易にし、生産性を向上させることを目指しました。
解決すべき課題と技術的イシュー
- データ統合と精度: 多数のコンソールやポータルに散在する顧客データを統合し、営業担当者が顧客とより有意義な会話を行えるようにする。目標精度は95%。技術的には、構造化データ(Snowflake)に対するText-to-SQLの精度向上が課題。
- スケールとアクセス制御: 数百のツールとデータセットを扱うため、スケーラビリティと適切なアクセス制御が不可欠。
- 全体的な顧客ビューとビジネス理解: 顧客の行動全体を把握し、ビジネスにとって何が良い/悪いかをLLMに理解させる必要がある。
- 再現性、説明可能性、標準化: LLMの確率的な性質に対し、決定的で説明可能な出力を生成する工夫が求められた。
- 効果測定: 評価データセットのキュレーションが困難。
構築したソリューション「Cisco AIアシスタント for CX」
- マルチエージェント設計: スーパーバイザーエージェントがユーザーのクエリを解釈・計画し、専門分野(リニューアル、導入、センチメント分析など)を持つドメインエージェントにタスクを割り当て。ディスカバリーエージェントは曖昧な質問の明確化を支援。
- マルチLLM: Claude, OpenAI, Mistral, Cohereなど、タスクや要件に応じて複数のLLMを使い分け。
- 機械学習パイプラインとの連携: Predict MLの出力をSnowflakeに永続化し、LLMが要約して利用。
- LangSmithの活用: 評価とオブザーバビリティにLangSmithを全面的に採用。
本番展開後の効果
- 本番稼働から数ヶ月で、営業担当者の業務時間を20%削減。
- 50以上のシグナルからのデータを統合し、人間では困難だった包括的な顧客インサイトを提供。
- 機械学習と生成AIの組み合わせにより、95%の出力精度を達成。
デモンストレーションでは、リニューアルマネージャーが「ATRで集計した上位5つの取引を表示し、リニューアルリスク、センチメント、導入スコアを教えて」といった複雑な自然言語の質問をすると、AIアシスタントが複数のエージェントを連携させて回答を生成する様子が示されました。LangSmithのトレース画面では、スーパーバイザーエージェントがタスクを計画し、各ドメインエージェントがSQLツールやベクトルストア検索、セマンティックモデル(Snowflake Cortex)を活用して情報を収集・処理する詳細なプロセスが確認できました。
セッション3: Building an Agentic Application
Lance Martin氏 (LangChain ソフトウェアエンジニア)
再びLance氏が登壇し、Day 1のメインテーマであるメールエージェントの構築を進めました。LangGraphの基本概念を踏まえ、より複雑なエージェントアーキテクチャをステップバイステップで構築していきます。
ダイジェスト
このセッションでは、受信メールを処理するアシスタントを構築しました。アーキテクチャは以下の通りです。
- ルーティングステップ: 受信メールを「無視 (ignore)」「通知 (notify)」「応答 (respond)」のいずれかに分類する。
- 応答処理エージェント: 「応答」と分類された場合に、メールへの返信を作成する。
この構成の意図は、常に実行されるルーティングステップ(ワークフロー)と、柔軟な対応が求められる応答処理(エージェント)を組み合わせることで、LangGraphによるワークフローの能力を示すことでした。
状態管理 (State)
MessagesState
を拡張し、メール入力 (email_input
) と分類決定 (classification_decision
) のためのキーを追加しました。
トリアージノード
LLMに受信メールの分類を指示するプロンプト(無視すべきメールの条件、応答すべきメールの条件など)を定義。ここで注目すべきは「構造化出力 (Structured Outputs)」の活用です。Pydanticモデルで出力スキーマ(決定、理由)を定義し、with_structured_output
メソッドでモデルにバインドすることで、LLMの出力を確実にパース可能な形式にしました。トリアージルーター関数は、状態からメールを取得し、LLMに分類させ、その結果に基づいて次の遷移先(応答エージェントまたは終了)と状態更新(メール内容をmessages
キーに格納するなど)を決定します。command
オブジェクトを使用することで、遷移先と状態更新を同時に指定できる利点が紹介されました。
応答エージェントの自作
create_react_agent
のような既存の抽象化を使わず、エージェントをゼロから構築しました。
- システムプロンプト: エージェントの役割(例:エグゼクティブアシスタント)、利用可能なツール(メール作成、会議スケジュール、カレンダー確認、完了)、メール処理の指示などを記述。
- ツール設定:
@tool
で定義したツール群をモデルにバインド。ここでは、エージェントに常にツールを呼び出させ、完了時にはdone
ツールを呼び出してフローを終了させる設計としている。これは、チャットインターフェースを介さず、Human in the Loopでやり取りするアンビエントエージェントに適したアプローチ。 - LLM呼び出しノード: プロンプトをフォーマットし、LLMを呼び出し、出力を
messages
に追加。 - ツール実行ノード: LLMからのツール呼び出しを受け取り、対応するツールを実行し、ツールメッセージを
messages
に追加。 - 条件付きルーター:
done
ツールが呼び出されるまでツール呼び出しを繰り返すループを制御。
ルーターとエージェントの結合
定義したトリアージルーターと応答エージェントを、LangGraphのグラフ構成機能を使って一つのワークフローとして結合しました。これにより、トリアージ結果に応じて応答エージェント(サブグラフとして扱われる)が呼び出されるシステムが完成しました。
動作テストとLangSmith Studioによるデバッグ
「通知」ケース(システム管理者からのメンテナンスメール)と「応答」ケース(APIドキュメントに関する質問メール)で動作をテスト。LangSmith Studio上で実行し、各ノードの動作や状態遷移、LLMの入出力などを詳細に確認できる様子がデモンストレーションされました。
Q&A
Q: done
ツールの役割は何ですか?何もしないように見えますが。
A: done
ツール自体は具体的なアクション(メール送信など)を行いませんが、モデルがこのツールを呼び出すことは、システムに対する「完了」のシグナルとなります。このシグナルを条件付きルーターで捉え、エージェントのループを終了させるなど、制御フローを決定するために使用します。ツール呼び出しは、外部APIを叩くだけでなく、エージェント内部のフローを指示するのにも非常に便利なトリックです。
Q: プロンプトをシステムメッセージに入れるべきか、AIメッセージ(あるいはユーザーメッセージ)に入れるべきか、使い分けの基準はありますか?
A: これはモデルプロバイダーによって見解が異なることもありますが、私の一般的な使い分けとしては、システムプロンプトには不変的な指示(エージェントの役割、一般的な処理方法など)を入れ、ユーザープロンプトには可変的な入力(具体的なメール内容など)を入れるようにしています。例えばトリアージルーターでは、メールの分類方法に関する一般的な指示はシステムプロンプトに、実際のメール内容はユーザープロンプトとしてLLMに渡しています。
セッション4: Evaluating Your Agent
Nick Huang氏 (LangChain デプロイエンジニア)
セッション3で構築したメールアシスタントを本番環境に投入する前に不可欠なステップ、「評価」について、Nick氏が解説しました。評価の重要性から具体的な手法、LangSmithを活用した実践的な評価方法までが網羅されました。
ダイジェスト
メールアシスタントが会議のスケジュール設定やメール返信といった重要なタクションを実行することを考えると、本番投入前の厳密な評価は不可欠です。このセッションでは、そのための具体的な評価戦略が提示されました。
評価の粒度
- 最終出力の評価: エージェントが生成した最終的なメール返信が、意味をなし、成功基準を満たしているか。
- ユニットテスト: アプリケーションの特定部分のテスト。特にトリアージルーターのように、後続の処理に大きな影響を与えるコンポーネントの評価が重要。
- 軌跡 (Trajectory) の評価: エージェントが正しいプロセス(ツール呼び出しの順序など)を経て回答にたどり着いているか。
評価対象の出力タイプと評価方法
- 構造化出力: トリアージルーターの分類結果など。正解データとの比較が容易(例:
expected == actual
)。 - 非構造化出力: 生成されたメール本文など。単純な文字列比較では不十分な場合が多く、LLMをジャッジとして利用し、事前に定義した成功基準に基づいて評価する方法が有効。
具体的な評価計画
- トリアージングステップのユニットテスト。
- ツール呼び出しエージェントの軌跡のユニットテスト。
- LLMをジャッジ (Judge) として使用した、非構造化最終出力のエンドツーエンド評価。
評価アプローチ
- Pytestのようなテストフレームワークの利用: 既存のテスト作成フローに近く、デコレータ(例:
@pytest.mark.langsmith
)を使うことでLangSmithに結果を記録可能。 - LangSmithネイティブなアプローチ: ゴールデンデータセット(入力と理想的な出力のペア)をLangSmith上でキュレーションし、評価を実行。LangSmithは、本番トレースからのデータセット作成、アノテーションキュー、合成データ生成などの機能を提供。
Pytestによる軌跡評価の実装
メール入力に対し、エージェントが期待されるツールを呼び出したかをテスト。期待されるツール呼び出しと実際のツール呼び出しを比較し、欠損があればLangSmithに記録。@pytest.mark.langsmith
デコレータにより、テスト結果(合格/不合格、レイテンシ、トークン数、コストなど)がLangSmithに記録され、詳細な分析が可能になります。
LangSmith SDKによるトリアージ評価の実装
LangSmith SDKを使い、トリアージの例(入力メールと期待される分類)からなるデータセットを作成。ターゲット関数(メールアシスタントにメール入力を渡し、分類決定を取得)と評価関数(ターゲット関数の出力とデータセットの参照出力を比較)を定義。evaluate
関数にこれらを渡して評価を実行し、結果をLangSmithで確認。期待と異なる結果が出た場合、LangSmith上でトレースを詳細に確認し、プロンプトやモデルの改善に繋げることができます。
LLM as a Judgeによる評価
モデルからの非構造化出力(例:メール本文)を評価するために、別のLLM(ジャッジLLM)を利用。ジャッジLLMには、評価基準(例:「正しいメールツールを使って質問を確認し、チームの誰かが調査することを確認するメールを送信してほしかった」)とエージェントの出力を与え、基準を満たしているか否かとその理由を構造化データ(例:CriteriaGrade
クラスのインスタンス)として出力させます。これにより、人間が直接評価する手間を削減しつつ、柔軟な基準で評価できます。
ニック氏は、LangSmithがAPIおよびSDKファーストであり、UIで行える操作の多くがプログラムからも実行可能であることを強調しました。
Q&A
Q: テストが失敗したらどうしますか?本番アプリケーションでのテスト失敗に取り組むための推奨事項はありますか?
A: ここで紹介したテストは主にオフライン評価、つまりCIパイプラインの一部として本番デプロイ前に実行するものです。これにより、変更が予期せぬ問題を引き起こさないかを確認できます。一方、本番稼働中のアプリケーションに対してはオンライン評価という考え方があり、これは本番トレースに対して実行され、リアルタイムでパフォーマンスを監視します。LangSmithではアラートや監視機能を通じて、本番環境での障害を検知し対応できます。
Q: ツール呼び出しの正しいシーケンスをテストできますか?
A: はい、可能ですし、多くの場合そうすべきです。単純なセット比較だけでなく、呼び出し順序の完全一致、サブセット/スーパーセット比較、さらにはツール呼び出しの引数に対する期待値(例:特定の日付で会議がスケジュールされたか)など、軌跡評価は非常に深い概念です。LangSmithのオープンソースパッケージには、これらの評価を支援する機能があります。
Q: フローに複数のLLMまたはエージェントがある場合、それぞれの出力をどのように評価できますか?
A: LangGraphでは、各ノードの出力を状態に書き込むことができるため、特定のLLMやエージェントの出力を個別に評価できます。また、エージェント全体を実行する代わりに、特定のノード(関数)だけを対象にユニットテストを行うことも可能です。
Q: LangSmithをLLM as a Judgeでどのように使用しますか?ユニットテストと多かれ少なかれ同じですか?
A: LLM as a Judgeもユニットテストの一形態と言えます。出力が構造化されていてコードで検証可能ならそれが簡単ですが、非構造化出力で人間的な判断や柔軟な基準が必要な場合にLLM as a Judgeが特に強力です。
Q: LLM as a Judge評価のためのゴールデンデータセットを合成する方法についての推奨事項はありますか?
A: 人間(特にドメイン知識を持つ専門家)をプロセスに組み込むことが有効です。LangSmithのアノテーションキュー機能を使えば、本番トレースをアノテーションキューに送り、専門家が「エージェントは正しいことをしたか?何をすべきだったか?」といった評価を簡単に行えます。これにより、実際の利用シーンに基づいた質の高いゴールデンデータセットを継続的に作成できます。
Q: 実験におけるバージョン管理、ならびに実験のトレーサビリティの確保はどのようにすれば良いですか?
A: LangSmithの実験にはメタデータフィールドがあり、ここにコードのバージョン、プロンプトのバージョンなどを記録できます。このメタデータを使って実験結果をフィルタリングしたり検索したりすることが可能です。プロンプトハブを使えば、プロンプトのバージョン管理もLangChain内で行えます。
Q: メトリクスはあるものの必ずしも堅牢ではない場合に、自信をもって提供するには、どのくらいの評価データが必要でしょうか?
A: これは非常に難しい問題で、万能な答えはありません。テスト駆動開発の考え方に基づき、エージェントが取りうる様々なパスや直面しうる様々な質問タイプをカバーするようにテストケースを設計することが重要です。本番トレースを出発点とすることは、実際にエージェントが直面する問題を把握する上で役立ちます。最初にベースとなる10~20の重要なテストケースを定義し、そこから徐々に拡充していくのが良いアプローチでしょう。
セッション5: Human in the Loop
Nick Huang氏 (LangChain デプロイエンジニア)
評価に続き、ニック氏はHuman in the Loopの概念と、それをメールアシスタントに組み込む方法を解説しました。特に機密性の高いアクションについては、人間の承認を介在させることの重要性が強調されました。
ダイジェスト
エージェントが自動でタスクを実行する際、特にメール送信やカレンダー登録のような機密性の高いアクションについては、ユーザーが事前に確認・承認できる仕組みが求められます。このセッションでは、そのためのUI「Agent Inbox」と、LangGraphを用いた実装方法が紹介されました。
Agent InboxについてはAIエージェントキャッチアップでも取り上げたことがあります。ぜひあわせてご覧ください。
Agent Inbox
エージェントが実行しようとしているアクション(例:会議のスケジュール)をユーザーに提示し、「無視」「編集」「承認」「フィードバックを与えて再考させる」といった選択肢を提供するUIです。
ヒューマンフィードバックを導入する箇所
- トリアージステップ: 「通知」と分類されたメールをAgent Inboxに提示し、ユーザーに応答させるか、無視するかを選択させる。
- 機密性の高いツール呼び出し: メール作成や会議スケジュールなど、実行前にユーザーの承認を得る。
- エージェントからの質問: エージェントがユーザーに追加情報を求める際に、Agent Inboxを介して質問を提示し、ユーザーからの回答を受け付けるための新しい「question」ツールも導入されました。
ヒューマンフィードバックの実装 (LangGraph)
トリアージノードへの実装
- トリアージ結果が「通知」の場合、専用の「トリアージ割り込みハンドラー」ノードに処理を移します。
- このハンドラーは、メール内容をAgent Inboxで表示するためのリクエストオブジェクト(アクション名、表示するボタンの種類、説明などを含むスキーマ)を作成し、LangGraphの「割り込み (Interrupt)」を発生させます。
- ユーザーがAgent Inboxでアクション(例:「応答する」)を選択すると、その応答がグラフに返され、それに基づいて次の遷移先(例:応答エージェント)が決定されます。
メール応答エージェントへの実装 (機密性の高いツール呼び出し)
- LLMが機密性の高いツール(メール作成、会議スケジュール、質問)を呼び出そうとした場合、専用の「割り込み処理ノード」で処理します。
- このノードは、呼び出されたツールに応じて、Agent Inboxに表示するアクション(無視、編集、承認、フィードバック)を設定し、リクエストを作成して割り込みを発生させます。
- ユーザーの応答タイプ(承認、編集、無視、フィードバック)に応じて、以下のような処理を行います。
- 承認: LLMが提案した引数でツールを実行。
- 編集: ユーザーが編集した引数でツールを実行。さらに、後続のLLMの混乱を避けるため、メッセージ履歴内の元のAIメッセージの引数も編集後のものに更新します。
- 無視: 実行を終了。
- フィードバック: ユーザーからのフィードバックをツールメッセージとしてメッセージ履歴に追加し、LLMに再度処理を促します。
Agent Inboxとの連携デモンストレーション
ローカルでlanggraph dev
コマンドを使ってLangGraphアプリケーションをサーバーとして起動し、Agent Inbox(フロントエンドクライアントとして機能)をそのサーバーに接続。ユーザーがメールアシスタントにタスクを依頼すると、機密性の高いアクションの前にAgent Inboxに通知が表示され、ユーザーが承認や編集を行うと、その結果がLangGraphアプリケーションに送り返されて処理が続行される様子が実演されました。
Q&A
Q: (ノートブックの例のように) invoke
で割り込みを処理することもできますか?
A: はい、invoke
でも割り込みを処理できます。ノートブックでは、割り込みが発生するまでのイベントストリームを捉えるためにstream
を使用していました。
Q: フィードバックをより永続的なものにし、将来のすべての実行に適用することは可能ですか?
A: はい、可能です。これは次のDavid氏の「記憶(メモリ)」に関するセッションで詳しく説明されます。
Q: 本番環境で実行する場合、Agent Inbox内の各保留中のメッセージはサーバー上のスレッドをブロックしていますか?
A: いいえ、ブロックしません。LangGraphのチェックポイント機能により、割り込みが発生するとスレッドの実行は一時停止され、その時点の状態が保存されます。ユーザーが応答して処理を再開する際には、保存された状態から再開されるため、リソースをブロックし続けることはありません。
Q: チェックポイントはどのくらいの期間存在できますか?どのくらい保存できますか?
A: アプリケーションの設定で、チェックポイントのTTL(Time To Live)を設定できます。
Q: これを行うための推奨方法はありますか?LangGraph Platformのようなものはありますか?
A: はい、LangGraph Platformというものがあります。
Q: 実際にリクエストを行うためにAPIトークンを安全に保存するにはどうすればよいですか?
A: LangGraph Platformには認証・承認レイヤーが組み込まれており、ユーザーに基づいて権限を管理できます。また、LangGraphコード内で環境変数からシークレットを読み込む方法もあります。
Q: 割り込みは、Agent Inbox UIの代わりに、外部アプリケーションのインボックスにルーティングできますか?
A: はい、可能です。Agent InboxはLangChainが提供する一つの方法ですが、独自のフロントエンドを構築し、異なるスキーマでLangGraphとやり取りすることも完全に可能です。
Q: エージェントが扱えるツールの数について、何か指針はありますか?10個程度が良いという話も聞きますが。
A: ツールの数に絶対的な上限はありません。重要なのは、ツール同士が明確に区別できるか、エージェントのプロンプトにどれだけの指示を詰め込んでいるか、などです。結局のところ、テストを通じて最適なバランスを見つけるしかありません。
Q: エージェントは私たちが与えている指示から学習しますか?
A: 現時点では直接的には学習しませんが、次のDavid氏のセッションで、記憶(メモリ)を使ってどのように実現できるかを見ていきます。
セッション6: Memory(Short & Long-term) / Deploying Your Agent
David Xu氏 (LangChain)
Day 1の最終セッションでは、David氏が登壇し、エージェントに「記憶(メモリ)」を実装することで、ユーザーの好みや過去の対話に基づいて自己改善する能力を与える方法を解説しました。さらに、構築したエージェントをLangGraph Platformを使って本番環境にデプロイする手順も示されました。
ダイジェスト
エージェントが真に役立つためには、過去のやり取りから学習し、ユーザーの好みを記憶し、それに基づいて将来の応答をパーソナライズする能力が不可欠です。このセッションでは、そのための「メモリ」機能の実装に焦点が当てられました。
LangGraphにおけるメモリ
- 短期記憶 (スレッドスコープメモリ): 単一の会話スレッド内でのみ永続的なメモリ。会話履歴のコンテキスト保持に利用されます(例:Nick氏のセッションでのチェックポインター)。
- 長期記憶: 複数のスレッドやセッションをまたいで永続する知識ベース。
LangGraph Store
長期記憶を扱うための柔軟なデータベース。以下の3つの実装タイプがあります。
- インメモリ (In-memory): Python Dict。永続性はなく、プロトタイピング向け。
- ローカル開発サーバー: 再起動後もデータをローカルファイルに永続化。開発向け。
- PostgreSQL: 本番環境向け。LangGraph Platformでデプロイすると自動的に提供される。
ストアへのメモリの追加 (.put
) と取得 (.search
) は、名前空間(例:ユーザーID + "memories")を指定して簡単に行えます。グラフ全体にメモリストアへのアクセス権を与えるには、グラフをメモリストアでコンパイルします。
メールアシスタントへの長期記憶の実装
- 目的: ユーザーからのフィードバックを保存し、将来の応答のパーソナライズや間違いの回避に活用する。
- メモリ構造: 簡単のため、文字列として保存。
- 更新方法: LLMを利用。既存のメモリプロファイル、最新のフィードバック、カスタム指示に基づいてメモリを更新。
デフォルトメモリの定義
エージェントに初期状態で持たせるべき知識を定義。
- メールのトリアージ方法: 応答/無視/通知の基準。
- 会議のスケジュール方法: 好ましい会議時間(例:30分)、許容範囲(例:15分でも可)。
- メールの書き方: プロフェッショナルで簡潔な文体、締め切りへの言及方法など。
ヘルパー関数の実装
get_memory
: 指定された名前空間からメモリを取得。存在しない場合はデフォルトコンテンツを返す。update_memory
: LLM(GPT)を使用してメモリを更新。既存のメモリプロファイル、ユーザーメッセージ(フィードバック)、カスタム指示(例:「メモリプロファイルを完全に上書きせず、的を絞った追加のみ行う」)を入力とし、更新されたメモリをストアに保存。
既存機能へのメモリ統合
- トリアージルーター: ハードコードされた指示の代わりに、長期記憶から取得したトリアージの好みをプロンプトに注入。
- トリアージ割り込みハンドラー: ユーザーが「通知」されたメールに対してフィードバック(例:「このメールには返信すべきだった」)を提供した場合、その情報を長期記憶に保存し、トリアージの好みを更新。
- LLMコールノード (応答エージェント内): 長期記憶からカレンダー設定や応答スタイルの好みを読み込み、ツール呼び出し(会議スケジュール、メール作成など)の際のプロンプトに注入。
- 割り込みハンドラー (応答エージェント内): ユーザーがツールコール(例:メール下書き)を編集したり、自由形式のフィードバックを与えたりした場合、その内容を長期記憶に保存し、関連する好み(メールスタイル、会議設定など)を更新。
自己改善するメールアシスタントのテスト
ユーザーがエージェントのアクションを修正なしで承認した場合、ツールコールを編集した場合、自由形式のフィードバックを与えた場合に、メモリがどのように更新され、将来の決定にどう影響するかをテストケースを通じて確認しました。例えば、会議の長さを45分から30分に編集すると、その情報が記録され、将来の会議スケジュールのデフォルトが30分になる、といった具合です。
LangGraph Platformによる本番デプロイ
構築した長期記憶を持つメールアシスタントを、LangGraph Platformを使って本番環境にデプロイするデモンストレーションが行われました。LangGraph Platformは、ローカルで開発したエージェントをワンクリックで本番APIとしてデプロイでき、スケーラビリティ、短期・長期記憶、cronジョブのようなスケジュール実行機能などを提供します。デプロイされたエージェントはAPI URL経由でアクセス可能になり、実際のGmail受信トレイと連携させ、定期的にメールをトリアージさせることも可能になります。
Q&A
Q: 長期記憶のスコープを定義する最良の方法は何ですか?(例:トリアージ、カレンダー、応答の好みを分離するか、1つのブロックにマージするか)
A: どのLLMコールが具体的にどのメモリを必要とするか、という観点から考えるのが自然です。例えば、トリアージルーターはトリアージの好みに関するメモリを、応答エージェント内のLLMコールはカレンダー設定や応答スタイルのメモリを必要とします。また、メモリの更新も考慮に入れるべきです。カレンダーツールコールが編集されたら、カレンダーの好みに関するメモリだけを更新したいですよね。このように、メモリがどこで使われ、どのように編集されるかに基づいて名前空間を分割するのが合理的です。将来的には、LangMemのようなライブラリを活用し、セマンティック検索などでより柔軟にメモリを取得することも考えられます。
Q: メモリはテキストとして保存されますか、それとも埋め込みとして保存されますか? また、長期記憶を利用しているエージェントを評価するための特定のテクニックはありますか?
A: メモリの保存形式は開発者次第です。テキストの一部を埋め込みとして保存し、セマンティック検索に利用することも可能です。長期記憶を利用するエージェントの評価は、まだ確立された手法があるわけではありませんが、メモリ取得の品質と、取得したメモリをどう利用して最終応答を生成するかの2段階で評価するアプローチが考えられます。
Q: 複数の異なるユーザーのメモリをどのように管理・維持しますか?プライバシーは?
A: ユーザーIDごとに異なる名前空間を使用することで、ユーザーごとのメモリを分離できます。メモリをプールすることも技術的には可能ですが、PII(個人識別情報)の扱いなど、プライバシーとデータセキュリティには細心の注意が必要です。
Q: エージェントが矛盾するフィードバックを受け取った場合、メモリは最新のものを優先しますか?
A: メモリ更新のロジックはカスタマイズ可能です。セッションで示したように、LLMにカスタムプロンプトを与えることで、どのようにフィードバックを解釈し、メモリを更新するかを詳細に制御できます。
Q: コンテキストウィンドウの制限がある中で、メモリのスケーラビリティをどのように保証しますか?
A: 現在は最も単純なアプローチ(各メモリタイプを単一の文字列として保存・更新)を取っていますが、LangMemのように複数のメモリをリストとして保存し、セマンティック検索や他のヒューリスティック(例:メール送信者に基づいて関連メモリを検索)で必要な情報だけを取得する方法があります。これにより、LLMに渡すコンテキストの量を制御しつつ、豊富な情報を活用できます。
Q: なぜ長期記憶にVector DBを使用しないのですか?
A: LangGraphのPostgreSQLストアはPGVectorをサポートしており、セマンティック検索が可能です。将来的にはリポジトリにもその実装例を追加する予定です。
Q: 長期記憶が大きくなるにつれて、それをどのように管理しますか?
A: 短期記憶のチェックポイントと同様に、長期記憶にもTTLを設定できます。また、LLMを使って定期的にメモリを要約・整理し、古い情報や冗長な情報を削除することも有効です。
Q: 2つのエージェントはどのようにメモリを共有しますか?
A: LangGraph Platformで複数のエージェントをデプロイし、リモートグラフインターフェースを使えば、あたかも同じグラフ内にあるかのようにエージェント間で状態を共有し、連携させることが可能です。
Q: メモリを効果的にソート・整理するためにプロンプトを反復処理するプロセスはどのようなものですか?
A: OpenAI GPTのプロンプティングガイドなどを参考に、シンプルな評価セット(期待するメモリ更新結果)を用意し、それに対してLLM(またはコードアシスタント)にメモリ更新プロンプトを実行させ、期待通りになるまでプロンプトを修正していく、という反復的なプロセスが有効です。
Q: エージェント設計全般に関するメンタルモデルはありますか?
A: できるだけシンプルな構成から始め、評価結果に基づいて徐々に複雑性を加えていくのが良いアプローチです。本当にエージェントが必要なのはどの部分かを見極め、その難しい部分に焦点を当てて最も単純なバージョンを構築し、必要に応じて改良を加えます。コンテキスト管理やツールコールの連鎖など、エージェント開発特有の難しさもあるため、明確な評価基準を設定し、それに基づいてプロンプトやツール定義を反復的に改善していくことが重要です。
Day 1を終えて
印象的だったのは、単にLLMを呼び出すだけでなく、ツール、状態管理、制御フロー、評価、Human-in-the-Loop、記憶(メモリ)といった要素をいかに洗練された形で組み合わせるかという、エンジニアリングの側面が強調されていた点です。Ciscoの事例は、これらの技術が実際のビジネス課題解決に大きく貢献しうることを示していました。まだLangGraph PlatformはGAしていないのですが、Ciscoの事例ではしれっとスライドでLangGraph Platformが使われていたのも、見逃せないポイントでした。明日のDay 2ではLangGraph Platformのまとまった話が出てくるらしいので、楽しみです。
余談ですが、アンバサダーミートアップで、共著した書籍にHarrison氏からのサインをもらいました・・・! Awesome Book!
また、Day 1の直後にXスペースで感想戦を行いましたので、こちらもご興味があれば、ご覧ください。
— LangChainJP (@LangChainJP) 2025年5月14日
本参加レポートが、イベントに参加できなかった方々や、AIエージェント開発に関心を持つすべての方々にとって、有益な情報となれば幸いです。
現場からは以上です。