Skill: fandywang87/ai-recsys-weekly-report (version 1.0.0)

--- name: AI RecSys Weekly Report slug: ai-recsys-weekly-report version: 1.0.0 description: > 自动生成关于"AI大模型（LLM、VLM等）技术在搜索、广告、推荐（搜广推）领域应用"的深度技术周报， 并自动同步到 IMA（腾讯文档/知识库）。触发词：AI搜广推技术周报、搜广推周报、大模型推荐报告、 推荐系统技术周报、生成式推荐周报、Transformer推荐系统报告、Scaling Law推荐系统、 MoE推荐系统、稀疏注意力推荐、RankMixer、OneTrans、MixFormer、BlossomRec。 当用户要求定期生成搜广推领域的技术研究报告、论文综述或行业动态分析时触发此 skill。 author: fandywang license: MIT-0 tags: - recommendation - search - advertising - weekly-report - automation - arxiv - transformer - llm triggers: - AI搜广推技术周报 - 搜广推周报 - 大模型推荐报告 - 推荐系统技术周报 - 生成式推荐周报 - Transformer推荐系统报告 - Scaling Law推荐系统 - MoE推荐系统 - 稀疏注意力推荐 --- # AI 搜广推技术周报 - 自动化 Skill > 本 Skill 将完整的"信息搜集 → 报告生成 → IMA 同步"流程打包，可迁移到任意 WorkBuddy 账号使用。 ## 前置依赖 ### 必须安装的 Skill 本 Skill 依赖以下 Skill，使用前请确保已安装： 1. **ima-skills**（或 **腾讯ima**）— 用于上传文件到 IMA 知识库 - 安装后需配置 Client ID 和 API Key（见下方「IMA 配置」） ### 可选但推荐的 Skill - **wechat-article-search** — 搜索微信公众号文章 - **zhihu-search-api-skill** — 搜索知乎文章 - **ArXiv论文追踪** — 搜索 ArXiv 最新论文 ## IMA 配置 在使用此 Skill 前，必须先配置 IMA 凭证： ```bash # 1. 打开 https://ima.qq.com/agent-interface 获取 Client ID 和 API Key # 2. 存储凭证 mkdir -p ~/.config/ima echo "你的Client_ID" > ~/.config/ima/client_id echo "你的API_Key" > ~/.config/ima/api_key ``` ## 使用方式 ### 方式一：单次执行（手动触发） 当用户要求"生成搜广推周报"、"出一份大模型推荐系统的技术报告"时，按以下步骤执行： #### Step 1：信息搜集 并行执行以下搜索（至少覆盖 ArXiv + 中文来源）： **ArXiv 论文搜索**（核心）： - `site:arxiv.org recommendation system transformer backbone 2025 2026` - `site:arxiv.org recommendation MoE mixture of experts ranking` - `site:arxiv.org sparse attention recommendation transformer` - `site:arxiv.org generative recommendation LLM` **中文技术文章搜索**： - 微信公众号：`大模型推荐系统 Transformer 搜广推` （通过 wechat-article-search 或 web_search） - 知乎：`搜广推 Scaling Law 推荐系统 大模型` （通过 zhihu-search 或 web_search） - 技术博客：InfoQ、腾讯云开发者社区、CSDN 等 **特定技术追踪**： - DeepSeek Sparse Attention (DSA) - Kimi Attention Residuals (AttnRes) - Qwen Gated Attention - Muon 优化器 - SwiGLU 激活函数 - DeepSeekMoE 对搜索到的重要论文，使用 `web_fetch` 获取 arXiv 页面的详细信息（标题、作者、摘要、核心贡献）。 #### Step 2：生成报告 将搜集到的信息整理为 Markdown 格式的技术周报，必须包含以下章节： 1. **本周热点综述**（3-5条核心趋势，每条含论文链接） 2. **深度技术解读**（选择2-5篇最重要的工作，每篇包含）： - 论文基本信息（标题、作者、机构、会议/期刊、链接） - 核心创新点 - 关键实验数据（具体数字） - 对搜广推领域的启示和建议 3. **技术对比分析**： - 至少一个对比表格（如不同架构对比、不同注意力机制对比） - 可选 ASCII 架构图展示演进路线 4. **创新思考与建议**（2-4条可操作的建议） 5. **趋势预测**（2-4个方向的前瞻性判断） 6. **延伸阅读推荐**（6-12条，分类整理：综述类 / 经典必读 / 技术博客） 7. **优化调整思考建议**（新增！本次研究的局限与后续改进方向） 8. **参考文献**（所有引用的完整列表，每项含可点击链接） **格式要求**： - 每篇论文/工作必须附带 arXiv 链接和 PDF 直接下载链接 - 尽可能附上中文解读链接（知乎/CSDN/博客园等） - 如有 GitHub 开源仓库，附上 GitHub 链接 - 报告字数：2000-4000 字 - 文件命名：`AI搜广推技术周报_YYYY-MM-DD.md` #### Step 3：上传到 IMA 知识库 **关键：必须使用 cos-upload.cjs 官方脚本上传 COS，不可用 curl 手动传。** 标准三步流程： ```bash # 配置常量（每次执行时替换实际值） FILE_PATH="<生成的报告路径>" FILE_NAME="AI搜广推技术周报_YYYY-MM-DD.md" FILE_EXT="md" KB_ID="<目标知识库ID>" # 用户需提供 MEDIA_TYPE=7 # Markdown 固定为7 CONTENT_TYPE="text/markdown" # 工具路径 NODE="/Users/fandywang/.workbuddy/binaries/node/versions/22.12.0/bin/node" # 注意：目标账号需要确认 node 路径，可能不同 COS_SCRIPT="<skill目录>/scripts/upload-to-ima.py" # 执行上传脚本 python3 "$COS_SCRIPT" --file "$FILE_PATH" \ --kb-id "$KB_ID" \ --title "$FILE_NAME" ``` 或直接调用 `scripts/upload-to-ima.py` 封装脚本（见下方脚本说明）。 ### 方式二：自动化定时任务 创建每周定时执行的自动化任务： ``` 名称: AI大模型搜广推技术周报 频率: FREQ=WEEKLY;BYDAY=MO;BYHOUR=9;BYMINUTE=0 prompt: 请加载 ai-recsys-weekly-report skill，完整执行一次周报生成并同步到 IMA 知识库。 知识库ID: <用户提供> cwds: <用户的工作空间路径> status: ACTIVE ``` ## 脚本说明 ### scripts/upload-to-ima.py IMA 知识库上传封装脚本，内部实现标准的三步流程： 1. `create_media` — 获取 media_id 和 COS 上传凭证 2. `cos-upload.cjs` — 使用腾讯云 SDK 上传文件到 COS 3. `add_knowledge` — 将已上传文件关联到知识库 **用法**： ```bash python3 scripts/upload-to-ima.py --file <报告路径> --kb-id <知识库ID> [--title <自定义标题>] ``` **依赖**： - Python 3.x - ima-skills 中的 `cos-upload.cjs` 脚本 - Node.js（用于运行 cos-upload.cjs） **重要注意事项**： - 如果 `cos-upload.cjs` 返回非零退出码，立即终止流程，不要继续调用 `add_knowledge` - Node 路径需要在脚本中配置正确（不同环境可能路径不同） - IMA 凭证从 `~/.config/ima/client_id` 和 `~/.config/ima/api_key` 读取 ## 研究范围参考 以下是本 Skill 覆盖的核心技术方向，供搜索时参考关键词： | 技术方向 | 代表性工作 | 搜索关键词 | |:---|:---|:---| | 统一 Backbone | OneTrans, RankMixer, MixFormer | unified backbone recommender, one transformer | | Scaling Law | 10亿参数推荐Transformer | scaling law recommendation system | | MoE 架构 | DeepSeekMoE, 专家路由 | mixture of experts recommendation | | 稀疏注意力 | BlossomRec, DSA, ISA | sparse attention sequential recommendation | | 残差连接革新 | Kimi AttnRes | attention residuals transformer | | 门控注意力 | Qwen Gated Attention | gated attention mechanism | | 优化器迁移 | Muon, Adam-mini | efficient optimizer recommendation | | 激活函数 | SwiGLU, GeGLU | activation function recommender | | 生成式推荐 | GRU4Rec, GenRec, MTGR | generative recommendation LLM |

path: README.md
content: # AI 搜广推技术周报 Skill - 安装与使用指南

## 一、这个 Skill 是什么？

这是一个 **可迁移的自动化 Skill**，将"AI大模型技术在搜广推领域的应用"技术周报的完整生成流程打包。安装后可以在任意 WorkBuddy 账号上：

- 手动触发：生成单次深度技术研究报告
- 自动化定时任务：每周自动执行并同步到 IMA 知识库

## 二、安装步骤

### Step 1: 解压 Skill 文件

将 `ai-recsys-weekly-report.zip` 解压到你的 Skills 目录：

```bash
# 创建 skills 目录（如果不存在）
mkdir -p ~/.workbuddy/skills

# 解压到 skills 目录
unzip ai-recsys-weekly-report.zip -d ~/.workbuddy/skills/

# 确认结构
ls ~/.workbuddy/skills/ai-recsys-weekly-report/
# 应该看到: SKILL.md, scripts/, references/
```

### Step 2: 安装依赖 Skill

本 Skill **依赖** `ima-skills`（腾讯 IMA 知识库操作）。在 WorkBuddy 中安装：

1. 打开 WorkBuddy
2. 进入 Skill 市场 / 设置
3. 搜索并安装 **ima-skills**（或 **腾讯ima**）

### Step 3: 配置 IMA 凭证

```bash
# 打开 https://ima.qq.com/agent-interface
# 获取 Client ID 和 API Key

# 存储凭证
mkdir -p ~/.config/ima
echo "你的Client_ID" > ~/.config/ima/client_id
echo "你的API_Key" > ~/.config/ima/api_key
```

### Step 4: 配置 Node.js 路径（重要！）

上传脚本依赖 Node.js 来运行 COS 上传组件。编辑脚本中的路径：

```bash
# 用你喜欢的编辑器打开
nano ~/.workbuddy/skills/ai-recsys-weekly-report/scripts/upload-to-ima.py

# 找到 NODE_PATH 配置行（约第25行），修改为你的 Node 路径：
# 常见路径:
#   macOS Homebrew: /opt/homebrew/bin/node
#   nvm: ~/.nvm/versions/node/vXX.XX.X/bin/node
#   WorkBuddy 内置: ~/.workbuddy/binaries/node/versions/XX.XX.X/bin/node
#   系统: /usr/local/bin/node

# 验证 node 是否可用:
node --version
```

### Step 5: 获取目标知识库 ID

你需要一个已有的 IMA 知识库来存储报告。获取方式：

```bash
# 方法1: 通过 IMA 客户端查看
# 打开 IMA -> 知识库 -> 点击目标知识库 -> 复制 ID

# 方法2: 如果已配置凭证，可以用 API 搜索
curl -s -X POST "https://ima.qq.com/openapi/wiki/v1/search_knowledge_base" \
  -H "ima-openapi-clientid: $(cat ~/.config/ima/client_id)" \
  -H "ima-openapi-apikey: $(cat ~/.config/ima/api_key)" \
  -H "Content-Type: application/json" \
  -d '{"query": "", "cursor": "", "limit": 20}'
```

记下目标知识库的 ID（格式类似 [REDACTED_SECRET]）。

## 三、使用方法

### 方式 A: 单次手动生成

在 WorkBuddy 对话中直接说：

> "帮我生成一份 AI 搜广推技术周报，同步到我的 IMA 知识库"

或更具体：

> "用 ai-recsys-weekly-report skill 出一份本周的大模型推荐系统技术报告，知识库ID是 xxx"

### 方式 B: 自动化定时任务

在 WorkBuddy 中创建自动化：

| 字段 | 值 |
|:---|:---|
| 名称 | AI搜广推技术周报 |
| 执行频率 | 每周一上午 9:00 |
| Prompt | 请加载 ai-recsys-weekly-report skill，完整执行一次周报生成并同步到IMA知识库。知识库ID: `<你的KB_ID>` |
| 工作空间 | 你的工作空间路径 |
| 状态 | ACTIVE |

RRULE 格式: `FREQ=WEEKLY;BYDAY=MO;BYHOUR=9;BYMINUTE=0`

## 四、报告输出说明

每次执行会产出：

1. **本地文件**: `AI搜广推技术周报_YYYY-MM-DD.md` (2000-4000字)
2. **IMA 知识库**: 同步到指定知识库
3. **报告内容**:
   - 本周热点综述 (3-5条)
   - 深度技术解读 (2-5篇论文)
   - 技术对比分析表格
   - 创新思考与建议
   - 趋势预测
   - 延伸阅读推荐 (6-12条)
   - 优化调整思考建议
   - 参考文献 (含链接)

## 五、自定义修改

### 修改研究范围

编辑 `references/research-scope.md`，可以：
- 添加/删除研究方向
- 更新代表性工作列表
- 调整搜索关键词

### 修改报告模板

编辑 `SKILL.md` 中的「Step 2: 生成报告」章节，可以：
- 增加/减少章节
- 调整字数要求
- 改变格式风格

### 修改信息源优先级

编辑 `SKILL.md` 中的搜索策略部分，可以：
- 增加 CSDN、掘金等中文来源
- 添加特定会议追踪（如只关注 KDD）
- 调整搜索关键词

## 六、常见问题

**Q: 上传失败提示"找不到 cos-upload.cjs"？**
A: 确保已安装 ima-skills skill，且脚本中 `COS_UPLOAD_SCRIPT` 路径正确。

**Q: Node.js 报错 command not found？**
A: 编辑 `scripts/upload-to-ima.py` 中的 `NODE_PATH` 变量，改为你系统的实际 Node 路径。

**Q: IMA 凭证错误？**
A: 检查 `~/.config/ima/client_id` 和 `~/.config/ima/api_key` 文件内容是否正确。

**Q: 想改报告的保存目录？**
A: 在自动化任务的 prompt 中指定输出路径，或在 SKILL.md 中修改默认路径。

**Q: 想同时发送多个知识库？**
A: 修改 `scripts/upload-to-ima.py`，支持多 kb-id 参数。

## 七、目录结构

```
ai-recsys-weekly-report/
├── SKILL.md                          # 主定义文件
├── README.md                         # 本安装指南
├── scripts/
│   └── upload-to-ima.py              # IMA 知识库上传封装脚本
└── references/
    └── research-scope.md             # 研究范围与技术方向参考
```

## 八、更新日志

- **v1.0** (2026-04-19): 初始版本
  - 完整的三步流程（搜集 → 生成 → 同步）
  - 标准 COS 上传（cos-upload.cjs）
  - 6大技术方向覆盖
  - 可配置的知识库 ID 和 Node 路径


path: references/research-scope.md
content: # 搜广推技术周报 - 研究范围与模板

## 核心研究方向

### 1. 统一 Backbone 架构

**背景**：传统推荐系统采用"序列建模 + 特征交互"两段式架构，存在信息孤岛和优化割裂问题。

**代表性工作**：
| 工作 | 机构 | 会议/时间 | 链接 |
|:---|:---|:---|:---|
| OneTrans | 字节跳动 | WWW 2026 | [arxiv.org/abs/2510.26104](https://arxiv.org/abs/2510.26104) |
| MixFormer | 抖音 | arXiv 2026.2 | [arxiv.org/abs/2602.14110](https://arxiv.org/abs/2602.14110) |
| RankMixer | 阿里 | - | [相关讨论](https://zhuanlan.zhihu.com/p/1917951263083038325) |

**搜索关键词**：`unified backbone recommender`, `one transformer recommendation`, `RankMixer`, `OneTrans`, `MixFormer`

### 2. Scaling Law in Recommendation

**背景**：验证推荐系统是否遵循类似 LLM 的 Scaling Law——模型越大、数据越多，性能是否持续提升？

**代表性工作**：
| 工作 | 机构 | 会议 | 关键数据 |
|:---|:---|:---|:---|
| 1B-Param Recommender Transformer | 音乐平台 | KDD 2026 | 收听+2.26%, 点赞+6.37% |
| MTGR (美团) | 美团 | 内部 | 生成式推荐 Scaling Law 落地 |

**搜索关键词**：`scaling law recommendation system`, `billion parameter recommender`, `large scale transformer recommender`

### 3. MoE (混合专家) 在推荐中的应用

**背景**：MoE 通过稀疏激活降低计算量，同时保持大模型的表达能力。DeepSeekMoE 是当前最先进的 MoE 变体。

**核心问题**：如何设计专家路由策略？不同品类/领域是否应该用不同专家？

**搜索关键词**：`mixture of experts recommendation system`, `DeepSeekMoE ranking`, `sparse expert routing recommender`

### 4. 稀疏注意力机制

**背景**：全量注意力的 O(n²) 复杂度限制了序列长度。稀疏注意力通过选择性计算降低成本。

**代表性工作**：
| 工作 | 来源 | 策略 | 链接 |
|:---|:---|:---|:---|
| BlossomRec | WWW 2026 | 块级双模式(长期+短期) | [arxiv.org/abs/2512.13368](https://arxiv.org/abs/2512.13368) |
| DeepSeek DSA | DeepSeek-V3.2 | Token级细粒度稀疏 | [解读](https://blog.csdn.net/v_JULY_v/article/details/155578958) |
| STRec | RecSys 2023 | 全局稀疏模式 | [ACM DL](https://dl.acm.org/doi/10.1145/3604915.3608779) |

**搜索关键词**：`sparse attention sequential recommendation`, `long sequence modeling recommender`, `efficient attention mechanism`

### 5. 注意力机制创新

| 技术 | 来源 | 核心思想 | 对搜广推的启发 |
|:---|:---|:---|:---|
| Kimi AttnRes | 月之暗面 2026.3 | 动态加权替代固定残差连接 | 即插即用，多目标优化场景适用 |
| Qwen Gated Attention | NeurIPS 2025 Best Paper | 门控注意力，消除Attention Sink | 特征重要性动态加权 |
| FlashMLA | DeepSeek 开源 | 高性能 Sparse Attention CUDA kernel | 工业部署算子基础 |

### 6. 优化器与激活函数迁移

| LLM 技术 | 原始用途 | 搜广推潜在应用 |
|:---|:---|:---|
| Muon 优化器 | LLM 快速训练 | 替代 AdamW, 2x 效率提升 |
| SwiGLU / GeGLU | LLM 表达能力增强 | 替代 ReLU/GELU |
| Adam-mini | 高效训练 | 降低显存占用 |

## 信息源优先级

### Tier 1（必搜）
- **ArXiv**: cs.IR (Information Retrieval), cs.LG (Machine Learning)
- **会议论文**: KDD, WWW, SIGIR, ICML, NeurIPS, RecSys, WSDM

### Tier 2（强烈建议）
- **微信公众号**: 搜索"大模型推荐"、"搜广推 Transformer"等
- **知乎专栏**: 深度技术分析文章
- **InfoQ / AICon**: 行业大会精华总结

### Tier 3（补充）
- **公司技术博客**: 腾讯云、阿里 DAMO、美团技术团队、字节跳动
- **GitHub Trending**: 关注 recommendation-system, llm-rec 相关项目
- **CSDN / 掘金**: 中文技术实践文章


path: scripts/upload-to-ima.py
content: #!/usr/bin/env python3
"""
IMA 知识库上传脚本 - 标准三步流程
  Step 1: create_media -> 获取 media_id + COS 凭证
  Step 2: cos-upload.cjs -> 上传文件到 COS
  Step 3: add_knowledge -> 关联到知识库

用法:
  python3 upload-to-ima.py --file <报告路径> --kb-id <知识库ID> [--title <标题>]

依赖:
  - ima-skills 的 cos-upload.cjs 脚本
  - Node.js (用于运行 cos-upload.cjs)
  - IMA 凭证文件: ~/.config/ima/client_id, ~/.config/ima/api_key

注意:
  - COS 上传失败时立即终止，不执行 add_knowledge
  - Node 路径需要根据实际环境配置 (见下方 NODE_PATH)
"""

import argparse
import json
import os
import subprocess
import sys
import urllib.request

# ============== 配置区（目标账号需修改） ==============
# cos-upload.cjs 脚本路径（相对于本脚本所在目录）
COS_UPLOAD_SCRIPT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                  "..", "..", "ima笔记", "knowledge-base", "scripts", "cos-upload.cjs")

# Node.js 路径 — 请根据目标环境修改
NODE_PATH = os.path.expanduser("~/.workbuddy/binaries/node/versions/22.12.0/bin/node")
# 备选: /usr/local/bin/node 或 which node 的结果


def load_credentials():
    """从配置文件读取 IMA 凭证"""
    client_id_path = os.path.expanduser("~/.config/ima/client_id")
    api_key_path = os.path.expanduser("~/.config/ima/api_key")
    if not os.path.exists(client_id_path) or not os.path.exists(api_key_path):
        print("ERROR: 缺少 IMA 凭证。请先运行:")
        print("  mkdir -p ~/.config/ima")
        print('  echo "your_client_id" > ~/.config/ima/client_id')
        print('  echo "your_api_key" > ~/.config/ima/api_key')
        sys.exit(1)
    with open(client_id_path) as f:
        client_id = f.read().strip()
    with open(api_key_path) as f:
        [REDACTED_SECRET]).strip()
    if not client_id or not [REDACTED_SECRET]"ERROR: 凭证文件为空")
        sys.exit(1)
    return client_id, api_key


def ima_api(client_id, api_key, path, body):
    """调用 IMA OpenAPI"""
    data = json.dumps(body).encode("utf-8")
    req = urllib.request.Request(
        f"https://ima.qq.com/{path}",
        data=data,
        headers={
            "ima-openapi-clientid": client_id,
            "ima-openapi-apikey": api_key,
            "Content-Type": "application/json",
        },
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read().decode("utf-8"))


def find_node():
    """查找可用的 Node.js 路径"""
    # 优先使用配置的路径
    if os.path.exists(NODE_PATH):
        return NODE_PATH
    # 回退到系统 PATH
    for candidate in ["/usr/local/bin/node", "/opt/homebrew/bin/node", "node"]:
        try:
            r = subprocess.run([candidate, "--version"], capture_output=True, timeout=5)
            if r.returncode == 0:
                return candidate
        except Exception:
            continue
    print(f"ERROR: 找不到 Node.js。请修改脚本中的 NODE_PATH 配置。当前: {NODE_PATH}")
    sys.exit(1)


def main():
    parser = argparse.ArgumentParser(description="上传 Markdown 报告到 IMA 知识库")
    parser.add_argument("--file", required=True, help="要上传的 Markdown 文件路径")
    parser.add_argument("--kb-id", required=True, help="目标知识库 ID")
    parser.add_argument("--title", default=None, help="自定义标题（默认使用文件名）")
    args = parser.parse_args()

    file_path = os.path.abspath(args.file)
    if not os.path.exists(file_path):
        print(f"ERROR: 文件不存在: {file_path}")
        sys.exit(1)

    file_name = args.title or os.path.basename(file_path)
    file_ext = file_path.rsplit(".", 1)[-1] if "." in file_path else "md"
    file_size = os.path.getsize(file_path)

    # 文件类型映射
    ext_map = {
        "md": (7, "text/markdown"),
        "pdf": (1, "application/pdf"),
        "docx": (3, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
        "txt": (13, "text/plain"),
    }
    media_type, content_type = ext_map.get(file_ext, (7, "text/markdown"))

    kb_id = args.kb_id.strip()
    client_id, [REDACTED_SECRET])
    node_bin = find_node()

    # 检查 cos-upload.cjs 是否存在
    cos_script = os.path.abspath(COS_UPLOAD_SCRIPT)
    if not os.path.exists(cos_script):
        # 尝试 skill 内置相对路径
        alt_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cos-upload-wrapper.cjs")
        if os.path.exists(alt_script):
            cos_script = alt_script
        else:
            print(f"ERROR: 找不到 cos-upload.cjs 脚本")
            print(f"  查找路径1: {os.path.abspath(COS_UPLOAD_SCRIPT)}")
            print(f"  查找路径2: {alt_script}")
            print(f"  请确保已安装 ima-skills skill")
            sys.exit(1)

    print(f"文件: {file_name} ({file_size} bytes)")
    print(f"类型: media_type={media_type}, content_type={content_type}")
    print(f"Node: {node_bin}")

    # === Step 1: create_media ===
    print("\n[Step 1] 创建媒体...")
    try:
        result = ima_api(client_id, api_key, "openapi/wiki/v1/create_media", {
            "file_name": file_name,
            "file_size": file_size,
            "content_type": content_type,
            "knowledge_base_id": kb_id,
            "file_ext": file_ext,
        })
    except Exception as e:
        print(f"FAIL: create_media API 调用异常: {e}")
        sys.exit(1)

    if result.get("code") != 0:
        print(f"FAIL: create_media 返回错误: {result.get('msg', result)}")
        sys.exit(1)

    media_id = result["data"]["media_id"]
    cos_cred = result["data"]["cos_credential"]
    print(f"OK media_id={media_id}")

    # === Step 2: COS Upload ===
    print("\n[Step 2] 上传 COS (cos-upload.cjs)...")
    upload_args = [
        node_bin, cos_script,
        "--file", file_path,
        "--secret-id", cos_cred["secret_id"],
        "--secret-key", cos_cred["secret_key"],
        "--token", cos_cred["token"],
        "--bucket", cos_cred["bucket_name"],
        "--region", cos_cred["region"],
        "--cos-key", cos_cred["cos_key"],
        "--content-type", content_type,
        "--start-time", str(cos_cred["start_time"]),
        "--expired-time", str(cos_cred["expired_time"]),
    ]

    try:
        r = subprocess.run(upload_args, capture_output=True, text=True, timeout=120)
        stdout = r.stdout.strip() if r.stdout else ""
        stderr = r.stderr.strip()[:300] if r.stderr else ""
        if stdout:
            print(f"输出: {stdout}")
        if stderr:
            print(f"日志: {stderr}")

        if r.returncode != 0:
            print(f"\nFAIL: COS 上传失败 (exit code={r.returncode})，终止流程")
            print("提示: COS 文件未成功写入，不要继续 add_knowledge")
            sys.exit(1)
    except subprocess.TimeoutExpired:
        print("FAIL: COS 上传超时 (>120s)")
        sys.exit(1)
    except Exception as e:
        print(f"FAIL: COS 上传异常: {e}")
        sys.exit(1)

    print("OK COS 上传成功")

    # === Step 3: add_knowledge ===
    print("\n[Step 3] 添加到知识库...")
    try:
        add_result = ima_api(client_id, api_key, "openapi/wiki/v1/add_knowledge", {
            "media_type": media_type,
            "media_id": media_id,
            "title": file_name,
            "knowledge_base_id": kb_id,
            "file_info": {
                "cos_key": cos_cred["cos_key"],
                "file_size": file_size,
                "file_name": file_name,
            },
        })
    except Exception as e:
        print(f"FAIL: add_knowledge API 异常: {e}")
        sys.exit(1)

    print(json.dumps(add_result, indent=2, ensure_ascii=False))

    if add_result.get("code") == 0:
        print("\n=== 全部成功！请刷新 IMA 知识库查看文件 ===")
    else:
        print(f"\nFAIL: add_knowledge 错误: {add_result.get('msg')}")


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)