重複メッセージを避けるサブエージェントの設計

Note

この記事では 、標準的なハーネスの特徴と挙動について説明します。 Access標準エージェントおよびエージェントフローで標準機能にアクセスする方法を学びましょう。

重複メッセージは文脈のギャップから生じます。 エージェント設計はあらゆる段階で文脈を考慮しなければなりません。

サブエージェントは、子エージェントまたは接続エージェントのいずれかで、親エージェントのプラン内で独自のオーケストレーションレイヤー上で動作します。 親からのリクエストを受け取り、タスクを完了します。 サブエージェントは3種類の出力を生成します:ユーザーに表示するコンテンツ、定義された出力を通じて返す値、そして呼び出しエージェントに送る暗黙の応答です。 親はサブエージェントとユーザーとのやり取りを見ることはできず、定義された出力と暗黙の応答を通じてのみ結果を知ります。 この限られた可視性は、重複メッセージや回答漏れを引き起こすことがよくあります。

Tip

エージェント間での作業分割のタイミングや複数エージェントの一般的なベストプラクティスについては、 マルチエージェントオーケストレーションパターンやベストプラクティスマルチエージェントパターンを参照してください。 この記事では、入力と出力がどのようにサブエージェントの回答を親エージェントのコンテキストに整合させるかを説明します。

本記事は 、標準ハーネスのコンテキスト配布 で説明されたコンテキストモデルと、 重複メッセージを避けるためのデザインベストプラクティスにおける設計決定を基にしています。

接続されたエージェントの親コンテキストをオフにしてください

親の会話コンテキストを受け取ったサブエージェントはそれに基づいて行動することができます。 もしそのコンテキストに親がまだ応答していないリクエストが含まれている場合、サブエージェントが応答したり、親がすでに処理したことを繰り返したり、間違った役割を担ったりする可能性があります。 これらの操作はしばしば重複メッセージを引き起こします。

接続されたエージェントには「 このエージェントに会話履歴を渡す」という設定があり、親の会話コンテキストを受け取るかどうかを制御します。 既定では、この設定は有効になっています。 接続されたエージェントが親からの入力だけから動作するように選択を解除し、会話全体からは動作しません。

「このエージェントに会話履歴を渡す」オプションが有効になっているスクリーンショットで、選択を解除するとエージェント間の履歴共有が妨げられることに注意してください。

チャイルドエージェントには同等の設定はありません。 親の内部で動作し、常に親の会話コンテキストを受け取ります。

割り当てられた作業のコンテキストを保持する必要がある接続エージェントや、デフォルトでコンテキストを持つ子エージェントの場合は、サブエージェントのスコープを保護するためのスコーピング入力を使いましょう。

範囲指定入力を使用する

時にはサブエージェントが親エージェントのコンテキストを必要とし、タスクを完了させることもあります。 そのコンテキストを渡す際には、スコーピング入力を含めてください。これはサブエージェントに何に取り組むべきかを正確に伝え、コンテキスト内の未回答のリクエストがタスクから外されないようにします。 コンテキストを渡さなければ、サブエージェントは親からルーティングされたリクエストしか持っていないため、スコープ入力は不要です。

サブエージェントのスコープを保護するために、The specific request this agent should fulfillのような記述を持つscopedRequestという入力を追加します。 オーケストレーション層はサブエージェントを呼び出す際に入力を埋めます。 親エージェントはリクエストの関連部分を特定し、その部分だけを渡します。たとえそのコンテキストに別の未回答のリクエストが含まれていてもです。

スコーピング入力は、親コンテキストを保持しなくても堅牢な設計です。 入力により、作成者はサブエージェントに送られるリクエストの内容をよりコントロールできます。

サブエージェントの指示をその入力にアンカーし、スコープされたリクエストから動作し、初期リクエストに似た他のものは無視するようにします。

サブエージェント命令の例:

Fulfill the request in the scopedRequest input. 
Treat it as your initial request and ignore any other initial requests in the conversation.

入力と出力を構成する

入力と出力は親とサブエージェントの間の契約です。 入力はサブエージェントが扱う対象をスコープし、出力は親に何が起こったかを伝え、会話の残りをオーケストレーションできるようにします。 親はサブエージェントとユーザーとのやり取りを見ることができないため、この契約だけが信頼できる信号です。

Important

出力が返らないサブエージェントは警告サインです。 出力がなければ、親はサブエージェントが応答した内容や残っている内容の記録を持たない。 サブエージェントがすでに返した回答を繰り返すか、サブエージェントが処理しなかったリクエストの一部を省略することもできます。

以下の入力と出力を設定し、それぞれの記述を親オーケストレーション層が読み取れるように書きます。

入力または出力 Description 使用方法
scopedRequest (入力) このエージェントが対応すべき具体的な要望。 親はユーザーのリクエストの該当部分だけを埋めます。 親の文脈にまだ答えられない他の要求があるときに、サブエージェントが間違った質問に答えるのを防ぐ。 サブエージェントの指示をこの入力に固定します。
answered (出力) ユーザーがすでにscopedRequestへの回答を受け取っている場合は、この通りです。 すべてのサブエージェントに設定してください。ユーザーにメッセージを送るか静かにするかに関わらず。 次に示す最上層命令は、親が同じ要求に再度応答しないように読み取ります。
scopedRequest (出力) このエージェントが担当した依頼。 スコープ付きのリクエストを繰り返して、作成した入力を独自のコンテキストに確実に保持できない最上位のオーケストレーションレイヤーに到達させます。 複数のサブエージェントが必要なマルチインテントターンでは、この機能によりトップレベルが正しく計画でき、誤ったサブエージェントを誤った質問に割り当てるのを避けられます。
interactionSummary (出力) ユーザーに提供された回答の簡潔な要約。 サブエージェントが直接ユーザーにメッセージを送ったときに返すと、親が何を伝えられたか知り、繰り返さないようにしましょう。
findings (出力) これは、親がユーザーに届けるためのscopedRequestへの回答です。 サブエージェントが応答しない場合はそれを返し、親エージェントが配信する内容を確保できるようにします。
openQuestions (出力) ユーザーのリクエストの中で、まだ回答されていない部分。 リクエストの一部しか満たせないサブエージェントや、そのサブエージェントの会話で新たなリクエストが浮上した場合は、親エージェントが残りを完了しツールチェーンを続けられるように返却してください。 サブエージェントは、残りの部分をどのエージェントが担当しているかを推測してはいけません。

どのコンポーネントがユーザーと通信するかを選択してください

親エージェントとサブエージェントのどちらがユーザーとやり取りするかを決めます。 ほとんどの場合、親エージェントがユーザーと通信し、結果を一つの応答にまとめることができます。 サブエージェントが長い応答を提供したり、複数ターンにわたる会話をする必要がある場合は、直接コミュニケーションを取らせましょう。 親が残りの会話を文脈を持って処理できるだけの情報を返してください。

どちらのコンポーネントが通信しても、トップレベル命令を1つ追加し、オーケストレーション層が各サブエージェントの出力を確認できるようにしてください。

このサンプルのトップレベル命令は、サブエージェントが直接ユーザーにメッセージを送る場合でも、沈黙を保つ場合でも、あらゆるケースで機能します。 必要に応じて編集やカスタマイズをしてください。

どのトピックやエージェントが呼ばれるたびに、返信を決める前に必ず「応答済み」のブール出力を確認してください。 トピックやエージェントはユーザーと独自のコミュニケーションチャネルを持っています。 「回答済み」が真の場合は、少なくとも1つの出力変数を使ってリクエストに適切に応答されたと常に仮定し、出力の記述に基づいてどの変数かを確認してください。 答えた内容に対して気まずく返事をしないようにしましょう。 回答されていない出力だけを提供し、次のステップへ自然に会話を続けましょう。

チャネル という用語は 統合チャネルを指すものではありません。 これはオーケストレーション層に、ユーザーが他のコンポーネントを通じてすでに答えを見ているかもしれないことを知らせるプロンプトデバイスです。

サブエージェントの記述を親オーケストレーションレイヤーに書き、サブエージェントをいつ使用し、出力を読み取るかを把握します。 例えば次が挙げられます。

Handles payroll questions. 
If its answered output is true, the user has already received their response and it should not be answered again.

サブエージェントがユーザーにメッセージを送るか静かに関わらず、すべてのサブエージェントに応答状態と値の出力を設定し、親に1つの命令でそれらを読み取らせます。 このアプローチでは、エージェントはサイレントサブエージェントと、出力のみで区別される直接メッセージをユーザーに送るサブエージェントを混同できます。 繰り返し メッセージを避けるための堅牢なトップレベル命令のデザインで詳しく学びましょう。

ユーザーのコミュニケーションを親に委譲する

すべてのユーザー通信をサブエージェントではなく親エージェント経由でルーティングすることを検討してください。 サブエージェントが入力として必要なものを開始前に収集し、終了後に出力として読み取り、ユーザーに直接メッセージを送らないように指示します。 ユーザーに一切手紙を書かないサブエージェントは、親がすでに答えたものに答えることができません。

サブエージェントに黙って調査結果を返すよう伝えろ。 例えば次が挙げられます。

Do NOT reply or communicate with the user directly. 
Only fulfill the scopedRequest provided in the input and respond with the result.

サイレントサブエージェントは、入力と出力の設定で説明されているfindingsopenQuestionsを返し、親に返答を渡し、残った作業にフラグを立てます。

openQuestions出力を返します。 これにより、オーケストレーション層がユーザーのリクエストの残りの部分を完了し、サブエージェントが求められた部分しか満たせない場合にツールチェインを継続できるようにします。

サブエージェントを沈黙させるには明確な指示が必要です。 デフォルトでは、サブエージェントは実行中に自分でユーザーにメッセージを送ることができます。 「 After running completion」設定はこれらのメッセージを防げません。なぜなら、サブエージェントが完了したときに親に何をすべきかだけを指示するからです。

Note

親エージェントに「ユーザーと話すのはあなただけです」と言うだけでは効果がありません。 親エージェントは実行中のサブエージェントを停止できず、サブエージェントは自分でユーザーにメッセージを送ることができます。 代わりに、サブエージェントに沈黙を指示し、その後確認を試みてください。

一部のサブエージェントは直接コミュニケーションを取らなければなりません

ユーザーに直接メッセージを送るサブエージェントは、ルール違反ではなく有効な選択ですが、親からの繰り返しメッセージを避けるための意図的な設計が必要です。

一部のユースケースでは、サブエージェントがユーザーに直接応答し、親コンテキストにコピーせずに長いレスポンスを届けるか、会話を続ける必要があります。 繰り返しメッセージやコンテキストの喪失を避けるために、出力で親にコンテキストを渡します。

サブエージェントに長文の回答を依頼し、要約を返してもらいましょう

サブエージェントはユーザーに直接完全な応答を提供し、回答を伝えた簡単な要約やメモだけを返します。 この方法は詳細な分析など長い回答には用い、返される情報は親の文脈に限定してください。 目的は、親コンテキストを小さく保ちつつ、必要な情報は持たせることです。

Return answeredinteractionSummary、どちらも「 入力と出力の構成」で説明されています。

サブエージェントにユーザーと会話をしてもらう

サブエージェントは複数のステップにわたりユーザーとメッセージをやり取りし、スコープ指定のリクエストを完了します。 主なリスクは、親が中間の会話ステップやサブエージェントの仕事、返答、あるいは新たなリクエストを知らないことです。 その結果、親は新しい要求に対応できず、後のステップで正しく応答できません。

入力と出力の設定で説明されているように、answeredscopedRequestinteractionSummaryを返します。

トップレベルの命令もこのユースケースをカバーしています。