审计
这页写给用管理台的管理员:顶栏「审计」页上的数字从哪来、每一块该怎么读,以及其他页面的变更记录分别放在哪里。
「审计」页看的是员工端上报的事件:工具调用、权限确认、策略有没有生效、护栏拦了什么。它回答「客户端实际发生了什么」。管理员在管理台里的操作(改策略、吊销设备……)不在这一页,而是记在各自页面的变更记录里,见各处的审计在哪里看。
事件只有计数和枚举类的字段,不含代码、对话、命令参数。要看会话原文,用轨迹,见轨迹采集与可观测。
联动:事件从哪里来
| 员工端发生了什么 | 什么时候到达管理台 | 上报失败时 | 员工看到什么 |
|---|---|---|---|
配好 backend.url 并登录过 | 自动上报,每攒满 100 条或每 15 秒发一批 | 失败的批次落盘到 ~/.sid-code/telemetry/,下次启动重放,每条最多重试 8 次,24 小时后清掉 | 无 |
| 设备凭据失效或被吊销(401) | 不再到达 | 这一批直接丢弃,不落盘;凭据修好后恢复上报 | 客户端日志里记一条警告,提示重新 /login,每次凭据失效只记一次 |
开了 no-telemetry 或 essential-traffic | 不上报 | 上个会话留在磁盘上的事件也不重放,原样留盘 | 无 |
| 没登录、没有设备凭据 | 不上报 | —— | 无,客户端不报错 |
几个细节:
- 鉴权:上报端点是
POST /api/v1/events,必须带设备凭据。归属(设备、组织、团队、用户)全部取自凭据,不信任请求体里的同名字段,所以这条通道是强归因。 - 关闭方式:员工设
SID_CODE_DISABLE_TELEMETRY=1,或在settings.json里设analytics.privacy_level。关掉之后管理台看不到这台设备的任何事件;如果它还在上传轨迹,会在页面上表现为「有轨迹零事件」(见隐私与数据流向)。 - 采样:Flag
event_sampling_config可以按事件名采样,被采掉的事件不会上报,见 Feature Flag。 - 重复投递会去重:服务端按「设备 + 事件名 + 发生时间 + metadata」算指纹,同一条事件重放多次只入库一次。
出处:packages/core/src/analytics/exporters/http.ts、disk-cache.ts、sink.ts;agent-backend: backend/app/modules/event/router/ingest.py、service/guard.py。
服务端的上限
| 情况 | 结果 |
|---|---|
| 没有设备凭据,或凭据无效、已吊销 | 401。先判鉴权,再看请求体 |
| 请求体超过 2 MiB | 413,整批拒收 |
| 一批超过 500 条 | 413,整批拒收 |
请求体不是 JSON,或没有 events 数组 | 400 |
| 单条事件有问题(名字不在白名单、字段形状不对) | 仍是 202。只有这一条被拒并计数,同批其他事件照常入库 |
| metadata 超过 64 个键 | 这一条被拒(metadata_too_many_keys) |
| 某个字符串值超过 1024 个字符 | 截断,不拒绝。截到 1024 字符,并在这条 metadata 里加 _truncated: true |
202 的响应体里有 accepted(入库)、deduped(重复跳过)、rejected(被拒)三个数,加起来等于请求里的条数。
事件名白名单
服务端只接受下面这些事件名,白名单外的一律不入库,记为被拒。这份名单和客户端 EVENT_NAMES 一致:两个仓库各有一份快照,agent-backend 的 tests/test_event_names_contract.py 要求两边完全相等,多一个少一个都会让测试失败。
| 分组 | 事件名 | 什么时候发 |
|---|---|---|
| 工具 | tool_call | 模型发起一次工具调用 |
tool_success | 工具调用成功 | |
tool_failure | 工具调用失败 | |
| 权限 | permission_prompt | 弹出权限确认 |
permission_allow | 一次调用被放行(规则放行或用户同意) | |
permission_deny | 一次调用被拒绝(规则拒绝或用户拒绝) | |
| 上下文 | context_compact | 执行了一次上下文压缩 |
context_compact_skipped | 本该压缩但跳过了,附带原因 | |
context_assembled | 每轮组装上下文时,记录用了多少 token、压缩档位 | |
| 命令 | command_invoke | 执行了一个斜杠命令 |
command_rejected | 斜杠命令被拒,附带原因 | |
| 错误 | error_occurred | 出现一次错误,附带错误类别和来源子系统 |
| 记忆 | memory_index_health | 记忆目录的健康度:文件数、索引条目数、孤立文件数 |
memory_inject | 记忆索引被注入到上下文 | |
memory_read | 用读文件工具读到了记忆文件 | |
memory_guard | 记忆相关的防护被触发 | |
| 策略与护栏 | policy_enforced | 加载企业策略一次,附带来源和结果(applied、none、unchanged、cache_fallback、error) |
guardrail_triggered | 一层护栏拦了东西,附带是真报、疑似误报还是未判定 | |
| 插件 | tool_invoked | 调用了企业市场安装的插件里的工具,附带插件名、组件、工具名 |
plugin_installed | 从企业市场装好一个插件,附带插件名和版本。v0.1.610 之后的客户端才上报,更早的版本装了插件这里也看不到 | |
| 启动 | startup_timing | 启动耗时。它不在客户端 EVENT_NAMES 常量表里,但在快照和白名单里都有 |
客户端加了新事件而服务端没同步时,新事件会在这一页的「被拒的事件名」里出现,原因是 unknown_event_name。
在管理台里操作
页面在顶栏「审计」。从「设备」页某一行点「审计」进来时,页面只看这台设备,顶部出现黄色提示「正在看设备 xxx」,点「清除」回到全部设备。
页面顶部的说明框写着「事件通道要设备凭据,和轨迹用 session_id 值 join」,下面逐块说明。
四个统计卡
| 卡片 | 怎么读 |
|---|---|
| 近 7 天事件 | 按到达时间统计,含补传。为 0 说明事件通道没接上 |
| 有轨迹零事件 | 有轨迹但一条事件都没有的会话数。大于 0 说明这些设备在上传轨迹,事件却没报上来,常见原因是员工关了遥测或没登录 |
| 有事件无轨迹 | 有事件但没有轨迹的会话数。事件先到、轨迹会话结束才上传,所以进行中的会话这样是正常的;持续存在才说明轨迹积压或进程崩溃 |
| rejected 累计 | 被拒事件的累计条数。正常应为 0 |
被拒的事件名
只有「rejected 累计」大于 0 时才出现。列是「名字」「原因」「次数」「最近一次」。原因的取值:
| 原因 | 含义 | 怎么处理 |
|---|---|---|
unknown_event_name | 事件名不在白名单里 | 多半是客户端加了新事件、服务端没同步。升级企业后端 |
bad_shape | 事件不是对象、没有事件名,或时间戳不是数字 | 客户端 bug,带着名字和次数反馈给 sid-code |
metadata_not_dict | metadata 不是对象 | 同上 |
metadata_too_many_keys | metadata 超过 64 个键 | 同上 |
metadata_nested_value | metadata 里出现了嵌套对象、数组或空值 | 同上 |
bad_plugin_fields | tool_invoked 的插件名不合规(小写字母数字开头,最长 64),或组件不是 mcp / skill | 检查插件在市场里登记的名字 |
按天到达量(received_at)
近 7 天每天到达的事件数,按到达日分桶。补传的事件算在到达那天,不算在发生那天。哪几天服务停了,柱子上会留下缺口;页面不自动推断停机窗口,要对照发版记录看。
插件调用(近 30 天)
只统计企业市场装的插件,数据来自 tool_invoked,不含调用参数。列是「插件」「插件合计」「人」「调用次数」「最近一次」。没登录的设备合并成一行「未登录设备(合计)」。
后端接口最多支持 90 天窗口,页面固定看 30 天。窗口内事件超过 5 万条时,卡片顶部会提示只统计了最新的那部分,数字是下限。
策略与护栏是不是在拦东西
近 7 天按设备汇总。每一列:
| 列 | 含义 |
|---|---|
| 设备 | 点击跳到设备页 |
| org / team | 设备所属组织和团队 |
| policy applied | 启动或轮询时,把一份策略真正应用到了运行时的次数 |
| policy none/error | 其余所有结果:没有策略、拉取出错、用了缓存、策略没变(304)。大于 0 时标黄 |
| 护栏真报 | 护栏拦截被确认是对的 |
| 护栏误报 | 护栏拦截疑似拦错了 |
| 护栏未判定 | 还判断不了对错的拦截 |
| permission_deny | 被权限规则或用户拒绝的调用次数 |
| 最后上报 | 这台设备最近一次事件的到达时间 |
| 下钻 | 点「事件」看这台设备的事件明细 |
怎么读:
- 只有
policy none/error、没有policy applied:这台设备一直没拿到策略。查它是否登录、backend.url是否配对、策略是否命中它(策略页的「预览命中」)。 - 两列都有:多数是交互会话的定期轮询,策略没变时回 304,计入 none/error,属于正常。看比例,不看有没有。
- 展开一行可以看到「误报 / (真报 + 误报)」的算式。未判定的条数不进分母。页面故意不给「误报率」百分比。
这里的数字来自上报数据,受采样和 24 小时磁盘缓存窗口影响。
会话覆盖(事件与轨迹的 join)
最近 50 个有事件的会话,按到达时间倒序。事件和轨迹用 session_id 的值对上,不是外键。
右上角两个开关「只看有轨迹零事件」「只看有事件无轨迹」用来筛出上面两张统计卡对应的会话。列里有「有轨迹」「事件条数」,以及 policy_enforced、guardrail_triggered、context_assembled 三类事件的条数。session_id 有轨迹时可以点进轨迹详情;「下钻」列点「事件」看明细。
事件明细(下钻终点)
从上面任一处点「事件」后出现,最多 200 条,点「关闭」收起。
| 列 | 含义 |
|---|---|
| 发生 (client_ts) | 员工机器上的时间,不做时钟校正 |
| 到达 (received_at) | 服务端收到的时间 |
| 到达延迟 | 两者之差。超过 1 分钟标黄,多半是落盘后补传 |
| 事件名 | —— |
| metadata | 点开看全部字段,原样展示 |
员工机器时钟不准时,到达延迟会偏大或为 0,按到达时间排查。
各处的审计在哪里看
管理员在管理台上的操作,各自记在对应页面里,不进「审计」页。
| 要查什么 | 在哪个页面 | 点什么 |
|---|---|---|
| 策略的变更 | 「策略」 | 每行「审计」看单份;右上角「全部审计」看全部 |
| 预算的变更 | 「成本」页的「预算(超限开关)」卡片 | 每行「审计」;卡片右上角「全部审计」 |
| Flag 的变更 | 「Flag」 | 每行「审计」;右上角「全部审计」 |
| 插件上架、发布、下架等 | 「市场」 | 每行「审计」;或「变更审计」页签 |
| CI 上传凭据的签发与吊销 | 「市场」页的「CI 上传凭据」页签 | 页签下方的「凭据审计」表 |
| 用户登录、角色变更、吊销 | 「用户」 | 页面下方的「登录审计」卡片;每行「登录记录」只看这个人 |
| 飞书文档的委托调用 | 「飞书授权」 | 「调用审计」卡片 |
| 设备的调整归属与吊销 | 「设备」 | 每行「变更记录」 |
| 组织与团队的增删改 | 「组织与团队」 | 页面下方的「变更审计(最近 100 条)」卡片 |
| 某台设备上报的事件 | 「设备」 | 每行「审计」,跳到本页并只看这台设备 |
遥控(bridge)的断开等操作在服务端有审计记录,但目前管理台没有查看它的界面。
用户的详细说明见用户与登录,设备见设备与注册码,策略见策略,预算和成本见成本。
能力边界(如实说)
1. 事件不含内容。 metadata 只有计数、枚举、工具名这一类字段,没有命令参数、文件内容、对话。MCP 工具名在普通事件里会被脱敏成通用名,只有企业市场插件的 tool_invoked 带插件名和工具名。要看「具体做了什么」,用轨迹。
2. 员工可以关掉上报。 开 no-telemetry 或 essential-traffic 之后,管理台看不到这台设备的事件。这一页能发现的只是「有轨迹零事件」这种间接信号;如果员工同时没开轨迹上传,就什么也看不到。
3. 会丢。 磁盘缓存只保留 24 小时,企业后端停机超过 24 小时,那段时间的事件永久丢失。401 的批次直接丢弃,不落盘。
4. 长字符串会被截断。 单个值超过 1024 个字符截断,事件本身保留,带 _truncated: true。
5. 白名单是 fail-closed。 客户端先升级、服务端没跟上时,新事件全部被拒,只在「被拒的事件名」里留下计数,原始事件不会补回来。
6. 时间是员工机器的时间。 发生时间不做时钟校正。
7. 采样会让数字变小。 用 Flag 给某个事件配了采样,这一页上的条数就是采样后的。
常见问题
审计页看不到某台设备
按顺序查:
- 这台设备有没有登录过、凭据有没有被吊销。没有有效设备凭据就不上报,客户端也不报错。员工端执行
sid-code auth status --verify看。 - 员工有没有开
SID_CODE_DISABLE_TELEMETRY=1或essential-traffic。 - 员工的
backend.url是不是指向这台企业后端。 - 开了「只看有轨迹零事件」后,这台设备的会话是否出现在列表里。出现说明轨迹通、事件不通,基本可以确定是上面第 1 或第 2 条。
「近 7 天事件」突然变成 0
事件通道整体断了。先看服务是否正常、设备凭据校验是否异常,再看是否有人用 Flag sink_killswitch 关掉了 sid-backend。
「被拒的事件名」里出现 unknown_event_name
客户端比服务端新。升级企业后端,新事件从升级后开始入库,之前被拒的不会补回来。
policy none/error 很高,是不是策略没生效
不一定。交互会话每 30 分钟左右轮询一次策略,策略没变时也计入这一列。只有这台设备完全没有 policy applied 时才需要排查。
事件明细里到达延迟很大
多半是员工机器当时离线或服务端不可用,事件落盘后在下次启动时补传。员工机器时钟不准也会造成假象。