AI 决策审计
License 提示
此功能需要 sandbox.decision_audit (ENTERPRISE)。
每个员工 PC 沙箱里的 AI 操作(路径访问、命令执行、PTY 打开)都会被 权限网关 实时裁决,并记录为一条审计事件。这些事件每 30 秒批量上传到 Sira 后端,持久化在 sandbox_decision_events 表,管理员可以通过"AI 决策审计"标签查询、过滤、追溯。
这条流和"平台审计"(
sandbox_audit_log)不同——平台审计记录的是管理员行为(注册沙箱 / 撤销 / 路由分配),决策审计记录的是 AI 在沙箱里实际做了什么。两者通常一起看。
事件结构
| 字段 | 说明 |
|---|---|
event_id | 客户端生成的 16 字节十六进制,UNIQUE,用于至少一次去重 |
source | path / exec / pty |
decision | allow / deny / warn |
path | 涉及的路径(path/exec 类) |
mode | r / w / rw / x |
caller | 调用方(智能体名 / SubAgent 名) |
session_id | 当前会话 |
reason | 决策原因("硬锁拒绝" / "用户允许一次" / "命中永久规则" 等) |
matched_command | 命令策略命中条目(exec 类) |
agent_version | sandrpod-agent 版本 |
host_os / host_arch | 客户端系统信息 |
raw_json | 完整原始事件,JSONB |
occurred_at | 客户端时间 |
received_at | 服务端入库时间 |
organization_id | 通过 sandbox_name 反查解析 |
sandbox_id | 来源沙箱 |
上传链路
sandrpod-agent
│ 每次裁决 → 追加 NDJSON 到 ~/.sandrpod/audit/active.log
│ active.log 满 8 MiB 触发轮转 → audit-YYYYMMDD-HHMMSS.log
│
▼ 每 30 秒 (失败时 exponential backoff,最长 10 分钟)
后端 POST /api/agent-system/sandboxes/audit/decisions/batch
│ Auth: Bearer {corp sandrpod token}
│ + Header X-Sandrpod-Sandbox-Name: {sandbox-name}
│ Body: { version: 1, events: [{...}] } max 1000 / 批
│
▼
后端通过 sandbox_name (全局唯一) 反查所属 organization_id
│ 确认 bearer token 与该 org 的加密 token 匹配 → 防多租户假冒
│
▼
按 event_id 去重 (SELECT-then-INSERT),写入 sandbox_decision_events多租户安全
所有事件入库时都使用 由 sandbox_name 反推得到的 organization_id,绝不使用 bearer token 所属的"默认组织"——避免共享 sandrpod token 时事件被错误归属到其他租户。
管理员查询界面
进入 /agent-system/sandboxes → "AI 决策审计" 标签。
过滤维度
| 维度 | 取值 |
|---|---|
source | path / exec / pty / 全部 |
decision | allow / deny / warn / 全部 |
sandbox_id | 指定某台沙箱 |
since / until | 时间范围 |
limit | 最大 500 条 |
排序与高亮
- 默认按
occurred_at DESC - deny 行红色高亮,并自动排到列表上方——突出"被拒绝的请求"通常更值得关注
行展开
点击任一行可看:
- 完整事件结构(包括
raw_json) - 调用栈摘要(哪个智能体的哪一步触发)
- 跳转到该会话(如果会话还在)
常见排查场景
1. 员工反馈"AI 怎么不读我的文件"
- 过滤:
source=path、decision=deny、sandbox_id=该员工沙箱 - 看
reason列:是不是命中了硬锁?是不是员工以前选过"永久拒绝"? - 解决:让员工跑
sandrpod-tray rules list检查规则,必要时撤掉对应条目
2. 怀疑某个 Skill 行为越界
- 过滤:
caller=skill_xxx_subagent、decision=warn或deny - 查看
path/matched_command列,归纳出该 Skill 实际触碰的资源
3. 突然大量 deny
- 时间范围最近 1 小时,
decision=deny - 看
host_os是否集中在某个 OS——可能是新版硬锁列表上线 - 看
caller是否集中在某个 Agent——可能是某次提示词更新让 AI 进入异常路径
技术细节
| 项 | 值 |
|---|---|
| 上传节奏 | 每 30 秒 |
| 单批最大 | 1000 条事件(HTTP 413 if 超限) |
批 version 字段 | 必须为 1 |
| 客户端缓冲文件 | ~/.sandrpod/audit/active.log,8 MiB 轮转 |
| 失败重试 | 指数退避,最大 10 分钟间隔 |
| 服务端去重 | 通过 event_id UNIQUE 索引保证至少一次 |
API 参考
读取(管理员):
GET /api/agent-system/sandboxes/audit/decisions
?source=path|exec|pty
&decision=allow|deny|warn
&sandbox_id=...
&since=ISO
&until=ISO
&limit=500需要 sandbox.decision_audit License。
写入(仅 sandrpod-agent 调用):
POST /api/agent-system/sandboxes/audit/decisions/batch
Authorization: Bearer <corp sandrpod token>
X-Sandrpod-Sandbox-Name: <sandbox-name>
{ "version": 1, "events": [ {...}, ... ] }