跳转到内容

模块 XVI —— 语音与实时 agent

模块 XVI 治理对话式与实时 agent。它是一个观察与治理平面:它不重新实现语音 SDK (Realtime API、WebRTC、ASR 或 TTS),也从不自己开启媒体流。它决定谁可以开启一个语音会话、 使用哪个模型和提供商、在哪条策略下,并跟踪该会话的元数据——绝不跟踪其内容。

开启一个语音接口被视为一个特权操作,而非一项自由操作。策略是默认 DENY: 一个没有任何允许策略的会话会被拒绝。一次开启是两阶段的,并通过 审批门进行 human-in-the-loop 门控;它绑定到一个 plan_hash, 因此一次审批不能被静默升级为一个更强的模型(anti-TOCTOU),归属于真实主体审计 (绝非 system),并以仅追加方式留存证据。模块本身从不调用提供商—— 执行经由一个单独的分发接缝离开。

另一半是观察:本模块只跟踪会话元数据——派生状态(live/idle/ended,在读取时由活动新近度计算, 不存储生命周期列)、轮次计数、时长、延迟(来自真实样本的诚实平均值与最大值),以及 BCP-47 语言。 据此它提出治理 finding:当遥测命名了一个没有任何策略允许的 agent/模型/提供商时提出一条策略违规, 当延迟越过某条策略 SLA 时提出一条延迟降级 finding,以及当尝试开启而没有配置任何门时提出一条 未治理开启 finding——该缺口被暴露,且该开启仍被拒绝。

本模块在共享数据模型中声明了三个实体:

实体 可变性 用途
session 可变(upsert) 会话元数据;零内容
policy 可变 治理声明——谁可以用哪个模型/提供商开启(默认 DENY)
decision 仅追加 开启/关闭决策的不可变 ledger

一条策略按 agent、允许的模型和允许的提供商匹配(各项可为具体值或通配符),并带有可选的 会话分钟数与延迟 SLA 边界。没有匹配策略即表示 DENY。 decision ledger 记录每个 open_request、 open 和 close,连同其策略裁决、门状态和结果状态。读取访问需要 viewer 角色及以上; 声明一条策略和开启一个会话是管理性的、租户级的、受审计的操作。这些模块路由发布在 独立的 beta 模块路由参考中,而非稳定核心契约中—— 它们的字段级形状存在于产品的类型化接口中。 此处没有金额;FinOps(模块 XI)拥有成本。

本模块拥有一个 deny-closed 的摄取接缝——它自己的 voice.telemetry.observed 事件—— 一个进程内探针将通过它馈送会话元数据。该传输层在构造上即为最小数据:遥测解析器携带一份 允许列表,并在看到一个被禁止的键时拒绝整个事件,因此任何音频、文字记录文本、ASR/TTS 文本、 prompt/响应内容或说话者 PII 都绝不会被持久化。唯一保留的文字记录信号是一个外部文字记录定位符的 单向哈希——证明文字记录存在,而绝非文字记录本身。治理 finding 以 finding.reported 的形式在提交之后带着哈希化的细节发出。

受治理的开启以 live 方式分发。运营者预配语音 dispatcher 后,获批开启会铸造一个服务端临时凭据,并返回它和连接坐标。语音与轮次检测由运营者的会话配置提供;已配置模型覆盖请求模型。未配置模型时,dispatcher 使用租户策略允许的请求模型。提供商主密钥绝不离开服务器。未预配时,分发接缝采用 deny-closed:获批开启被如实记录为“已声明,未开启”,而不伪造成功。

用 olivares modules on voice 启用现有模块。运行模块集合改变时,引擎保存选择并重启一次;olivares modules ls 显示是否运行。模块规范要求 voice 依赖 FinOps 和 governance。关闭 voice 会保留策略、会话元数据和决策账本。

dispatcher 在引擎主机上通过 OLIVARES_VOICE_DISPATCH_CONFIG 预配,其值为运营者拥有的 JSON 文件的绝对路径。仅允许引擎账户读取该文件;提供商主密钥属于该文件,不得放入 CLI 参数、策略行或客户端连接包。OpenAI adapter 的格式如下:

{
"providers": [
{"ref": "openai", "kind": "openai", "api_key": "<server-held provider key>"}
],
"policies": [
{
"agent_ref": "contact-agent",
"provider_ref": "openai",
"model": "<your permitted realtime model>",
"voice": "marin",
"max_duration_seconds": 60
}
]
}

为引擎服务设置环境变量并重启。提供了不可读或无效的 JSON 文件会使启动失败。没有 dispatcher 配置时,保持“已声明,未开启”行为。运营者文件选择 provider adapter 和会话设置;租户 voice 策略另行授权请求的 agent、模型和提供商。两者使用相同的模型与提供商引用。

用 olivares login 登录后,声明策略并请求批准:

终端窗口
olivares voice policies set --agent-ref contact-agent \
--allowed-model-ref '<your permitted realtime model>' --allowed-provider-ref openai \
--max-session-minutes 1 --max-latency-ms 300
olivares voice sessions open --session-ref contact-1 --agent-ref contact-agent \
--model-ref '<your permitted realtime model>' --provider-ref openai -o json

首次请求返回 op_status: requested、approval_ref 和 CLI 退出码 7,不打开媒体连接,也不铸造提供商凭据。请所需的独立批准者通过 governance 批准页面,或 olivares governance approvals approve <approval-ref> 批准该引用。默认本地批准桥接的新请求中,请求者不能批准自己的请求,包括使用同一账户的其他凭据。用 --approval-ref <approval-ref> 重复相同的开启请求。策略拒绝或批准仍待处理时返回 403 和 CLI 退出码 3;adapter 失败返回 502。预算和 estate-stop 检查仍适用。

成功的已配置请求返回 op_status: dispatched。其 dispatch_ref 是 JSON 字符串,包含短期 credential、connect 坐标、transport、模型和到期时间。将该响应视为凭据,不要贴入报告或日志。对于 OpenAI,客户端使用短期凭据,在返回的 connect URL 交换 SDP offer,随后拥有 WebRTC 媒体连接。仅铸造凭据不能证明媒体已连接。决策账本保留的是含凭据连接包的 SHA-256 指纹,而非连接凭据。旧存储包也在读取时指纹化;现有仅追加行不重写。普通 provider handle 保留原值。

检查保留的元数据和决策:

终端窗口
olivares voice sessions get contact-1 -o json
olivares voice sessions decisions contact-1 -o json
olivares voice policies ls -o json

引擎重启前后使用相同数据目录。策略和仅追加决策在重启后,以及关闭再开启 voice 后,仍可用;提供商凭据仍须单独预配。上述 JSON 命令使用与 API 相同的租户限定 /v1/m/voice 路由。