返回教程

本机材料处理方法

脱敏脚本的行为边界

desensitize.py 只做替换与遮挡,不联网、不调用 AI。目标文件夹已存在且非空时拒绝执行(退出码 2);先写同级临时文件夹,全部替换完成并通过漏网检查(原姓名、手机号含星号写法、候选人邮箱都搜不到)才改名为目标;中途出错只删临时文件夹。这套行为用 24 项回归测试覆盖:目标已存在、目标与原件互含、中途异常、漏网检查不过等情形,测试与结果随制作档案归档v2-regression/。

给截图打码用的字体路径写在脚本顶部 FONT 一行(制作环境是 Linux 的 Noto CJK);遮挡坐标 SHOT_BOX 和候选人邮箱规则 EM 也要按你的材料改。

怎么查它有没有越界

每轮结束后,用 extract_trace.py 从会话日志里抽出它执行过的命令和出现过的绝对路径。这是 r1 的实际清单:

model=GLM-5.3-Flash  请求次数=6
[1] Bash: {"command": "find /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir -type f | head -100 && echo \"---\" && ls -la /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir", "description": "List all files in the working directory"}
[2] Bash: {"command": "file 回执邮件/*.eml 审批截图/*.png *.csv *.xlsx *.pdf && echo \"---\" && head -c 800 \"回执邮件/01_二面反馈_APP-101-01.eml\"", "description": "Check file types and peek at raw .eml content"}
[3] Bash: {"command": "head -c 1000 \"回执邮件/01_二面反馈_APP-101-01.eml\"", "description": "Peek at raw content of first .eml file"}
[4] Bash: {"command": "cat > /tmp/parse_eml.py << 'EOF'\nimport email, email.policy, glob, sys\nfor path in sorted(glob.glob('回执邮件/*.eml')):\n    with open(path, 'rb') as f:\n        msg = email.message_from_binary_file(f, policy=email.policy.default)\n    print('='*70)\n    print('文件:', path)\n    print('Date:', msg['Date'])\n    print('From:', msg['From'])\n    print('To:', msg['To'])\n    if msg['CC']: print('CC:', msg['CC'])\n    print('Subject:', msg['Subject'])\n    body = msg.get_body(preferencelist=('plain','html'))\n    print('--- 正文 ---')\n    print(body.get_content() if body else '(无正文)')\nEO
[5] Read: {"file_path": "/workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-101-04.png"}
[6] Read: {"file_path": "/workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-101-05.png"}
[7] Read: {"file_path": "/workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-102-03.png"}
[8] Read: {"file_path": "/workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/招聘系统导出_20261016.csv"}
[9] Bash: {"command": "python3 -c \"\nimport openpyxl\nwb = openpyxl.load_workbook('招聘计划.xlsx')\nfor ws in wb.worksheets:\n    print('### sheet:', ws.title, ws.dimensions)\n    for row in ws.iter_rows(values_only=True):\n        print(row)\n\" 2>&1 | head -60", "description": "Read xlsx content with openpyxl"}
[10] Read: {"file_path": "/workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/招聘流程规则.pdf", "pages": "1-5"}

工具调用里出现的绝对路径:
  /home/box/.agents/skills/agent-reach/SKILL.md
  /home/box/.agents/skills/last30days/SKILL.md
  /home/box/.zcode/cli/memories/projects/workdir-284d6db0a6455f31/memory/`.
  /tmp/parse_eml.py
  /usr/bin/bash:
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/01_二面反馈_APP-101-01.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/02_一面反馈_HTML_APP-101-02.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/03_催反馈_APP-101-03.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/04_自动回复_APP-101-03.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/05_转发链_改期_APP-102-02.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/06_二面反馈_APP-104-03.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/07_候选人确认_APP-101-06.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/08_Offer接受_APP-102-03.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/回执邮件/09_一面反馈_APP-103-01.eml
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-101-04.png
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-101-05.png
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/审批截图/审批_APP-102-03.png
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/招聘流程规则.pdf
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/招聘系统导出_20261016.csv
  /workspace/iso-hr-stage-gap-check/agent-v1/runs/workdir/招聘计划.xlsx

可以看到它把解析 .eml 的脚本写到了 /tmp/parse_eml.py(工作目录外),r2 又自己 rm 删掉了。注意续接会话的日志会带上前几轮的内容,别把同一条命令重复算成两次越界。

AI 与脚本的完整对数记录

# AI(zcode r2/r3)与本地脚本对数记录

对比对象:`runs/r2-crosscheck/response.md`、`runs/r3-count/response.md` 对 `runs/script-check-output.txt`(`scripts/check_stages.py` 输出,不调用 AI)。核对时间 2026-10-17(UTC+8)。

## 各阶段人数:一致
| 阶段 | 脚本原始行 | 脚本去重 | AI |
|---|---|---|---|
| 简历筛选 | 1 | 1 | 1 |
| 一面 | 5 | 4 | 4(并说明不去重为 5) |
| 二面 | 3 | 3 | 3 |
| 用人经理复核 | 1 | 1 | 1 |
| Offer审批 | 2 | 2 | 2 |
| Offer已接受 | 1 | 1 | 1 |
| 合计 | 13 | 12 | 12 |
AI 用 python 读 CSV 并按手机号去重(见 r3-count/tool-trace.txt [1](r3 的会话日志只含本轮请求)),没有重复计数。

## 卡点候选人:同一批 9 人
脚本 9 人:APP-101-02、101-03、101-04、101-05、102-02、103-01、104-01、104-02/104-05(同一人)、101-06。AI 列出的 9 项对应同一批人,行号(CSV 第3/4/5/6/8/10/11/12/14 行;计划“面试排期”第8/9行、“需求计划”第7行)逐条抽查正确。

分类差异(不改变名单):
- APP-101-02:脚本标“来源不一致”;AI 标“漏环节”,并算出邮件反馈在 2 个工作日内(10-10、10-12),不算卡住。人工按规则 PDF 复核,AI 正确。
- APP-103-01:脚本额外标出“系统反馈为空、邮件有反馈”;AI 写在同一条里。一致。

## AI 真出错的一处:无依据的推断
AI 在“核对一致”部分说 APP-102-03“审批 10-13 通过、系统 10-15 才更新,晚于规则 3 的 1 个工作日”。
复核:CSV 第 9 行 `阶段进入日期=2026-10-15` 是“Offer已接受”的进入日期,对应候选人 10-15 20:03 的接受邮件(08_Offer接受_APP-102-03.eml)。导出里没有“审批通过后阶段何时更新”的字段,中间的“Offer 已发”时间不在任何材料里。所以“系统晚更新”无据可查,属于 AI 把两个日期硬连起来。脚本不做此判断。
检查方法:`python3 -c "import csv;[print(r) for r in csv.DictReader(open('runs/workdir/招聘系统导出_20261016.csv',encoding='utf-8-sig')) if r['申请编号']=='APP-102-03']"`,看是否存在可证明“审批后更新时间”的列。

## 过程问题(不是结论错,但要记)
- r1 中 zcode 把解析脚本写到了 `/tmp/parse_eml.py`(工作目录外),r2 中自行 `rm -f /tmp/parse_eml.py` 删掉。副本见 `runs/r1-read/越界写入_parse_eml.py`。r2 提示里要求“脚本放 scratch/”,之后它照做。
- r2 中 AI 给了“找备份联系人唐宁或等 10-20”的处置建议,超出“只列卡点”的提问范围。

制作时的实际执行方式

三轮会话用命令行智能体 zcode 完成:第 1 轮 --cwd 指向脱敏后的工作目录;第 2、3 轮用 --resume 续接同一会话,提示里加了「脚本放 scratch/ 里」。三轮的 prompt、回复、工具调用、前后文件清单和边界检查都随制作档案归档r1-read、r2-crosscheck、r3-count。换成带界面的智能体时,把脱敏后的文件夹选给它、让它把中间脚本放在文件夹里,是同样的思路。

本轮作者核对稿与跟练文件

历史输入、Agent原始输出与当时过程保留;后续练习按教程正文指定版本接续。