人の確認を、処理の一部として組み込む
生成した回答案を確認してから送る、申請内容を本人が見直してから登録する、といった場面では、人の判断を実行手順へ組み込みます。これをHuman-in-the-loopと呼びます。AIを使う仕事の途中に、人が承認・修正・拒否できる段階を置く考え方です。
「重要な操作の前に確認してください」とプロンプトへ書くだけでは、確認待ちの状態がアプリケーションに保存されるとは限りません。何を実行しようとしているのかを提示し、そこで実行を止め、判断が返るまで待ち、判断に従って再開する仕組みが必要です。
LangChainとLangGraphでの位置づけ
LangChainでは、ツール実行前などに確認を挟むための部品を利用できます。これは、実行の途中へ処理を差し込むmiddleware(ミドルウェア)の一つで、詳しくは次の節で扱います。より独自の処理では、LangGraphのinterruptという中断の仕組みを使って、人の判断を待つ構成を作れます。どちらの場合も、中断中の状態と、再開する対象を保持することが重要です。
LangGraphでこの中断・再開を構成するときは、checkpointerで状態を記録し、threadの識別子で再開する対象を指定します。人の判断を再開の入力として渡し、待機していた処理へ戻す流れになります。画面に確認の文を表示するだけの動作と、処理の続きまで保存して待つ動作は異なります。
LangChainの確認用middlewareを使う場合も、状態を保存するcheckpointerと、同じ確認待ちの処理へ戻るためのthreadの指定が必要です。確認を挟む部品と、待機中の情報を保持する仕組みを組み合わせます。
第7節では、checkpointerが会話を続けるための状態を保存しました。ここでは、同じ考え方を使って「どんな操作の確認を待っているか」を保存します。たとえば「申請案を作成済み、登録は未実施、承認待ち」という状態です。承認が返った後で登録し、拒否された場合には登録しない、という経路へつながります。
確認する人へ示す情報は、「何かを実行してよいか」だけでは不十分です。どの機能を、どの引数で、誰のどの情報へ適用するかが分からなければ、意味のある承認になりません。申請を登録するなら、対象の利用者、日付、金額、登録先など、操作内容を確認できる形にします。
承認・修正・拒否で、進む経路を変える
承認された場合は、確認された内容を実行へ進めます。修正が必要なら、変更後の内容に対して条件を再確認します。拒否された場合は実行しない経路へ進めます。人が画面を見たという事実だけで、すべてを承認済みと扱わないことが大切です。
判断を記録するときは、何に対する承認なのかを対応づけます。承認後にモデルが引数を変更したのに、以前の承認をそのまま流用すると、確認した内容と実行内容がずれます。確認対象の内容と実行対象の内容が一致するように設計します。
また、返答が来ない、権限のある人が確認できない、といった場合もあり得ます。待機を継続するのか、期限切れにするのか、別の担当へ引き継ぐのかは、業務上の条件として決めます。
再開時には、同じ処理が再び実行される可能性がある
中断した処理を再開する際には、利用する仕組みに応じて、nodeの先頭などから再び処理される箇所があります。LangGraphのinterruptを含むnodeも、再開時には先頭から実行されるため、中断前に置いた処理をもう一度行う可能性を考える必要があります。
単にデータを読むだけなら問題が小さくても、中断前にメールを送信していれば、再実行で二重送信になるおそれがあります。外部へ変更を加える処理は、確認との位置関係を整理し、同じ操作を繰り返しても結果が重複しないようにする必要があります。
同じ操作を繰り返しても、一回実行した場合と同じ結果になる性質を、冪等性(べきとうせい)と呼びます。たとえば一つの申請操作に識別子を付け、既にその操作が登録済みなら再登録しない、といった対策が考えられます。モデルへの再問い合わせと、外部システムへの再実行は、同じように繰り返してよい処理ではありません。
「止まった」と「終わった」を区別する
承認待ちの中断、利用者による拒否、エラーによる停止、正常完了は、別の状態です。画面にすべて「完了」と表示すると、実際には登録されていない申請を、登録済みと誤解する原因になります。LangChainやLangGraphで状態を扱う意味は、こうした仕事の現在地を明確にすることにもあります。
エージェントの応用では、生成だけでなく、状態、制御、外部の実行を組み合わせて考えます。次の章では、その実行の途中へルールを加えるmiddlewareや、RAGとの組み合わせ、評価・運用の考え方へ進みます。