跳转至

变量注入速查手册(v2)

受众: 模板编排人员(运营、产品) 目的: 在 AdminPortal InitFlow 编排器中编写初始化流程时,快速查找平台注入的可用变量 契约版本: v2(TFRM-245「机器人模板系统强化」)。权威单一信源 internal/shared/initflow/context_schema.go, 发现接口 GET /api/v1/admin/digital-employee-templates/init-variables(返回 factNamespaces/credentialTypes/scopes)。 v1 扁平变量({{ServiceURL}}/{{AdminSecret}}/{{AdminKey}}/{{RobotID}}/{{Password}}/{{Namespace}}) 已于 TFRM-249 硬切退役——存量模板经 cmd/migrate-init-flow-v2 迁移。

变量分三族,按「可暴露性」划分:事实 {{Robot.*}}(非密身份/位置)、Feature {{Feature.*}}(用户业务参数)、 凭证 {{Credentials.*}}(密,须先在模板顶层 credentials[] 声明)。


1. 事实变量 {{Robot.*}}(平台自动注入,非密)

在 path、headers、body、condition 中通过 {{Robot.X}} 引用,无需声明。

变量 说明 示例值
{{Robot.Id}} 机器人唯一标识(cluster+namespace 内唯一) friday
{{Robot.AccountId}} 机器人自身 Account ID(AccessToken sub/aud 命名空间;回填过渡期可能为空) 4242
{{Robot.Namespace}} K8s 租户命名空间(Istio 路由 Header X-TF-Namespace) tenant-a
{{Robot.ServiceUrl}} 机器人服务地址(自动拼接到 request.path 前,无需硬编码) http://cr.ns.svc.cluster.local:8080
{{Robot.Type}} 机器人类型 tfrserver / tfropenclaw
{{Robot.Org}} 所属组织 ID 7

{{Robot.ServiceUrl}} 由系统根据实例所在 K8s namespace / CR 名称自动计算(见 §4)。


2. Feature 变量 {{Feature.*}}(用户配置真值,含声明敏感字段)

Feature 是模板定义的:每个模板通过 JsonSchema 定义需要用户填写的配置字段,用户部署时填写,平台展平注入。

敏感字段照常用 {{Feature.*}} 引用(TFRM-527)。模板 configSchema 里给字段标 x-secret: true (或 format: password)只改变平台侧行为——值加密存储、API 不回显;不改变模板怎么写,也没有 {{Secret.*}} 命名空间。运营勾选/取消 x-secret 时无需同步改模板。

密值经 Spec / confz 抵达业务 Pod 是既定通道。与之相对,Manager 自铸的系统凭证走 §3 的 {{Credentials.*}},那类才禁止出现在 CR Spec。

{{Feature}}              ← 完整 JSON 字符串(很少直接用)
{{Feature.字段名}}        ← 顶层字段
{{Feature.父字段.子字段}}  ← 嵌套字段(按点路径)

模板 Feature 配置为:

{
  "feishuToken": "t-xxx",
  "webhook": {"url": "https://example.com/hook", "secret": "s-yyy"},
  "maxRetry": 3
}

则可用变量:{{Feature.feishuToken}} / {{Feature.webhook.url}} / {{Feature.webhook.secret}} / {{Feature.maxRetry}}。


3. 凭证变量 {{Credentials.*}}(密,须先声明)

凭证是 Manager 自铸的系统密值(robot_jwt / gateway_token / machine_client),与事实/Feature 分开治理: 只能在 InitFlow 中用,禁止出现在 CR Spec——它们另有直写 K8s Secret 的下发通道,不该经 CR 流转。 (注意与 §2 的区别:用户填写的第三方密钥属 Feature,经 CR 下发是既定通道。) 使用两步:① 在模板顶层 credentials[] 声明需要哪些凭证;② 步骤中用 {{Credentials.<name>}} 引用。 首次引用才铸造,声明未引用不铸。

3.1 声明(模板顶层 credentials[])

{
  "version": "2.0",
  "name": "标准机器人初始化",
  "credentials": [
    {"name": "mgmt", "type": "robot_jwt", "scopes": ["robot:admin"]}
  ],
  "steps": [ ... ]
}
字段 说明
name 引用名,{{Credentials.<name>}};run 内唯一、须字母起头、禁点
type 凭证类型(见 3.2)
scopes 仅 robot_jwt:签进短 JWT 的最小权限(⊆ 有效 scope 词表,见 /api/v1/oauth/scopes);其余类型须省略
ttl 仅 robot_jwt:形如 "30m";省略=用部署级默认;其余类型须省略

3.2 凭证类型

type 适用机器人 引用方式 说明
robot_jwt tfrserver {{Credentials.<name>}} Manager 现签短 RS256 JWT(sub/aud=robot:<id>,scope 按声明最小权限求交)——管理 API 认证首选(取代旧 {{AdminSecret}})
gateway_token tfropenclaw {{Credentials.<name>}} LLM Key 托管网关 Token(数据面调用)
machine_client tfrserver {{Credentials.<name>.clientId}} / {{Credentials.<name>.clientSecret}} 机器身份 client_id/client_secret(OAuth client_credentials 换发)
a2a_jwt — — 预留,暂不铸造

3.3 认证请求示例(tfrserver 管理 API)

{
  "version": "2.0",
  "name": "示例",
  "credentials": [
    {"name": "mgmt", "type": "robot_jwt", "scopes": ["robot:admin"]}
  ],
  "steps": [
    {
      "type": "http",
      "name": "调用管理 API",
      "request": {
        "method": "POST",
        "path": "/v1/factory/drafts/release",
        "headers": {"admin_key": "{{Credentials.mgmt}}"}
      },
      "assert": [{"source": "status", "op": "eq", "value": 200}]
    }
  ]
}

认证 Header 键名 admin_key(原 {{AdminKey}} 常量,现直接写字面量)。Header 具体形态 (admin_key vs Authorization: Bearer)随机器人管理面在 INT(TFRS-265)收敛,以届时约定为准。


4. {{Robot.ServiceUrl}} 解析规则

系统根据实例部署位置自动计算(见 internal/user/service/digital_employee_service/init_executor_v2.go getServiceURL):

场景 格式
TFRServer(有集群域名) https://{Cluster.Domain}(Istio + BFF 路由)
TFRServer(无集群域名) http://{CRName}.{Namespace}.svc.cluster.local:8080
TFROpenClaw http://tfopenclaw-{RobotID}.{Namespace}.svc.cluster.local:18789
Mock(本地测试) http://localhost:9999(或 ECHO_SERVER_PORT)

5. 步骤提取的变量

HTTP 步骤 extract 从响应提取,后续步骤直接引用:

{
  "type": "http", "name": "登录",
  "request": {"method": "POST", "path": "/api/login"},
  "extract": [
    {"var": "token", "from": "body", "path": "$.data.accessToken"},
    {"var": "reqId", "from": "header", "headerName": "X-Request-Id"}
  ]
}

后续引用:"headers": {"Authorization": "Bearer {{token}}"}。


6. 变量优先级

步骤提取变量(extract / script,local 层)  ← 最高
  ↓
平台注入变量({{Robot.*}} / {{Feature.*}} / {{Credentials.*}},environment 层)  ← 最低

6.1 变量解析不出值时会怎样(TFRM-527)

场景 行为
Spec / defaultSpec 里有未解析占位 部署直接中止,错误列出全部未解析变量名
InitFlow 步骤里有未解析占位 记 WARN 日志(含步骤名 + 变量名),流程继续

Spec 侧之所以硬失败:未解析的 {{...}} 会原样写进 CR → K8s Secret → Pod 环境变量,被机器人当成真值使用 (真实事故:LiteLLM 收到字面量 {{Feature.llmVkey}},返回 401)。

需要输出字面的 {{ 时用 \{{ 转义,例如 "\{{not_a_var}}" → 输出 {{not_a_var}};转义内容不会被 当作未解析变量。


7. 循环变量

forEach

变量 说明 默认名 可自定义
{{_item}} 当前迭代元素 _item itemVar 字段
{{_index}} 当前迭代索引(从 0 开始) _index indexVar 字段

对象元素自动展平:{{item.name}}、{{item.type}}。

loop

变量 说明
{{_iteration}} 当前轮次索引(从 0 开始)

8. 常用 InitFlow 片段

条件配置

{
  "type": "if",
  "condition": {"left": "{{Feature.enableFeishu}}", "op": "eq", "right": "true"},
  "steps": [
    {"type": "http", "name": "配置飞书", "request": {"method": "POST", "path": "/api/feishu"}}
  ]
}

轮询等待就绪

{
  "type": "loop",
  "maxIterations": 10,
  "delay": 3000,
  "breakWhen": {"source": "body", "path": "$.status", "op": "eq", "value": "ready"},
  "steps": [
    {"type": "http", "name": "轮询状态", "request": {"method": "GET", "path": "/api/health"}}
  ]
}