先限定好能碰的工具范围——Muse-Glimmer-30B 的自主执行才敢放开

文章导读
想让 Muse-Glimmer-30B 这类 30B 级模型自己多跑几步,第一件要定下来的不是提示词,而是它能碰的工具范围。权限收在哪一层,取决于三个可验证的东西:工具白名单是否闭合、写操作有没有可还原的备份点、单次任务的工具种类和调用次数是否封顶。这三道约束先立住,多步自主执行才有放开的空间。
📋 目录
  1. 壹 把可用工具按只读、可写、对外发请求三类分开
  2. 贰 给写操作加前置备份与失败还原点
  3. 叁 限制单次任务的工具种类与总调用次数
  4. 肆 记录模型每次自主决策时看到的上下文
  5. 伍 确认什么信号出现时要收回自主权限
A A

想让 Muse-Glimmer-30B 这类 30B 级模型自己多跑几步,第一件要定下来的不是提示词,而是它能碰的工具范围。权限收在哪一层,取决于三个可验证的东西:工具白名单是否闭合、写操作有没有可还原的备份点、单次任务的工具种类和调用次数是否封顶。这三道约束先立住,多步自主执行才有放开的空间。

自主执行的放开顺序建议按「只读工具 → 本机可写工具 → 对外发请求工具」逐类推进。判断能不能往下一类放,不看模型答得多顺,而看三类证据:权限配置里白名单是否闭合、写操作是否有可验证的还原点、调用日志能否还原每一步的上下文。任一条缺失时,把权限退回上一类,而不是继续加工具。

把可用工具按只读、可写、对外发请求三类分开

第一轮不要同时挂三类工具。适用场景是把 Muse-Glimmer-30B 接进本地仓库或运维脚本;操作动作是先只挂只读工具跑几轮任务,确认不会越界读路径、不会把只读工具当跳板;验证方式是逐条核对日志里的工具名与参数是否都落在白名单内;风险边界是只读放开并不等于安全,凭据文件同样要挡。

  • 只读类:read_file、list_dir、grep 或 ripgrep、git status / git log / git diff、uname、df、进程列表。这类不改状态,但可能读到 .env、密钥文件。
  • 可写类:write_file、apply diff、rm / mv、git add / commit、改配置文件、装依赖、重启本机服务。这类会留下副作用,恢复要靠备份。
  • 对外发请求类:HTTP POST/PUT/DELETE、调用第三方 API、发邮件或 IM 消息、写远端数据库、推代码到远端。影响出了本机就不好收回,建议最后才放。

放开任意一类之后,需要复测的行为项至少这几条:

  1. 参数越界:绝对路径、../、指向白名单外的符号链接。
  2. 失败表现:参数缺失或工具报错时,模型是停下来,还是换一组参数继续试。
  3. 重复调用:同一工具、同一参数在一轮任务里被调用几次。
  4. 串联调用:只读工具的输出是否被直接拼进可写工具或对外请求的参数里。

白名单配置建议显式写 allow 和 deny 两份,root 固定在工作目录:

{
  "tools": {
    "allow": ["read_file", "list_dir", "grep", "git_status", "git_diff"],
    "deny": ["write_file", "shell", "http_request"],
    "root": "/srv/workspace",
    "max_read_bytes": 262144
  },
  "mode": "read_only"
}

只写 allow 时,框架对未列出工具的处理方式需要结合具体实现确认;把 deny 也写出来,可以避免默认放行造成的越权。

给写操作加前置备份与失败还原点

备份要发生在模型动手之前。适用场景是允许 Muse-Glimmer-30B 改文件或执行有副作用的命令;操作动作是任何写工具执行前先固定目标路径清单、按任务 ID 备份、记录文件哈希;验证方式是对比备份目录与原始文件;风险边界是备份目录本身不能被模型的可写工具覆盖或删除。

TASK_ID=$(date +%s)
mkdir -p /srv/backup/$TASK_ID
cp -a /srv/workspace/. /srv/backup/$TASK_ID/snapshot/
git -C /srv/workspace status `--porcelain` > /srv/backup/$TASK_ID/git_state.txt
find /srv/workspace -type f -newer /srv/backup/$TASK_ID/stamp -print > /srv/backup/$TASK_ID/changed.txt

还原触发条件建议收敛成清单,由编排层判断,不交给模型自己决定:

  • 任务结束但校验命令(测试、lint、配置文件解析)返回非零。
  • 模型自报无法继续,或在同一步连续失败。
  • 调用次数触顶、任务超时、人工中止。
  • 写操作的目标落在任务描述范围之外。

还原失败时的兜底:保留备份目录不删,把工作区切成只读模式,把 diff 和 changed.txt 交给人工,不要再让模型自动重试写操作。还原动作本身也要记日志,否则事后分不清是模型改的还是回滚改的。

先限定好能碰的工具范围——Muse-Glimmer-30B 的自主执行才敢放开

限制单次任务的工具种类与总调用次数

上限的设定依据是任务描述里声明的步骤数加一点余量,而不是拍一个很大的数。描述里写三步的活,读类上限给六到八次、写类给一到两次、对外请求类默认零,是接入初期常见的起步值,具体数值需要结合任务复杂度和运行环境确认。

{
  "task_id": "job-001",
  "limits": {
    "read": 8,
    "write": 2,
    "external": 0,
    "total": 12,
    "same_tool_repeat": 2
  }
}

超限后的处理方式:挂起任务,输出已完成步骤和待决策点,等人工确认后再续跑;不要让模型自己放宽上限,也不要允许它改写 limits 字段。日志里需要留下的记录包括任务 ID、工具名、参数摘要(敏感值打码)、调用序号、返回状态、剩余额度和超限事件的处理结果。验证方式是按任务 ID 能还原出完整调用序列,以及每个时刻的剩余额度。

记录模型每次自主决策时看到的上下文

留上下文是为了事后解释模型为什么选了这个工具。适用场景是所有开了自主执行的回合;操作动作是按步写入结构化日志;验证方式是能按任务 ID 和步号重放当时的输入;风险边界是 reason 只是模型自述,不能当成事实依据。

上下文中必须落盘的部分是四类:任务目标、当前步、可用工具列表、上一步返回。

{"task_id":"job-001","step":3,
 "goal":"把 config.yaml 的超时值改为任务描述给定值",
 "available_tools":["read_file","write_file","git_diff"],
 "last_result":{"tool":"read_file","status":"ok","bytes":812},
 "chosen":{"tool":"write_file","args":{"path":"config.yaml"}},
 "reason":"目标文件已读取且内容与任务匹配"}

任务目标、可用工具列表、上一步返回要原样落盘,不要只存一句摘要;同时记录实际执行的参数,方便和模型自述比对。日志按 JSONL 追加写入,一行一步,便于用 grep 或脚本按任务 ID 重放。

确认什么信号出现时要收回自主权限

停止放开的判断依据写在日志和权限层能观察到的信号上,而不是模型的态度上。可观察的信号清单:

  • 调用白名单外的工具,或参数里出现白名单外的路径。
  • 同一路径被写两次以上,或同一工具同一参数被重复调用。
  • 修改范围超出任务描述提到的文件。
  • 对外请求里带上任务中没提到的字段或凭据。
  • 把只读工具的输出直接拼进对外请求的参数。
  • 还原点校验失败,或还原动作本身报错。
  • 同一步骤反复重试且没有新的信息输入。

出现单条越权或越界信号时,先把权限退回上一类,例如从可写退回只读;出现多条,或涉及对外请求的信号时,停掉自主执行并转人工接管。这类判断和降级动作建议写在编排层里,提示词里写「不要越权」不能当作权限边界。每次降级后,结合该任务的调用日志确认触发原因,再决定是否恢复。