---
schema_version: "1"
id: e4c0464110d04d7ccde61760743ddf82468dcf368407ef7fb9ba50ec8b5dc933
title: 与新 Agentforce Builder 和客服人员脚本的混合推理
collection: architect
version: current
locale: zh-cn
portal_url: https://docs.salesforce.com/architect/current/zh-cn/fundamentals/guides/hybrid-reasoning-agentforce-builder-agent-script.md
canonical_url: https://architect.salesforce.com/docs/architect/zh-cn/fundamentals/guide/hybrid-reasoning-agentforce-builder-agent-script.html
source_site: architect.salesforce.com
content_type: documentation
content_hash: 8dce8240f118afce3a3ca1c9b0e16aee20c1b6495609b818c55d598dd5e8b29c
products:
  - 基本知识
  - Architect Site Content Repo
updated_at: 2026-05-01T00:00:00Z
---
# 导言

_注意：根据我们最新的产品命名约定，本文中的“主题”已重命名为“子代理”。_

您可能会构建在测试环境中表现良好的客服人员，但在处理两次相同工作流时，客服人员会遵循完全不同的路线。这一根本限制显示了以前的 Agentforce 模型如何处理执行：从意图解释到操作选择的每个决策都由 LLM 实时做出，没有保证通过工作流的路径。

响应相同的输入，LLM 会产生不一致的结果。上下文、系统提示或令牌生成的微妙变化足以将客服人员发送到不同的路由。对于许多交互，这种变化是可以接受的。但是，对于需要可审计性、可再现性和可追溯性的多阶段工作流，它不是。贷款批准、库存转移或患者分类流程不能取决于客服人员，客服人员每次都会以不同的方式解释这些步骤。

新的 Agentforce 生成器和客服人员脚本通过将确定性执行与 LLM 推理分开来解决此问题。Agentforce 的混合模型确保客服人员遵循每个工作流执行的精确定义结构，同时在真正需要判断、自然语言理解或上下文解释的地方仍然使用 LLM 推理。

## 以前的 Agentforce 限制

在 Agentforce 的早期版本中，客服人员作为简单的反应性循环进行操作。从解释意图到选择下一个操作，LLM 仅根据用户最近的输入实时做出每个决定。没有保证的执行路径，没有持续的状态，也没有强制实施一系列步骤的机制。

**无法保证执行路径**

因为每个决策都取决于 LLM 的实时推理，所以输入、系统提示或模型版本的微小变化都会对相同的请求产生不同的操作选择。这使得以前的模型难以严格测试：在暂存中通过的工作流在生产中的行为可能不同，并且没有可靠的方法可以出于调试或审计目的复制特定的执行路径。

**每次交互都支付了全部 LLM 成本**

即使是简单的对话场景，也需要至少三个 LLM 周期：子客服人员选择、操作选择和最终响应生成。多步骤任务扩展到五个或更多周期。对于设计高用量或延迟敏感工作流的架构师，这不仅仅是一个性能问题。这意味着您不能将推理循环短路到不需要判断的步骤，因为架构没有区分两者的机制。

**非确定性执行造成了审计差距**

在受监管的行业中，可审计性意味着能够证明特定交易以特定的方式遵循了特定流程。纯粹的非确定性模型无法提供这种保证。如果运行之间的执行路径不同，审计跟踪也会不同，并且“客服人员决定”在合规审查中不是站得住脚的答案。

**州在对话中没能幸存**

依赖单轮处理意味着客服人员没有早期步骤的持久记忆。如果对话稍有偏差，客服人员可能会删除此前捕获的上下文，并强制用户重新启动。对于多步骤事务工作流，这创建了可靠性上限：流程中的步骤越多，完成前上下文丢失的可能性越高。

**不记得已完成的步骤**

如果没有状态管理，客服人员没有用户已经完成哪些强制步骤的记录。这会产生不可预测的循环，客服人员将返回到用户已经完成的步骤。除了用户体验影响之外，这还造成了更深的架构问题：设计可靠的顺序工作流是不可能的，因为客服人员无法强制实施顺序。

## 新 Agentforce 架构的工作方式

新的 Agentforce 自 2026 年 2 月起正式发布,从纯概率 LLM 推理转向混合模型。它不是通过 LLM 路由每个决策，而是将确定性执行与 LLM 推理分开，并让每个决策只处理它适合的内容。为了支持这一点，Agentforce 引入了两个创作工具：适用于基于代码的开发的 Agent 脚本，以及 Agentforce Studio，一种无代码构建环境。

**Agentforce Builder**

Agentforce Builder 是开发新客服人员的推荐环境。它托管在 Agentforce Studio 中，并替换旧的设置体验，该体验仍然可用，但不再是主要的编写路径。在生成器中，您可以在可视画布视图中工作，也可以直接在脚本视图中工作，编辑定义客服人员行为的客服人员脚本。

**客服人员脚本**

客服人员脚本是一种特定于域的声明性语言 (DSL)，它定义了客服人员行为方式的一切内容：配置、业务逻辑和提示。它的结构是键值对，可以跨越多行或包含嵌套子属性，并且它被设计成人类可读的，不需要底层图形架构的Knowledge。

客服人员脚本允许您在同一客服人员中表达两种根本不同类型的指令：确定性逻辑指令和提示指令。确定性逻辑指令定义了条件和操作序列，这些条件和操作序列作为没有 LLM 参与的代码执行。提示指令定义了 LLM 在运行时解释的自然语言指导。两者之间的边界是明确而谨慎的,理解在哪里放置该边界是您在使用新的 Agentforce 构建时做出的核心设计决策之一。

**实践中的确定性逻辑**

当指令具有确定性时，客服人员会遵循定义的执行路径，而不管用户如何表达他们的输入。以下示例显示了加载客户智能仪表板的子代理。它检查客户 ID，获取简档数据、订单历史和支持票证，然后计算客户终身价值和流失风险。这些步骤都不需要 LLM 推理。

每次满足特定条件时，此逻辑都会按固定顺序调用操作。

```
instructions: ->
        # Ask for user_id if we don't have it
        if @variables.user_id=="":
           | Ask the user for customer ID to view personalized insights. Do not proceed until you have the customer ID.
             Use {!@actions.set_user_id} to update the user_id variable and set context.

        # Fetch customer data if we have user_id
        if @variables.user_id!="":
           run @actions.fetch_user_profile
              with user_id=@variables.user_id
              set @variables.user_profile = @outputs.profile
           # Chain additional data fetches
           run @actions.fetch_account_data
              with user_id=@variables.user_id
              set @variables.account_data = @outputs.account
           run @actions.fetch_order_history
              with user_id=@variables.user_id
              with limit=10
              set @variables.recent_orders = @outputs.orders
           run @actions.fetch_support_history
              with user_id=@variables.user_id
              set @variables.support_history = @outputs.tickets
           # Compute insights
           run @actions.calculate_customer_value
              with user_id=@variables.user_id
              with orders=@variables.recent_orders
              set @variables.customer_lifetime_value = @outputs.clv
              set @variables.loyalty_status = @outputs.loyalty_tier
           run @actions.assess_churn_risk
              with account=@variables.account_data
              with orders=@variables.recent_orders
              with support_tickets=@variables.support_history
              set @variables.churn_risk_score = @outputs.risk_score
           run @actions.generate_recommendations
              with profile=@variables.user_profile
              with clv=@variables.customer_lifetime_value
              with churn_risk=@variables.churn_risk_score
              set @variables.recommended_actions = @outputs.recommendations


```

**提示说明和有意的 LLM 切换**

当确定性逻辑处理可以表示为代码的条件和序列时，提示指令处理需要判断、解释或自然语言生成的一切。当 Atlas 推理引擎遇到带有提示说明的节点时，它会触发 LLM 调用。当它没有时，它会确定性地执行。

以下示例显示了产品和服务的子代理。该指令是多行提示，告诉 LLM 如何响应、何时查找信息以及如何处理不明确。当可能的用户输入范围太广，无法用条件逻辑预测，或者当响应的质量取决于 LLM 解释上下文和生成自然响应的能力时，这就是正确的模式。

节点上的提示指令会触发 LLM 调用。这不是偶然的 - 这是客服人员脚本使 LLM 边界明确和可执行的机制，而不是将其留给运行时推理。

该子代理显示了确定性逻辑和 LLM 切换在起作用。

```

   instructions:->
      | Answer the user's questions about products and services clearly and accurately.
        When the user asks about a specific product, use {!@actions.get_product_info}
        to look up current information.
        When answering:
        - Be specific and provide helpful details
        - If the question is unclear, ask for clarification
        - Stay focused on product-related subagents
        - Use {!@actions.get_product_info} to get accurate, up-to-date information
        Subagents you can help with:
        - Product features and specifications
        - Pricing and packages
        - Availability and delivery
        - Comparisons between products


```

**三阶段执行漏斗**

Agentforce 生成器和客服人员脚本是编写层，但客服人员图表和 Atlas 推理引擎实际上运行您的客服人员。从设计上讲，您无法直接访问这两个组件。分离编写和执行允许平台强制执行确定性行为，而与脚本的编写方式无关。

漏斗经过三个阶段。

1. **写作**是您工作的地方。客服人员脚本在 Agentforce Builder 的画布视图或脚本视图中均可读和编辑。这是您直接交互的唯一图层。
2. **编译**是 Salesforce 编译器将您的客服人员脚本转换为客服人员图表的地方，客服人员图表是专为机器执行而不是人类可读性优化的序列化执行计划。您不能在此层调试。编译生成运行时可以高效遍历的表示。
3. **运行时执行**是 Atlas 推理引擎接管的地方。它读取客服人员图表，根据当前会话状态进行遍历，并在每个节点上决定是否确定性地执行或调用 LLM。引擎在此处明确强制执行保护条款和条件路由，而不是推断。

**客服人员图表**

客服人员图表是介于人类可读脚本和实际运行时执行之间的中间表示。其结构针对使用它的状态机进行了优化，而不是针对编写脚本的架构师。了解它的存在以及它代表的内容非常重要，因为它是推理引擎用来强制执行脚本定义的执行计划的工件。

**Atlas 推理引擎**

Atlas 推理引擎是状态机执行器。每次轮次时，它都会根据会话状态遍历客服人员图，将确定性节点作为代码执行，并仅在提示指令存在时触发 LLM 调用。它还强制执行保护条款并处理条件路由。推理引擎是实际实施混合推理模型的地方；脚本定义了边界，引擎遵守它。

![三阶段执行漏斗显示 Agentforce 生成器、客服人员脚本编译为客服人员图表和 Atlas 推理引擎运行时执行情况](https://architect.salesforce.com/ns-assets/hybrid-reasoning-pipeline.png)

## LLM 边界：判断结束和代码开始的地方

客服人员图表不是 LLM 包装。它是一个混合推理引擎，将确定性执行与概率推理区分开来。管理规则很简单：如果您可以将决策表示为代码，它应该被编写为逻辑。如果决策需要判断、解释或自然语言生成，LLM 应该处理它。此设计决策是新 Agentforce 模型中最重要的架构选择。LLM 边界在哪里直接影响解决方案的成本、延迟、可审计性和可靠性。

Atlas 推理引擎会评估每个传入用户轮次，并将其路由到两个路径中的一个。

**路径 A:确定性执行**

此路径没有 LLM 暴露。它的行为类似于运行时编译的代码。推理引擎对用户的意图进行分类，并确定逻辑指令匹配，完全绕过 LLM。编译的客服人员脚本从上到下运行，如果-否则规则会在每次轮次无条件执行。流、Apex 或 API 操作使用确定性参数调用，不涉及提示汇编或模型调用。结果通过带有完整审计日志的 Trust 层传递回。

**路径 B：LLM 推理**

当推理引擎无法仅使用逻辑指令解析意图时，它会采用这条路径。它遍历客服人员图并评估每个节点。具有提示说明的节点触发 LLM 调用。没有它们的节点会确定性地执行。提示指令的存在是触发器，它在脚本中是明确的，而不是在运行时推断。

**什么触发 LLM 调用**

在执行生命周期中有 8 个点调用了 LLM。子代理分类，或决定哪个子代理匹配用户的请求，是一个分类，尽管在分类明确时短路路径可以绕过完整的 LLM 调用。客服人员推理（客服人员决定下一步要采取什么操作）总是通过 LLM。响应生成也是如此，最终响应从水合提示中汇总。

其余触发器更具可操作性：基准性验证确认输出基于检索的数据；操作模拟在预览和模拟环境中模拟响应，而不是实时执行；结构化输出生成处理响应需要符合定义模式的情况；本地化和进度指示符生成处理格式化和瞬时消息传递，其中不存在预先编写的默认值。

**什么保持确定性**

图形遍历和状态转换从不涉及 LLM。只要`before_reasoning`和`after_reasoning`生命周期块仅包含没有提示指令的操作节点，它们就会确定性地执行。数学、数据获取、验证和条件逻辑都属于代码。任何执行 Flow、Apex 或 REST API 的操作都直接停留在确定性路径上。任何没有提示指令的节点都会在没有 LLM 调用的情况下执行。

与团队明确这一界限非常重要。每个不必要的 LLM 调用都会增加延迟、成本和可变性。默认情况下，架构师应推送确定性逻辑，并将 LLM 保留给任务实际需要推理能力的情况。

**设计指导：默认将逻辑推送到代码**

在编写可表示为条件、变量分配或操作筛选器的提示指令时，使用客服人员脚本逻辑指令。每个不必要的 LLM 调用都会增加延迟、成本和可变性。

默认位置应该是确定性的。隔离每个可以编码为规则的客服人员行为，并将其移动到客服人员脚本中。需要自然语言综合、上下文判断或复杂解释的剩余任务属于提示节点。这不是限制；而是边界如预期正常工作。LLM 处理它最适合的内容，所有其他内容作为代码运行。

## 解析边界：`before_reasoning`、`reasoning` 和 `after_reasoning`

客服人员脚本中的主要执行单位不是用户轮次。它是解析：通过子代理的三个生命周期块的单个完整周期。每次子客服人员需要处理某件事时，Atlas 推理引擎都会启动解析，这发生在三种情况下：第一次进入子客服人员时，每次工具调用完成并返回结果后，以及同一子客服人员中的每个新用户轮换时。

了解解析边界非常重要，因为它决定了每个块运行多少次，因此您可以和不可以依赖给定逻辑块只执行一次。

每个子代理定义三个执行区域：

| 块              | 运行时                                              | LLM 参与               |
| ------------------ | --------------------------------------------------------- | ----------------------------- |
| `before_reasoning` | 在每个解析开始时，在 LLM 看到任何内容之前 | 无                          |
| `reasoning`        | 在确定性解析期间，在任何 LLM 调用之前   | 混合                         |
| `after_reasoning`  | 推理完成并且 LLM 已响应后       | 无（带有重要警告） |

`before_reasoning`和`after_reasoning`都是完全确定性的。它们执行操作，设置变量，并应用条件逻辑，而无需涉及 LLM。这使得它们成为脚本中可靠的低成本块。

**何时使用 `before_reasoning`**

`before_reasoning` 在每个解析的开头运行，没有例外。它在第一次进入子代理时执行，并在每次工具调用或新用户在该子代理中转向后再次执行。`before_reasoning` 中的`run @actions.X`是代码。与 LLM 可能遵循也可能不遵循的提示块中的指令不同，`before_reasoning` 无条件执行。

使用此块进行会话初始化：获取上下文记录，从 Apex 或流设置会话变量。这也是身份验证和权利检查的地方，因为您想要在 LLM 看到任何工具之前验证它们。上下文水合作用也适合这里：调用数据检索操作，以便 LLM 接收预填充的变量，而不是需要请求它们。必须在每个解析上增加的任何计数器或审计变量都应在此处设置，因为`before_reasoning`中的 `set` 指令以漏斗指令无法保证的方式得到保证。

此处不属于每个会话仅运行一次的逻辑，因为 `before_reasoning` 在每个解析上运行，而不仅仅是第一个条目。任何依赖于当前轮次的用户输入的内容也不属于此处，因为该输入尚未处理。转换不应`before_reasoning`:这里的`transition to`指令将无条件触发每个解析并创建循环。

如果您需要每个会话初始化一次，请明确保护它：

```
before_reasoning:
   if @variables.sessionInitialized == False:
       run @actions.InitializeSession
       set @variables.sessionInitialized = True
```

一个用户轮次可以触发多个解析：在输入时触发一次，然后在每次工具调用后再次触发。该功能有三个实际后果：`before_reasoning` 中的初始化操作将在每个用户在多操作流中运行不止一次，在此处递增的计数器变量将反映解析计数，而不是轮次计数，并且具有副作用的操作、外部 API 调用或记录写入不应存在于`before_reasoning`中，除非对每个解析的重新执行是明确可接受的。

`before_reasoning` 不是构造函数。它是每次解析都运行的预检查。相应地进行设计。

**何时使用 `after_reasoning`**

在 LLM 响应并捕获操作输出后，`after_reasoning` 将在推理循环完成后运行。这是操作后确定性检查的领域：评估操作输出和基于结果的分支。确定性转换，或根据变量状态而不是 LLM 判断转移到下一个子代理，请坐在这里。当您需要以可预测的顺序链接子客服人员而没有 LLM 路由决策时，变量清理和编排顺序也是如此。

将`after_reasoning`视为护栏层。在 LLM 完成工作后，您可以在此强制执行业务规则和状态管理，确保关键流程流保持可预测性，无论 LLM 生成了什么。

**明智使用`is_displayable: True`**

设计编排流的每个架构师都需要了解这种平台行为。在操作上设置`is_displayable: True`时，一旦 LLM 决定显示该输出，平台就会退出推理循环。该退出会立即发生，这意味着 `after_reasoning` 永远不会执行。

这是已知的平台行为，但它对编排有直接影响:当可显示操作是流的一部分时，您放在`after_reasoning`中的任何逻辑都将被跳过。

答案很简单。将**必须执行**可靠的逻辑移动到后续子代理的`before_reasoning`块中，而不是当前子代理的`after_reasoning`块中。

**设计指导：将初始化逻辑放在何处**

在设计子代理时，决定逻辑的位置非常重要。此框架涵盖了最常见的情况：

| 场景                                                                        | 放在哪里                                           |
| ------------------------------------------------------------------------------- | --------------------------------------------------------- |
| 必须在 LLM 看到任何上下文之前运行                                        | `before_reasoning`                                        |
| 运行每个解析，包括新用户轮次的重新输入                          | `before_reasoning`                                        |
| 取决于该回合的操作输出                                         | `reasoning` 中的条件`if`块                     |
| 需要基于结果的确定性子代理转换                     | `after_reasoning`（但请参阅下面的`is_displayable`说明） |
| 下游操作使用 `is_displayable: True` 时需要编排逻辑 | 下一个子客服人员的`before_reasoning`                   |
| 使用需要判断或用户上下文的逻辑                               | 带有提示说明的`reasoning`                      |

基本原则很简单。当您编写提示指令告诉 LLM“始终运行”操作时，这是一个建议。根据上下文，LLM 可以遵循也可以不遵循。当您在 `before_reasoning` 中放置 `run` 指令时，这就是代码。它毫无例外地在每个解析上执行。

## 使操作对 LLM 有条件可用

条件操作可用性是客服人员脚本根据运行时变量状态从 LLM 中显示或隐藏操作的机制。当`available when`条件评估为 `false` 时，该操作将从提交给 LLM 的工具列表中完全删除。任何假值，包括 `None`、`False`、`0` 或空字符串，都会禁止该操作。

这不是告诉 LLM“暂时不要调用它”的提示说明，而是硬平台级大门。LLM 不能调用它不能访问的操作。

```
actions:
   execute_transfer: @actions.execute_transfer
       available when @variables.validation_passed
       with from_account=@variables.source_account
       with to_account=@variables.destination_account
       with amount=@variables.transfer_amount
```

在此示例中，在 `validation_passed` 评估为`true`之前，LLM 不可见`execute_transfer`。大门由平台强制执行，而不是由指令强制执行。

**设计指导：不要让 LLM 设置大门变量**

在执行关联操作之前，为 `available when` 子句中的每个变量提供设置变量的确定性代码路径。使用 `before_reasoning` 或确定性`run`和`set`块，`reasoning`便使变量保持已知状态。如果您依赖 LLM 来设置门变量，您已经重新引入了门设计用来防止的可变性。根据对话，LLM 可能会或可能不会设置它，这意味着大门可能会或可能不会打开。

**操作循环问题**

当 LLM 重复调用相同的操作而从未达到最终状态时，就会发生操作循环。当两个条件同时为真时，就会发生这种情况：`available when`条件在操作运行后仍然满足，推理指令没有明确告诉 LLM 停止调用它。

平台不会在调用后自动禁止操作。如果大门保持打开，推理指令不明确，LLM 会无限期地在每个解析上调用相同的操作。

以 `available when @variables.interest != ""` 为例。如果操作执行，但兴趣变量不为空，大门将在下一个解析中保持打开状态。LLM 将操作视为可用，没有指示它停止，并再次调用它。

有两种可靠的方法可以打破循环。第一个是将门变量设置为关闭状态，作为操作执行后逻辑的一部分，以便`available when`在下一次解析时评估为`false`。第二个是使用单独的`has_run`布尔值，它在第一次执行后关闭网关。这两种方法都赋予大门一种确定性的关闭状态，这是平台抑制操作所需的条件。

## 使代理银行转账具有确定性

银行转账是理解这些模式在实践中如何协同工作的有用镜头。工作流从外部看起来很简单：将资金从一个账户转移到另一个账户。实施需要多个复杂步骤。在执行转移之前，客服人员必须收集客户详细信息，验证金额，检查转移限制，确认可用余额，然后才能显示转移操作。每个步骤取决于前面的步骤。其中任何一个都不应听任 LLM 判断。

<img src="https://architect.salesforce.com/ns-assets/hybrid-reasoning-bank-transfer-flow.png" alt="显示验证步骤、保护条款和确定性执行流的银行转账工作流" style="width:75%;margin-top:1rem;margin-bottom:1rem;" />

**收集和验证输入**

第一个子代理从用户那里收集源客户、目标客户和转移金额。在所有这三个项都存在并且有效之前，它不会继续。客服人员脚本按顺序检查每个字段：如果源客户丢失，它会询问。如果目标丢失，它会询问。如果金额为零或负数，则会询问。`validation_passed` 变量仅在清除所有检查后设置为 `true`。

下面的脚本在实践中显示了这一点。请注意，`validation_passed` 在每个故障点明确设置为 `false`，并且指示 LLM 不要继续。确定性检查无条件运行，而提示指令处理面向用户的响应。

```
instructions:->
        | Always ensure to request the following data from the user, and to store it using {!@actions.store_details}
           - source account number
           - destination account number
           - amount to transfer
            Only after you have all the data, you can proceed with the next steps.

        if not @variables.source_account:
            set @variables.validation_information = "Missing source account"
            set @variables.validation_passed = False
            | You need the source account number before proceeding.
              Ask the customer for the source account number.
        else:
            set @variables.validation_passed = True
        if @variables.source_account and not @variables.destination_account:
           set @variables.validation_information = "Missing destination account"
           set @variables.validation_passed = False
           | You need the destination account number before proceeding.
              Ask the customer for the destination account number.
        else:
           set @variables.validation_passed = True
        if not @variables.source_account or not @variables.destination_account:
            | Do NOT proceed with the transfer yet.
        if @variables.transfer_amount <= 0:
            set @variables.validation_information = "Invalid transfer amount"
            set @variables.validation_passed = False
            | The transfer amount must be greater than zero. Ask the customer
              how much they want to transfer.
              Do NOT proceed with the transfer yet.
        else:
           set @variables.validation_passed = True


```

**强制执行业务规则**

客服人员验证输入后，会检查转移金额是否超过配置的转移限制。这是业务规则成为代码而不是指令的地方。限制不是 LLM 的原因；它是在脚本中定义的硬阈值，并在每个解析上被确定性地检查。

如果金额超过限制，`validation_passed`会设置回`false`，LLM 会为用户提供三个选项：转移最大允许金额、拆分为多个转移或联系支持以获取更高的限制。在用户解决异常之前，客服人员无法继续。请注意，这里的提示指令是如何执行 LLM 推理的：以对话方式显示选项并处理用户的回应。业务规则本身是确定性的，但围绕它的对话不是。

以下脚本显示了限制检查的工作方式。确定性条件根据限制变量评估转移金额，如果超过阈值，将`validation_passed`设置为`false`，并委派给提示指令来处理面向用户的响应。

```
instructions:->
   if @variables.transfer_amount > @variables.transfer_limit:
      set @variables.validation_information = "Amount exceeds transfer limit"
      set @variables.validation_passed = False
      | ⚠️ STOP: The requested amount (${!@variables.transfer_amount}) exceeds
        the maximum transfer limit of ${!@variables.transfer_limit}.
        Inform the customer and ask if they'd like to:
        1. Transfer the maximum allowed amount (${!@variables.transfer_limit})
        2. Split into multiple transfers
        3. Contact support for higher limits
        Do NOT proceed with the transfer.

```

**应用保护条款**

金额和限额检查完成后，客服人员会获取源帐户余额，并确认资金充足。保护条款阻止客服人员在不满足先决条件时尝试操作。与告诉 LLM 检查余额的提示指令不同，客服人员脚本中的保护子句使检查无条件。LLM 不决定是否运行它。

如果余额不足，客服人员会计算短缺，并为用户提供具体替代项。`validation_passed` 设置为 `false`，直到此检查通过，这意味着转移操作仍处于关闭状态。

下面的脚本显示了获取余额的确定性操作调用，然后是评估它的条件检查。提取仅在尚未检索余额时运行，避免后续解析器上的冗余 API 调用。

```
instructions:->
   # Fetch balance if needed
   if @variables.source_account and not @variables.source_balance:
      run @actions.get_account_balance
         with account_number = @variables.source_account
         set @variables.source_balance = @outputs.balance

   # Validate sufficient funds
   if @variables.source_balance < @variables.transfer_amount:
      set @variables.validation_information = "Insufficient funds"
      set @variables.validation_passed = False
      | ⚠️ STOP: Insufficient funds in the source account.
        - Available balance: ${!@variables.source_balance}
        - Requested transfer: ${!@variables.transfer_amount}
        - Shortfall: ${!@variables.transfer_amount-@variables.source_balance}
        Ask if they'd like to transfer a smaller amount.
        Do NOT proceed with the transfer.

```

**表面错误清晰**

保护条款设置状态。错误消息会传达它。当`validation_passed`是`false`时，客服人员需要为用户提供足够的信息来解决问题，而无需重新启动。模糊的错误消息会产生摩擦；结构化错误消息会更快地关闭循环。

以下脚本显示了实践中的资金不足错误消息。它不仅仅告诉用户转移失败。它显示了可用的余额、请求的金额、计算的短缺，并提供了具体的下一步，所有这些都是从会话变量中汇总的，而不是由 LLM 生成的。

```
| ⚠️ STOP: Insufficient funds.
  - Available: ${!@variables.source_balance}
  - Requested: ${!@variables.transfer_amount}
  - Short by: ${!@variables.transfer_amount - @variables.source_balance}
  Would you like to transfer ${!@variables.source_balance} instead?
```

短缺计算发生在脚本中，而不是在 LLM 中。建议的替代方案（转移可用余额）是从会话状态中确定的。LLM 在这里的作用纯粹是演示性的：它传递脚本已经构建的消息。

**门控转移操作**

上述步骤中的每个验证检查都会设置或清除相同的变量：`validation_passed`.该变量目前正在完成其最重要的工作。`execute_transfer` 操作是有条件可用的，这意味着它仅在 `validation_passed` 为`true`时显示在 LLM 的工具列表中。在通过每个前面的检查并设置该变量之前，从 LLM 的角度来看，该操作不存在。

这是应用于生产工作流的早期大门部分的模式。转移操作不会被提示指令隐藏。它被平台隐藏。无论多大的对话压力或不明确的措辞都不能使 LLM 在满足先决条件之前调用它。

下面的脚本显示了如何配置网关。`available when` 子句直接引用`validation_passed`，操作参数绑定到在前面步骤中收集和验证的会话变量。

```
actions:
   execute_transfer: @actions.execute_transfer
      available when @variables.validation_passed
      with from_account=@variables.source_account
      with to_account=@variables.destination_account
      with amount=@variables.transfer_amount
```

所有 3 个参数（`from_account`、`to_account` 和 `amount`）都是从会话变量中确定性传递的。在此操作可用时，每个值均已验证。LLM 没有从对话上下文中汇编参数；而是从状态中读取它们。

**在整个工作流中跟踪状态**

以上部分中的模式仅适用于会话状态在整个工作流中持续存在的情况。第一步中捕获的帐号在第四步中可用。验证结果集位于另一个检查门操作中。对话可能会偏离，用户可以提出跟进问题，客服人员仍然可以准确知道对话进行中的位置。

下面的变量块显示了此工作流的完整会话状态。每个变量都有一个定义的类型、一个默认值和一个描述。两个变量处理大部分编配工作：`validation_passed` 控制每个门的操作可用性，`validation_information` 携带有关检查失败原因的可读上下文，LLM 可以向用户显示这些上下文，而无需说明基础状态。

```
variables:
   source_account: mutable string = ""
      description: "Account to transfer from"

   destination_account: mutable string = ""
      description: "Account to transfer to"

   transfer_amount: mutable number = 0
      description: "Amount to transfer"

   source_balance: mutable number = 0
      description: "Balance of source account"

   transfer_limit: mutable number = 10000
      description: "Maximum allowed transfer amount"

   validation_passed: mutable boolean = False
      description: "Whether all validations passed"

   validation_information: mutable string = ""
      description: "Human readable validation information"

```

每个变量以已知默认状态开始。字符串默认为空，数字为零，布尔`validation_passed`默认为 `false`。这意味着大门默认关闭。工作流必须积极赢得每一步的继续权利，而不是从大门打开开始并依靠检查来关闭它。

## 何时使用确定性逻辑

银行转账示例说明了确定性逻辑是正确的工具，但它并不总是最好的选择。理解边界与理解模式同样重要。

当工作流需要保证的执行顺序时，当错误产生重要后果时，当流程需要产生可重复的审计跟踪时，或者当业务规则定义良好，足以表示为条件和阈值时，确定性逻辑是正确的选择。财务、医疗保健和保险工作流通常属于这一类。

当交互的价值在于灵活性而不是精度时，没有严格确定性约束的纯 LLM 推理更有意义。开放式客户支持、业务流程仍在发展的早期阶段产品以及风险较低的信息查询都是 LLM 推理变化无常的特点，而不是问题。

在实践中，大多数生产客服人员都需要两者。边界落入何处的决定不是确定性和概率性之间的二元选择；而是您在节点级别为客服人员工作流的每个部分做出的设计决策。

| 使用确定性逻辑                 | 使用 LLM 推理                               |
| ------------------------------------------- | --------------------------------------------------- |
| 输入验证和消毒           | 自然语言理解和意图检测 |
| 业务规则实施                   | 生成会话、感同身受的回应     |
| 顺序流程编排            | 处理不明确或意外的输入             |
| 状态管理和上下文保留   | 提供解释和澄清           |
| 防止无效操作的保护条款 | 调整语气和消息传递以适应用户上下文         |

**边界是设计决策**

银行转账示例说明了一种设计哲学：确定性执行和 LLM 推理之间的界限是您在构建生产代理时做出的最直接的架构决策。

设置一个过于僵硬的边界，您最终会得到一个僵硬、维护成本高昂且无法处理真实对话自然变化的客服人员。如果边界错误，就会产生一个灵活但不可预测的客服人员，他们在测试中表现良好，但在生产中表现不同，并且无法产生可靠的审计跟踪，也无法得到高风险交易的信赖。

新的 Agentforce 模型为您提供了有意放置该边界的工具。客服人员脚本允许您在同一文件中表达确定性逻辑和提示指令，并使用显式语法使边界可见。Atlas 推理引擎会在运行时强制执行逻辑和提示。`before_reasoning` 和 `after_reasoning` 块为您提供了 LLM 调用两侧的保证执行区域。条件操作可用性确保 LLM 只能在满足先决条件时采取行动。

这些功能都不是孤立的。他们共同协作，为构建企业可以通过任务关键型工作Trust任的客服人员创建一致的架构。混合推理模型认识到确定性和灵活性在您的架构中都有其作用；架构师的工作是准确决定每个作用的应用。

## 引用

[客服人员脚本模式](https://developer.salesforce.com/sample-apps/agent-script-recipes)

[Agentforce 开发人员指南](https://developer.salesforce.com/docs/ai/agentforce/guide/agent-script.html)

[Agentforce 的客服人员图表：通过混合推理](https://engineering.salesforce.com/agentforces-agent-graph-toward-guided-determinism-with-hybrid-reasoning/)实现指导决定论

## 关于作者

Gulal Kumar 是 Salesforce 的软件工程架构师，拥有超过 20 年的经验。他的专长涵盖 AI、集成、API 和企业架构，专注于通过安全、弹性和创新的 AI 解决方案推动业务转型。在 [LinkedIn](https://www.linkedin.com/in/gulal/) 上与他联系。

Miriam McCabe 是建筑师福音团队的高级总监和领导。她的工作重点是通过深入的技术内容、实时编程和社区参与，使全球 Salesforce 架构师社区在客服人员时代处于领先地位。在 [LinkedIn](https://www.linkedin.com/in/miriammccabe/) 上关注她。
