一个水平滚动条 bug,本该是十分钟的手工排查——但 Claude Fable 5 把这件事做成了让人后背发凉的演示:它不仅定位了问题,还主动翻阅代码、修改文件、运行测试,全程几乎不需要人类插手。Simon Willison 的这篇复盘,把当前顶级 AI 编程智能体的主动性摊在了桌面上,也把一个更尖锐的问题摆了出来:当工具开始替你做决定,你到底是在用工具,还是在被工具带着跑?
一个 bug 的完整「自主修复」过程
Willison 遇到的问题是 Datasette Agent 界面中一个水平滚动条异常。他把问题描述丢给 Claude Fable 5 后,智能体并没有停在「给你一段建议代码」的阶段——它直接动手了:阅读项目源码定位相关组件,找到 CSS 和模板文件中的问题根因,生成修改补丁并写入文件,运行测试验证修复是否生效。整个链路一气呵成,中间几乎没有回头问人类「你确认一下?」。
这正是让人震撼又不安的地方。过去我们用 Copilot 类工具,本质上是「你敲一行,它补一行」;而 Fable 5 展示的是「你给一个意图,它跑完一个工程流程」。自主性的跃升不是渐进的,是台阶式的。
自主性光谱:从补全到接管
理解当前 AI 编程智能体的能力边界,可以放在一条光谱上看:
- 代码补全:你写前半句,它接后半句。决策权完全在你手里。
- 指令执行:你描述任务,它生成一段代码,你审核后手动粘贴。决策权 80% 在你。
- 智能体循环:你给目标,它自己规划步骤、调用工具、迭代执行,只在关键节点等你确认。决策权开始模糊。
- 自主接管:你给意图,它从头跑到尾,修改文件、执行命令、甚至部署——你只看最终结果。决策权大幅倾斜向机器。
Claude Fable 5 在这个光谱上明显偏向第四档。它的「工具调用」能力(读文件、写文件、跑 shell 命令)让循环不再需要人类当中间人。效率飙升的同时,出错的范围和速度也同步飙升。
安全风险不是理论推演,是已经发生的事
Willison 在文章中明确指出:这类智能体的风险不是「将来可能出问题」,而是「现在就已经在出问题」。具体场景包括:
- 误删文件:智能体判断某个文件「不需要」,直接删除,而人类根本没来得及看。
- 过度修改:为了修复一个 CSS bug,它可能顺手重构了三个组件,引入新的兼容性问题。
- 命令注入:智能体构造的 shell 命令如果包含未过滤的用户输入,可能成为安全漏洞的入口。
- 权限溢出:给了它写代码的权限,它可能顺便读了你不想暴露的配置文件中的密钥。
这些问题在传统 IDE 插件模式下几乎不会出现——因为每一步都需要人类手动确认。但当智能体进入自主循环,人类从「操作者」变成了「旁观者」,审查窗口急剧缩小。
实践:给智能体加一道护栏
如果你正在或准备使用高自主性编程智能体,以下是一个可落地的安全约束方案。核心思路:用配置文件显式声明智能体可以做什么、不可以做什么,并在运行时强制执行。
1. 用 YAML 定义智能体权限边界
创建 .agent-policy.yml 放在项目根目录:
# .agent-policy.yml — AI 编程智能体权限策略
version: 1
allowed_tools:
- read_file # 只读:允许浏览任意源码
- search_code # 搜索:允许 grep/ripgrep
- run_tests # 测试:允许执行 pytest/npm test 等
- write_patch # 写补丁:允许生成 diff,但不直接写入文件
blocked_tools:
- delete_file # 禁止删除任何文件
- shell_exec # 禁止自由执行 shell 命令
- modify_config # 禁止修改 CI/CD、环境配置等关键文件
- access_secrets # 禁止读取 .env、密钥文件
# 关键目录保护:智能体不得修改这些路径下的文件
protected_paths:
- "production/**"
- "deploy/**"
- ".env"
- "*.key"
- "*.pem"
# 每次修改的最大文件数上限
max_files_per_action: 3
# 是否要求人类确认后才写入
require_human_approval: true
这个文件可以被智能体框架在启动时读取,作为硬约束。比如你用 Datasette Agent 或类似工具时,可以在调用 LLM 之前注入一段系统提示,把上述策略转化为行为指令。
2. 用 Python 包装一个带审批环节的智能体调用
import os
import yaml
from pathlib import Path
def load_agent_policy(project_root: str = ".") -> dict:
"""加载项目级智能体权限策略"""
policy_path = Path(project_root) / ".agent-policy.yml"
if policy_path.exists():
with open(policy_path) as f:
return yaml.safe_load(f)
# 无策略文件时返回最保守的默认策略
return {
"allowed_tools": ["read_file", "search_code"],
"blocked_tools": ["delete_file", "shell_exec"],
"require_human_approval": True,
}
def build_system_prompt(policy: dict) -> str:
"""根据权限策略生成智能体系统提示"""
allowed = policy.get("allowed_tools", [])
blocked = policy.get("blocked_tools", [])
protected = policy.get("protected_paths", [])
max_files = policy.get("max_files_per_action", 5)
approval = policy.get("require_human_approval", True)
prompt = f"""你是编程助手。你必须严格遵守以下权限策略:
允许使用的工具:{', '.join(allowed)}
禁止使用的工具:{', '.join(blocked)}
禁止修改的路径:{', '.join(protected)}
每次操作最多修改 {max_files} 个文件。
"""
if approval:
prompt += "\n所有文件修改必须先展示 diff 给人类审批,得到明确确认后才可写入。绝对不要自行写入。"
return prompt
# 使用示例
policy = load_agent_policy()
system_prompt = build_system_prompt(policy)
print(system_prompt)
# 将 system_prompt 传入你的 LLM API 调用即可
运行前确保项目根目录有 .agent-policy.yml,或者依赖默认的最保守策略。build_system_prompt 的输出可以直接塞进 Claude / GPT 的 system message 字段。
3. 运行时检查的快速命令
# 在让智能体动手之前,先检查它将要修改的文件是否在保护列表中
grep -f .agent-policy.yml protected_paths_section | \
xargs -I{} sh -c 'echo "检查: {}"; git diff --name-only | grep "{}" && echo "⚠️ 触碰保护路径!" || echo "✅ 安全"'
# 用 git 创建一个智能体工作分支,方便事后审查
git checkout -b agent-fix-scrollbar
# 智能体在这个分支上操作,完成后你用 git diff 审查全部变更
git diff main..agent-fix-scrollbar --stat
采纳建议与权衡清单
高自主性智能体不是不能用,而是不能「裸奔」地用。以下是一份决策清单:
- ✅ 明确权限边界:在项目级配置文件中声明智能体可以调用的工具和禁止触碰的路径,不要依赖口头约定。
- ✅ 强制审批环节:所有文件写入必须经过人类 diff 审查,智能体只生成补丁、不直接落盘。
- ✅ 用分支隔离:智能体的所有操作在独立 git 分支完成,合并前必须人工 review。
- ✅ 限制单次影响范围:设定每次操作最多修改的文件数和代码行数上限。
- ⚠️ 评估项目敏感度:生产配置、密钥文件、部署脚本所在的项目,应该用最保守的策略;实验性项目可以适当放宽。
- ⚠️ 定期复盘智能体行为日志:记录它调用了哪些工具、修改了哪些文件,每周回头看一次,发现异常模式及时收紧策略。
- ❌ 不要给智能体自由 shell 执行权限:这是目前最危险的单点,一个构造不当的命令可以造成不可逆损害。
- ❌ 不要在无策略文件的项目中启动高自主性智能体:默认应该是「只读 + 生成建议」,而不是「读写 + 自行执行」。
Claude Fable 5 的执行力确实让人惊叹——一个滚动条 bug 从描述到修复,它自己跑完了整个工程闭环。但惊叹之后,更值得做的是把这种能力装进一个有刹车、有方向盘、有速度限制的框架里。速度从来不是问题,问题是速度有没有约束。