PAI-Rec 引擎诊断与配置校验

本 Skill 为阿里云 PAI-Rec(可编程推荐系统)引擎提供全面的诊断和校验能力,包括接口排查和配置分析。

场景说明

PAI-Rec 是阿里云的可编程推荐系统,提供智能推荐能力。本 Skill 帮助用户:

  1. 诊断 PAI-Rec 引擎接口问题:当引擎 API 返回错误或意外结果时,通过 EAS 服务日志和引擎配置追踪请求以定位根因。
  1. 校验引擎配置:在部署前分析引擎配置文件是否存在潜在问题、不一致或错误配置。

架构:PAI-EAS 服务 + PAI-Rec 引擎 + 引擎配置管理

关键组件

  • PAI-EAS 服务:托管推荐引擎的弹性算法服务
  • PAI-Rec 引擎:处理请求的推荐引擎
  • 引擎配置:定义引擎行为的配置文件
  • 服务日志:含请求追踪的 EAS 服务日志

安装

前置检查:需要 Aliyun CLI >= 3.3.3

运行 aliyun version 确认 >= 3.3.3。若未安装或版本过低,
运行 curl -fsSL https://aliyuncli.alicdn.com/setup.sh | bash 安装 / 更新,
或见 references/cli-installation-guide.md 获取安装说明。

前置检查:需要更新 Aliyun CLI 插件

[必须] 运行 aliyun configure set --auto-plugin-install true 启用插件自动安装。
[必须] 运行 aliyun plugin update 确保已有插件始终为最新版本。

鉴权

前置检查:需要阿里云凭证
安全规则:
- 绝不读取、回显或打印 AK/SK 值(例如 echo $ALIBABA_CLOUD_ACCESS_KEY_ID 是禁止的)
- 绝不要求用户在对话或命令行中直接输入 AK/SK
- 绝不使用字面凭证值运行 aliyun configure set
- 使用 aliyun configure list 检查凭证状态
```bash
aliyun configure list
```
检查输出中是否有有效 profile(AK、STS 或 OAuth 身份)。
如果不存在有效 profile,就此停止。
1. 从阿里云控制台获取凭证
2. 在本会话之外配置凭证(通过终端中的 aliyun configure 或 shell profile 中的环境变量)
3. 待 aliyun configure list 显示有效 profile 后再返回并重试

RAM 策略

[必须] 权限失败处理: 当任何命令或 API 调用在执行过程中因权限错误失败时,遵循以下流程:
1. 阅读 references/ram-policies.md 获取本 Skill 所需的完整权限列表
2. 使用 ram-permission-diagnose skill 引导用户申请必要权限
3. 暂停并等待用户确认所需权限已授予

本 Skill 所需的详细 RAM 策略见 references/ram-policies.md

参数确认

重要:参数确认 —— 执行任何命令或 API 调用前,
所有用户可自定义的参数(例如 RegionId、服务名、实例 ID、
环境名、配置名等)都必须与用户确认。
未经用户明确批准,不要假设或使用默认值。

必需参数

参数名必填 / 可选说明默认值
service-name必填PAI-EAS 服务名
cluster-id必填EAS 集群 / 地域 ID
instance-id必填PAI-Rec 实例 ID
request-id必填(诊断用)引擎 API 响应中的请求 ID
config-name可选引擎配置名
environment可选引擎环境(Prod/Pre)
engine-config-id可选特定引擎配置版本 ID
region可选阿里云地域

可观测性(每条 aliyun 命令都必须遵守)

加载本 Skill 时,为整个会话生成一次随机 session ID(32 字符小写十六进制字符串)。在下方用作 {session-id}

规则:每条调用云 API 的 aliyun CLI 命令都必须包含 --user-agent 标志。

本地工具命令(如 configurepluginversion)不支持该标志,应排除。

--user-agent AlibabaCloud-Agent-Skills/alibabacloud-pai-rec-diagnosis/{session-id}

示例(假设 session-id 为 a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6):

aliyun eas describe-service --cluster-id cn-hangzhou --service-name my_service --user-agent AlibabaCloud-Agent-Skills/alibabacloud-pai-rec-diagnosis/a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6

在任何 aliyun API 命令调用上,都不要跳过、改变格式或省略 --user-agent

核心工作流

[必须] 分配每会话工作目录 —— 所有临时工件
(原始配置转储、日志转储、脱敏输出)必须写在唯一的
每会话目录下,以避免并行 Skill 调用之间的并发覆盖。在
工作流开始时、任何产生工件的 CLI 调用之前运行以下命令,并在整个会话中复用 $WORKDIR
将完整模板作为位置参数传入(在 BSD/macOS 和
GNU/Linux mktemp 上都可用);不要使用 -t prefix,它会回退到 $TMPDIR
(例如 macOS 上的 /var/folders),甚至在沙箱 shell 中可能失败。
```bash
export WORKDIR=$(mktemp -d /tmp/pairec-diag-XXXXXX)
```
下方显示的所有文件路径($WORKDIR/engine_configs_list.json 等)都位于
此目录内,不得替换为硬编码的 /tmp/... 路径。
[必须] 只使用下方定义的工作流。 不要发明额外
步骤(例如实例资源检查、网络探测),也不要用人工分析替代已定义的工作流步骤。

工作流 1:PAI-Rec 引擎接口诊断

此工作流帮助诊断 PAI-Rec 引擎 API 返回错误或意外结果时的问题。

输入示例:

服务名:embedding_recall
API 响应:
{
    "code": 299,
    "msg": "items size not enough",
    "request_id": "941b4e14-d1c5-489f-a184-b2b17f8b4fdb",
    "size": 0,
    "experiment_id": "",
    "items": []
}

#### 步骤 1:获取 EAS 服务信息

获取服务详情以找到 EAS 服务 ID 和配置:

aliyun eas describe-service \
  --cluster-id <cluster-id> \
  --service-name <service-name>

要提取的内容:

  • Resource:EAS 服务资源 ID(例如 eas-r-1v4qb1yan3qmnjwxqe
  • ServiceConfig.envs:包含以下内容的环境变量:
  • REGION:地域
  • INSTANCE_ID:PAI-Rec 实例 ID
  • CONFIG_NAME:引擎配置名
  • PAIREC_ENVIRONMENT:环境(product/prepub)

#### 步骤 2:从 API 响应提取请求 ID

解析 API 响应 JSON 获取 request_id 字段。这将用于搜索服务日志。

#### 步骤 3:查询 EAS 服务日志

用请求 ID 作为搜索服务日志的唯一过滤条件。搜索 PAI-Rec 业务日志时不要传 --start-time / --end-time

aliyun eas describe-service-log \
  --cluster-id <cluster-id> \
  --service-name <service-name> \
  --keyword <request-id> \
  --page-size 500

[关键] --keyword &lt;request-id&gt; 是强制的——禁止本地后处理:

  • 必须--keyword &lt;request-id&gt;(服务端过滤,对完整 request_id 精确大小写敏感匹配)。API 只返回匹配关键词的日志行。
  • 不得省略 --keyword 然后本地过滤(例如通过 headgreppython3jq 或任何脚本管道)。
  • 不得在没有 --keyword 的情况下多次调用 describe-service-log,希望通过扫描完整日志流找到相关行。
  • 如果带 --keyword 的调用返回空结果,报告未找到匹配日志——不要回退到获取未过滤日志。
  • --page-size 500 在单页捕获整个追踪;一个请求的匹配条目通常 < 30。
❌ 错误(获取所有日志,本地过滤——禁止):
```bash
aliyun eas describe-service-log --cluster-id cn-beijing --service-name embedding_recall | head -300
aliyun eas describe-service-log --cluster-id cn-beijing --service-name embedding_recall | grep "request_id"
```
✅ 正确(服务端关键词过滤——必需):
```bash
aliyun eas describe-service-log --cluster-id cn-beijing --service-name embedding_recall --keyword 0c6cbd91-5618-4705-8e08-9126bf4600f7 --page-size 500
```

[关键] 时间范围会静默丢弃业务日志:

  • --keyword(无时间范围)时,CLI 返回匹配 request_id 的完整 PAI-Rec 应用追踪(controller.go / feed.go / recall.go / rank_service.go 等)。
  • --start-time / --end-time——即使窗口覆盖真实时间戳——也会静默丢弃业务日志,只返回基础设施噪音(/bin/sh 心跳、502 Bad Gateway 重试、postgres.go dbstat)。
  • 仅对无 --keyword 的宽泛扫描使用时间范围,格式为 yyyy-MM-dd HH:mm:ss UTC(无 T / 无 Z);ISO-8601 形式如 2025-04-28T00:00:00Z 会被拒绝并报 InvalidParameter

#### 步骤 4:列出引擎配置

映射环境并列出匹配配置:

环境映射:

  • productProd
  • prepubPre
aliyun pairecservice list-engine-configs \
  --instance-id <instance-id> \
  --environment <Prod|Pre> \
  --status Released \
  --name <config-name> > "$WORKDIR/engine_configs_list.json" 2>&1

[必须] 始终传 --name &lt;config-name&gt; 做服务端过滤:

&lt;config-name&gt; 已从步骤 1 得知(ServiceConfig.envs.CONFIG_NAME);将其作为 --name 转发。省略它会返回整个实例的配置清单(常数百个无关条目),强制客户端过滤,浪费 token,并有触及 CLI 默认分页导致目标行被静默丢弃的风险。--name 是服务端的精确匹配过滤;不要用 grep / jq select 后处理替代。同一规则适用于本 Skill 中每次 list-engine-configs 调用(包括工作流 2 步骤 1)。

要提取的内容:

  • 找到 Status: Released 的配置
  • 获取 EngineConfigIdVersion

#### 步骤 5:获取引擎配置详情

aliyun pairecservice get-engine-config \
  --instance-id <instance-id> \
  --engine-config-id <engine-config-id> > "$WORKDIR/raw_engine_config.json" 2>&1

[必须] 展示前脱敏 —— 配置可能含明文密码或

访问密钥。打印到终端前始终通过脱敏器管道;只有脱敏输出

(凭据替换为 *REDACTED*)才应出现在那里。原始文件

$WORKDIR/raw_engine_config.json 可直接传给 scripts/validate.py(它不打印凭据值)。

python3 scripts/sanitize_config.py "$WORKDIR/raw_engine_config.json"

要提取的内容:

  • ConfigValue:实际引擎配置(JSON/YAML)

#### 步骤 5.5(可选):静态配置健全性检查

对检索到的 ConfigValue 运行 scripts/validate.py 以排除结构性 /

引用错误。见 references/config-validation.md

printf '%s' "$CONFIG_VALUE" | python3 scripts/validate.py --stdin

何时运行:当日志指向某配置元素,或首次诊断该配置时。

何时跳过:当日志显示非配置根因(缺少 scene_id、上游 5xx)时。

[不得] 不要替换或重复 validate.py(与工作流 2 § 步骤 3 相同限制)。

[必须] 范围规则: 发现仅在绑定到当前 request_id 的日志证据时才进入最终诊断。

#### 步骤 5a(条件性):检索实验配置

条件: API 响应中 experiment_id 非空(例如 "ER14_L21_L26#EG21_L38#EG38#E44_GL36_GL37")。

解析: 从字符串提取 EG{id}(实验组)和 E{id}(实验)数字 ID。忽略 ERLGL 前缀——它们不携带配置。

对每个 EG{id}:

aliyun pairecservice get-experiment-group \

--instance-id <instance-id> \

--experiment-group-id <id> > "$WORKDIR/experiment_group_<id>.json" 2>&1

对每个 E{id}:

aliyun pairecservice get-experiment \

--instance-id <instance-id> \

--experiment-id <id> > "$WORKDIR/experiment_<id>.json" 2>&1


**要提取的内容:** `Config` 字段——包含覆盖参数(例如 `default.RecallNames`、`rankconf`、`filterNames`、`default.SortNames`),它们取代基础引擎配置。

**覆盖优先级(低 → 高):** 基础引擎配置 < ExperimentGroup.Config < Experiment.Config。在步骤 6 应用以理解实际运行时行为。

**校验实验配置** 相对基础配置(引用存在性检查):

python3 scripts/validate.py "$WORKDIR/raw_engine_config.json" \

--experiment-config "$WORKDIR/experiment_group_<id>.json" \

--experiment-config "$WORKDIR/experiment_<id>.json"


#### 步骤 6:综合分析

一起分析以下组件:
1. **API 响应**:错误码、消息和返回数据
2. **服务日志**:request_id 的追踪日志,显示处理流程
3. **引擎配置**:可能影响行为的设置
4. **实验覆盖**(若 `experiment_id` 非空):有效配置 = 基础配置叠加实验参数

**要检查的常见问题:**
- 配置不匹配(例如召回设置、过滤规则)
- 实验覆盖(例如实验从基础配置改变了 `RecallNames` / `rankconf`)
- 资源限制(例如条目不足、超时设置)
- 数据源问题(例如表访问、特征可用性)
- 环境不一致(例如 prepub 环境用了 prod 配置)

**[必须] 仅证据报告规则:**

交付给用户的最终诊断**必须**严格基于 EAS 服务日志和引擎配置直接显示的内容。应用以下约束:

- **只报告观察到的。** 引用证明每个论断的确切日志行(文件:行号、级别、消息)和确切配置片段。
- **陈述从日志证据到 API 响应的直接因果链**,就此打住。
- **不要添加**以下任何内容,除非用户明确要求:
  - 日志 / 配置中不可见的推测性根因(例如"客户端可能发了错误的 X")
  - 修复建议或补救步骤
  - 条件性"如果 X 则 Y"场景
  - 无关的最佳实践建议(安全、兜底设计、命名等)
  - 对日志 / 配置未覆盖的上游系统、客户端代码或数据源的猜测
- **如果证据不足以得出结论**,明确说明需要什么额外数据(特定日志行、其他配置版本、其他环境),而非猜测。
- **建议仅限主动请求。** 仅在用户在后续明确要求时才提供修复 / 建议。

---

### 工作流 2:PAI-Rec 引擎配置校验

此工作流校验引擎配置是否存在潜在问题。

**输入:** 配置名和环境(Prod/Pre)

#### 步骤 1:列出配置版本

如果用户未提供 `engine-config-id`,列出可用版本:

aliyun pairecservice list-engine-configs \

--instance-id <instance-id> \

--environment <Prod|Pre> \

--name <config-name>


**向用户展示:**
- `Version`:版本号
- `Status`:配置状态(Released/Draft/Archived)
- `GmtCreateTime`:创建时间戳
- `EngineConfigId`:版本 ID

请用户选择版本或提供 `engine-config-id`。

#### 步骤 2:获取配置详情

aliyun pairecservice get-engine-config \

--instance-id <instance-id> \

--engine-config-id <engine-config-id> > "$WORKDIR/raw_engine_config.json" 2>&1


**[必须] 展示前脱敏** —— 打印到终端前始终脱敏:

python3 scripts/sanitize_config.py "$WORKDIR/raw_engine_config.json"


#### 步骤 3:运行 Schema + 规则校验

**[必须]** 将提取的 `ConfigValue` JSON 喂给 `scripts/validate.py`。该脚本
强制执行 JSON Schema(`references/schema.json`)+ 引用一致性规则,通过时退出
状态 0,失败时 1。

从保存的 JSON 文件(推荐)

python3 scripts/validate.py "$WORKDIR/raw_engine_config.json"

或通过 stdin 直接管道 ConfigValue

printf '%s' "$CONFIG_VALUE" | python3 scripts/validate.py --stdin


需要 `jsonschema`(`pip install jsonschema`);若缺失,脚本回退到
仅规则校验而不做 Schema 检查。

**[不得] 不要替换或重复 `validate.py`:**
- 不要跳过它;不要用 Python / jq / grep / 任何其他工具手写等价检查——该脚本是权威校验器。
- 脚本运行后不要重新实现、重新检查或"双重确认"任何规则;逐字信任其输出,包括干净的 `0 error(s), 0 warning(s)` 运行。
- 如果脚本无法运行(缺少 Python、依赖问题等),修复环境并重跑——不要回退到手动检查。
- 脚本范围之外的检查仍允许(见步骤 4)。

**脚本检查内容(摘要):**

1. **结构** —— JSON 良构性、必填字段、类型(`RecallConfs`、
   `FilterConfs`、`SortConfs`、`AlgoConfs`、`SceneConfs`、`RankConf`、
   `FeatureConfs`、`UserFeatureConfs`、`DebugConfs`、`FeatureLogConfs`、
   `CallBackConfs`、`PipelineConfs` 等)
2. **枚举值** —— `RecallType` / `FilterType` / `SortType` /
   `DebugConfs.OutputType` / `GeneralRankConfs.ActionConfs[].ActionType`
3. **引用一致性** —— `SceneConfs.RecallNames` → `RecallConfs`;
   `FilterNames` → `FilterConfs`;`SortNames` → `SortConfs`;
   `RankConf.RankAlgoList` → `AlgoConfs`;任何 `DaoConf.AdapterType` +
   `*Name` → 对应 `*Confs`(Hologres / Redis / MySQL / TableStore /
   FeatureStore / …)
4. **业务规则**
   - `User2ItemExposureFilter` 配 `WriteLog=true` + FeatureStore adapter:必须设置
     `TimeInterval > 0`
   - `accumulator` 模式下的 `PriorityAdjustCountFilter`:`Count` 必须严格
     递增(用 `Type="fix"` 实现每次召回独立上限)
   - `PipelineConfs.*.Name` 必须全局唯一
   - `DebugConfs.Rate` 必须是 `[0, 100]` 内的整数
5. **重复名称检测** 在 `RecallConfs`、`FilterConfs`、`SortConfs`、
   `AlgoConfs` 内

详细用法、退出码、示例输出和完整规则列表见
[references/config-validation.md](references/config-validation.md)。

#### 步骤 4:基于证据的报告

**[必须] 报告必需的第一行:** 逐字引用 `validate.py` 的 stdout
——要么 `Validation passed: configuration is well-formed`,要么
`Validation finished: N error(s), M warning(s)`。缺少这确切一行的报告
无效;从步骤 3 重新开始。

**人工检查仅允许** 用于 `validate.py` 范围之外的关注点:环境 / 地域 /
模型签名不匹配、跨版本差异、`RankScore` 变量与模型输出字段之间的
命名冲突,以及脚本自身要求人工判断的任何 `[WARNING]` 的根因读取。
除非能将它们绑定到这些范围外关注点之一,否则不要添加脚本未报告的发现。

**报告结构:**

- ✅ 检查通过 —— 引用 `validate.py` 的 `0 error(s), 0 warning(s)` 行
- ⚠️ 警告 —— 复制脚本的每条 `[WARNING] <path>: <message>`,
  加上人工检查中的任何范围外不一致
- ❌ 错误 —— 复制脚本的每条 `[ERROR] <path>: <message>`
- 缺失证据说明 —— 仅当列出 ≥1 条 ⚠️ 警告时:说明什么额外数据会将该警告升级为确认错误。0 警告时,省略此节;不要用通用范围外免责声明(跨版本差异、远程连通性、地域 / 端点一致性)填充它——那些是证据-only 规则禁止的主动最佳实践建议。

不要添加推测性修复或最佳实践题外话;仅在用户明确要求时提供建议。

---

成功验证方法

详细验证步骤见 references/verification-method.md

快速验证:

  1. 诊断工作流:
  • 服务信息成功检索
  • 找到含 request_id 的日志
  • 配置正确加载
  • 根因已识别
  1. 校验工作流:
  • 配置成功检索
  • 所有校验检查已执行
  • 问题清晰报告
  • 建议已提供(如适用)

清理

本 Skill 执行只读阿里云 API 调用(不创建远程资源)。临时工件

进入 /tmp 下的每会话本地 $WORKDIR(见核心工作流前言)。本 Skill 自动删除 $WORKDIR

——操作系统级临时策略会回收它(macOS 定期清理 /tmp;大多数

Linux 发行版在重启时或通过 systemd-tmpfiles 清理)。要更快释放磁盘空间,

在工作流外手动运行 rm -rf /tmp/pairec-diag-*

最佳实践

  1. 日志查询——仅关键词,无时间范围,无本地过滤:对于请求级诊断,向 aliyun eas describe-service-log--keyword &lt;request_id&gt; 并保持 --start-time / --end-time 未设置。绝不省略 --keyword 然后本地后处理(例如 | head| grep| python3)——这破坏了服务端过滤,浪费 token,并可能漏掉第一页之外的日志。将关键词与时间范围组合会因 CLI 怪癖过滤掉业务日志(见工作流 1 步骤 3)。仅对宽泛的非请求扫描使用时间范围,且只用 yyyy-MM-dd HH:mm:ss UTC 格式(无 T / 无 Z)。
  2. 信任 validate.py:对于工作流 2,将 scripts/validate.py 视为其目录中规则的唯一事实来源。不要跳过它手写检查,也不要在干净运行后手动重新校验其规则。人工检查保留给其范围之外的关注点(环境 / 地域 / 模型签名、跨版本差异、RankScore 与模型输出命名)。
  3. 环境意识:始终验证配置匹配目标环境(Prod vs Pre);问题持续时与已知良好版本对比。
  4. 日志保留:EAS 服务日志保留期有限;问题出现后及时诊断。
  5. 仅证据结论:将每个陈述建立在具体日志行或配置片段上。遵循系统化工作流,而非仅从错误消息跳到结论。不要推测,不要提议修复,也不要主动提供最佳实践建议,除非用户明确要求。如果证据不足,说明缺什么而非推断。

参考链接

参考文档说明
RAM 策略PAI-Rec 和 EAS API 所需的 RAM 权限
相关命令完整 CLI 命令参考
验证方法详细验证流程
CLI 安装指南阿里云 CLI 安装说明
配置示例示例引擎配置和常见模式
配置校验scripts/validate.py 用法、退出码、规则目录
故障排查指南常见问题与解决方案
配置脱敏LLM 分析前的凭据脱敏