AGN 网络当前最大的问题是角色越界:Coordinator 角色(尤其是 DeepSeek)会直接修改代码、运行 git apply 等本应由 Executor 执行的操作。根本原因是系统内没有任何角色边界强制机制——角色完全是隐式的(由运行的脚本决定),没有权限检查、没有命令过滤、没有写路径限制。
此外还存在稳定性问题:超时机制无效、崩溃后任务进入死锁状态、跨设备配置不同步等。
本计划目标:
- 建立强制性的角色权限系统
- 提供 Coordinator 执行受控操作的安全通道
- 修复已确认的稳定性漏洞
- 确保跨设备行为一致
Phase 1: Role Guard 基础设施 (P0 — 必须首先完成)
P0-1: 创建角色权限配置文件
新建文件: config/role_permissions.json
定义每个角色的权限边界:
writable_dirs: 允许写入的目录白名单blocked_command_patterns: 禁止的命令正则黑名单utility_request_commands: 需要走 Admin 审批通道的命令
{
"version": 1,
"roles": {
"coordinator": {
"writable_dirs": ["dispatch", "ssot", "memory", "runtime", ".agn_workspace"],
"blocked_command_patterns": [
"^git\\s+(apply|commit|push|cherry-pick|rebase|reset)",
"^sed\\s+-i",
"^codex\\s+exec",
"^rm\\s+-",
"^chmod"
],
"utility_request_commands": ["git clone", "git checkout"]
},
"executor": {
"writable_dirs": ["results", "dispatch/acks", "reports", ".agn_workspace", "runtime"],
"blocked_command_patterns": ["^rm\\s+-rf\\s+/"],
"utility_request_commands": []
},
"reviewer": {
"writable_dirs": ["verdicts", "reports", ".agn_workspace", "runtime"],
"blocked_command_patterns": [
"^git\\s+(apply|commit|push)",
"^codex\\s+exec",
"^rm\\s+-rf"
],
"utility_request_commands": []
},
"admin": {
"writable_dirs": ["*"],
"blocked_command_patterns": [],
"utility_request_commands": []
}
}
}
设计选择: 命令使用黑名单(Coordinator 仍可执行 git status/log/diff、读文件等),目录使用白名单。
P0-2: 创建 Role Guard 模块
新建文件: scripts/role_guard.py (~150 行)
核心函数:
get_current_role() -> str: 从os.environ["AGN_ROLE"]读取,未设置时默认"admin"(向后兼容)check_command(cmd, role) -> (bool, str): 检查命令是否被角色黑名单拦截check_write_path(path, role) -> (bool, str): 检查写路径是否在角色白名单内log_violation(role, action, detail): 写入audit/events.jsonl
关键设计: 缓存配置文件(按 mtime 变更时重新加载),避免每次调用都读磁盘。
P0-3: 在 agent_runner.py 拦截点集成 Role Guard
修改文件: scripts/agent_runner.py
两个拦截点:
run_command()(第 242 行) — 命令执行入口:- 在
subprocess.run()前调用check_command() - 被拦截的命令返回
return_code=126+stderr="ROLE_GUARD_BLOCKED: {reason}" - 记录审计事件
action="role_violation"
- 在
atomic_write_json()(第 114 行) — 文件写入入口:- 调用
check_write_path()验证目标路径 - 被拦截时抛出
PermissionError
- 调用
P0-4: 在启动脚本注入 AGN_ROLE
修改文件: scripts/agn_up.sh
start_proc "agn_coordinator" env AGN_ROLE=coordinator python3 scripts/coordinator_loop.py ...
start_proc "agn_executor" env AGN_ROLE=executor python3 scripts/executor_worker.py ...
start_proc "agn_reviewer" env AGN_ROLE=reviewer python3 scripts/reviewer_worker.py ...
run_agn_task.py 保持 admin 角色(人工直接调用的一次性脚本)。
P0-5: 审计违规日志
Role Guard 拦截的每个操作记录到 audit/events.jsonl:
{
"action": "role_violation",
"role": "coordinator",
"blocked_action": "command",
"command": "git apply some.patch",
"reason": "blocked_command_pattern matched",
"timestamp": "..."
}
复用现有 phase_a/audit.py 的 append_audit() 基础设施。
Phase 2: 安全通道与稳定性修复 (P1)
P1-1: Command Request 审批队列
新建文件: scripts/command_request.py (~100 行)
当 Coordinator 需要执行超出权限的操作(如 git clone)时:
- 写入
dispatch/command_requests/<request_id>.json - Admin 通过 API 审批
- 审批后由系统以
admin角色执行
修改文件: phase_a/main.py — 新增两个端点:
POST /api/command-requests/{id}/approvePOST /api/command-requests/{id}/reject
P1-2: Coordinator 集成 Command Request
修改文件: scripts/coordinator_ingest.py, scripts/coordinator_loop.py
Coordinator 需要 git clone 时,调用 command_request.submit_request() 而非直接执行。Coordinator Loop 在下一个 tick 检查审批状态。
P1-3: 跨设备配置同步
修改文件: config/kirara_state_sync.json, scripts/kirara_state_sync.py
将 config/role_permissions.json 和 config/providers.json 加入 KiraraState 同步路径,确保所有设备使用相同的角色权限配置。
P1-4: 角色配置验证脚本
新建文件: scripts/validation/verify_role_config.py
验证项:JSON schema、正则合法性、目录存在性、跨设备一致性。
新增 Makefile target: verify-role-config
P1-5: 修复无效超时机制
修改文件: scripts/executor_worker.py (第 56-76 行)
问题: 当前 threading.Timer(_TIMEOUT, lambda: None) 不会终止子进程。Timer 触发一个空 lambda,然后通过 timer.is_alive() 间接检测超时——但存在竞态条件。
修复: 改用 deadline 模式:
deadline = time.monotonic() + _EXECUTOR_TASK_TIMEOUT
# ... 执行任务 ...
if time.monotonic() > deadline:
task_timed_out = True
同时确保 run_command() 的内部 timeout_sec 参数与外部超时一致,让 subprocess.run(timeout=...) 实际终止进程。
同样修复 scripts/reviewer_worker.py 中的对应代码。
P1-6: 僵死任务检测与恢复
修改文件: scripts/coordinator_loop.py
问题: Worker 崩溃后,dispatch 文件存在但无 result,任务进入死锁。
修复: 在 process_once() 中增加过期检测:
- dispatch 存在但 result 缺失,且 dispatch 的 mtime 超过
AGN_STALE_DISPATCH_TIMEOUT(默认 30 分钟),标记为失败或重新 dispatch。
P1-7: Provider 降级回退
修改文件: scripts/agent_runner.py
问题: Reviewer provider 不可用时,任务被当作 reject 处理,触发 hallucination lock。基础设施故障不应惩罚任务。
修复: 在 config/providers.json 中增加 fallback_order,provider 失败时尝试下一个。只有所有 provider 都失败才递增 qa_retry_count。
P1-8: Coordinator Loop 错误详情
修改文件: scripts/coordinator_loop.py (第 264 行)
当前 bare except Exception 只递增计数器,异常详情丢失。修复:在 append_audit 调用中包含 str(exc) 截断后的错误信息。
P1-9: 扩展任务状态机
修改文件: phase_a/task_engine.py
当前只有 4 个状态,缺少 halted 和 awaiting_utility。扩展 derive_status() 使其覆盖完整生命周期。增加 VALID_TRANSITIONS 字典文档化合法状态转换。
P1-10: Schema 验证扩展
修改文件: scripts/schema_validate.py
新增 validate_ssot_task() 和 validate_role_permissions() 验证器。
Phase 3: 打磨 (P2)
P2-1: run_agn_task.py Role Binding
修改文件: scripts/run_agn_task.py
允许 JSON 输入包含 role_binding 字段,在调用 executor/reviewer 前动态切换 AGN_ROLE 环境变量。
P2-2: Memory Sync 冲突保留
修改文件: scripts/memory_sync.py
write_conflicts_snapshot() 改为追加合并模式,避免覆盖历史冲突记录。
P2-3: Role Guard 测试
新建文件: tests/test_role_guard.py
测试用例:
- Coordinator 运行
git apply→ 返回 rc=126 - Executor 写
results/→ 成功 - Reviewer 写
dispatch/→ 失败 - Admin 全部成功
- 审计日志包含
role_violation事件
P2-4: 跨设备配置漂移检测
新建文件: scripts/validation/verify_config_drift.py
对比本地与 KiraraState 中的配置版本,报告差异。
实施顺序
Phase 1 (P0):
P0-1 → P0-2 → P0-3 → P0-4 → P0-5 (串行依赖链)
Phase 2 (P1):
P1-5, P1-6, P1-7, P1-8 (可与 Phase 1 并行,互不依赖)
P1-1 → P1-2 (串行依赖)
P1-3, P1-4 (依赖 P0-1)
P1-9 (依赖 P1-1)
P1-10 (依赖 P0-1)
Phase 3 (P2):
P2-1, P2-2 (依赖 P0 完成)
P2-3 (依赖 P0 全部完成)
P2-4 (依赖 P1-3)
关键架构决策
命令黑名单 + 目录白名单: 黑名单防止 Coordinator 执行危险命令,但不阻断其正常的只读操作(git status/log/diff 等)。白名单控制写权限——未列出的目录不可写。
环境变量
AGN_ROLE: 在进程启动时注入,模型无法篡改(模型控制 prompt,不控制进程环境)。防线在 Python 层的role_guard.py,在subprocess.run()之前拦截。文件式 Command Request 队列: 与现有架构一致(文件即消息总线),无需引入新数据库。
向后兼容:
AGN_ROLE未设置时默认admin,现有脚本、测试、手动调用均不受影响。不使用 chmod/assume-unchanged: GPT Codex 建议的方案是脆弱的、OS 依赖的。Role Guard 方案更健壮、可审计、跨平台一致。
验证方式
- Unit test:
pytest tests/test_role_guard.py— 角色拦截逻辑 - Smoke test:
AGN_ROLE=coordinator python3 -c "..."尝试被禁命令,验证 rc=126 - 集成测试:
make agn-smoke启动完整流程,检查audit/events.jsonl无 role_violation - 跨设备: 两台设备运行
make verify-role-config,对比输出一致 - 回归:
make verify-agn-mvp全量验证确保无破坏
涉及的关键文件
| 文件 | 操作 | 用途 |
|---|---|---|
config/role_permissions.json | 新建 | 角色权限定义 |
scripts/role_guard.py | 新建 | 角色检查核心模块 |
scripts/agent_runner.py | 修改 | run_command() 和 atomic_write_json() 注入拦截 |
scripts/agn_up.sh | 修改 | 注入 AGN_ROLE 环境变量 |
scripts/command_request.py | 新建 | Coordinator 受控操作审批 |
phase_a/main.py | 修改 | 新增 command-request 审批 API |
phase_a/task_engine.py | 修改 | 扩展状态机 |
scripts/coordinator_loop.py | 修改 | 僵死检测 + 错误详情 |
scripts/executor_worker.py | 修改 | 修复超时机制 |
scripts/reviewer_worker.py | 修改 | 修复超时机制 |
scripts/memory_sync.py | 修改 | 冲突追加保留 |
scripts/schema_validate.py | 修改 | 新增验证器 |
config/kirara_state_sync.json | 修改 | 增加同步路径 |
tests/test_role_guard.py | 新建 | 角色系统测试 |
scripts/validation/verify_role_config.py | 新建 | 配置验证 |
scripts/validation/verify_config_drift.py | 新建 | 漂移检测 |
下面按“可实现性 + 风险点 + 需要补齐的工程细节”来拆解这份方案。整体评价:方向正确、切入点也对。但如果照文档原样落地,会在若干关键边界上出现“看似有 guard、实际仍能越界”或“误杀导致系统不可用”。重点要补的是:命令规范化、路径规范化、默认 admin、写入面覆盖、审批队列防重放、超时与僵死恢复的判定精度。
0) 这套方案解决的“根因”是否对
对。你描述的越界本质不是模型不听话,而是系统没有把“角色”变成可执行的权限边界。 把边界收敛到两个“真正的能力出口”:
- 命令执行入口
run_command() - 文件写入入口
atomic_write_json()
这是正确的架构抓手:只要系统里所有写与命令都必须经过这两个出口,Role Guard 才会成为强约束。
隐患:现实项目里写入与命令往往不止这两个出口。后面会讲如何做“覆盖面闭合”。
1) P0-1 角色权限 JSON:黑名单命令 + 白名单目录
优点
- 对 Coordinator:允许 read-only 运维命令(git status/diff/log)而禁止改 repo 的命令,是合理的。
- 写目录白名单比“禁止某些目录”更安全,因为默认拒绝。
必须补齐的细节
- 命令匹配必须基于“规范化后的 argv”而不是原始字符串 否则会被轻易绕过,比如:
- 前导空格、换行、
bash -lc "git apply …" env GIT_DIR=... git apply ...python -c 'import os; os.system("git apply ...")'如果check_command()只对字符串做 regex,会出现“看似拦了 git apply,但拦不住通过 shell 包装的 git apply”。
需要明确:系统允许 shell 吗 如果允许
bash -lc,你必须把它视为“任意命令执行”,这会直接把 Role Guard 打穿。最稳的策略是:在run_command()层面规定只接受argv: list[str],并且shell=False。如果当前系统必须用 shell,那么你的 blocked patterns 要升级为“检测 shell 载荷里的二次命令”,难度会上一个数量级。writable_dirs 必须做路径规范化与反符号链接穿透 否则
memory/../repo/file或通过 symlink 指向 repo 的路径都能越权写。 你需要明确写路径检查是基于:
realpath后的绝对路径- 并拒绝写入任何不在允许根目录下的 realpath
- 白名单里出现
"*"的 admin 是可以,但默认 admin 是危险的AGN_ROLE未设置默认 admin 的“向后兼容”会变成绕过 Role Guard 的第一入口:任何启动脚本漏注入、任何新 worker、任何手动运行都自动获得全权限。 更稳的做法是:
- 兼容模式必须显式开启,比如
AGN_COMPAT_ADMIN=1才允许默认 admin - 或者默认降级成 coordinator/readonly,而不是 admin 否则“偶发 misconfig”会直接变成“全权执行”。
- blocked_command_patterns 里
^rm\s+-会误杀rm -i这类低风险,也会漏掉rm\t-rf等变体 命令匹配如果基于 argv,就不需要靠这种粗 regex;可以更精确地拦截:rm+ 任意含-r或-f或路径为/或空等。
2) P0-2 role_guard.py:缓存 mtime 的设计
优点
- mtime reload 能减少开销,合理。
风险点
- mtime 缓存不是一致性保证 跨设备同步、文件系统时间漂移、复制覆盖都可能导致 mtime 行为不如预期。你至少要有:
version字段校验- schema 校验
- 以及加载失败时的“默认拒绝策略” 加载失败不能 fallback 到 admin 或 allow-all,否则一旦配置坏了,系统变成无 guard。
- 审计日志必须是“追加、不可覆盖、写失败也不影响拦截结果” Role Guard 的第一职责是阻止越界,日志是第二职责。不要因为 audit 写失败而放行命令或写入。
3) P0-3 在两个拦截点集成:run_command 与 atomic_write_json
优点
- 选对了位置:命令与写入是最核心的能力出口。
最大的覆盖面风险
你的系统里很可能存在:
- 非 JSON 的写入:
open(..., "w")写文本、写 patch、写临时文件 shutil.move/copy,pathlib.Path.write_text- 直接调用
git本身产生的写(即使没git commit,git checkout也会改工作树) - 第三方工具写 cache
如果这些写入不经过 atomic_write_json(),Coordinator 仍可能越界写 repo。
因此你需要做“覆盖闭合”,至少两条路选一条作为 AGN 标准:
- 标准化所有写入口:强制工程约定,任何写必须走一个统一的
agn_write_*API(json/text/binary)。 - OS 级隔离:每个角色跑在不同用户或容器或 chroot/sandbox 下,仅允许挂载可写目录。这样 Python 层 guard 只是第二道防线。
在不引入 OS 隔离的前提下,P0 至少应扩展到:统一 file write API 覆盖 json/text/bytes,否则这是“看似完成 P0,实际仍可越界”的最大风险。
4) P0-4 注入 AGN_ROLE:环境变量是否足够硬
“模型无法篡改环境变量”这句话在你当前体系里大概率成立,因为模型只产出文本,不直接控制宿主进程环境。
但要注意两点:
- 如果 Coordinator 能执行
run_command(),它就能启动子进程并传 env。 所以你的get_current_role()不应只看os.environ["AGN_ROLE"],还应由父进程在启动时写一个只读的 role 事实来源,例如:
- 启动参数
--role=coordinator - 或运行目录下一个仅宿主能写的
runtime/role.lock否则 Coordinator 通过 shell/子进程可能伪造 role。
- 对每个 worker 进程来说,role 应该是“不可变”的。 运行中变更 role 是高风险操作,除非经过 admin 通道。
5) P1-1/P1-2 审批队列:是可行的,但需要“防重放 + 幂等 + 限定执行上下文”
审批队列是正确方向,因为它把“偶尔需要的越权操作”从隐性越界变成显式治理。
必须补齐的工程要点:
- 请求必须绑定执行上下文
例如
git clone应该绑定:
- 允许的目标目录(必须在 admin 允许的某个 sandbox 下)
- 允许的远端 URL 域名白名单或 repo 白名单
- 允许的分支/commit(如适用)
否则 Coordinator 可以提交“看似合理的 clone”,实际拉恶意 repo 或覆盖敏感路径。
审批必须是一次性的、不可重复执行的 需要 request_id + 状态机(pending/approved/executed/rejected/expired),并且 executed 后拒绝再次执行。
执行器必须用“固定模板”执行 不要让 Coordinator 提交任意字符串命令让 admin 执行。审批对象应该是结构化字段(operation + args),由系统渲染成命令。 否则你等于建了一个“请 admin 帮我执行任意命令”的接口。
6) P1-5 超时修复:思路对,但文档里的“deadline 模式”不够
你指出的问题是对的:Timer 不杀子进程等于没超时。
但用 deadline 做“事后标记 timed_out”仍然不够,关键是要确保子进程被终止,并且不会留下孤儿进程。你需要明确:
subprocess.run(timeout=...)会抛 TimeoutExpired,并杀掉子进程,但不一定杀掉子进程树- 如果 worker 会启动 shell 或工具再 fork,可能留下孙进程
最稳的是:
- 每次 run_command 创建独立进程组
- 超时后终止进程组
- 并把超时作为明确错误码回写结果
否则“超时”只是在逻辑上超时,系统资源仍被吃掉,依然会死锁。
7) P1-6 僵死任务检测:mtime 判定是必要但不充分
mtime 超过 30 分钟就判死,有两个误判风险:
- 长任务(比如大仓库分析/编译)可能 legitimately > 30 分钟
- worker 仍在跑但没有写 result(比如输出被卡住)会被当作死
更稳的僵死判定应至少加入一个“心跳或租约”概念:
- worker 领取任务时写
dispatch/leases/<task_id>.json,包含 last_seen - worker 每 N 秒续约
- coordinator 发现 lease 过期才重派
这样不会把“慢但活着”当死,也能精准检测“死但没写 result”。
8) P1-7 Provider fallback:正确,但要避免“静默降级造成语义漂移”
Fallback 机制能提升可用性,但要在审计与结果语义上做到可解释:
- 每次 fallback 必须记录:原 provider、失败原因、最终 provider
- 对 reviewer 这种角色,fallback 可能造成“审查标准变化” 因此在 verdict 里要写明:由哪个 provider 给出结论,以免你误以为是同一标准。
另外,“只有所有 provider 都失败才递增 qa_retry_count”这点是对的:基础设施失败不该惩罚任务。
9) P1-9 状态机扩展:你需要的是“显式等待态 + 人工介入态”
awaiting_utility 与 halted 都是必需的,因为它们对应:
- awaiting_utility:等待 admin 批准队列,不应算失败
- halted:系统性故障或安全风险触发停机,不允许自动重试
这里关键是要把合法转移写死,并让 coordinator loop 严格执行,否则状态机会被模型输出“带着跑偏”。
10) 验证方式:现有验证还缺两类“绕过测试”
你列的单元测试是必要但不足。必须补两类测试,否则 Role Guard 容易被绕过:
shell 包装绕过测试 例如 coordinator 尝试通过
bash -lc或python -c os.system间接执行被禁命令,必须被挡住,或者系统明确禁止 shell。路径穿透与 symlink 绕过测试
memory/../repo/filememory/link_to_repo/file都必须被拒绝。
- 默认 admin 的回归测试
任何未设置
AGN_ROLE的进程应在 CI 中直接失败或进入只读模式。否则以后你一加新脚本就漏注入,guard 形同虚设。
11) 我建议你把这份方案“升格”为两条并行防线
为了真正把越界问题终结,建议把架构目标写成:
第一道强制边界:OS/运行时隔离 每个角色跑在独立用户或容器,挂载不同可写目录。Coordinator 根本看不见 repo 的写权限。 这样即使 Python guard 有漏洞,仍无法写。
第二道边界:Role Guard 拦截 + 审计 用于更细粒度的策略控制与审计记录。
如果你短期不做 OS 隔离,那就必须把“所有写入都走统一 API”做到位,形成覆盖闭合,否则 P0 很容易变成“心理安全感”。
12) 最关键的修改建议清单
AGN_ROLE默认不再是 admin。兼容模式必须显式开启。run_command()强制shell=False,只接受 argv;否则必须把 shell 视为高危并直接禁用给非 admin。- 命令检查基于 argv 语义匹配,不基于原始字符串 regex。
- 写路径检查基于 realpath 绝对路径,并拒绝 symlink 穿透与
..。 - 扩展写入拦截覆盖:json/text/binary 的统一写 API,或 OS 隔离二选一。
- Command Request 只允许结构化操作,不允许任意命令字符串;审批绑定目录与白名单资源。
- 超时必须能杀进程组,不能只做 deadline 标记。
- 僵死恢复用 lease/heartbeat,不只用 mtime。
- fallback 必须审计并在结果中注明实际 provider。
- 增加绕过测试:shell 包装、symlink、默认 role 漏注入。