決定論的制御に留まらない Agent ScriptがもたらしたAgentforceの質的変化

みなさんこんにちは。エンジニアの竹田です。

先週ついにAgent ScriptがGAになりました。今年のDreamforceでAgent Scriptが発表されてAgentforce関係者の話題を呼んだわけですが、それから3か月後のGAでした。

それぞれのSalesforce環境で利用可能になり、同時にDeveloper Guideも公開されています。

Agent ScriptというのはいわゆるDSLDomain Specific Language)ですね。Domain(対象領域)に特化した言語であり、Agent ScriptはAgentの定義に特化した言語といえるでしょう。

(Agentforceという単語を使っていないですね。AgentforceだけでなくAI Agent全般への適用を考えていたら面白いのですが)

私も早速Developer Guideを参考にしつつAgent Scriptを試してみました。

今までのAgentforceと同様にtopicとactionが中心的な役割をすることから、一見するとAgentの定義の仕方が変わっただけのようにも見えますが、実はそんなことはないのです。色々と試してみたところ、やはり当初の期待通りAgent ScriptによってAgentforceでできることが大きく変わっていることが分かりました。Salesforceがアナウンスしている通り「決定論的に」制御できるという点もあるのですが、もう一つのキーワードは「動的」です。

今回は筆者が試した中でわかってきた、Agent ScriptがもたらしたAgentforceの質的な変化をご紹介したいと思います。

まずは基本編

Agent Scriptで作ったAgentは基本的には今まで通り、ユーザからの入力に応じてtopicを選択し、topicで定義された 指示内容(instruction)に応じて応答を返すという動作をします。このときAgentは必要に応じてtopic毎に定義されたaction(Flow/Apexで定義された処理、あるいはPrompt Templateを使ったLLM呼び出し)を実行します。

ここまでは今まで通りとはいえ、その中身は大きく変わっています。

(基本的なことはもう知っているよという人は、後半の応用編へどうぞ)

topicの遷移

Agent Scriptではtopic_selectorという特殊なtopicが登場します。

topic_selectorはその名の通りtopicを選択するtopicです。ユーザからの入力があると、topic_selectorのinstruction内で定義された内容に応じて主たる処理をするためのtopicを選択し、その選択されたtopicに遷移させるという動きになります。

新しくAgentを作成するとtopic_selectorとしてデフォルトのものが用意されますが、開発者側でその内容をカスタマイズすることもできます。またtopic_selectorを別途開発したものに置き換えることも可能です。

Developer Guideに記載のtopic_selectorの例.

start_agent topic_selector:
    description: "Welcome the user and determine the appropriate topic based on user input"
    reasoning:
        instructions: ->
            | You are a topic selector for a Customer Service Bot assistant.
              Welcome the guest and analyze their input to determine the most appropriate topic to handle their request.
              NEVER escalate to a human unless explicitly requested. A bad experience shouldn't automatically escalate.
        # This section lists the tools that the LLM
        # can choose to use. In this example, the LLM has two tools:
        # transitioning to the Identity topic or transitioning to the
        # Order_Management topic

        actions:
            # Transitions deterministically route execution to the specified topic.
            # Once the LLM chooses to use this tool, the execution is guaranteed
            # to transition.
            go_to_identity: @utils.transition to @topic.Identity
                description: "verifies user identity"
                available when @variables.verified == False
            go_to_order: @utils.transition to @topic.Order_Management
                description: "Handles order lookup, refunds, order updates, and summarizes status, order date, current location, delivery address, items, and driver name."
                available when @variables.verified == True

通常のtopicの定義では先頭に“topic”と記述するのですが、ここではその代わりに“start_agent”と付けることで、常に処理の最初に実行されるtopicとして指定しています。また、この例ではactionsのところで@utils.transitionを使って次のtopicへの遷移を定義していることが分かります。

この例を見るとわかる通り、topic_selector内ではinstructionで自然言語を使った制御やactionの実行が可能になっています。これにより、topic選択においては今までにできなかった柔軟な対応が可能になっています。たとえば認証済みユーザの場合と未認証ユーザを判断しつつ、topicを分けるということもできるようになるわけですね。

詳細な文法はこちらのDeveloper Guideをご覧ください。

また、topic_selector以外の任意のtopic内でも別のtopicに遷移させるということも可能です。 先ほどの例と同様に、任意のtopic内でこのようにactionの定義として@utils.transitionを登録しておけば、Agentが自律的に遷移先のtopicを選択してそのtopicに遷移してくれます。

actions:
  go_to_faq: @utils.transition to @topic.General_FAQ

結果的に、 topic_selector → 1つ目のtopic → 2つ目のtopic... といった具合に、ユーザからの入力値に応じてtopicを遷移させることができるわけです。

このtopic_selectorでtopicを判断して遷移して...という処理はユーザからの入力に対して毎回実施されます。このとき今までのユーザとAgentとのやり取りの履歴も同時にAgentforceの推論エンジンに渡るので、Agentはこれまでの経緯を踏まえて適切なトピックを選択できるというわけです。

topicの遷移については、この辺りにも解説がありますので、参考にしてみてください。

actionの実行

Agent Scriptでも今までと同じくactionがあり、Apex/FlowやPrompt Templateをactionとして定義して実行できます。

今までと違うのは、actionの実行方法が3種類あるということです。

実行方法1: Agentによる自律的なaction実行

基本的には、Agentが(内部ではAgentforceの推論エンジンが)今まで通りtopicに定義されたinstructionとactionの定義を見て、自律的に実行すべきacitionを選択して実行してくれます。

この場合のAgent Scriptの定義の仕方ですが、2つあるactionsのセクションを使って定義します。

topic
└reasoning
   └instructions
   └actions ②
└actions ①

Agent Scriptではtopicの階層構造がこのようになっていて、2つのactionsの定義があります。

※実際にはAgent ScriptではPythonのようにインデントで階層構造を表現します。

最初に設定すべきは①のtopic宣言の1つ下のレベルにあるactionsで、ここでactionを定義します。

    actions:
        suggest_products:
            description: "Returns suggested products based on the designated criteria "
            inputs:
                inquiry: string
                    description: "Search criteria for product recommendations"
            outputs:
                list_of_product: string
            target: "flow://suggest_items"

この例だと“suggest_products”をactionとして定義したうえで、その処理実体としてFlowである“suggest_items”を設定しています。

そして②に該当するtopicの下のreasoningのさらに下にあるactionsの内に、先ほど定義したactionの実行の仕方を定義します。ここでの実行の仕方というのは、actionへのパラメータの与え方や出力値の取り扱い方のことです。

        actions:
            suggest_products: @actions.suggest_products
                with inquiry = ...
                set @variables.criteria = @outputs.list_of_product

この例だとパラメータinquiryには“...”を指定しています。“...”とは、これまでのユーザとのやり取りやinstructionとして指定された指示内容から解釈して、うまいこと適切な値を推測しなさいという意味です。

またactionの出力値であるlist_of_productを変数criteriaに代入するということも指定しています。

このように①②のactionsセクションでactionを設定しておくと、Agentが必要な時に自律的にsuggest_productsを実行してくれるようになります。

実行方法2: Agentに明示的にactionの実行条件を指示

先ほど紹介したactionの実行方法は、Agentがactionの定義内容(descriptionなどで定義されたactionの説明を含む)から実行すべきactionを自律的に判断するというものでした。

Agent Scriptではさらに踏み込んで、実行条件などを含めて明示的にactionの実行を指定することもできます。具体的にはtopic毎の自然言語文によるinstructionの中でactionを指定するのです。

たとえば先ほどのactionである“suggest_products”が定義されているとして、instructionの中で{!@actions.アクション名}という構文を使って次のように指定します。

        instructions: ->
            | If the user want some product, suggest products by using {!@actions.suggest_products}.

こうすることでinstructionの中に(自然言語で)actionの実行条件など書いておけば、Agentにどんな時にどのactionを使うべきかを指示できるわけです。これは今までのAgentforceではなかったaction実行の柔軟性が得られていると言っていいでしょう。

実行方法3: 推論エンジンに頼らずactionを実行

ここまではactionの選択と実行はすべてAgentにお任せでしたが、そうではなく明示的にactionを実行することも可能です。これには、instructionsの中で 「run @actions.アクション名」 という構文を使います。

        instructions: ->
            run @actions.criteria_for_product_suggestion
                set @variables.criteria = @outputs.criteria

この例では別途定義したactionである “criteria_for_product_suggestion”を実行し、出力値を変数“criteria”に代入するように指定しています。

この方法だとAgentの自律的判断に頼らずに確実にactionを実行することができるので、Agentの制御がやりやすくなっていますね。

instructionの制御

Agent Scriptの紹介でよく取り上げられる決定論的な制御も新しい機能ですね。これはinstructionの中に制御文を入れられるということを意味します。

このあたりは、こちらのDeveloper Guideが分かりやすいので、読んでみてください。

応用編

さてここからは応用編です。

まずはこちらのAgent Scriptをご覧ください。先ほど紹介したinstructionに関するDeveloper Guideにある例からの抜粋です。

  | Tell the user that the expected delivery date for order number {!@variables.order_ID} is {!@variables.updated_delivery_date}

{!@variable.変数名}という構文を使って、自然言語で構成されたinstructionの中に変数値を埋め込んでいますね。

これが何を意味するかというと、いままで固定的だったinstructionの文を変数を使って変化させられるということになります。

変数にはactionの出力値を入れられるので、状況に応じてAgentがやるべきこと(instruction)をApex/FlowやPrompt Templateを使って動的に決められるということになりますね。

また、そもそもAgentが何をするべきか?ということ自体(つまりinstruction部分)をLLM(Prompt Template経由で)に決めさせられるようになるということも意味しています。さらにメタなレベルでの制御が可能になりましたね。

さて、この動的なinstructionはどのように実現できるでしょうか?今回はシンプルな例として商品をお勧めするAgentをつくって、その中でFlowを使ってinstruction内に動的に商品をお勧めする基準を注入するということをやってみました。

実際に記述したAgent Scriptのうち該当部分はこちらです。

        instructions: ->
            run @actions.criteria_for_product_suggestion
                set @variables.criteria = @outputs.criteria
            | Suggest products by combining the user's desired conditions with the following condition {!@variables.criteria}

まずrunを使ってaction「criteria_for_product_suggestion」を実行しています。これはFlowを実行するactionです。そして変数criteria にactionの実行結果を代入しています。

このaction(Flow)は動的にお勧めの基準となる文字列を返すものであると考えてください。

今回は実験のためにこのaction(Flow)は固定で「Suggest the highest-priced items whenever possible.」(できるだけ高い商品を勧めて)という文字列を返すようにしています

(もちろんFlowの代わりにPrompt Templateを呼び出してLLMに文言を作ってもらうことも可能です)

それから、instructionの中の自然言語で指定した部分に、{!@variables.criteria}として変数criteriaの値を埋め込んでいます。 結果的にinstruction文の内容としては「Suggest products by combining the user's desired conditions with the following condition: Suggest the highest-priced items whenever possible.」というものになります。

またAgentには商品をお勧めする手段として、“suggest_products”というactionを登録しています。

    actions:
        <中略>
        suggest_products:
            description: "Returns suggested products based on the designated criteria "
            inputs:
                inquiry: string
                    description: "Search criteria for product recommendations"
            outputs:
                list_of_product: string
            target: "flow://suggest_items"

このactionはFlowを呼び出すものです。そのFlowの中ではPrompt Templateを呼び出していて、そのPrompt Templateでは入力された条件にちょうどいい商品をLLMが判断・取得する処理が書かれています。

(本当はactionに直接Prompt Templateを指定したかったのですが、謎のエラーが発生して解消できなかったのでFlow経由にしています)

該当のtopic部分のスクリプト全体としては次の通りです。

topic Suggest_Outdoor_Products:
    label: "suggest outdoor products"
    description: "Provide recommendations for outdoor products based on user inquiries."
    reasoning:
        instructions: ->
            run @actions.criteria_for_product_suggestion
                set @variables.criteria = @outputs.criteria
            | Suggest products by combining the user's desired conditions with the following condition: {!@variables.criteria}
        actions:
            suggest_products: @actions.suggest_products
                with inquiry = ...
                set @variables.criteria = @outputs.list_of_product
    actions:
        criteria_for_product_suggestion:
            description: "Criteria to suggest products."
            outputs:
                criteria: string
            target: "flow://Criteria_for_product_suggestion"
        suggest_products:
            description: "Returns suggested products based on the designated criteria "
            inputs:
                inquiry: string
                    description: "Search criteria for product recommendations"
            outputs:
                list_of_product: string
            target: "flow://suggest_items"

さて、それではいよいよこのtopicを実行します。Agentforce Builder内のPreviewを使って実行してみましょう。

Agentに対して「Please recommend warm outerwear.」(暖かいアウターをお勧めして)と入れると... 「Alpine Down Pa4ka 1000」という商品がお勧めされました。

Agent Script実行結果

確かに用意した商品の中では値段が高いもので、かつ暖かいアウターでもあります。なんとなくちゃんと動いていそうです。

念のためログを確認してみると。。。。こんなものが

{
  "inquiry": "warm outerwear, prioritize highest-priced options"
}

action “suggest_products”に渡す引数inquiryとして「warm outerwear, prioritize highest-priced options」(暖かいアウター、ただし価格の高さで優先高くしたうえで)と条件が付いていますね。

スクリプト中にある「with inquiry = ...」の「...」の部分はAgentが考えて適切な引数を渡すようにする指示です。

ちゃんとAgentが、ユーザ入力と動的に与えた条件を組み合わせて適切な引数値を作ったうえでactionを呼び出しているようです。

これは面白いですね。工夫次第で今までにはなかった柔軟できめ細やかな指示をAgentに与えることができますね。

おわりに

今回はAgent Scriptの機能をいち早く紹介してみました。 いままでのAgentforceではできなかったことができるようになり、大きな質的変化があったということがお判りいただけたと思います。

同時に今までよりも複雑になっているので、難しく感じた方もいらっしゃるかもしれませんが、そこはエンジニアとしての腕の見せ所。うまく使いこなして、価値あるAgentをみんなで生み出していきましょう!