使用文档

从接入到治理:网关端点、策略表达式、内容安全、限流预算与 AI 策略评估的完整参考。

适用于 Aegis 控制面 v0.1+ 与企业代理社区版

快速开始

Aegis 模型网关提供三种接入模式,协议均为 OpenAI 兼容(/v1/chat/completions)与 Anthropic 兼容(/v1/messages,含流式);本地网关另有 /v1/models 模型列表端点。把客户端的 baseURL 指向任一模式端点即可接入,策略、密钥托管与计量在三种模式下完全一致。

三种模式的网关端点

模式端点适用场景认证
桌面拦截(模式一)http://127.0.0.1:8931/v1每位用户在自己电脑运行企业代理,同机 Agent(Claude Code、WorkBuddy 等)直连本机网关;密钥与提示词不出本机。免认证(仅本机可达)
集中式网关(模式二)http://<代理IP>:8931/v1企业代理部署在服务器并监听局域网地址,全公司统一入口,可挂负载均衡 / VIP;多台代理无状态对等。远程调用必须携带 Agent 的 ak_ 密钥(代理本地离线校验)
SaaS 中继(云 Agent)https://<控制面域名>/api/gateway/v1飞书、n8n Cloud 等无代理环境的云 Agent 直接调用云端网关。HTTP Bearer + ak_ 密钥

集中式端点的确切地址以控制台「网关 → 接入端点」中各企业代理上报的地址为准;默认端口 8931,可在代理设置中修改。

ak_ 密钥

  • 在控制台「Agent 管理」中对具体 Agent 点击「签发 API 令牌」获得,前缀 ak_,仅显示一次,请立即保存。
  • 以 HTTP Bearer 方式携带;每个 Agent 一把密钥,可按 Agent 轮换、吊销。
  • 桌面模式(127.0.0.1)无需密钥;集中式与中继模式必须携带,密钥在代理本地离线校验,控制面宕机不影响鉴权。

curl 示例(SaaS 中继)

bash
curl -X POST "https://<控制面域名>/api/gateway/v1/chat/completions" \
  -H "Authorization: Bearer ak_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-chat",
    "messages": [{ "role": "user", "content": "你好,介绍一下你自己" }]
  }'

换成桌面或集中式端点时,仅需替换 URL 并按模式决定是否携带 Authorization 头。模型名以「模型秘钥」中凭证的承接模型为准。

策略引擎

策略由「动作 + 资源 + 主体 + 效果(ALLOW/DENY)+ 可选条件表达式」组成。RBAC 定义“谁可能做什么”,条件表达式(ABAC) 在每次调用时基于实时属性进一步收窄。

9 个动作与执行位置

动作含义求值位置 / 语义
model:invoke调用模型网关每次调用前实时求值(云端中继 + 企业代理本地离线执行);default-deny
mcp:invoke调用 MCP网关 / 企业代理的 MCP 路由(tools/call);与 tool:execute 同时校验
tool:execute执行工具网关 / 企业代理;资源为聚合工具名(服务器名__工具名)
skill:use使用 Skill企业代理本地网关(skill 端点);资源为 Skill ID
mcp:discover发现 MCP企业代理(tools/list 发现阶段)
agent:register注册 Agent控制台;仅 DENY 生效
agent_version:publish发布 Agent 版本控制台;仅 DENY 生效
audit:export导出审计控制台;仅 DENY 生效
policy:override变更策略控制台;仅 DENY 生效
企业代理上没有控制台登录身份,因此只有 EVERYONE 与 AGENT 两类主体的规则在代理生效(AGENT 规则在调用方携带 x-aegis-agent 头或由令牌绑定时匹配);ROLE / USER 主体规则只在控制台生效。

默认拒绝语义

  • 网关:default-deny。没有命中任何 ALLOW 即拒绝(403 policy_denied,reason=default_deny);同一请求命中 DENY 与 ALLOW 时 DENY 优先。
  • 控制台:仅 DENY 生效。管理动作(注册 / 发布 / 导出 / 改策略)默认放行,只有显式 DENY 命中才拦截;ALLOW 规则在控制台不授予任何权限。

放行示例:要让所有 Agent 都能调用 gpt-4o,需要在策略页新建一条规则:动作 model:invoke、 资源 gpt-4o(或 * 表示全部模型)、主体 EVERYONE、效果 ALLOW。 只建 DENY 规则不会放行任何调用——网关默认拒绝,必须显式 ALLOW。

条件表达式完整参考

条件表达式写在规则的「条件」中(JSON { expr: "..." } 的 expr 字段),每次调用时对本次请求的属性求值。 表达式为无副作用沙箱语言:支持字符串 / 数字 / 布尔 / null 字面量、点路径变量、运算符、内置函数与括号; 没有赋值、三元、逗号序列等语法。

可用变量(按动作与时机)

变量含义model:invokemcp / skill / discover控制台动作
model请求的模型名有值空串 ""空串 ""
agent.idAgent ID有值(带 x-aegis-agent 头或令牌绑定时)有值无
agent.typeAgent 类型 SHARED / USER_SIDE / CLOUD有值有值无
tenant.plan租户套餐(COMMUNITY / CLOUD_PRO / ENTERPRISE / HOSTED)有值有值有值
usage.inputTokens输入 token 计数调用前求值,恒为 0恒为 0恒为 0
usage.outputTokens输出 token 计数调用前求值,恒为 0恒为 0恒为 0
subject主体标识agentId,未识别时为 anonymous同左当前用户邮箱
策略在调用上游模型之前求值,此时 token 用量尚未产生,因此 usage.* 恒为 0——不要用 usage 变量做放行判断,token 预算请使用「限流与预算」。未知变量或缺失字段求值为 undefined(安全降级,不会抛错)。

运算符

  • 比较:== != < <= > >=(数字与字符串均可比较;== 为宽松比较,数字与数字字符串可相等,null 与 undefined 互等)
  • 逻辑:&& || !(短路求值)
  • 算术:+ - * / %(+ 可用于字符串拼接)
  • 括号:用 ( ) 分组控制优先级。

内置函数

函数说明
startsWith(a, b)字符串 a 是否以 b 开头
endsWith(a, b)字符串 a 是否以 b 结尾
contains(a, b)字符串包含子串;a 为数组时判断元素存在
matches(a, regex)JavaScript 正则匹配;正则非法时返回 false(不报错)
len(a)字符串 / 数组长度,或对象键数量
lower(a) / upper(a)大小写转换

两种写法完全等价——方法式只是语法糖,接收者路径会成为第一个参数:

expr
startsWith(model, 'gpt')   // 函数式
model.startsWith('gpt')    // 方法式,等价

示例(由浅入深)

  • model == 'gpt-4o' —— 精确匹配某个模型。
  • model.startsWith('gpt') —— 前缀匹配一族模型。
  • model.startsWith('gpt') && tenant.plan == 'ENTERPRISE' —— 组合:仅企业版租户可用 gpt 系。
  • agent.type == 'CLOUD' && !model.startsWith('glm') —— 云 Agent 只允许 glm 系(作 DENY 条件即“云 Agent 禁其他模型”)。
  • matches(model, '^gpt-4o(-[0-9]4)?$') —— 正则精确圈定 gpt-4o 及其日期变体。
  • contains(lower(model), 'gpt') || contains(lower(model), 'glm') —— 函数组合,大小写不敏感地匹配多个关键字。
  • len(model) > 0 && model != 'internal-only' —— 排除特定模型。
  • subject == 'anonymous' —— 识别未携带 Agent 身份的匿名调用(常作 DENY 条件拒绝匿名)。
  • subject == 'zhangsan@corp.com' —— 控制台动作按用户邮箱限制(如仅拒绝某人导出审计)。

DENY 规则:条件不命中即不拦截

条件表达式结果为 false、或变量缺失导致比较不成立时,该规则不命中:DENY 规则不会拦截。 例如 DENY + model:invoke + agent.id == 'agt_xxx' 只拒绝这一个 Agent,其他 Agent 不受此规则影响 (但网关语义下仍需 ALLOW 才放行;控制台语义下无 DENY 命中即放行)。

表达式语法错误:DENY 规则不生效(fail-closed)

表达式解析或求值出错(括号不配、未知函数、运算符写错等)时,该规则按不命中处理—— 也就是说,写错了的 DENY 规则不会拦截任何请求(fail-closed 指的是规则自身被关闭,而不是请求被关闭)。 错误文本会记录在审计 policy_evaluated 事件的 conditionError 字段中,便于排查。 网关语义下请求最终仍因 default-deny 需要 ALLOW 才放行;控制台语义下则直接放行。

expr
model.startsWith('gpt'      // 括号未闭合 → 语法错误
                                  // 该 DENY 规则不生效,conditionError 记入审计
usage.outputTokens > 0          // 合法但恒为 false(调用前求值)→ 规则永不命中

内容安全

内容安全对每次请求的 messages 文本做敏感内容检查(当前仅检查请求内容,不扫描响应)。 云端中继即时生效;企业代理在下次心跳后自动生效;独立模式在代理本地设置中配置。

检查项

  • 手机号(中国大陆号段)
  • 身份证号(18 位,含校验位)
  • 银行卡号
  • IP 地址(IPv4)
  • 敏感词:内置种子词库 + 自定义敏感词(每行一个,匹配不区分大小写)
  • 自定义正则:每行一个 JavaScript 正则表达式,可匹配工号、项目代号等私有模式

两种处理模式

  • BLOCK(阻断):命中即返回 403 content_blocked,响应中仅说明命中的检查类别,不回显敏感内容本身。
  • AUDIT_ONLY(仅审计):放行并在审计中记录命中类别,适合灰度观察自定义规则的误报率。

限流与预算

控制台「设置 → 限流与预算」提供两道闸口,0 表示不限。

配置项语义

配置项语义
rpmPerKey每个 API key(ak_)每分钟允许的请求数。超限返回 429 rate_limited,错误信息含建议重试间隔,客户端应退避重试。
dailyTokenBudget租户每日 token 预算(输入 + 输出合计)。每日零点重置;计数为各网关进程内存实现(非分布式),云端中继与各企业代理分别计数。
budgetHardStop开:预算用尽即 429 budget_exceeded 硬断,当日不再放行;关:不拦截,但首次跨过 80% 时告警一次(审计 budget_threshold 事件)。

429 行为与区分

  • 限流与预算硬断都返回 HTTP 429,但 error.type 不同:rate_limited(每 key 每分钟)与 budget_exceeded(每日预算)。
  • 收到 rate_limited 应等待后重试;收到 budget_exceeded 说明当日预算已用尽,应联系管理员调整预算或等待零点重置。
  • 80% 告警只触发一次(按“首次跨过”判定),用于提前介入,不影响调用。

AI 策略评估

AI 策略评估在每次模型调用前,用所选「判定模型」对 system 提示词 + 最后一条用户消息做结构化判定, 让大模型自身参与治理决策(Jev 式结构化判定)。云端中继即时生效;企业代理在下次心跳后自动生效。

原理:结构化的判定输出

判定 Prompt 要求决策模型只输出一个 JSON 对象:

json
{
  "decision": "allow | block | review",
  "categories": ["类别英文名"],
  "confidence": 0.93,
  "reason": "中文理由,不超过 120 字"
}
  • decision:allow 放行 / block 阻断 / review 仅标记。
  • categories:类别列表,如 none、password_leak、credential_leak、sensitive_data、policy_violation。
  • confidence:0 到 1 的置信度;reason:可读的判定依据。
  • 解析容错:缺失字段给默认值、未知 decision 值按 allow 处理、完全无法解析视为判定失败(见「超时与失败行为」)。

配置项

配置项说明
启用 + 模式BLOCK:decision=block 返回 403(含类别与理由);AUDIT_ONLY:全部放行、只留审计记录。
判定凭证与模型从「模型秘钥」中已测试连接、勾选了可用模型的凭证里选择。
判定 Prompt 模板留空使用内置默认;支持变量 {{system}} {{user}} {{model}} {{agent}} {{plan}}。
判定超时(毫秒)默认 8000ms;超时按失败处理。
failOpen开:超时 / 错误 / 无法解析时放行并记录;关:失败即阻断。

判定计费

每次判定都是一次真实的模型调用,按所选判定模型的价格正常计费(与业务调用同价,计入成本归因)。 请求越频繁、判定模型越贵,治理成本越高——建议为判定选择轻量低价模型。

review 为什么不拦截:review 是设计上的“观察档”——只打标、不阻断,避免对正常办公的误伤。 需要拦截时,判定模型应输出 block,且模式为 BLOCK。

接入任意 OpenAI 兼容决策端点

判定服务不限于内置供应商目录:模型秘钥支持指向任意 OpenAI 兼容端点(如 Jev 等决策服务), 网关会按凭证上保存的 Base URL 直连该端点。接入步骤:

  • 控制台「模型秘钥 → 添加密钥」,服务商选择「自定义(OpenAI 兼容)」;
  • 填入该决策服务的 Base URL 与 API Key(例如 https://jev.example.com/v1);
  • 点击「测试连接」,从上游可用列表中勾选判定要用的模型;
  • 回到「设置 → AI 策略评估」,在「判定模型」下拉中选择该凭证的模型即可。

超时与失败行为

  • 判定超时、上游报错或输出无法解析为 JSON 时,按 failOpen 配置处理:开=放行并记录审计(含 error 与 failOpen 标记);关=阻断。
  • 治理路径(策略/内容安全/限流)与模型调用相互独立:判定服务宕机不影响其他治理层生效。

审计与来源

每一次策略求值都会留下 policy_evaluated 审计事件(含 reason、命中策略名、conditionError); 模型调用、内容命中、限流、预算事件同样入链,形成不可变哈希链,可在控制台「审计」页校验链完整性。

三种事件来源

来源含义来源标识
云端网关SaaS 中继处理的调用与判定source_relay
企业代理连接模式的企业代理(数据面)同步的事件source_edge
独立代理社区版独立模式代理本地产生的事件source_standalone

控制台审计页可按来源筛选,便于区分“云端直接发生”与“边缘同步上报”的事件。

常见问题(FAQ)

1. MCP 调用返回 403 policy_denied,怎么办?

网关与代理对 MCP 采用默认拒绝:mcp:invoke 与 tool:execute 两个动作都需要显式 ALLOW。 到「策略」页为该 Agent(或 EVERYONE)新建 ALLOW 规则,动作选 mcp:invoke 与 tool:execute,资源填聚合工具名 (形如 服务器名__工具名)或 *。仅添加 DENY 规则不会放行任何调用。

2. 为什么我的策略没有生效?

  • 生效时延:云端中继即时生效;企业代理要等下次心跳(默认约 60 秒)同步策略缓存。
  • 语义错位:把 ALLOW 规则当成“只读不动”——网关是 default-deny,没有匹配的 ALLOW 一律 403。
  • 资源名不匹配:大小写敏感,且 MCP 工具要用聚合名(服务器名__工具名)。
  • 条件表达式结果为 false:用审计里的 conditionError 与 reason 定位。

3. 表达式报错了怎么排查?

  • 先看「审计」中对应请求的 policy_evaluated 事件,conditionError 会给出解析错误与位置。
  • 常见错误:括号不闭合、引号不配、把 && 写成 and、调用不存在的函数。
  • matches() 的正则非法不会报错,只是恒为 false——正则规则不命中时先检查正则本身。
  • 注意 fail-closed 语义:表达式报错的 DENY 规则不生效(规则被关闭),修好后才会真正拦截。

4. 判定结果是 review,为什么没有拦截?

这是设计行为:review 只标记、不拦截,避免误伤正常办公。需要拦截时,判定模型应输出 block, 且「AI 策略评估」的模式为 BLOCK(AUDIT_ONLY 模式下 block 也只记录不拦截)。

5. 如何只给某个 Agent 放开某个模型?

新建 ALLOW 规则:动作 model:invoke、资源 该模型名、主体类型选 AGENT、主体填该 Agent 的 ID。 其他 Agent 不受影响(它们仍需自己的 ALLOW)。也可用资源 * + 条件 agent.id == '...' 达到同样效果。

6. 响应缓存与内容安全是什么关系?会不会绕过检查?

不会。每个请求都先经过策略、内容安全与 AI 判定,之后才查响应缓存;命中缓存只跳过上游模型调用 (按 0 token、0 成本计量),所有治理检查照常执行。客户端也可用请求头 x-aegis-no-cache: 1 跳过缓存强制回源。

7. 收到 429,是限流还是预算用完了?

看响应体 error.type:rate_limited 是每 key 每分钟超限,等待错误信息中的间隔后重试即可;budget_exceeded 是租户当日 token 预算用尽(需开启 budgetHardStop 才会硬断),需管理员调高预算或等零点重置。

8. usage.inputTokens 写的条件为什么不命中?

策略在调用上游前求值,此时 token 计数尚未产生,usage 变量恒为 0。想用 token 做预算控制,请使用「限流与预算」的 dailyTokenBudget;想在表达式里限制调用规模,可以用其他变量(如 tenant.plan、model)组合。

9. 桌面模式和集中式模式的认证有什么差别?

桌面模式监听 127.0.0.1,只接受本机连接、免认证,适合个人拦截;集中式模式监听局域网地址,远程调用必须携带 ak_ 密钥,由代理本地离线校验——控制面短时不可用也不影响鉴权与策略执行。

10. 策略修改后多久生效?

云端中继立即生效;企业代理在下次心跳(默认约 60 秒)后生效;独立模式在代理本地配置,保存即生效。 下发到代理的策略缓存为空时(从未同步成功)本地请求会放行并标记 cached_empty,连接恢复后自动收敛。