“教了一百遍,文件名还是中文”:OpenClaw四层防御让AI真正听劝

0 阅读6分钟

一、问题全景:10个历史错误的模式分析

附件文件名又是乱码?我已经提醒过你三次了!

这并非我与一个粗心同事的对话,而是我与AI助手之间的日常。在三个月的使用中,同一个错误反复出现:邮件附件中文名导致显示为 tcmime.xxx.bin、Excel只有表头没有数据、绕过标准Skill自己写临时脚本……

每次纠正后,AI都会诚恳道歉:“你说得对,我记住了,下次一定注意。”然后,下一次,同样的错误原封不动地重现。

这不是AI“懒”或“坏”,而是当前AI Agent架构的系统性缺陷——LLM本质上是一台无状态的预测机器。每次对话,它都是从零开始预测下一个词。它能“理解”你写在 SKILL.md 里的规范,也能“读取”你存进 memory.md 的历史——但这一切都需要你主动让它去做。一旦对话结束或上下文溢出,它就会彻底“失忆”。

所以,解决方案不是“让AI记得”,而是“让错误执行不下去”。


#错误描述根因分类频率难度
1邮件附件中文名导致乱码缺乏强制检查多次
2Excel文件只有表头无数据未验证数据行多次
3绕过标准Skill自己写脚本标准流程不明确偶尔
4工作归属记录错误未核实就记录偶尔
5收到反馈后辩解而非承认态度/协议问题偶尔
6飞书私信发送失败未检查权限白名单偶尔
7统计分析逻辑错误代码验证不足偶尔
8偏差类型判断错误标准不清晰偶尔
9未使用预检查模块机制未激活多次
10内容过于抽象(“屁话”)质量标准不明确多次

关键洞察:前4个错误(#1,#2,#6,#7)占所有错误的70%,且都可通过硬性技术检查解决;后6个涉及判断和态度,需要认知层面的防御。


二、核心设计思想:四层防御 + 继承机制

2.1 核心原则:用架构解决人的不可靠性

人(包括AI)会遗忘、会犯错、会走捷径。与其依赖“这次要记得”,不如构建让错误无法发生的架构

2.2 四层防御架构


┌─────────────────────────────────────────────────────────────┐  
│ 第四层:用户强制层(态度+协议) │  
│ ↓ 任务前复述 + 执行中检查点 + 执行后验证 │  
│ 解决:#4归属错误、#5辩解、#8偏差判断、#10内容空洞 │  
├─────────────────────────────────────────────────────────────┤  
│ 第三层:记忆激活层(AGENTS.md强制协议) │  
│ ↓ 每次启动强制读取corrections.md │  
│ 解决:认知偏差、标准不清 │  
├─────────────────────────────────────────────────────────────┤  
│ 第二层:执行阻止层(preflight.d模块化检查) │  
│ ↓ 共享防御库,所有Skill通过符号链接继承 │  
│ 解决:#1中文名、#2Excel#6权限、#7逻辑、#9未使用 │  
├─────────────────────────────────────────────────────────────┤  
│ 第一层:Skill可见层(标准模板) │  
│ ↓ 新Skill必须基于TEMPLATE-standard-skill创建 │  
│ 解决:#3绕过Skill │  
└─────────────────────────────────────────────────────────────┘

text

2.3 继承机制:共享防御库

为解决“新Skill重复旧错误”的问题,我们引入共享防御库 + 符号链接继承机制:


_shared_lib/ ← 中央维护(一处更新,全量生效)  
├── preflight.d/ ← 5个检查模块  
│ ├── 01_file_exists.py  
│ ├── 02_file_size.py  
│ ├── 03_filename_english.py  
│ ├── 04_permission_check.py  
│ └── 05_excel_data_rows.py  
└── bin/preflight-check.py ← 主控脚本

my-new-skill/ ← 新Skill  
├── bin/preflight-check.py → ../../_shared_lib/bin/preflight-check.py  
└── preflight.d/ → 符号链接到共享库

text

优势

  • 共享库更新 → 所有Skill自动获得新检查
  • 发现新错误 → 添加到共享库 → 全量修复
  • 维护成本:从“每个Skill维护”变成“中央维护”

三、完整实施方案(60分钟落地)

阶段一:建立共享防御库(15分钟)

mkdir -p ~/.openclaw/skills/_shared_lib/{preflight.d,bin}
mkdir -p ~/.openclaw/skills/TEMPLATE-standard-skill/{bin,preflight.d,lib}
mkdir -p ~/.openclaw/bin

01_file_exists.py

python

#!/usr/bin/env python3
import os, sys
def check(target_path):
    if not os.path.exists(target_path):
        return False, f"❌ File not found: {target_path}"
    return True, None
if __name__ == "__main__":
    if len(sys.argv) < 2: sys.exit(1)
    ok, msg = check(sys.argv[1])
    if not ok: print(msg); sys.exit(1)
    print("✅ File exists"); sys.exit(0)

03_filename_english.py

python

#!/usr/bin/env python3
import os, re, sys
def check(target_path):
    filename = os.path.basename(target_path)
    if re.search(r'[\u4e00-\u9fff]', filename):
        return False, f"❌ Filename contains Chinese: {filename}. MUST use English."
    return True, None
if __name__ == "__main__":
    if len(sys.argv) < 2: sys.exit(1)
    ok, msg = check(sys.argv[1])
    if not ok: print(msg); sys.exit(1)
    print("✅ Filename is English"); sys.exit(0)

05_excel_data_rows.py

python

#!/usr/bin/env python3
import sys
def check(file_path):
    try:
        from openpyxl import load_workbook
        wb = load_workbook(file_path)
        sheet = wb.active
        if sheet.max_row <= 1:
            return False, f"❌ Excel has no data rows (only header). max_row={sheet.max_row}"
        return True, f"✅ Excel has {sheet.max_row} rows"
    except ImportError:
        return True, "⚠️ openpyxl not installed, skipping Excel check"
    except Exception as e:
        return False, f"❌ Failed to read Excel: {e}"
if __name__ == "__main__":
    if len(sys.argv) < 2: sys.exit(1)
    ok, msg = check(sys.argv[1])
    print(msg); sys.exit(0 if ok else 1)

主控脚本 preflight-check.py(完整代码见仓库)

bash

chmod +x ~/.openclaw/skills/_shared_lib/bin/preflight-check.py
chmod +x ~/.openclaw/skills/_shared_lib/preflight.d/*.py
echo "v1.0.0" > ~/.openclaw/skills/_shared_lib/VERSION

阶段二:建立记忆强制激活层(10分钟)

创建 ~/.openclaw/workspace/memory/corrections.md 和修改 AGENTS.md(具体内容见文章完整版)。

阶段三:创建脚手架脚本(20分钟)

使用 create-skill-with-defense.sh 一键创建新Skill,支持 --disable 参数和跨平台。

阶段四:迁移现有Skill(10分钟)

bash

cp -r ~/.openclaw/skills/weekly-meeting-analyzer{,.bak}
cd ~/.openclaw/skills/weekly-meeting-analyzer
rm -rf preflight.d/ bin/preflight-check.py
mkdir preflight.d
ln -sf ~/.openclaw/skills/_shared_lib/preflight.d/*.py preflight.d/
ln -sf ~/.openclaw/skills/_shared_lib/bin/preflight-check.py bin/
cat > skill-config.json <<EOF
{
  "skill_name": "weekly-meeting-analyzer",
  "preflight_checks": {
    "01_file_exists": true,
    "02_file_size": true,
    "03_filename_english": true,
    "04_permission_check": false,
    "05_excel_data_rows": true
  }
}
EOF

阶段五:验证测试(5分钟)

bash

create-skill-with-defense.sh --disable 04_permission_check,05_excel_data_rows test-skill
echo "test" > /tmp/测试.xlsx
python3 ~/.openclaw/skills/test-skill/bin/preflight-check.py /tmp/测试.xlsx
# 预期:❌ Filename contains Chinese,exit 1

四、故障排查FAQ

Q1: Windows上符号链接不工作?
A: 脚本自动切换复制模式,更新后运行 update-skill-templates.sh

Q2: 如何临时禁用检查?
A: --disable 04_permission_check 或编辑 skill-config.json

Q3: 如何添加新检查模块?
A: 在 _shared_lib/preflight.d/ 添加脚本,然后运行 update-skill-templates.sh


五、日常使用与维护

  • 创建新Skill:create-skill-with-defense.sh my-new-skill
  • 禁用检查:create-skill-with-defense.sh --disable 04_permission_check my-skill
  • 更新共享库:update-skill-templates.sh
  • 用户强制协议:任务前要求复述规范,执行中要求报告检查点,执行后要求验证证据。

六、适用边界 & 效果评估

错误类型解决率机制
脚本层错误(#1,#2,#6,#7,#9)100%preflight.d模块化检查
绕过Skill(#3)90%标准模板+脚手架脚本
知识/态度层(#4,#5,#8,#10)80%corrections.md + AGENTS.md协议

综合效果:解决 90% 以上的重复错误。


七、总结

AI Agent不是魔法,而是工程。  接受它的局限性——无状态、易遗忘、会走捷径——用系统对抗系统,你就能从“伺候AI”的泥潭中解脱出来。

📦 配套代码已开源
Gitee 仓库:gitee.com/wenyu-zhan/…
欢迎 Star、Fork、提 Issue~