mcpField
I
investigating-agentforce-architecture

investigating-agentforce-architecture

github.com/forcedotcomAgent 工作流1.1k903 次安装1 天前更新
代码仓库

关于 investigating-agentforce-architecture

用于 Salesforce 管理员和 Agentforce 开发者的技能,可将单个 Agentforce Agent 的声明式元数据整理为架构树和文档。它通过并行查询构建统一视图,并标示未解析引用;不读取运行时审计数据。

主要功能

  1. 01归一化规划器、主题与动作结构
  2. 02关联 Flow、Apex、提示词和插件
  3. 03并行 Tooling SOQL 查询
  4. 04生成 JSON 架构树与 Markdown 文档
  5. 05缓存元数据并标示未解析引用

适用场景

  1. 01梳理 Agentforce Agent 的声明式架构
  2. 02查看动作依赖的 Flow 与 Apex
  3. 03生成可供审阅的架构文档

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill investigating-agentforce-architecture

安装后在 Claude Code 中输入/investigating-agentforce-architecture确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
assets/cli/
describe_sobject.yaml
describe_tooling_sobject.yaml
list_metadata_genaiprompttemplate.yaml
org_display.yaml
retrieve_genai_plugin.yaml
show_access_token.yaml
assets/mermaid/
action_tree.mmd
data_flow.mmd
dependency_graph.mmd
invocation_sequence.mmd
planner_state.mmd
assets/soql/
apex_class_bodies_by_ids.soql
apex_class_bodies_by_names.soql
bot_definition_details.soql
bot_version_lookup.soql
flow_definition_by_ids.soql
flow_definition_ids_by_names.soql
flow_definition_view_by_durable_ids.soql
flow_metadata_by_id.soql
functions_by_plugins.soql
planner_attrs_by_parent_ids.soql
planner_bundle_functions.soql
planner_definition_by_agent_chain.soql
plugin_functions_by_plugin_ids.soql
plugin_instructions_by_plugin_ids.soql
plugins_by_planner.soql
references/
architecture_sections.md
contract.json
soql_fields.md

详细介绍

investigating-agentforce-architecture — 已声明的架构快照

某个 Agentforce Agent 的设计时元数据树:规划器 → 主题 → 工具 → 流 → Apex → 提示词 → NGA 插件。仅读取已声明的元数据 — BotDefinition、GenAiPlanner*、GenAiPlugin*、GenAiFunction*、Flow、ApexClass、GenAiPromptTemplate。不读取运行时审计记录。

运行时耗时:通常为 30–45s,硬上限 ≤60s(参考测试样例)。顺序执行的基准耗时为 90–220s;并行 Tooling SOQL 扇出可提速 3–5 倍。包含大量流的大型机器人耗时大致随流数量线性增长 — 每次流元数据检索都需要一次往返。

内联运行 — 不使用子 Agent。每个阶段都是确定性的文件处理。

如果用户未提供足够信息以继续

如果调用时未提供 agent_api_name 且未提供组织别名,请原样打印以下内容 — 不要改述,也不要预先运行任何脚本。触发条件:$ARGUMENTS 为空,或未指定 Agent(没有 --agent 标志,且文本中没有已知的 Agent API 名称),或未指定组织(没有 --org 标志,且文本中没有已知别名)。

应记录哪个 Agent,以及在哪个组织中记录?

我需要:

  • Agent API 名称 — BotDefinition 的 DeveloperName(例如 MyAgent、MySalesAgent)。不是标签。
  • 组织别名 — 用于 sf CLI 身份验证的别名(你通过 sf org login 配置的别名)

可选:

  • 版本 — 类似 v5 的 agent_version_api_name。如果省略,我会解析活动的 BotVersion。
  • --force — 忽略缓存的树;重新获取所有内容。
  • --reprobe — 重新运行 7 天频道探测缓存(仅在 Salesforce 发布新版本后需要)。

我会内联运行元数据流水线。生成的文件位于 ~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/ 下(可通过 --data-dir 覆盖)。

流水线调用

用户提供 --org <alias> + --agent <api_name>(以及任意可选标志)后,运行以下代码块。一次 python3 调用即可驱动整个流水线。main.py 会写入 .emit_ctx.json;emit_result.py 会读取该文件,并将最终的 === RESULT === 块作为 stdout 的最后内容打印出来。

set -euo pipefail

# zsh arrays are 1-indexed by default; bash arrays are 0-indexed.
# This block uses 0-indexed semantics throughout (_args[$i] starting at i=0),
# so under zsh + `set -u` the very first read of `_args[0]` would trip
# `parameter not set`. KSH_ARRAYS makes zsh treat arrays as 0-indexed,
# matching the bash shebang's expectation. No-op under bash.
[ -n "${ZSH_VERSION:-}" ] && setopt KSH_ARRAYS

SKILL_ROOT="${SKILL_ROOT:-${PLUGIN_ROOT:-$HOME/.vibe/skills}/investigating-agentforce-architecture}"

# Argument parser. Accepts both `--org foo` and `--org=foo`.
# `$ARGUMENTS` is the raw user input Claude Code substitutes.
ARG_ORG=""
ARG_AGENT=""
ARG_VERSION=""
ARG_FORCE=""
ARG_REPROBE=""
ARG_PARALLELISM=""
ARG_MAX_MERMAID=""

# shellcheck disable=SC2206
_args=($ARGUMENTS)
i=0
while [ $i -lt ${#_args[@]} ]; do
 tok="${_args[$i]}"
 case "$tok" in
 --org=*) ARG_ORG="${tok#--org=}" ;;
 --org) i=$((i+1)); ARG_ORG="${_args[$i]:-}" ;;
 --agent=*) ARG_AGENT="${tok#--agent=}" ;;
 --agent) i=$((i+1)); ARG_AGENT="${_args[$i]:-}" ;;
 --version=*) ARG_VERSION="${tok#--version=}" ;;
 --version) i=$((i+1)); ARG_VERSION="${_args[$i]:-}" ;;
 --parallelism=*) ARG_PARALLELISM="${tok#--parallelism=}" ;;
 --parallelism) i=$((i+1)); ARG_PARALLELISM="${_args[$i]:-}" ;;
 --max-mermaid-nodes=*) ARG_MAX_MERMAID="${tok#--max-mermaid-nodes=}" ;;
 --max-mermaid-nodes) i=$((i+1)); ARG_MAX_MERMAID="${_args[$i]:-}" ;;
 --force) ARG_FORCE="1" ;;
 --reprobe) ARG_REPROBE="1" ;;
 esac
 i=$((i+1))
done

# Usage block if required flags missing. Agent reads stderr,
# prints verbatim, and stops — does NOT pre-run main.py.
if [ -z "$ARG_ORG" ] || [ -z "$ARG_AGENT" ]; then
 cat >&2 <<'USAGE'
> Which agent should I document, and in which org?
>
> I need:
> - **Agent API name** — the BotDefinition.DeveloperName (e.g. `MyAgent`)
> - **Org alias** — for `sf` CLI auth (the alias you configured with `sf org login`)
>
> Optional flags:
> - `--version v5` — pin a specific BotVersion (default: Active+highest)
> - `--force` — bypass cache
> - `--reprobe` — force channel-probe refresh
> - `--parallelism N` — ThreadPoolExecutor size (default 5)
> - `--max-mermaid-nodes N` — cap Mermaid node count (default 80)
USAGE
 exit 2
fi

# Fresh work dir per invocation. Epoch + random suffix avoids collisions
# between concurrent runs on the same host.
WORK_DIR="/tmp/investigating-agentforce-architecture-$(date +%s)-$RANDOM"
mkdir -p "$WORK_DIR"

# Input validation at the boundary, BEFORE any python3 call.
# fs_guard exits 1 and prints an INVALID_INPUT RESULT block on failure;
# `|| exit 1` is mandatory — bare calls silently continue past failures.
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_AGENT" agent_api_name api_name || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_ORG" org_alias not_empty || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR symlink || exit 1
python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$WORK_DIR" WORK_DIR owned || exit 1
if [ -n "$ARG_VERSION" ]; then
 python3 "$SKILL_ROOT/scripts/_shared/fs_guard.py" "$ARG_VERSION" agent_version api_name || exit 1
fi

# Single python3 call drives all pipeline phases. main.py writes
# `.emit_ctx.json` into $WORK_DIR — emit_result.py then renders the
# RESULT block from that ctx. No subprocess-per-phase.
_main_args=(--org-alias "$ARG_ORG" --agent "$ARG_AGENT" --work-dir "$WORK_DIR")
[ -n "$ARG_VERSION" ] && _main_args+=(--version "$ARG_VERSION")
[ -n "$ARG_FORCE" ] && _main_args+=(--force)
[ -n "$ARG_REPROBE" ] && _main_args+=(--reprobe)
[ -n "$ARG_PARALLELISM" ] && _main_args+=(--parallelism "$ARG_PARALLELISM")
[ -n "$ARG_MAX_MERMAID" ] && _main_args+=(--max-mermaid-nodes "$ARG_MAX_MERMAID")

# main.py returns nonzero on terminal failures; we DON'T short-circuit —
# emit_result still publishes the failure RESULT block. `set -e` is
# temporarily relaxed around this single call.
set +e
python3 "$SKILL_ROOT/scripts/main.py" "${_main_args[@]}"
_rc=$?
set -e

# Final RESULT block is emit_result.py's stdout — MUST be the last thing
# stdout sees. emit_result exits 0 on render success; the bash harness
# propagates main.py's rc for the agent's exit status.
WORK_DIR="$WORK_DIR" python3 "$SKILL_ROOT/tools/emit_result.py"
exit "$_rc"

输入

输入标志必需默认值
org_alias--org是—
agent_api_name--agent是—
agent_version_api_name--version否活动的 BotVersion
force_refresh--force否false(遵循缓存)
reprobe--reprobe否false(遵循 7 天频道探测缓存)
parallelism--parallelism否5
max_mermaid_nodes--max-mermaid-nodes否80
data_dir--data-dir否~/.vibe/data/investigating-agentforce-architecture
cache_dir--cache-dir否~/.vibe/cache/investigating-agentforce-architecture

输出

所有生成文件均位于 ~/.vibe/data/investigating-agentforce-architecture/<org_id15>/<agent_api_name>__<agent_version>/ 下(默认路径;可通过 --data-dir <path> 覆盖):

<agent>_<ver>_metadata_tree.json   primary artifact — normalized planner/topic/action/flow/apex/prompt/plugin tree
<agent>_<ver>_architecture.md      human-readable section-by-section rendering (H1 + 7 numbered sections, plus a conditional Dependency graph appendix). Mermaid diagrams are embedded inside the relevant sections (Action tree, Data flow, and Dependency graph)

流水线 — 内联运行,不使用子 Agent

resolve_bot.py        → BotDefinition + BotVersion + planner name lookup
retrieve_planner.py   → Metadata API zip retrieve for GenAiPlannerBundle (+ NGA plugins if present)
parallel_retrieve.py  → 6 parallel Tooling SOQL channels fan out from the planner id
                          (resolved by the `planner_definition_by_agent_chain` seed query):
                          - plugins_by_planner (GenAiPluginDefinition)
                          - planner_bundle_functions (GenAiPlannerFunctionDef join)
                          - functions_by_plugins (GenAiFunctionDefinition)
                          - planner_attrs_by_parent_ids (GenAiPlannerAttrDefinition)
                          - plugin_functions_by_plugin_ids (GenAiPluginFunctionDef join)
                          - plugin_instructions_by_plugin_ids (GenAiPluginInstructionDef)
parse_bundle.py       → parse retrieved XML into normalized node shapes
parse_wave.py         → BFS expansion: flow/apex/prompt refs discovered in nodes
                          → SOQL for Flow/Apex bodies (batched by id list)
                          → Metadata retrieve ONLY for GenAiPromptTemplate (+ NGA external plugins conditionally)
finalize.py           → merge waves into metadata_tree.json
render_architecture.py → <agent>_<ver>_architecture.md + Mermaid invocation graph (capped at --max-mermaid-nodes)

频道策略 — 优先使用 SOQL。

  • 对每个规范化树节点(规划器、插件、函数、插件函数、插件指令、规划器函数、规划器属性)使用 Tooling SOQL — 通过规划器 ID 键控 6 个并行频道,另有 planner_definition_by_agent_chain 种子查询,用于从 Agent 链中解析规划器 ID。
  • 对 Flow(按 ID)和 Apex(按 ID 或名称)的主体使用 Data API SOQL — 批量查询。
  • 元数据检索仅用于两种情况:(a) GenAiPromptTemplate(提示词主体无法通过 Tooling SOQL 清晰获取);(b) 当规划器为 Native Generative Agent 类型时的 NGA 外部插件(经典 ReAct 类型会跳过)。

这就是提速 3–5 倍的原因。简单实现会通过 Metadata API 压缩包顺序检索所有内容;并行 Tooling SOQL 扇出可在单次扇出中覆盖约 80% 的树。

规划器形状 — 经典 ReAct 与 NGA

此技能将两个规划器系列规范化为统一的树结构:

形状GenAiPlannerDefinition.PlannerTypeInvocationTarget 风格是否使用 NGA 插件?
经典 ReActReactAiPlannerV1 / SequentialPlannerIntentClassifier / 等DeveloperName 字符串否
NGAConcurrentMultiAgentOrchestration / AnthropicCompatibleV1 / 等有时为 15/18 位 Id(按 ID 前缀路由)是(通过 Metadata retrieve 获取外部插件)

resolve_invocation_target.py 中的 ID 前缀路由器可区分这两者:看起来像 ID 的 NGA InvocationTarget(01p… = ApexClass、301… = Flow 等)会通过按 ID 限定范围的 SOQL 解析;DeveloperName 目标则通过按名称限定范围的 SOQL 解析。未知前缀会以 _unresolved[] 的形式呈现,且 reason="unknown-id-prefix:<prefix>" — 绝不会被静默丢弃。

缓存

  • 树缓存:除非传入 --force,否则会重复使用 metadata_tree.json。缓存键包含此技能中所有 .soql / .yaml / .mmd 模板的资源哈希 — 更新模板后,缓存会自动失效。
  • Channel 探测缓存:每个 org 的 sf sobject describe 结果缓存 7 天,用于验证 SOQL 资源引用的每个字段名。如果 Salesforce 季度版本更新重命名或移除了字段,则会触发 status: PROBE_FAILED;使用 --reprobe 可强制刷新。

前置条件

工具必需
sf CLI(已通过身份验证并连接到目标 org)是 — sf org login web --alias <alias>
Python 3.10+是

需要时加载的参考文档

不要提前加载。仅在用户的问题需要时加载:

  • references/soql_fields.md — 此技能涉及的 13 个 sObject(2 个 Data API + 11 个 Tooling)的字段参考,包含 [mandatory] 与 [optional] 标签。用户询问特定字段或调试 INVALID_FIELD SOQL 错误时加载。
  • references/contract.json — metadata_tree.json 的机器可读架构。编写使用此树的下游工具时加载。
  • references/architecture_sections.md — 渲染后的 <agent>_<ver>_architecture.md 的分节结构。

需要预先了解的不变量

  • 流水线是确定性的。 相同的 (org, agent, version) 和静态 org 元数据会生成字节完全一致的 <agent>_<ver>_metadata_tree.json 与 <agent>_<ver>_architecture.md。只有清单时间戳会在多次运行间变化。
  • 仅向前遍历。 每个发现的引用都从规划器向其子项前进,不会向后查找。
  • 部分结果会明确呈现,不会被隐藏。 任何未解析的引用都会进入 _unresolved[],并附带 reason=...。任一 channel 失败时,STATUS=PARTIAL_OK;只有运行无错误时,STATUS=OK。
  • 循环检测按分支进行。 如果同一个 flow 沿其自身祖先链被访问,则会输出 _cycle_back_to:<path>,而不是继续递归。防御性保护 MAX_BFS_DEPTH=20 为按分支维护的祖先集合提供兜底;实际 Agent 通常会在触发任一限制前结束。(早期文档曾声称硬上限为 5;那是历史限制,后来因共享实用工具 flow(如 handleFlowFault)会在每棵嵌套树中触发该限制而被弃用 — 原因见 config.MAX_BFS_DEPTH。)
  • 子项按 api_name 字母顺序排列(不区分大小写)。 在根级别,Topics 排在非 topic plannerActions 之前。Flow 的 actionCall 顺序不会排序 — 它就是 flow 作者设定的执行顺序。

评论

支持 Markdown