12 KiB
name, description, when_to_use, aliases, allowed_tools
| name | description | when_to_use | aliases | allowed_tools |
|---|---|---|---|---|
| intervention-data | 生成和校验单句精确干预、正则干预候选 TSV,复用标签大师的 target 语法校验,并从历史干预表推断 code 到下发 domain 的固定映射。 | 当用户希望新增、检查或整理干预规则,例如给某个 query 或多轮正则生成干预条目、确认设备和标签是否合法、推断下发 domain 时使用。 | intervention, rule-intervention, 干预数据 | read_file, write_file, edit_file, grep_search, glob_search, ask_user_question, python_exec |
使用这个 skill 处理“query/多轮表达 -> 干预候选 -> 合并 + 上传 HDFS”的任务。
干预数据目前有两类,文件无扩展名(HDFS 上文件名是 260610 这种纯日期),内容是真实 TAB 字符分隔的纯文本,绝不是字面 \t 两字符。下文所有 \t 都表示一个真实的 TAB。
- 单句精确干预(codeTopQuery):一行 4 列,
设备\tquery\tcode\t下发domain示例:unify 播放音乐 Agent(tag="音乐") contentCopilot|music unify 小爱同学 Chat(type="wakeup") dialogCopilot|michat - 正则干预(codeIntervene):一行 3 列,
设备\t正则\t标签示例:unify ^query#播放歌曲关机又关机$ Agent(tag="音乐") unify ^beforeQuery#播放歌曲#query#关机又关机$ Agent(tag="音乐") glass ^query#这是什么$ QA()
精确干预的 code 和正则干预的 标签 使用同一套 target 语法,和 label-master 的输出一致,但不包含复杂度判断。校验时必须复用 skills/label-master/scripts/validate_label_output.py 的逻辑。
关键约定
unify表示全部设备。- 设备必须优先从下载下来的最新干预文件中归纳,不要随手发明设备名。
- 单句精确干预的
下发domain必须由人拍板:脚本基于最新干预文件按code → 下发domain频次给出 top-N 候选 + 计数,agent 列出来让用户从用户给的 tag 信息出发选一个,不要默认用多数派直接落盘。 - 正则干预支持多轮。多轮正则使用
beforeQuery#上一轮#query#当前轮这种片段表达,最终通常包在^...$中。 - 默认只生成候选行 + 校验结果,不直接追加到历史干预文件。上传 HDFS 必须等用户明确确认。
- 所有产物优先写到当前会话的
$AUTORESEARCH_CHAT_ROOT/output/或scratchpad/下,不要写到项目根目录的output/。
HDFS 干预文件路径
线上干预的权威源在 HDFS。两类文件 × 四个环境(p4t = 测试,ptr = 灰度,preview = 预发,production = 生产):
| 类型 | HDFS 目录 |
|---|---|
| 单句精确干预(codeTopQuery) | hdfs://zjyprc-hadoop/user/s_ai_service/nlp/PlanningPredict/all/<env>/strategy/codeTopQuery |
| 正则干预(codeIntervene) | hdfs://zjyprc-hadoop/user/s_ai_service/nlp/PlanningPredict/all/<env>/strategy/codeIntervene |
<env> 取值:p4t / ptr / preview / production。每个目录下文件名"形式"按日期 yymmdd 命名(纯数字、无扩展名,例:260609),但实际值不要求严格等于当天日期——新增一份就是上一份按一天 +1(要正确处理月末/年末进位),最大值仍须落在合法 yymmdd 范围内(最大不超过今天)。最新文件 = 文件名尾号最大的那一个。
推荐流程
- 先确认链接到远端(强制第一步,不通过就停下)。
- "远端"概念同 model-iteration:bash 实际跑在远端 jupyter pod 工作区,
$AUTORESEARCH_CHAT_ROOT是后端注入的远端 chat 工作区路径(位于共享 NFS:/mnt/<email_prefix>/autoresearch-zk-users/<chat_session_id>/)。系统提示里的"当前会话目录"是后端宿主机本地路径,不是远端,不能拿来跑脚本或读历史文件。 - 起手第一条 bash 必须是预检(同时验远端 + HDFS 工具):
pwd && echo "AUTORESEARCH_CHAT_ROOT=$AUTORESEARCH_CHAT_ROOT" && uname -a && which hls hget hput - 通过条件:
pwd返回远端绝对路径(一般/root/zk_agent_workspaces/LOCALID_xxx或类似 Linux 路径)、$AUTORESEARCH_CHAT_ROOT非空、hls/hget/hput都能找到。 - 不通过的情形(任一命中就停下问用户):
$AUTORESEARCH_CHAT_ROOT为空 → 后端没注入,会话没绑定 chat。pwd是 Windows 路径(如D:\...、/d/...)或后端本地路径(如/home/mi/zk-data-agent-wsh/...)→ 当前在本地,不是远端。hls/hget/hput找不到 → 远端环境没装 HDFS 客户端,下一步拉文件直接卡死。- bash 报命令找不到 / 没权限 → 远端 pod 没起来。
- "远端"概念同 model-iteration:bash 实际跑在远端 jupyter pod 工作区,
- 获取最新的干预文件(强制第二步,所有后续校验和上传都基于这一步拉下来的文件)。
- 先确认 (a) 干预类型:精确干预 →
codeTopQuery,正则干预 →codeIntervene;(b) 目标环境(p4t/ptr/preview/production,用户没说就问,建议先在p4t验证)。 - 用
hls列目录,按文件名尾号取最大的那个作为最新文件,然后用hget拉下来:ENV=p4t # 或 ptr / preview / production TYPE=codeTopQuery # 或 codeIntervene HDFS_DIR=hdfs://zjyprc-hadoop/user/s_ai_service/nlp/PlanningPredict/all/$ENV/strategy/$TYPE hls "$HDFS_DIR" LATEST=$(hls "$HDFS_DIR" | awk '{print $NF}' | grep -v '^$' | sort -V | tail -1) echo "LATEST=$LATEST" WORK="$AUTORESEARCH_CHAT_ROOT/intervention/${ENV}_${TYPE}" mkdir -p "$WORK" # base 不带扩展名(HDFS 上原文件名就是日期),保持原貌 hget "$LATEST" "$WORK/base" wc -l "$WORK/base" # 抽 1-2 行肉眼校验是不是真 TAB 分隔(cat -A 把 TAB 显成 ^I) head -2 "$WORK/base" | cat -A - 设备枚举、
code → 下发domain频次、重复/冲突检查全部基于这份刚拉下来的base,不要再用本地历史快照(旧快照可能已过时)。文件是 TAB 分隔纯文本,无扩展名,不要当 csv/json 处理。
- 先确认 (a) 干预类型:精确干预 →
- 先确认用户要哪种干预方式(如果第 1 步还没定就在这里定,确定后回到第 1 步拉对应文件):
- 单句精确干预:query 必须完全命中。
- 正则干预:适合一类表达、多轮上下文或需要泛化的高频 case。
- 确认设备。用户没说设备时,必须问设备;可以提示
unify表示全部设备。设备枚举从 base.tsv 第一列归纳。 - 确认目标标签/code。它必须是完整 target,例如
Agent(tag="地图导航")、QA()、Chat()或合法 function 调用。 - 如果是单句精确干预:
- 确认
query。 - 下发domain 必须人选:基于 base 文件统计该
code(target)历史上配过的下发domain频次,给出 top-N 候选 + 计数,让用户结合自己提的 tag 信息选一个。例:把结果(如# 用 awk 抽该 target 的下发domain 分布 awk -F'\t' -v t='Agent(tag="音乐")' '$3==t {print $4}' "$WORK/base" \ | sort | uniq -c | sort -rn | head -512345 contentCopilot|music / 87 contentCopilot|audio_book / ...)作为候选给用户,不要默认取第一个直接落盘。
- 确认
- 如果是正则干预:
- 确认当前轮 query。
- 如果有多轮,确认前序 query 顺序。
- 用户给了原始正则就保留;没给时由脚本生成
^query#...$或^beforeQuery#...#query#...$。
- 调用
scripts/generate_intervention_candidate.py生成候选 TSV 和校验报告(产物写到$AUTORESEARCH_CHAT_ROOT/output/或scratchpad/)。 - 合并 + diff 给人看。把候选行追加进
base副本,跑 unified diff:cp "$WORK/base" "$WORK/merged" cat candidate >> "$WORK/merged" # candidate 是上一步生成的候选行文件,纯 TAB 分隔 diff -u "$WORK/base" "$WORK/merged" | tee "$WORK/diff.patch" - 展示给用户:干预类型、设备、候选行(原文 TAB 分隔)、校验结果、diff 摘要、目标 HDFS 路径。用户没明确说"上传 / 推到 X 环境 / hput"前不要执行 hput——这是写远端 + 影响线上的不可逆动作,必须等确认。
- 用户确认后 hput 上传。新文件名规则:取
LATEST的尾号「按一天」+1——必须正确处理月末 / 年末进位(260131 +1 = 260201,261231 +1 = 270101,260228 在闰年 +1 = 260229、平年 +1 = 260301),不是数值+1(那样 260131+1=260132 直接失效)。用date做日期算术:说明:HDFS 上文件名"形式"按日期来,实际值是「上一份按一天 +1」而不是严格当天日期;只要 +1 后仍是合法 yymmdd 且不超过今天就行。如果上一份已经是今天(OLD_NUM == TODAY),OLD_NUM=$(basename "$LATEST") # 例:260609 或 260131 NEW_NUM=$(date -d "20${OLD_NUM} + 1 day" +%y%m%d) TODAY=$(date +%y%m%d) # 校验:date 解析失败(OLD_NUM 本身就不合法)会直接报错;新尾号也必须是合法 yymmdd if ! [[ "$NEW_NUM" =~ ^[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$ ]]; then echo "ERR: $NEW_NUM 不符合 yymmdd 形式,停下问用户"; exit 1 fi if [ "$NEW_NUM" -gt "$TODAY" ]; then echo "ERR: $NEW_NUM=$NEW_NUM 超过今天 $TODAY(说明上一份就是今天的,已经发过一版),停下问用户"; exit 1 fi hput "$WORK/merged" "$HDFS_DIR/$NEW_NUM" hls "$HDFS_DIR" | tail -3 # 校验新文件已落、尾号最大date +1 day会算出明天 → 命中"超过今天"分支,停下问用户怎么处理(通常是当天已经发过一版,要不要并入现有版本,或推迟到明天再发)。 - 展示最终结果:上传后的 HDFS 路径 + 新文件尾号。
脚本能力
skills/intervention-data/
SKILL.md
knowledge/
type_match_agent.json
scripts/
intervention_common.py
analyze_intervention_sources.py
audit_intervention_sources.py
generate_intervention_candidate.py
validate_intervention_records.py
analyze_intervention_sources.py
读取历史干预文件,输出设备枚举、code -> 下发domain 多数映射、常见标签,以及 knowledge/type_match_agent.json 中的下发表。
示例:
python skills/intervention-data/scripts/analyze_intervention_sources.py
generate_intervention_candidate.py
从 JSON 输入生成候选 TSV,并自动校验。输入可以来自文件或 stdin。
audit_intervention_sources.py
审计现有两个历史干预文件,只输出摘要,不修改文件。适合验证当前 skill 的校验规则和存量数据是否贴合。
示例:
python skills/intervention-data/scripts/audit_intervention_sources.py
单句精确干预示例:
{
"mode": "exact",
"device": "unify",
"query": "播放周杰伦的歌",
"target": "Agent(tag=\"音乐\")"
}
正则多轮干预示例:
{
"mode": "regex",
"device": "miCar",
"before_queries": ["第一个"],
"query": "红绿灯少的路线",
"target": "Agent(tag=\"地图导航\")"
}
validate_intervention_records.py
校验候选 TSV。支持 --mode exact 或 --mode regex。
规则包括:
- 列数正确。
- 设备合法。
code/标签优先通过 label-master 校验;如果 label-master 未收录但历史干预表中已经稳定出现,允许作为候选通过,并给出 warning 让用户确认知识库是否需要补齐。- 单句精确干预的
下发domain与历史多数映射一致,默认不一致为 warning,--strict-domain时为 error。 - 单句精确干预还会用
type_match_agent.json做配置校对;配置值可以是更宽泛前缀,例如音乐 -> contentCopilot可以兼容历史里的contentCopilot|music。 - 正则可编译,且包含
query#片段。 - 与历史文件重复或冲突时给出 warning/error。
展示格式
生成候选后,优先用这个格式回复:
我生成了一条候选干预,先不写入历史文件。
- 类型:单句精确干预 / 正则干预
- 设备:xxx
- 标签:xxx
- 校验:通过 / 有问题
候选 TSV:`设备 query code 下发domain`
需要确认:是否写入某个文件,或是否调整设备/标签/正则。
如果校验失败,先解释失败原因,不要要求用户直接落盘。