# Vivix Streaming Avatar 参数调查与业务映射（2026-10-06）

来源：docs.vivix.ai 全文（`llms-full.txt`）+ Create Session OpenAPI schema + 本工作区 `GET /v1/models` 实测。
业务需求：`docs/live-rooms-progress-2026-10-05.md`（单人间：姜伊夏厨房 / 申智安书房；双人间：沙发夜景）。
价格：`docs/live-component-plan-2026-09-24.md` §11（Starter $19/月，并发 2，单会话 30 min，$0.32/min/会话）。

## 0. 一句话模型

`vivix-a1-stream` = **一张起始图 → 一个会说话会动的人**。一个会话里可以注册多个 avatar / 多张图，但**同一时刻只渲染一个人**（`session.active_avatar_id`）。文档明确要求起始图"眼睛和嘴清晰、没有其他人遮脸"。所以：

- 单人直播 = 一个会话，完全够用，且功能最全。
- 双人同画面 = A1 做不到真·同帧；只能两路会话合成，或等 W 系列（`vivix-w1-stream`，私测，**本 key 未开通**：models 只返回 `vivix-a1` / `vivix-a1-stream`）。

A1 有三种"喂内容"的方式，决定了延迟和控制权：

| 方式 | 谁出词 | 谁出声 | 延迟（实测/文档） | 适合 |
|---|---|---|---|---|
| 对话模式（`conversation.item.create` + `response.create`） | Vivix LLM 或 `llm_config` 指到我们的 OpenAI 兼容端点 | Vivix TTS（内置/克隆/ElevenLabs/自带 key） | 最低；`tag_audio_enabled` 先"嗯"一声 | 单人间接粉丝语音/文字 |
| 脚本模式（`response.script.vocal.type = speech`） | 我们（Letta agent） | Vivix TTS | 2.2 s（实测） | 我们现有大脑 + Vivix 嘴 |
| 脚本模式（`vocal.type = audio`，base64/URL） | 我们 | 我们（MiniMax 克隆音色） | 2.8–4.5 s（实测，现网方案） | 音色必须是我们的 |
| 纯渲染（`a2a_config.enable_a2a = true, provider = passthrough`） | 我们 | 我们，**持续音频推进 RTC 房间** | 接近实时 | 需要服务端 Agora 推流 SDK，重 |

## 1. Create Session 参数逐项（定义 → 业务价值 → 我们怎么用）

### 1.1 顶层

| 参数 | 定义 | 业务价值 | 用法 |
|---|---|---|---|
| `model` | `vivix-a1-stream`；可带 tag `name:1.0.7` / `name:latest` 锁版本 | 锁版本避免模型升级改变动作风格 | 上线后锁具体 tag（需 models 列表返回带 tag 的条目） |
| `idempotency_key` | 重试建会话不重复开（不重复计费） | 429/5xx 重试安全 | 用 `session_id + host` |
| `session.mode` | 只有 `video_avatar` | — | 省略 |
| `session.active_avatar_id` / `source_image_id` | 开场渲染谁、用哪张图 | 多 avatar/多图时的开场选择 | 单会话切镜模式用 |
| `output.aspect_ratio` | `9:16` / `1:1` / `16:9`，须和起始图一致 | 竖屏=手机直播间/TikTok；双人合成时两张 9:16 拼成接近 16:9 | 单人 9:16；双人每路 9:16 |
| `output.resolution` | `480p` / `720p` | 480p 省带宽但脸糊；720p 为上限 | 720p |
| `max_duration_seconds` | 会话上限，默认 1200，受套餐上限（Starter 30 min）；最小 4 | 控成本；到期即断，**必须续期** | 我们已有到期前先关后开续期逻辑（约 5 s 黑场）。Pro 60 min / Max 不限 |
| `auto_close.disconnected_timeout_seconds` | 控制 WS 全断多久自动关（10–3600，0 关闭） | 我们服务崩了不会一直烧钱 | 60（已设） |
| `auto_close.interaction_idle_timeout_seconds` | 多久没"被接受的交互"自动关（30–3600，0 关闭）。**avatar 自己说话不算交互**，只有 `conversation`/`response.create`/`session.update`/用户说话算 | 讲故事时我们每句都发 `response.create`，所以会刷新；但中间长动作/静默会误关 | 直播场景设 **0** |
| `recording_mode` | `on` / `off` | 关掉省存储/隐私；要回放再开 | `off` |
| `delivery.media.transport` | `trtc`（默认）/ `agora`；凭证由 Vivix 签发 | 不用自己的 RTC 账号；**但 Agora App 是 Vivix 的，我们配不了 Media Push（旁路 RTMP）** → 推 TikTok 必须自己拉流再 ffmpeg 推 | agora（已用） |

### 1.2 `avatars[]`（人物）

| 参数 | 定义 | 业务价值 | 用法 |
|---|---|---|---|
| `avatar_id` | 我们起的 ID | 一会话多角色切换的句柄 | `liu_lian` / `shen_zhian` |
| `instructions` | 该角色的人设 + 说话规则（Character → Identity → Personality → Chat Style → Hard Rules） | 只在对话模式生效；脚本模式不改词 | 若走对话模式，把 Letta 人设块 + 主播功夫 12 条放这里；Hard Rules 必加"只输出口语文本，不要括号/舞台提示/emoji"，否则 TTS 会念 "(微笑)" |
| `voice.{provider, provider_voice_id, model, speed}` | 每角色独立音色（仅当会话级 `tts_config` 省略时生效）；speed 0.7–1.2 | 一个会话两个人两种声音（切镜模式必需） | 克隆后填 `qwen3tts` + voice_id |
| `visual.source_images[]` | 该角色可切换的多张起始图 | **换装 / 换场景 / 换景别**：预生成"沙发近景 / 全身跳舞 / 情侣睡衣 / 泳队队服"各一张，运行时 `session.update` 切 | 对应待办 #5 换装 still |
| `source_images[].description` | 描述图里**已有**的东西（服装、手里拿的、姿势） | 让动作规划器知道手是空的/拿着锅铲，避免手里的东西凭空消失 | 姜伊夏厨房图写"双手空、围裙、岛台有锅" |
| `source_images[].opening.dialogue` | 这张图一开始渲染就念的**固定开场白** | **一接通就开口**（9-24 的硬需求），不等 LLM | "欢迎来到我的厨房…" |
| `source_images[].opening.action.{prompt,duration_ms}` | 开场动作 VMP | 挥手/比心做开场 | 挥手 3000 ms |
| `source_images[].opening.starting_at` | 首帧后延迟几 ms 再开场 | 给观众画面先稳 1 s | 800 |
| `visual.default_source_image_id` | 多图时默认图 | — | 近景对话图 |
| `visual.instructions` | 该角色默认视觉指令（姿态、视线、动作范围） | 比 motion prompt 轻量，描述"坐姿不要站起来、视线常看镜头" | 双人合成：左侧的人"偶尔看向画面右侧" |

### 1.3 `pipeline_config`（创建后不可改）

| 参数 | 定义 | 业务价值 | 用法 |
|---|---|---|---|
| `tts_config.tts_voice_id` | 内置音色 / Vivix 克隆 voice_id；会话级，**覆盖所有 avatars[].voice** | 一人一会话时最简 | 克隆申/姜音色（Starter 可克隆 10 个；样本 10–20 s WAV ≥16 kHz，`POST /v1/files/audios` → `POST /v1/voices`） |
| `tts_config.tts_provider / tts_model_id / tts_api_key / tts_endpoint / payload.speed` | 换 ElevenLabs / 自己 DashScope 账号；语速 | 英文演员用 ElevenLabs；中文内置 Qwen Audio | 中文内置即可 |
| `asr_config.provider / language` | `doubao`（多语）/ `nova-3`（英文） | 粉丝**语音**连麦时才需要 | 文字直播间不需要 |
| `llm_config.llm_base_url / llm_model / llm_api_key` | 把对话模型指到**我们的 OpenAI 兼容端点** | **让 Vivix 的低延迟管线用我们的大脑**（Letta agent 包一层 chat-completions 壳） | 单人间低延迟方案（见 §3 S2） |
| `llm_config.llm_temperature / llm_max_output_tokens / llm_extra_payload` | 生成参数 | 控句长（直播一句 ≤ 40 字） | 0.7 / 120 |
| `motion_enhanced.prompt` | **说话时**的动作规划器 prompt；必须保留 `{summarized_persona}`、`{VLM}` 占位符；输出 `{"motions":[{vmp,duration}]}` | 指定手势风格、幅度、"看向搭档" | 双人合成关键：说话时"头转向画面右侧的搭档再回正" |
| `motion_planner.prompt` | **听/等待时**的动作规划器；输出单段 `{"motion":[{vmp}]}`，无 duration | 不说话的人也在反应（点头、侧头看搭档、笑） | 双人合成关键：没说话的那位"侧头看向左侧，轻点头" |
| `a2a_config.enable_a2a / provider=passthrough` | 纯渲染：我们往 RTC 房间推的音频直接驱动口型 | 最低延迟 + 我们的音色；但要服务端 Agora 推流 SDK | 暂不做 |
| `tag_audio_enabled` | LLM 回复第一行"嗯/hmm"先播，掩盖思考延迟 | 粉丝提问后 0.5 s 内有反应 | 对话模式开；配合 instructions 里的 Short vocal cue 规则 |

### 1.4 `conversation`（对话模式默认值）

| 参数 | 定义 | 业务价值 |
|---|---|---|
| `instructions` | 会话级共享规则，和 avatar instructions、每次 `response.instructions` 叠加 | 放"直播间协议"：`[进场] 名字` / `[评论] 名字：内容` 怎么处理 |
| `tools[]` | function calling 定义 | 观众说"跳个舞" → 模型调 `play_performance(dance)` → 我们发脚本；"换睡衣" → `change_outfit` → `session.update` |
| `response_defaults.temperature / max_output_tokens` | 默认生成参数 | — |
| `turn_detection.type` | `manual`（我们触发）/ `server_vad`（服务端听用户说完自动答） | 语音连麦用 server_vad；文字直播间 manual |
| `input_audio_transcription.enabled / language` | 转写用户语音 | 连麦时出字幕 |

### 1.5 `assets`（预注册，零延迟触发）

| 参数 | 定义 | 业务价值 |
|---|---|---|
| `assets.images[]`（`OBJ_0…`） | 道具参考图，描述里带 `<OBJ_0>` 标签 | 带货/拿锅铲/举奖牌：动作规划器认得这个物体 |
| `assets.audio[]` | 预录音频（WAV/MP3 URL） | 片头曲、固定台词原声 |
| `assets.speech_text[]` | 固定台词文本 | 欢迎语、下播语，`speech_asset` 直接播 |
| `assets.visual_prompts[]` | 预写好的动作 VMP | **把 14 条动作（比心/跳舞/摸头/飞吻/靠肩/投喂/俯卧撑…）注册成 asset**，评论触发时只发 ID |

运行中可用 `asset.add` / `avatar.add` 追加（只增不改）。

## 2. 运行时控制（WebSocket）

### 2.1 客户端 → 服务端

| 事件 | 作用 | 我们的用法 |
|---|---|---|
| `conversation.item.create`（role=user/system） | 塞一条上下文；等 `conversation.item.created` 再 `response.create` | 观众事件：`[进场] 老王` / `[评论] 老王：你们怎么认识的`；system 项放导演提示 |
| `response.create` | 让它答（对话模式）或播脚本 | 每句话一次 |
| `response.instructions` | **只对这一次回复**生效的指令 | **导演层原生入口**：`"用一句话欢迎老王，提他的名字，然后接着讲刚才的故事"`，不污染人设 |
| `response.input` | 替换这一次的上下文（`[]` = 清空） | 讲固定章节时不带聊天历史 |
| `response.conversation = none` | 这次输出不写进对话历史 | 脚本台词不污染记忆（现用） |
| `response.scheduling_policy` | `interrupt`（默认，打断当前）/ `after_current_response`（排队 1 条）/ `reject_if_busy` | **粉丝评论优先**：评论来了用 `interrupt`；讲故事下一句用 `after_current_response`；只能排 1 条，长队列我们自己管（现用） |
| `response.script.vocal` | `speech`（Vivix TTS）/ `speech_asset` / `audio`（我们的音频 base64/URL）/ `audio_asset` | 现用 `audio` base64（MiniMax）；可换 `speech` 省 1–2 s |
| `response.script.visual.prompt` / `visual_prompt_asset_id` / `duration_ms` | 动作 VMP；`[SHOT_SEP]` 分多段，每段 duration_ms | 现用 4000 ms；跳舞类用全身图 + 3 段 |
| `response.cancel` | 取消当前回复并清排队 | 新评论打断（现用） |
| `session.update.{active_avatar_id, source_image_id}` | 切人 / 切图 | 切镜模式切人；换装；对话景别 ↔ 全身跳舞景别 |
| `asset.add` / `avatar.add` | 运行中追加 | 临时加一位嘉宾 |

### 2.2 服务端 → 客户端（要听的）

| 事件 | 业务含义 |
|---|---|
| `response.render.started / stopped(status)` | **真实开口 / 真实说完**；用它驱动字幕高亮、"已说出"记忆确认、下一句排队 |
| `response.done.status` | completed / cancelled / failed / incomplete |
| `response.output_text.delta / done` | 字幕流（脚本 speech 也会推文本） |
| `response.output_item.done(function_call)` | 工具调用 → 我们执行 → `conversation.item.create(function_call_output)` → `response.create` |
| `session.update.done(status)` | 切图真正完成（`session.updated` 只是受理）。我们遇到过 `media update failed` |
| `session.bootstrap.opening.done` | 开场白播完 |
| `session.closed(close_reason)` | 到期 / 空闲 / 断连 |
| `error(code)` | 30006 并发满；10008 限速（REST 60 次/分） |

## 3. 场景一：单人直播间（姜伊夏厨房 / 申智安书房）

需求：一接通就讲；没人说话一直讲故事；有人进场/评论立刻接住再回到故事；观众点菜动作。

### S1 现成大脑 + Vivix 嘴（改动最小，推荐先做）

- 建会话：9:16 720p；`source_images`：近景对话图（默认）+ 全身动作图；`opening.dialogue` = 开场白；`tts_config.tts_voice_id` = **Vivix 克隆音色**（上传 15 s 原声样本）；`interaction_idle_timeout = 0`；`assets.visual_prompts` 注册 6 条动作。
- 讲故事：Letta agent 逐句出词 → `response.script.vocal.speech` + 每句一个 `visual.prompt`（由句意生成或用 asset）→ `after_current_response` 排队，下一句在 `render.started` 时再推。
- 进场/评论：导演层决定 → `response.cancel`（如果当前句不重要）→ 新脚本 `interrupt`；回完 → 继续故事。
- 点菜（比心/跳舞）：评论匹配关键词 → 需要全身的先 `session.update(source_image_id=full_body)` 等 `update.done` → `visual_prompt_asset_id` → 播完切回近景。
- 预期开口延迟 ≈ 2.2 s（已测）；Letta 思考另算。

### S2 Vivix 管线 + 我们的大脑当 LLM（延迟最低，支持语音连麦）

- `llm_config.llm_base_url` 指向我们服务上的一个 **OpenAI chat-completions 兼容壳**，壳内调 Letta agent（记忆仍在 letta-stage）。
- `conversation.instructions` 放直播协议；`tag_audio_enabled = true` + instructions 里的 Short vocal cue 规则 → 粉丝提问 0.5 s 内先"嗯"。
- 进场/评论 = `conversation.item.create(user, "[评论] 老王：…")` + `response.create(interrupt)`；一直讲故事 = 空闲计时器到 → `response.create` 带 `response.instructions: "接着讲第 N 章，一段话，结尾留悬念"`。
- 粉丝语音：`turn_detection=server_vad` + 麦克风推进 Agora 房间，Vivix 自己 ASR → 答。
- 代价：Letta 的"提议/成稿"两阶段要压成一次 chat-completions；gateway 需新写。

### S3 纯渲染 passthrough

需要服务端持续向 Agora 房间推 PCM（Linux Agora SDK 或无头浏览器），工程量大，延迟收益有限，**不做**。

## 4. 场景二：双人一个画面互动

| 路线 | 原理 | 互动真实度 | 现在能做 | 成本 |
|---|---|---|---|---|
| **D1 两路 A1 合成**（推荐立即做） | 同一张沙发夜景图裁左右两半当两路起始图；页面/ffmpeg 无缝拼接；`motion_planner` 让没说话的人"侧头看向搭档、点头、笑"；`motion_enhanced` 让说话的人"转头看向搭档再回镜头"；`[both_laugh]` 两路同时发 visual 脚本 | 中：有对视感、无肢体接触、中缝需遮 | ✅ 并发 2 已有 | 2 × $0.32/min |
| **D2 W1 Streaming World**（私测） | 一张 `opening_frame`（双人沙发图）+ `references` A/B（各自肖像 + 音频样本 + 性格文本）+ `initial_prompt`；运行时 `event.create` 用自然语言 steer："老王进来问他们怎么认识，A 先接，B 补一句拆台"；Vivix 自己规划对话轮次、动作、镜头；`caption.*` 出字幕 | 高：同帧、真互动、可肢体接触 | ❌ key 未开通，需向 Vivix 申请 | 未公开 |
| **D3 自有 H3 + HeyGem**（10-05 三层架构） | H3 预生成双人动作/台词库 + HeyGem 实时口型贴闭嘴底片 | 高（素材层）/ 中（实时层） | ⏳ 需 GPU pod | GPU 时薪 |

W1 对我们的意义：导演层/记忆层（Letta）不变，只是把"两路脚本"换成"一条 steer 事件"；Vidu/A1 的"一句一动作"变成 Vivix 自己编排的多轮互动。它是终局形态，但不在我们手里。**建议同时申请 W1 私测**（platform.vivix.ai 联系 api@vivix.ai，说明双人直播间用例）。

## 5. 现网 `app/vivix_stage.py` 用到 / 没用到

已用：`model`、`output 9:16/720p`、`avatars[0].visual.source_images[0]`、`tts_config.tts_voice_id`（内置，仅占位）、`delivery agora`、`max_duration_seconds`、`auto_close.disconnected_timeout`、`response.create(script.vocal.audio base64 + visual.prompt 4000 ms, conversation none, after_current_response)`、`response.cancel`。

没用、且对业务价值高（按优先级）：
1. `source_images[].opening`（一接通就开口）
2. Vivix 克隆音色 + `vocal.type=speech`（省 1–2 s、省 MiniMax）
3. `motion_planner.prompt` / `motion_enhanced.prompt`（双人对视；听者有反应）
4. `assets.visual_prompts`（14 条动作零延迟）
5. 多 `source_images` + `session.update`（换装、全身跳舞景别）
6. `interaction_idle_timeout_seconds = 0`（防误关）、`recording_mode = off`
7. `response.render.started/stopped` 驱动"已说出"确认（现在按音频时长估算）
8. `llm_config` → 我们的大脑（S2）

## 6. 本 key 能力盘点（2026-10-06 实测 `vivix_GK9e…`，Starter 套餐）

| 模型 / 端点 | 文档状态 | 本 key | 对我们的用途 |
|---|---|---|---|
| `vivix-a1-stream` | GA | ✅（仅裸名，无 tag → **不能锁版本**） | 实时数字人（现网 B 版） |
| `vivix-a1` | GA | ✅；`GET /v1/videos/generations/*` 可访问 | 异步数字人视频：一张图 + 音频/台词 → 720p 说话片段。可替代/补充 H3 做**素材层**（第 1 层）的单人台词片 |
| `vivix-w1` | GA（文档） | ❌ 不在列表 | 多参考（图+音）世界视频，8 s，可做**双人同帧预生成片**（第 1 层） |
| `vivix-w1-stream` | 私测 | ❌ | 多角色同帧实时（D2） |
| `/v1/streaming-world/*` | — | ❌ `20005 not found` | — |
| `/v1/voices` 克隆 | Starter 10 个 | 可用；当前可见 1 个公共测试音色，**0 个自有克隆** | 待上传申/姜样本 |
| 并发 / 时长 | Starter 2 / 30 min | ✅ 已实测两路同开 | 双人 D1 刚好；单人间 + 双人间同时开播需 Pro（3） |
| 开着的会话 | — | 0（干净） | — |

需向 Vivix 申请：`vivix-w1`（GA 却未开，可能随套餐/审核）、`vivix-w1-stream` 私测。两者都是双人同帧的关键。

## 7. 结论

- **单人间**：A1 完整覆盖需求。先 S1（克隆音色 + opening + assets + idle=0），再评估 S2。
- **双人同屏**：A1 结构上做不到真同帧；立即做 D1 合成（含听者动作），并行申请 W1 私测；D3 作为自有兜底。
- **TikTok 推流**：Vivix 签发的 Agora 房间不能配 Media Push；需要我们自己订阅拉流 → ffmpeg → RTMP。
