关于 field-service-objective-designer-configure
用于 Salesforce Field Service 排程策略的服务目标设计技能,通过结构化权衡访谈选择目标并推导权重。它以 Minimize Travel 为基准生成 serviceObjectives[],供后续记录创建步骤使用。
主要功能
- 01按类别引导选择目标
- 02通过权衡问题推导权重
- 03说明惩罚率计算方式
- 04记录目标专属参数
- 05生成 serviceObjectives[] 配置块
适用场景
- 01为策略设定排程目标
- 02比较出行与其他目标
- 03为记录创建准备目标数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill field-service-objective-designer-configure安装后在 Claude Code 中输入/field-service-objective-designer-configure确认已加载。
详细介绍
管理 Sfs 服务目标设计器
何时使用此技能
通过结构化的权衡访谈,为 Salesforce Field Service 调度策略设计服务目标。引导用户选择目标,并以最小化行程时间(锚点)为基准,通过建立交叉等效关系推导权重。生成包含惩罚率解读和通俗易懂的策略摘要的最终权重表。在工作规则设计完成后调用;记录创建由 sfs-sobject-create 负责。
工作流
Salesforce Field Service – 服务目标设计器
为调度策略设计服务目标。 此技能收集目标选择,并通过结构化的权衡访谈逐一推导每个目标的权重,最终输出一个 serviceObjectives[] 区块。它不会创建任何 Salesforce 记录。完成后,将任务交给 sfs-sobject-create。
访谈阶段: 调度策略 → 工作规则 → 服务目标(此技能)→ 记录创建
此技能仅涵盖服务目标阶段。policy 区块(来自 sfs-scheduling-policy-designer)和 workRules[] 区块(来自 sfs-work-rule-designer)作为上下文传入;此技能会添加 serviceObjectives[],并将完整设计交给 sfs-sobject-create。
背景:SFS 评分机制
优化器会为每个候选排班分配惩罚分。惩罚总分越低,排班越好。每个服务目标都会根据其权重和自身的尺度(该目标的最坏情况)贡献惩罚分。
最小化行程时间的权重是锚点——其值设为 1000,所有其他权重均以此为基准推导。适用于所有目标的通用公式如下(仅陈述一次,不会针对每个目标重新推导):
penaltyPerViolation = max( 1, roundingFn( (1000 × weight) / scale ) ) × finalMultiplier
total_penalty = ceil( violations / granularity ) × penaltyPerViolation
共享的 ×1000 内部乘数会带来两个结果:
- 在两个目标之间进行推导时,该乘数会抵消——因此,访谈中使用的连续近似仍然有效,且每个“从 weight_X 推导 weight_Y”的公式都不含 ×1000 项。对于整数权重,舍入函数并非精确(ASAP 的 round、Skill Level/Preference 的 roundInt),因此可能产生少量偏差;以下将针对各目标标出。
max(1, …)下限可确保每个纳入的目标即使权重很低,也能产生一定影响。
一个例外: Same Site 的最终乘数(×0.01)使其有效乘数变为 ×10,而不是 ×1000——这是唯一需要调整“直接除以另一目标的费率”这一快捷算法的地方。
各目标的惩罚公式
使用这些公式展示计算过程并反推权重。通用机制(×1000、下限、推导为何仍然有效)已在上文说明,此处不再重复。
最小化行程时间(锚点)——尺度为 120 分钟(2 小时 = 默认 MaxGrade__c),round5,×1/60(每分钟 → 每秒)。penaltyPerViolation_travel = max(1, round5(1000×weight_travel/120)) × (1/60)。权重为 1000 时 → 8333.33333 → 138.88889 分/秒(按整秒粒度计算)。连续近似:travel_penalty(X_min) ≈ X × weight_travel/120——权重为 1000 时约为 8.333 分/分钟。
精度: 行程时间按秒计算;加班时间(尺度相同)按分钟计算,因此 61 秒的行程比 60 秒的行程成本更高。只有当权重低于约 0.12 时,下限才会生效。
Same Site——尺度为 1(二元),round5,×0.01 → 有效乘数为 ×10,是个例外。penaltyPerViolation_same_site = max(1, round5(1000×weight_same_site)) × 0.01。权重为 50 时 → 每次违规 500 分。
精度: 对整数权重,round5 的结果精确。每个事件的惩罚固定,与时间无关。有效乘数为 ×10,而不是 ×1000。
尽量减少加班 — 机制与尽量减少出行完全相同(scale 120,round5,weight 1000 → 8333.33333),但有两处不同:最终乘数为 ×1.0,而不是 ×1/60,因此费率按分钟计算(8333.33333 pts/min);惩罚按整分钟计组——overtime_penalty(X_sec) = ceil(X_sec/60) × penaltyPerViolation——所以 61 秒的时段与 120 秒的时段费用相同。penaltyPerViolation_overtime = max(1, round5(1000×weight_overtime/120)) × 1.0。连续形式:≈ Z × weight_overtime/120;与出行相当。
*精度:*当 weight ≈0.12 以下时,最小值限制生效。
首选资源 — Scale 1(二元),roundInt,×1.0。penaltyPerViolation_preferred = max(1, roundInt(100 × 10.0 × weight_preferred)) × 1.0(100×10.0 = 1000,只是拆分表示)。weight 为 375 时 → 每次违规 375,000 pts。推导:weight_preferred = T_equiv × (weight_travel/120) — 当 weight_travel 为 1000 时:= T_equiv × 8.333。
*精度:*整数 weight 不会产生舍入误差(精确形式为 X_violations × 1000 × weight_preferred)。仅当 weight 低于 0.001 时触发最小值限制。
资源优先级 — Scale 10(优先级 0–10;0 = 最佳,10 = 最低),不舍入(原始小数值)。penaltyPerViolation_resource_priority = max(1, (weight_resource_priority/10.0) × 1000)。weight 为 1875 时 → 每个优先级点 187,500 pts。优先级 P 的总值:P × penaltyPerViolation。P=0 → 0;P=10 → 最大值。
*精度:*使用完整浮点值,不舍入。呈线性关系——优先级 5 = 最大值的 50%。
技能等级 — Scale 10(10 点技能量表),roundInt。penaltyPerViolation_skill_level = max(1, roundInt(1000×weight_skill_level/10))。技能等级 S 的总值:S × penaltyPerViolation。
*适用性:*有多项技能要求时,SFS 会对分数取平均值;没有技能要求时,不产生影响。Least vs. Most Qualified 模式(在访谈中处理)会改变首选方向,但不会改变公式。
*精度:*整数 weight 不会产生舍入误差。当 weight 低于约 0.01 时,最小值限制可忽略不计。
技能偏好 — Scale 10(技能优先级 1–10;1 = 最偏好,10 = 最不偏好;null → 10),roundInt。penaltyPerViolation_skill_preference = max(1, roundInt(1000×weight_skill_preference/10))。技能优先级 SP 的总值:SP × penaltyPerViolation。适用性(相同 Skill Type,或与配套 Match Skills 规则匹配)在访谈中处理。
*精度:*整数 weight 不会产生舍入误差。与 SP 呈线性关系。
就近分组 — Scale 1(二元——是否属于某个集群),round5,×1.0(完整的 ×1000,与 Same Site 的 ×0.01 不同)。penaltyPerViolation_group_nearby = max(1, round5(1000×weight_group_nearby)) × 1.0。weight 为 167 时 → 每次违规 167,000 pts。推导:weight_group_nearby = T_equiv × (weight_travel/120) — 当 weight_travel 为 1000 时:= T_equiv × 8.333。
*精度:*每个事件采用固定值——无论距离多远,每个未归入其集群的预约费用都相同。
尽量减少空档 — Scale 1(每个符合条件的空闲间隔 = 1 次违规;可配置的最短时长为 30 分钟至 24 小时,较短的间隔不计入),round。penaltyPerViolation_gaps = max(1, round(1000×weight_gaps))。总值:Σ over routes/shifts [ clump_counter(route) × penaltyPerViolation ]。
*精度:*整数 weight 不会产生舍入误差(精确形式为 clump_count × 1000 × weight_gaps)。当 weight 低于 0.001 时,最小值限制可忽略不计。按每个路线计每个空档——一个资源有 3 个空档,费用就是费率的 3 倍。
对话流程
两条全局规则(适用于以下所有内容):
阶段 1:**将每个推导出的权重向上舍入到下一个...
阶段 2:绝不要跨目标比较原始权重值,以便...
步骤 1:选择目标
首先说明这个概念:服务目标是软性评分标准,用于评估已经通过工作规则筛选的候选项;与工作规则不同,目标不会淘汰任何候选项,只会影响优化器更倾向于选择哪个符合条件的候选项。告诉用户,“最小化行驶距离”始终会自动作为锚定目标纳入,其权重固定为 1000,其他每个目标的权重都会通过权衡计算相对于它推导得出,因此用户无需选择它。
然后按以下固定顺序,每次只展示一个类别中的其余九个目标,并询问用户的选择;收到用户选择后,再进入下一个类别:
1. 客户体验目标 — 展示以下三个目标,并询问用户想选哪些(如果有):
- 尽快服务(ASAP)— 尽早为客户提供服务
- 同一地点(Same Site)— 如果两项工作在同一地点,则连续安排
- 邻近分组(Group Nearby)— 将地理位置相近的工作安排在一起
2. 成本/效率目标 — 展示以下三个目标(“最小化行驶距离”已自动纳入),询问用户想选其余两个中的哪些:
- 最小化行驶距离(Minimize Travel)(已自动纳入 — 锚定目标,权重固定为 1000)
- 最小化空档(Minimize Gaps)— 让技术人员持续保持忙碌
- 最小化加班(Minimize Overtime)— 避免支付加班费
3. 劳动力/分配质量目标 — 展示以下四个目标,并询问用户想选哪些(如果有):
- 首选资源(Preferred Resource)— 尽可能安排首选/指定的技术人员
- 资源优先级(Resource Priority)— 优先安排优先级较高的资源(例如员工优先于承包商)
- 技能水平(Skill Level)— 为工作匹配合适的专业水平
- 技能偏好(Skill Preference)— 遵循某项技能类别内的偏好排序(例如语言偏好)
各目标的后续问题 — 在用户回答所属类别后、进入下一个类别前,立即提问:
- 最小化行驶距离(始终询问 — 在成本/效率类别结束时询问一次):“计算最小化行驶距离时,是否也应计入往返资源驻地的路段 — 即从驻地到第一个工作地点的行程,以及从最后一个工作地点返回驻地的行程?还是应将这些路段排除在评分之外?”分别记录两个独立标志:
excludeTravelFromHome和excludeTravelToHome(true = 排除)。默认两者均为 false。 - 同一地点(仅在已选择时询问):“只有在两个预约的纬度/经度完全相同的情况下,才将它们视为同一地点吗?这适用于园区或农场等场景。还是使用默认分组方式(预约之间的行驶时间约为 1 秒)?”记录为
useExactLocation(true = 仅限经纬度完全相同)。默认 false。 - 最小化空档(仅在已选择时询问):询问用户的公司将多长的最短闲置时间视为空档(30 分钟–24 小时)。记录为
params.minGapMinutes;默认值为 30。这样询问可以将“多长时间算空档”与“多大程度上要减少空档”区分开来。
三个类别都已回答且后续问题均已记录后,进入步骤 2。
步骤 2:权衡访谈
针对每个已选择的目标(“最小化行驶距离”除外),提出一个权衡问题。目标是找出一个交叉点,让用户认为两个选项同样可接受 — 这种等价关系可用于计算权重。用户回答后,将两个惩罚表达式设为相等,求出未知权重,再根据全局规则向上取整。始终展示计算过程。
在开放式问题旁提供具体的预设答案。 给出问题模板后,提供少量现成的交叉点选项,涵盖轻度/中度/强烈偏好,供用户直接选择,而不必自己编造数字。同时始终邀请用户描述自己的确切权衡方式。预设答案只是为了方便,不代表使用另一种计算方式。
ASAP 权衡
“如果现在就能安排预约,但需要额外花 [X] 分钟出行;或者在 [Y] 小时后安排,且无需额外出行——在什么情况下,你会觉得两者大致一样合适?”
预设:“额外出行 15 分钟 ≈ 延迟 12 小时”(轻度)、“额外出行 30 分钟 ≈ 延迟 24 小时”(中度)、“额外出行 60 分钟 ≈ 延迟 48 小时”(强烈)。
计算(用户提供出行时间 X 分钟、延迟时间 Y 小时):
travel_penalty(X) = asap_penalty(Y × 60)
X × (weight_travel / 120) = (Y × 60) × (weight_asap / 43200)
weight_asap = X × weight_travel × 6 / Y
当 weight_travel = 1000 时:weight_asap = X × 6000 / Y。
**整数公式验证:**确认 penaltyPerViolation = max(1, round(1000 × weight_asap / 43200)),然后计算 effective_weight = penaltyPerViolation × 43200 / 1000。如果 effective_weight 有明显差异(偏差 >5%),请注明。
**低权重警告:**如果派生权重 < 22,请警告用户:SFS 会将每分钟惩罚限制为 1(下限)——任何 1–21 的权重都会产生相同的优化器行为。
同地点权衡
**说明:**请勿将同地点与出行时间进行比较——同地点的预约本来就在同一地点。请与 ASAP(如果已选择)或首选资源(如果已选择)进行比较。
如果已选择 ASAP——同地点与 ASAP 的比较:
“想象有两个预约在同一地点。优化器可以选择:(A) 将两者分配给同一资源,但安排时间比原本可能的时间晚 [H] 小时。(B) 将两者分开安排,这样现在就能安排。在什么延迟情况下,你会说‘直接分开安排’?”
预设:“最多愿意晚 1 小时,以便安排在一起”(弱)、“最多愿意晚 4 小时”(中度)、“最多愿意晚 8 小时”(强烈)。
计算(延迟阈值 D_equiv,单位为分钟):weight_same_site = D_equiv × (weight_asap / 43200)
如果未选择 ASAP,但已选择首选资源——同地点与首选资源的比较:
“为了满足其中一个预约的首选资源分配,你愿意将同地点的预约分开(分配给不同资源)吗?还是即使这意味着忽略首选资源,也要将它们安排在一起?”
预设:“同等重要”(F = 1)、“同地点的重要性是两倍”(F = 2)、“同地点的重要性是一半”(F = 0.5)。
计算:weight_same_site = F × weight_preferred
如果两者都未选择——回退到出行比较:
“额外出行多少分钟,才值得将同地点的预约分开安排?”
预设:“额外 10 分钟”、“额外 20 分钟”、“额外 30 分钟”。
计算:weight_same_site = T_equiv × (weight_travel / 120)
尽量减少加班权衡
“如果现在就能安排预约,但需要加班 [Z] 分钟;或者在 [H] 小时后于正常工作时间安排——在什么情况下,你会觉得两者同样可以接受?”
预设:“加班 15 分钟 ≈ 延迟 6 小时”(强烈避免加班)、“加班 30 分钟 ≈ 延迟 12 小时”(中度)、“加班 60 分钟 ≈ 延迟 24 小时”(乐于接受加班)。
计算(用户提供加班时间 Z 分钟、延迟时间 H 小时):
overtime_penalty(Z) = asap_penalty(H × 60)
Z × (weight_overtime / 120) = (H × 60) × (weight_asap / 43200)
weight_overtime = weight_asap × H / (Z × 6)
如果已选择 ASAP,则必须先计算 weight_asap。
加班与出行的回退比较(未选择 ASAP 时):weight_overtime = T_equiv × weight_travel / Z,其中 T 是用户认为相较于 Z 分钟加班更愿意接受的等效出行时间(分钟)。
首选资源权衡
“如果预约已指定首选资源,满足这一偏好的重要性有多高?想象一下,首选资源有空,但需要额外出行 [X] 分钟——在什么情况下,你会说‘直接使用距离更近的资源’?”
预设:“额外 15 分钟”(轻度)、“额外 30 分钟”(中度)、“额外 60 分钟”(强烈)。
计算(出行阈值 T_equiv):weight_preferred = T_equiv × (weight_travel / 120)
保持相邻分组的取舍
背景说明: 保持相邻分组和最小化出行距离是天然的竞争目标——保持一组预约不拆分,可能会增加总出行距离。需要权衡的是:用户最多愿意为保持一组预约完整而增加多少总出行时间?
“为了让同一组中的所有预约安排在一起,你最多愿意在日程中增加多少总出行时间?如果维持分组的成本超过这个限度,优化器就应该拆分这组预约,以节省出行时间。”
预设:“额外 10 分钟”(较弱)、“额外 20 分钟”(中等)、“额外 30 分钟”(较强)。
计算公式(T_equiv):weight_group_nearby = T_equiv × (weight_travel / 120)
资源优先级取舍
可分享的背景信息:
“资源优先级目标允许你按 0–10 的等级为服务资源排序,其中 0 表示最高优先级(最佳候选人),10 表示最低优先级。例如,你可以将内部员工的优先级设为 1,将承包商设为 5 或更高。优化器会根据资源的优先级值按比例施加惩罚:优先级为 5 的资源会受到完整目标权重 50% 的惩罚,而优先级为 0 的资源完全不会受到惩罚。”
“假设有两个可用资源:资源 A 是内部技术人员(优先级 1),但距离多出 [X] 分钟。资源 B 是承包商(优先级 [P]),距离更近。到什么程度时,你会说‘直接用承包商吧’?”
预设:“额外 30 分钟”(较轻)、“额外 60 分钟”(中等)、“额外 90 分钟”(较强)。
计算公式(T_equiv,员工优先级 P_high = 1,承包商优先级 P_low):weight_resource_priority = T_equiv × weight_travel / (12 × (P_low - P_high))
示例(员工 1,承包商 5,T_equiv = 90):= 90 × 1000 / (12 × 4) = 1,875
技能等级取舍
可分享的背景信息:
“技能等级目标会引导优化器选择满足预约技能要求的资源,并可倾向于选择资历最低或最高的资源。惩罚值按资源的原始技能等级乘以目标权重计算——因此,与技能等级为 1 的资源相比,技能等级为 8 的资源会受到 8 倍的权重惩罚。”
步骤 1 — 询问他们希望使用哪种模式:
“你想使用哪种模式?
- 资历最低 — 优先选择仍满足要求的技能等级最低的资源。适用于为复杂任务保留资深资源,或控制成本。
- 资历最高 — 优先选择可用的技能等级最高的资源。适用于最大限度提高一次修复率,或优先考虑结果质量的情况。”
如果选择资历最低:
“假设有两个符合条件的资源:初级技术人员(技能等级 [S_low])和高级技术人员(技能等级 [S_high])。高级技术人员距离更近。在资历最低模式下,优化器会优先选择初级技术人员,为更困难的任务保留高级技术人员。你愿意接受多少分钟的额外出行时间来安排初级技术人员?”
如果选择资历最高:
“假设有两个符合条件的资源:初级技术人员(技能等级 [S_low])和高级技术人员(技能等级 [S_high])。初级技术人员距离更近。在资历最高模式下,优化器会优先选择高级技术人员。你愿意接受多少分钟的额外出行时间来安排高级技术人员?”
预设:“额外 15 分钟”(较轻)、“额外 30 分钟”(中等)、“额外 45 分钟”(较强)。
计算公式(无论使用哪种模式都相同):weight_skill_level = T_equiv × weight_travel / (120 × (S_high - S_low))
示例——资历最低(S_low=4,S_high=8,T_equiv=30):= 30 × 1000 / (120 × 4) = 62.5 → 向上取整为 63
技能偏好权衡
需分享的背景:
“当工单包含多个相同技能类型的技能要求,且其中一项技能优先于另一项时,适用技能偏好目标。每项技能要求的技能优先级值为 1 到 10,其中 1 表示优先级最高,10 表示优先级最低。优化器会根据该优先级值按比例分配惩罚值。”
还需记录 技能类型(此目标生效的必要条件)。技能偏好针对一种技能类型进行评估,即由配套的“匹配技能”工作规则评估的技能类别(例如语言),且该规则使用“至少匹配一项技能(OR)”。询问:
“此偏好要对哪种技能类型进行排序?请提供其 Developer Name——它必须与设为‘至少匹配一项技能(OR)’的‘匹配技能’工作规则所用的技能类型相同,因为在 AND 匹配下,技能偏好不会生效。”
记录为 skillType 参数(技能类型 Developer Name,映射到目标上的 {ns}Skill_Type__c)。如果用户尚未为该技能类型定义使用 OR 逻辑的“匹配技能”规则,请标记出来。
“想象有一个工单,客户可以由会说 [Skill A] 的技术人员(技能优先级 [SP_high_pref])或会说 [Skill B] 的技术人员(技能优先级 [SP_low_pref])提供服务,但客户更偏好 [Skill A]。会说 [Skill A] 的技术人员路程更远。为了安排会说 [Skill A] 的技术人员,您最多愿意接受多长的额外路程时间?”
预设:“额外 15 分钟”(轻微)、“额外 30 分钟”(中等)、“额外 45 分钟”(强烈)。
计算公式(T_equiv,SP_high_pref = 优先级较高,SP_low_pref = 优先级较低):weight_skill_preference = T_equiv × weight_travel / (12 × (SP_low_pref - SP_high_pref))
示例(西班牙语优先级为 1,英语优先级为 6,T_equiv = 45):= 45 × 1000 / (12 × 5) = 750
最小化空档权衡
最小空档时长已在第 1 步记录为 params.minGapMinutes(默认值为 30)。不要再次询问。本节仅介绍权重计算。
如果选择了 ASAP——最小化空档与 ASAP 的权衡:
“优化器可以选择:(A) 在技术人员的日程中留出空档,并将新预约安排在提前 [H] 小时的时间。(B) 压缩日程以消除空档,但该预约会延后 [H] 小时。延迟多久时,您会认为‘就留出空档并提前安排’?”
预设:“最多可接受延后 2 小时,选择留出空档”(弱)、“最多可接受延后 4 小时”(中等)、“最多可接受延后 8 小时”(强烈)。
计算公式(延迟阈值 D_equiv,单位为分钟):weight_gaps = D_equiv × weight_asap / 43200
示例(weight_asap = 250,D_equiv = 240 分钟):= 240 × 250 / 43200 = 1.389 → 向上取整至 2
如果未选择 ASAP——改用路程时间比较:
“在整个日程中,额外增加多少分钟的路程时间,才值得在技术人员的班次中留出空档,而不是压缩日程?”
预设:“额外 10 分钟”、“额外 20 分钟”、“额外 30 分钟”。
计算公式:weight_gaps = T_equiv × weight_travel / 7200
**整数公式验证:**确认 penaltyPerViolation = max(1, round(1000 × weight_gaps))。如果计算出的权重非常小(低于约 1),请提醒用户,max(1,…) 下限会将惩罚值钳制为固定的最小值。
步骤 3:输出结果
回答完所有权衡问题后,用表格整洁地汇总结果,每个纳入的目标占一行,显示其权重和一行理由,理由须以用户陈述的权衡为依据(例如,对于 ASAP,说明用户给出的“X 分钟行程 ≈ Y 小时延迟”临界点;对于 Same Site,说明“拆分 1 次 ≈ ASAP 延迟 D 分钟”;依此类推)。Minimize Travel 始终以 1000 为基准。
然后使用每单位的惩罚点数说明相对优先级,不要使用原始权重,因为各目标的乘数不同。按以下方式计算各项比率:Travel:weight_travel / 120,单位为每分钟;ASAP:weight_asap / 43200,单位为每分钟延迟;Overtime:weight_overtime / 120,单位为每分钟;Same Site:weight_same_site × 10,单位为每次事件(×10,而非 ×1000);Preferred Resource 和 Group Nearby:weight × 1000,单位为每次事件;Resource Priority:weight × (P / 10),单位为每个资源(展示几个相关的优先级层级);Skill Level:S × weight × 100,单位为每个资源(展示相关技能层级);Skill Preference:weight × (SP / 10),单位为每项技能分配(展示相关优先级);Minimize Gaps:weight_gaps × 1000,单位为每个间隔(固定值)。
使用这些比率,用通俗易懂的语言解释相对优先级,并以用户最初陈述的权衡为依据——例如:“这体现了您所表达的偏好:30 分钟行程相当于 12 小时延迟。”如果隐含的优先级与用户的预期不符,可提出重新进行任何一项权衡问题。
政策概览(2–3 句业务摘要)
呈现权重和惩罚比率后,撰写一段 2–3 句的高层次业务摘要,说明此调度政策的优化目标,作为面向不关心数学细节的利益相关者的简明说明。
生成方法:
阶段 3:按类别对目标分类
客户体验(ASAP、Same Site、Group Nearby);成本/效率(Minimize Travel、Minimize Gaps、Minimize Overtime);员工队伍/分配质量(Preferred Resource、Resource Priority、Skill Level、Skill Preference)。
阶段 4:通过比较惩罚比率,确定哪个类别占主导地位...
阶段 5:根据临界点识别关键权衡冲突...
阶段 6:用 2–3 句说明主要和次要...
使用基于用户实际表达的价值取向的业务语言(例如“最多开车 2 小时”“最多等待 24 小时”),而不是惩罚计算结果。这段摘要也适合作为调度政策记录的 Description 字段——交接时可向用户推荐使用。
输出构建规范(交接契约)
这是此技能的最终交付物,也是与 sfs-sobject-create 之间唯一的契约。设计确定后(政策设置、工作规则、相关性分组、权重),输出一个结构化构建规范,格式为 JSON 对象。sfs-sobject-create 会原样使用该对象,不会重新推导意图,因此内容必须完整且自成一体。
严格边界:仅输出设计值。不要包含 Salesforce 对象名称、字段 API 名称、记录 ID、复合 API 引用语法或创建顺序——这些属于数据层技能。使用规范类型名称(与此处完全一致,例如 Match Skills、Minimize Travel、Resource Priority)及业务参数描述规则/目标。未知参数 → 省略或标记为 null;绝不虚构 API 字段名称。
{
"specVersion": "1.0",
"policy": {
"name": "scheduling policy name",
"description": "free text; include the Policy at a Glance summary",
"inDayOptimization": true,
"commitMode": "Always Commit | Rollback"
},
"workRules": [{
"type": "canonical work rule type name (e.g. 'Match Skills')",
"name": "instance display name — see naming convention below",
"mandatory": false,
"params": {}, // business params only. e.g. Service Resource Availability absolute break: breaks:[{mode:'absolute',startClock:'12:00',durationMinutes:30}]; offset break: breaks:[{mode:'offset',earliestStartOffsetMinutes:180,latestEndOffsetMinutes:210,durationMinutes:30}]; Maximum Travel from Home: maxTravelFromHome:45, maxTravelFromHomeType:'Travel Time'
"relevanceGroup": { "basis": "Service Appointment | Service Territory Member | null", "booleanField": "scoping Boolean field name, or null for policy-wide" }
}],
"serviceObjectives": [{
"type": "canonical objective type name (e.g. 'Minimize Travel')",
"name": "instance display name — see naming convention below",
"weight": 1000,
"params": {}, // objective-specific business params. e.g. Skill Level mode:'Least Qualified'; Resource Priority priorityField concept; Minimize Gaps minGapMinutes; Skill Preference skillType; Minimize Travel excludeTravelFromHome/excludeTravelToHome; Same Site useExactLocation
"relevanceGroup": { "basis": "Service Appointment | Service Territory Member | null", "booleanField": "scoping Boolean field name, or null for policy-wide" },
"rationale": "one-line human trace of how the weight was derived (the stated crossover)"
}],
"prerequisites": ["human-readable notes the user must satisfy before deployment — e.g. 'Create Boolean field Break_Group_France__c on Service Territory Member and set it true for French resources.'"],
"notes": "caveats, low-weight-floor warnings, or unresolved ambiguities"
}
输出规则:
阶段 7:命名约定(每条规则和目标)
name = 规范类型名称 + 缩写后的策略名称,中间以 " - " 分隔 — 例如,策略“先测试较短项” → “匹配技能 - 先测试”、“最小化行程 - 先测试”。缩写策略名称(删去“较短项优先”/“策略”等填充词);不要原样附加策略名称。例外: 两条 Arrival Window Match Time 规则保留各自的名称(Arrival Window Start、Arrival Window End)——在名称后附加缩写后的策略名称,而不是替换类型名称:“Arrival Window Start - 先测试”、“Arrival Window End - 先测试”。
阶段 8:始终包含权重为 1000 的 Minimize Travel,以及且仅有一条 `"mandatory"
true` 的 Service Resource Availability 规则,即使从未讨论过。绝不输出 Earliest Start Permitted 或 Due Date。
阶段 9:每个子集一个实例 — 如果一条规则/目标……
阶段 10:权重必须为整数,且已按……向上取整
阶段 11:参数应为业务值,而不是字段映射 — “12
00 至 15:00 之间休息 30 分钟”应作为时长/时间传入;字段布局映射由数据层技能负责。
阶段 12:明确指出前置条件 — 任何相关性组布尔字段……
阶段 13:**不要创建任何内容。**输出后,告诉用户……
移交
当用户确认权重和摘要后,目标设计阶段即告完成。委托给 sfs-sobject-create,传入上述构建规范(包括来自 sfs-scheduling-policy-designer 的 policy 块、来自 sfs-work-rule-designer 的 workRules,以及来自此技能的 serviceObjectives),以便按依赖顺序创建调度策略、工作规则及其服务目标。
“目标设计已完成。接下来,我会将任务移交给记录创建流程,由其按正确顺序创建所有 Salesforce 记录——调度策略、工作规则和服务目标。准备继续了吗?”
─────
运行时上下文(Headless 360 / agentic): 在 Headless 360 / agentic 上下文中运行此技能时,尽可能优先使用 dispatch 工具,而非 CLI 工具(sf project deploy、sfdx、shell 命令)。可用的操作列于下方的 steps: 中;每项均已在实时 org 中验证。使用 dispatch 调用规范路径。只有在某项功能没有对应 API 路径时,才可使用 CLI 作为回退方案。
关键约束
前置条件:
- 已在组织中安装 FSL 托管软件包。(检查:
Tooling API: GET /services/data/v68.0/tooling/query with q=SELECT SubscriberPackage.NamespacePrefix FROM InstalledSubscriberPackage. Filter client-side for a NamespacePrefix starting with FSL (matches FSL, FSLQA, FSLMPTEST, FSLMPPERF). No FSL* record — abort: this skill cannot design objectives for an org without FSL.) - 技能偏好目标要求组织中至少存在一条 SkillType 记录,才能进行部署。技能正文会询问用户 Skill Type Developer Name;如果 SkillType 中没有记录,请警告用户:在 sfs-sobject-create 写入目标之前,必须先创建目标 Skill Type。(检查:
SOQL: SELECT COUNT() FROM SkillType. Zero → surface in the interview if the user selects Skill Preference; the emitted spec should add a prerequisites[] entry naming the Skill Type Developer Name the user needs to create.) - 对于依据为 Service Territory Member 的相关性组,预期用于范围限定的 Boolean 字段必须已作为 boolean 类型的自定义字段存在于 ServiceTerritoryMember 上(只有 IsDeleted 是标准字段)。如果用户为 STM 范围限定指定 Boolean 字段,生成的 prerequisites[] 条目应列出该字段,以便元数据工作流在部署前添加它。(检查:
Global describe on ServiceTerritoryMember; filter fields whose type equals boolean. On a fresh FSL install, only IsDeleted is present. Any STM-basis Relevance Group requires customer-authored Booleans; surface the dependency in the emitted prerequisites[] rather than blocking.)
操作规则:
- ASAP — Scale 为 43,200 分钟(30 天),取整。
penaltyPerViolation_asap = max(1, round(1000×weight_asap/43200))。按整分钟计算:asap_penalty(X_sec) = ceil(X_sec/60) × penaltyPerViolation。连续计算:asap_penalty(Y_min) ≈ Y × weight_asap/43200。 精度: 权重 1–21 无效 — round(1000×21/43200)=0,钳制为 1,因此所有这些权重都会产生相同的 1 分/分钟速率。超过该范围后,偏差较小(权重 250 → 实际值 259.2,偏差 3.7%)。需要精确计算时,请使用整数公式验证。 - 此处不要创建任何 Salesforce 记录,也不要启动创建流程 — 所有 Salesforce API 调用均由
sfs-sobject-create负责。交接消息:
操作参考
按用途分组的操作。使用这些操作作为上述工作流的构建模块。
摘要
| 操作 | 用途 | 状态 | 调用 | 依赖项 |
|---|---|---|---|---|
resolve-fsl-namespace | 验证 | — | GET /services/data/v68.0/tooling/query | — |
enumerate-service-objective-record-types | 读取 | — | GET /services/data/v68.0/query | resolve-fsl-namespace |
describe-service-goal-schema | 读取 | — | GET /services/data/v68.0/sobjects/FSLMPPERF__Service_Goal__c/describe | resolve-fsl-namespace |
list-scheduling-policy-goal-junction | 读取 | — | GET /services/data/v68.0/sobjects/FSLMPPERF__Scheduling_Policy_Goal__c/describe | resolve-fsl-namespace |
list-skill-types | 读取 | — | GET /services/data/v68.0/query | — |
list-service-appointment-boolean-fields | 读取 | — | GET /services/data/v68.0/sobjects/ServiceAppointment/describe | — |
list-service-territory-member-boolean-fields | 读取 | — | GET /services/data/v68.0/sobjects/ServiceTerritoryMember/describe | — |
list-existing-service-goals | 读取 | — | GET /services/data/v68.0/query | resolve-fsl-namespace |
emit-service-objectives-block | 写入 | — | — | enumerate-service-objective-record-types、describe-service-goal-schema、list-scheduling-policy-goal-junction、list-skill-types、list-service-appointment-boolean-fields、list-service-territory-member-boolean-fields |
handoff-to-sobject-create | 委派 | — | — | emit-service-objectives-block |
依赖关系图
graph TD
resolve_fsl_namespace["resolve-fsl-namespace (validate)"]
enumerate_service_objective_record_types["enumerate-service-objective-record-types (read)"]
describe_service_goal_schema["describe-service-goal-schema (read)"]
list_scheduling_policy_goal_junction["list-scheduling-policy-goal-junction (read)"]
list_skill_types["list-skill-types (read)"]
list_service_appointment_boolean_fields["list-service-appointment-boolean-fields (read)"]
list_service_territory_member_boolean_fields["list-service-territory-member-boolean-fields (read)"]
list_existing_service_goals["list-existing-service-goals (read)"]
emit_service_objectives_block["emit-service-objectives-block (write)"]
handoff_to_sobject_create["handoff-to-sobject-create (delegate)"]
resolve_fsl_namespace --> enumerate_service_objective_record_types
resolve_fsl_namespace --> describe_service_goal_schema
resolve_fsl_namespace --> list_scheduling_policy_goal_junction
resolve_fsl_namespace --> list_existing_service_goals
enumerate_service_objective_record_types --> emit_service_objectives_block
describe_service_goal_schema --> emit_service_objectives_block
list_scheduling_policy_goal_junction --> emit_service_objectives_block
list_skill_types --> emit_service_objectives_block
list_service_appointment_boolean_fields --> emit_service_objectives_block
list_service_territory_member_boolean_fields --> emit_service_objectives_block
emit_service_objectives_block --> handoff_to_sobject_create
读取操作
enumerate-service-objective-record-types
枚举 <NS>__Service_Goal__c 上处于活动状态的 RecordType.DeveloperName 值。这是组织公开的服务目标类型的权威枚举。serviceObjectives[] JSON 块中生成的每个目标都必须对应此集合中的一个 DeveloperName — sfs-sobject-create 依赖它来写入正确的 RecordTypeId。目标组织中,Group Nearby 并非独立的 RecordType;如果面试中提到它,技能应先确认组织是否公开了此选项,再提供该选项。
调用: GET /services/data/v68.0/query
输入:
q(String) — SOQL:SELECT Id, DeveloperName, Name, IsActive FROM RecordType WHERE SObjectType='<NS>__Service_Goal__c' AND IsActive = true ORDER BY DeveloperName。将命名空间替换为 resolve-fsl-namespace 发现的值。
依赖: resolve-fsl-namespace
输出: 记录列表,包含 DeveloperName(例如 Objective_Asap、Objective_Minimize_Travel、Objective_Same_Site、Objective_Skill_Level、Objective_Skill_Preferences、Objective_PreferredEngineer、Objective_Resource_Priority、Objective_Minimize_Gaps、Objective_Minimize_Overtime、Objective_Custom_Logic)、Name(人类可读的 Field Service 标签)和 Id。技能会将用户通过对话选择的目标映射到 DeveloperName。目标组织 sfs-headless-skill-building 预期有 10 条活动记录。
备注: 经探测验证,目标组织有 10 个活动的 DeveloperName 值。技能面试未公开的目标类型(Objective_Custom_Logic)也会被枚举,因此技能可以明确拒绝这些类型,而不是在部署时被静默阻止。
describe-service-goal-schema
检查 Service_Goal__c sObject,以公开面试流程所需驱动的配置字段。加载 picklist 枚举(Custom_Type__c 有 14 个值;Prioritize_Resource__c 在技能级别模式问题中有 Least Qualified / Most Qualified 两个选项)、承载技能参数的字符串列(Skill_Type__c、Resource_Priority_Field__c、Object_Group_Field__c、Resource_Group_Field__c),以及用于 Gap_Duration__c 和 Ignore_Home_Base_Coordinates__c 等参数的数值/布尔列。sObject 路径使用发现的命名空间前缀 — 显示的路径适用于目标组织 sfs-headless-skill-building;运行时请替换为已解析的 。
调用: GET /services/data/v68.0/sobjects/FSLMPPERF__Service_Goal__c/describe
依赖: resolve-fsl-namespace
输出: 从 describe.fields[] 中按名称提取:Custom_Type__c(picklist 取值范围 — 涵盖各目标类型的 14 个值)、Prioritize_Resource__c(picklist,默认值为 "Least Qualified",另一选项为 "Most Qualified")、Gap_Duration__c(double,单位为分钟;对应 params.minGapMinutes)、Ignore_Home_Base_Coordinates__c(boolean;对应 travel-home 标志)、Skill_Type__c(string;对应 Skill Preference)、Resource_Priority_Field__c(string,默认值为 "fsl__priority__c";对应 Resource Priority)、Object_Group_Field__c 和 Resource_Group_Field__c(字符串;Relevance Group 范围限定字段)、Custom_Logic_Data__c(长文本区域;仅用于 Objective_Custom_Logic)。
备注: describe 响应还包含全部 10 个 RecordTypeId。使用方可以从此 describe 或 enumerate-service-objective-record-types 步骤中的 SOQL 查询获取 RecordTypeId — 在安装正常的情况下,两者一致。
list-scheduling-policy-goal-junction
检查 Scheduling_Policy_Goal__c 关联对象,该对象通过 Weight 将 Service_Goal 关联到 Scheduling_Policy。下游的 sfs-sobject-create 会向此关联对象写入行——对于输出的 serviceObjectives[] 块中的每个(策略、目标、权重)三元组,写入一行。关键列:FSLMPPERF__Scheduling_Policy__c(主从关系)、Service_Goal__c(主从关系)、Weight__c(Number(9,0),不可为空)。(9,0) 精度在架构层面落实了该技能的全局规则 #1(权重必须为整数)。sObject 路径使用已发现的命名空间前缀。
调用: GET /services/data/v68.0/sobjects/FSLMPPERF__Scheduling_Policy_Goal__c/describe
依赖: resolve-fsl-namespace
输出: 在 describe.fields[] 中确认:FSLMPPERF__Weight__c 的 type=double、precision=9、scale=0、nillable=false;两个主从关系查找字段均存在,且目标分别为 Scheduling_Policy__c 和 Service_Goal__c。如果非目标组织上的 Weight__c 最终显示为可空,请注明这一差异——该技能向上取整为整数的规则仍然正确,但架构层面并未落实该规则。
备注: 此 describe 是供设计技能使用的架构可见性读取;实际的关联对象行写入由 sfs-sobject-create 执行。在此处明确 Weight__c(9,0) 约束,可发现未来技能偏差导致的遗漏向上取整问题。
list-skill-types
读取现有 SkillType 记录。Skill Preference 目标需要 Skill Type Developer Name;访谈必须能够提供枚举值集合,或在集合为空时警告用户。在目标组织 sfs-headless-skill-building 上,SkillType 没有记录——根据平台元数据,Skill Preference 可以提供,但在用户创建 SkillType 记录之前无法使用。
调用: GET /services/data/v68.0/query
输入:
q(String) — SOQL:SELECT Id, DeveloperName, MasterLabel FROM SkillType ORDER BY DeveloperName。标准 sObject——无需替换命名空间。
输出: SkillType 的记录列表,包含 DeveloperName 和 MasterLabel。若列表为空,访谈仍应记录用户期望的 Developer Name 字符串,但应将其放入输出的 prerequisites[] 块中,以便 sfs-sobject-create 标记或延后写入。
备注: Skill 正文明确询问:“此偏好要在什么 Skill Type 中排序?请提供其 Developer Name。”此步骤使访谈能够在存在实际记录时自动补全。
list-service-appointment-boolean-fields
列出 ServiceAppointment sObject 上的所有 Boolean 字段。访谈在 Relevance Group 的依据为 Service Appointment 时使用此列表:组的范围限定 Boolean 必须存在于此对象上。将响应字段筛选为 type == "boolean" 的字段;同时显示自定义名称(__c)和标准名称。与同级的 sfs-work-rule-designer 探测相同;两种技能共用 SA-boolean 领域。
调用: GET /services/data/v68.0/sobjects/ServiceAppointment/describe
输出: 从 describe 响应中取出 fields[] where type == "boolean";提取 name、label、custom 和 defaultValue。目标组织的基线:18 个 Boolean 字段,其中 13 个自定义字段(均以 FSLMPPERF__ 为前缀:Auto_Schedule__c、Emergency__c、InJeopardy__c、IsFillInCandidate__c、IsMultiDay__c、Pinned__c、Prevent_Geocoding_For_Chatter_Actions__c、Same_Day__c、Same_Resource__c、Schedule_over_lower_priority_appointment__c、UpdatedByOptimization__c、Use_Async_Logic__c、Virtual_Service_For_Chatter_Action__c),另有 5 个标准字段(IsBundle、IsBundleMember、IsDeleted、IsManuallyBundled、IsOffsiteAppointment)。
备注: 以 Service Appointment 为范围的 Relevance Group 要求此处已存在指定的 Boolean 字段。如果访谈参与者指定的字段不在此集合中,请提示他们先通过元数据工作流创建该字段,再继续;或者在输出的 prerequisites[] 块中指出缺失的字段。
list-service-territory-member-boolean-fields
列出 ServiceTerritoryMember sObject 上的所有布尔字段。仅供基于 Service Territory Member 的 Relevance Group 使用:组的范围限定布尔字段必须存在于此对象上。将响应字段筛选为 type == "boolean"。与同级 sfs-work-rule-designer 使用相同的探查。
调用: GET /services/data/v68.0/sobjects/ServiceTerritoryMember/describe
输出: 全新安装的 FSL 中,ServiceTerritoryMember 上没有自定义布尔字段(只有标准字段 IsDeleted)。因此,每个基于 ServiceTerritoryMember 的 Relevance Group 都依赖用户必须先创建的自定义布尔字段。如果自定义布尔字段查询结果为空,技能必须在生成的 prerequisites[] 块中说明此依赖(技能正文示例:“在 Service Territory Member 上创建布尔字段 Break_Group_France__c,并将其设为 true,以标记法国资源。”)。
注意: 与 ServiceAppointment 相比(探查确认目标组织中有 13 个来自 FSL 软件包的自定义布尔字段),基于 ServiceTerritoryMember 范围限定的 Relevance Group 完全由用户编写。
list-existing-service-goals
读取现有的 <NS>__Service_Goal__c 记录,作为访谈过程中的参考示例。当上游 sfs-scheduling-policy-designer 指示存在修改入口时,此操作很有用——访谈可以将策略上的当前目标作为基线展示给用户,让用户从此基础上修改。
调用: GET /services/data/v68.0/query
输入:
q(String) — SOQL:SELECT Id, Name, RecordType.DeveloperName FROM <NS>__Service_Goal__c ORDER BY RecordType.DeveloperName。替换为 resolve-fsl-namespace 查出的命名空间。
依赖: resolve-fsl-namespace
输出: 现有目标列表。目标组织中有 9 条种子记录,涵盖全部 10 种 RecordType,但不包括 Objective_Custom_Logic。仅将其用作参考资料;生成的 serviceObjectives[] 块应体现访谈中设计的内容,而不是照搬此列表。
注意: 类型通过 RecordType.DeveloperName 区分;Service_Goal__c 上没有 FSLMPPERF__Type__c 字段(与同级 Work_Rule__c 的模式一致)。
写入操作
emit-service-objectives-block
访谈的最后一步。用户确认目标集和权重后,此技能会在对话频道中生成一个 JSON 块,格式为 { serviceObjectives: [ { type, name, weight, params, relevanceGroup, rationale } ] },并附带顶层 prerequisites[] 列表,其中包含任何由用户编写的依赖项(用于 STM 基准 Relevance Group 的自定义布尔字段、SkillType Developer Name、自定义 Resource Priority 字段)。委派技能(sfs-sobject-create)会使用这些内容写入相应的 Service_Goal 和 Scheduling_Policy_Goal 联接记录。这是客户端工作流边界,不是 API 调用。
依赖: enumerate-service-objective-record-types、describe-service-goal-schema、list-scheduling-policy-goal-junction、list-skill-types、list-service-appointment-boolean-fields、list-service-territory-member-boolean-fields
其他操作
resolve-fsl-namespace
解析已安装的 FSL 托管包命名空间前缀。在生产环境中,前缀为 FSL;在内部组织中,前缀为 FSLQA / FSLMPTEST / FSLMPPERF。此技能中后续的每次 SOQL 查询、describe 和 JSON 块输出,都必须使用带有所发现前缀的 <NS>__Service_Goal__c 和 <NS>__Scheduling_Policy_Goal__c——不要硬编码 FSLMPPERF。
调用: GET /services/data/v68.0/tooling/query
输入:
q(String) — SOQL:SELECT SubscriberPackage.NamespacePrefix, SubscriberPackage.Name FROM InstalledSubscriberPackage。不要添加 WHERE 子句——Tooling API 会拒绝针对 NamespacePrefix 的筛选条件。查询时不加筛选;在客户端进行筛选。
输出: 从 records 数组中,选取 SubscriberPackage.NamespacePrefix 以 FSL 开头的第一条记录(区分大小写)。该 NamespacePrefix 即为此组织运行时使用的 <NS>。如果结果为空,则表示未安装 FSL——中止操作,并告知用户安装 FSL 包。
备注: 此模式已在兄弟技能 sfs-scheduling-policy-designer 和 sfs-work-rule-designer 中验证。在当前目标组织 sfs-headless-skill-building 中,发现的前缀为 FSLMPPERF。
handoff-to-sobject-create
输出 emit-service-objectives-block 后,移交给 sfs-sobject-create。 委托内容将传递累积的设计上下文:来自 sfs-scheduling-policy-designer 的父策略、来自 sfs-work-rule-designer 的 workRules[] 块,以及来自此技能的 serviceObjectives[] 块;同时还会传递发现的 FSL 命名空间,以确保后续写入使用正确的前缀。所有 Salesforce API 调用均由 sfs-sobject-create 负责——此技能仅输出设计值,不会自行创建记录。
依赖: emit-service-objectives-block
备注
- 组合方式: 这是由 3 个设计器和 1 个部署器组成的链路中的第三个设计器: sfs-scheduling-policy-designer → sfs-work-rule-designer → THIS → sfs-sobject-create 每个设计器都会生成一个 JSON 子块;完整链路完成且用户批准后,部署器才会写入 Salesforce 记录。此技能的子块是 serviceObjectives[],以及设计中隐含的任何 prerequisites[] 条目。
- 权威来源: 访谈提供的 10 种目标类型来自步骤 enumerate-service-objective-record-types 中列出的 RecordType DeveloperName 值。如果某个组织在其 FSL 安装中自定义了其他记录类型(例如较新版本中的 Group Nearby),访谈应将其呈现出来;如果某个组织停用了部分类型,访谈应将其隐藏。
- 幂等性: 此技能生成数据,但不会写入。下游的幂等性问题由 sfs-sobject-create 的写入路径负责(Service_Goal 按 (policy, RecordType) 或名称去重;Scheduling_Policy_Goal 连接对象按 (Scheduling_Policy, Service_Goal) 去重)。连接对象架构中的 Weight__c(9,0) NOT NULL 约束要求写入路径提供整数权重——此技能的全局规则 #1(对每个派生权重向上取整)可确保符合要求。
- 权重推导: 所有权重推导计算(以 Minimize Travel 为锚点,权重为 1000、ASAP 交叉点、Same Site 与 ASAP / Preferred Resource 的比较、Same Site 有效 ×10 倍数的 ×0.01 特例等)都是由 Agent 在客户端执行的确定性算术运算——不涉及任何线缆操作。 输出前会向上取整为整数,以满足部署时的 Scheduling_Policy_Goal.Weight__c(9,0) NOT NULL 约束。
- 线缆形状参考: 访谈和下游部署必须遵循这些字段形状事实,均取自这些类型当前的 sObject describe:
- FSLMPPERF__Service_Goal__c.FSLMPPERF__Custom_Type__c — 包含 14 个有效值的选项列表。技能提供的 10 个目标通过 RecordType.DeveloperName 映射;选项列表的取值范围更广,还包括 Objective_Task_Priority 和一个旧版按距离确定优先级的值,其存储字符串包含非 ASCII 组合字符(如有需要,切勿手动输入;应从 describe 中读取)。
- FSLMPPERF__Service_Goal__c.FSLMPPERF__Prioritize_Resource__c —
选项列表(2),值为
Least Qualified(默认值)和Most Qualified。 此字段对应 Skill Level 目标的mode参数。 - FSLMPPERF__Service_Goal__c.FSLMPPERF__Gap_Duration__c — Number(4,0),可为空。对应技能的
minGapMinutes。 - FSLMPPERF__Service_Goal__c.FSLMPPERF__Resource_Priority_Field__c —
String(255),默认公式为
"fsl__priority__c"。 - FSLMPPERF__Scheduling_Policy_Goal__c.FSLMPPERF__Weight__c — Number(9,0),不可为空。因此上限为 999,999,999。技能计算的相对于锚点的权重远低于此上限。
- 连接对象不可变性: FSLMPPERF__Scheduling_Policy_Goal__c 有两个主从关系查找字段 (FSLMPPERF__Service_Goal__c 和 FSLMPPERF__Scheduling_Policy__c) 均标记为 updateable=false。连接对象行的父级绑定在创建后不可更改:若要将目标重新指向其他策略,或更换策略/目标,部署器必须删除并重新创建连接对象行。两个查找字段上的 Cascade-delete=true 表示删除任一父记录都会删除连接对象;FSLMPPERF__Weight__c 本身可更新,创建后可原地调整。