首页
/ OpenMontage avatar-video 技能实战:HeyGen 数字人形象选择、预览与 default_voice_id 策略全解

OpenMontage avatar-video 技能实战:HeyGen 数字人形象选择、预览与 default_voice_id 策略全解

2026-09-05 11:02:26作者:袁立春Spencer

本篇指南基于 OpenMontage 仓库中 avatar-video 技能包的核心参考文档 avatars.md,系统讲解 HeyGen v2 API 中数字人(Avatar)的完整操作链路:如何列出与预览形象、通过 avatar_id 前缀区分公共/自定义形象、为不同视频格式选择 avatar_style、以及为什么应优先使用形象的 default_voice_id 而不是手动配声音。读完本文,你可以在 OpenMontage 的 Agent 工作流(或自己的脚本)中独立完成“选形象 → 预览确认 → 取默认音色 → 生成视频”的可靠流程。

avatars.md 在 OpenMontage 中的位置

.agents/skills/avatar-video/ 是 OpenMontage 中专门处理“精确控制型”数字人视频的 Agent 技能包,其入口 SKILL.md 定义了五步默认工作流:列出形象 → 列出声音 → 撰写脚本 → 生成视频 → 轮询状态,而 avatars.md 正是第 1 步的参考实现:

  1. List avatarsGET /v2/avatars → pick an avatar, preview it, note avatar_id and default_voice_id。见 avatars.md
  2. List voicesGET /v2/voices。见 voices.md ……
  3. Generate the videoPOST /v2/video/generate。见 video-generation.md

所有请求都需要 X-Api-Key 请求头,因此运行前必须设置环境变量:

export HEYGEN_API_KEY=your_key_here

SKILL.md 还规定:如果环境中存在 HeyGen MCP 工具(mcp__heygen__*),应优先使用它们(例如 mcp__heygen__get_video 查询状态),而“列出形象/声音”和“生成视频”则通过直接 API 调用完成——本文覆盖的就是这两类直接调用。

预览先行:生成视频前先看形象

数字人视频的核心风险是“生成后才发现问题形象不符合预期”,因此文档给出的第一条纪律是:生成前先预览。每个形象都带 preview_image_url(静态图)和 preview_video_url(动画短视频),两者都是公开可访问的 URL,无需下载、无需鉴权,可直接在浏览器打开:

字段 说明
preview_image_url 形象的静态图片(JPG),公开 URL
preview_video_url 展示形象动画的短视频片段

文档提供的 TypeScript 预览函数,一次列出前 5 个形象并输出预览地址:

async function listAndPreviewAvatars(openInBrowser = true): Promise<void> {
  const response = await fetch("https://api.heygen.com/v2/avatars", {
    headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! },
  });
  const { data } = await response.json();

  for (const avatar of data.avatars.slice(0, 5)) {
    console.log(`\n${avatar.avatar_name} (${avatar.gender})`);
    console.log(`  ID: ${avatar.avatar_id}`);
    console.log(`  Preview: ${avatar.preview_image_url}`);
  }

  // Preview URLs can be opened directly in any browser
  for (const avatar of data.avatars.slice(0, 3)) {
    console.log(`Open in browser: ${avatar.preview_image_url}`);
  }
}

完整的“先预览后生成”工作流

  1. 列出可用形象 —— 获取名称、性别与预览 URL;
  2. 向用户展示预览 URL —— 分享 preview_image_url 做视觉确认;
  3. 用户按名称或 ID 选定形象
  4. 获取形象详情,拿到 default_voice_id
  5. 用选定的形象生成视频

这一步也是 SKILL.md “Best Practices” 的第一条:在生成前先让用户看到形象,避免浪费积分。

列出全部可用形象

curl

curl -X GET "https://api.heygen.com/v2/avatars" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

TypeScript(含完整类型定义)

interface Avatar {
  avatar_id: string;
  avatar_name: string;
  gender: "male" | "female";
  preview_image_url: string;
  preview_video_url: string;
}

interface AvatarsResponse {
  error: null | string;
  data: {
    avatars: Avatar[];
    talking_photos: TalkingPhoto[];
  };
}

async function listAvatars(): Promise<Avatar[]> {
  const response = await fetch("https://api.heygen.com/v2/avatars", {
    headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! },
  });

  const json: AvatarsResponse = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data.avatars;
}

注意响应体中除了 avatars 数组,还包含 talking_photos(照片说话人)数组——character.type"talking_photo" 时使用后者,参见 video-generation.mdtalking_photo_id 字段的说明。

Python

import requests
import os

def list_avatars() -> list:
    response = requests.get(
        "https://api.heygen.com/v2/avatars",
        headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"]}
    )

    data = response.json()
    if data.get("error"):
        raise Exception(data["error"])

    return data["data"]["avatars"]

响应格式

{
  "error": null,
  "data": {
    "avatars": [
      {
        "avatar_id": "josh_lite3_20230714",
        "avatar_name": "Josh",
        "gender": "male",
        "preview_image_url": "https://files.heygen.ai/...",
        "preview_video_url": "https://files.heygen.ai/..."
      },
      {
        "avatar_id": "angela_expressive_20231010",
        "avatar_name": "Angela",
        "gender": "female",
        "preview_image_url": "https://files.heygen.ai/...",
        "preview_video_url": "https://files.heygen.ai/..."
      }
    ],
    "talking_photos": []
  }
}

error 字段非空时表示请求失败,应直接把 error 作为错误抛出——文档中的 TS/Python 实现均遵循这一约定。

形象类型:公共形象 vs 自定义形象

HeyGen 的形象库包含任意账号都可使用的公共形象,以及由自己的训练素材生成的自定义形象。区分方式很简单:avatar_id 是否以 custom_ 开头。

// List only public avatars
const avatars = await listAvatars();
const publicAvatars = avatars.filter((a) => !a.avatar_id.startsWith("custom_"));

const customAvatars = avatars.filter((a) => a.avatar_id.startsWith("custom_"));

从文档结构看,自定义形象通常还会进入“形象分组”体系(见下文 Avatar Groups),custom_ 前缀 + 分组接口两者结合,可以在批量生成场景中精确锁定“我的品牌代言人”这一类形象,而不受公共库更新影响。

Avatar Styles:四种渲染风格与适用场景

同一个形象支持不同的 avatar_style 渲染风格,直接决定它在成片中的呈现形态:

风格 说明
normal 全身/标准取景,常规镜头
closeUp 面部特写,表情表现力更强
circle 圆形取景框(talking head)
voice_only 仅音频,不渲染视频

风格与使用场景的对应关系:

使用场景 推荐风格
全屏出镜视频 normal
私人化/亲近感内容 closeUp
画中画(PiP)叠加 circle
角落小窗组件 circle
播客/纯音频内容 voice_only
带动画图形叠加的形象视频 normalcloseUp + 透明背景

在视频配置中使用风格

avatar_stylevideo_inputs[].character 下的可选字段,在 POST /v2/video/generate 请求体中这样写:

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal", // "normal" | "closeUp" | "circle" | "voice_only"
      },
      voice: {
        type: "text",
        input_text: "Hello, world!",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
      },
    },
  ],
};

Circle 风格 + 绿幕:画中画合成的推荐组合

circle 风格最适合叠加合成场景。文档给出的做法是:形象设为 circle,背景设为绿色 #00FF00 以便色度键抠像(或使用 WebM 透明端点):

// Circle avatar for picture-in-picture
{
  character: {
    type: "avatar",
    avatar_id: "josh_lite3_20230714",
    avatar_style: "circle",
  },
  voice: { ... },
  background: {
    type: "color",
    value: "#00FF00", // Green for chroma key, or use webm endpoint
  },
}

OpenMontage 仓库中恰好有对应的下游处理工具可衔接这个绿幕方案:green_screen_composite.pygreen_screen_processor.py 负责把绿幕素材抠像后合成到目标画面,skills/core/ffmpeg.md 则提供了 ffmpeg 层的色度键参数参考。

搜索与过滤形象

列表接口返回全量形象,实际选型时通常先按性别或名字做本地过滤。文档给出两个纯函数式工具:

// 按性别过滤
function filterByGender(avatars: Avatar[], gender: "male" | "female"): Avatar[] {
  return avatars.filter((a) => a.gender === gender);
}

const maleAvatars = filterByGender(avatars, "male");
const femaleAvatars = filterByGender(avatars, "female");

// 按名称模糊搜索
function searchByName(avatars: Avatar[], query: string): Avatar[] {
  const lowerQuery = query.toLowerCase();
  return avatars.filter((a) =>
    a.avatar_name.toLowerCase().includes(lowerQuery)
  );
}

const results = searchByName(avatars, "josh");

这类“列表全量拉取 + 本地过滤”的模式,与 SKILL.md 中“Validate inputs — Check avatar and voice IDs exist before generating”的最佳实践一致:先确认 ID 真实存在,再提交生成请求。

Avatar Groups:形象分组管理

形象按组(group)组织,便于在账号内管理批量形象。

列出形象分组

curl -X GET "https://api.heygen.com/v2/avatar_group.list?include_public=true" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

查询参数:

参数 类型 默认值 说明
include_public bool false 是否在结果中包含公共形象
interface AvatarGroupItem {
  id: string;
  name: string;
  created_at: number;
  num_looks: number;
  preview_image: string;
  group_type: string;
  train_status: string;
  default_voice_id: string | null;
}

interface AvatarGroupListResponse {
  error: null | string;
  data: {
    avatar_group_list: AvatarGroupItem[];
  };
}

async function listAvatarGroups(
  includePublic = true
): Promise<AvatarGroupListResponse["data"]> {
  const params = new URLSearchParams({
    include_public: includePublic.toString(),
  });

  const response = await fetch(
    `https://api.heygen.com/v2/avatar_group.list?${params}`,
    { headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
  );

  const json: AvatarGroupListResponse = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data;
}

分组条目中的 num_looks 表示组内形象数量,train_status 反映训练状态,default_voice_id 则给出组级默认音色——这些字段在管理自训形象时尤其有用。

获取组内形象

curl -X GET "https://api.heygen.com/v2/avatar_group/{group_id}/avatars" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

在视频生成中使用形象

形象配置最终汇入 POST /v2/video/generatevideo_inputs 数组(单请求 1–50 个输入对象)。最小可用的单场景配置:

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Welcome to our product demo!",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
      },
    },
  ],
  dimension: { width: 1920, height: 1080 },
};

多场景视频则在同一 video_inputs 数组中放入多个对象,每个场景可使用不同形象、不同声音:

const multiSceneConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Hi, I'm Josh. Let me introduce my colleague.",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
      },
    },
    {
      character: {
        type: "avatar",
        avatar_id: "angela_expressive_20231010",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Hello! I'm Angela. Nice to meet you!",
        voice_id: "2d5b0e6a8c3f47d9a1b2c3d4e5f60718",
      },
    },
  ],
};

完整的请求字段(dimensiontestcaptionbackground 等)与轮询逻辑,分别在 video-generation.mdvideo-status.md 中有定义。

使用形象的 default_voice_id(推荐做法)

文档的核心主张是:大多数形象自带一个经过配对优化的 default_voice_id,应优先使用它,而不是手动挑选声音。理由有四:

  1. 性别保证匹配 —— 形象与声音是预先配对好的;
  2. 口型同步更自然 —— 默认音色针对该形象做过优化;
  3. 代码更简单 —— 不需要单独拉取声音列表再做匹配;
  4. 质量更有保障 —— 这是 HeyGen 官方测试过的组合。

推荐三步流程

1. GET /v2/avatars           → 获取 avatar_id 列表
2. GET /v2/avatar/{id}/details → 获取所选形象的 default_voice_id
3. POST /v2/video/generate   → 使用 avatar_id + default_voice_id 生成

获取形象详情

curl -X GET "https://api.heygen.com/v2/avatar/{avatar_id}/details" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

响应示例:

{
  "error": null,
  "data": {
    "type": "avatar",
    "id": "josh_lite3_20230714",
    "name": "Josh",
    "gender": "male",
    "preview_image_url": "https://files.heygen.ai/...",
    "preview_video_url": "https://files.heygen.ai/...",
    "premium": false,
    "is_public": true,
    "default_voice_id": "1bd001e7e50f421d891986aad5158bc8",
    "tags": ["AVATAR_IV"]
  }
}

其中 premiumis_publictags 可用于做资格判断(例如筛选免费公共形象),default_voice_id 可能为 null,代码必须处理这种情况。

TypeScript 实现

interface AvatarDetails {
  type: "avatar";
  id: string;
  name: string;
  gender: "male" | "female";
  preview_image_url: string;
  preview_video_url: string;
  premium: boolean;
  is_public: boolean;
  default_voice_id: string | null;
  tags: string[];
}

async function getAvatarDetails(avatarId: string): Promise<AvatarDetails> {
  const response = await fetch(
    `https://api.heygen.com/v2/avatar/${avatarId}/details`,
    { headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
  );

  const json = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data;
}

// Usage: Get default voice for a known avatar
const details = await getAvatarDetails("josh_lite3_20230714");
if (details.default_voice_id) {
  console.log(`Using ${details.name} with default voice: ${details.default_voice_id}`);
} else {
  console.log(`${details.name} has no default voice, select manually`);
}

完整示例:用任意形象的默认声音生成视频

async function generateWithAvatarDefaultVoice(
  avatarId: string,
  script: string
): Promise<string> {
  // 1. Get avatar details to find default voice
  const avatar = await getAvatarDetails(avatarId);

  if (!avatar.default_voice_id) {
    throw new Error(`Avatar ${avatar.name} has no default voice`);
  }

  // 2. Generate video with the avatar's default voice
  const videoId = await generateVideo({
    video_inputs: [{
      character: {
        type: "avatar",
        avatar_id: avatar.id,
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: script,
        voice_id: avatar.default_voice_id,
      },
    }],
    dimension: { width: 1920, height: 1080 },
  });

  return videoId;
}

如果 default_voice_id 为空,回退策略是手动匹配性别:声音列表见 voices.md,确保 gender 与形象一致。

如何选对形象:分类、准则与检查清单

形象分类

类别 示例 最适合
商务/职业 Josh、Angela、Wayne 企业视频、产品演示、培训
休闲/亲和 Lily 及各类生活化形象 社交媒体、非正式内容
主题/节日 节日主题、cosplay 形象 特定营销活动、季节性内容
表现力强 名字中带 "expressive" 的形象 强代入感叙事、动态内容

选择准则

商务/职业内容:

  • 选择中性着装(商务休闲或正装)的形象;
  • 避开主题化或节日形象(节日装扮、便服);
  • 通过预览确认职业感;
  • 结合目标受众选择性别与外貌特征。

休闲/社交内容:

  • 选择空间更大,主题形象可用于特定营销;
  • 形象气质要与内容基调匹配。

常见错误

  1. 用节日形象做商务内容 —— 在产品介绍中穿节日装扮会显得不专业;
  2. 不预览就生成 —— 务必打开预览 URL 确认外貌;
  3. 忽视 avatar_style —— circle 风格不适合全屏出镜;
  4. 声音性别错配 —— 始终使用 default_voice_id,或手动保证性别一致。

生成前检查清单

  • [ ] 已在浏览器中预览形象图片/视频;
  • [ ] 形象外貌匹配内容基调(专业 vs 休闲);
  • [ ] avatar_stylenormal / closeUp / circle)匹配视频格式;
  • [ ] 声音性别与形象性别一致;
  • [ ] 在有 default_voice_id 时优先使用它。

实用辅助函数

文档还沉淀了三个可直接复用的辅助函数,覆盖“按 ID 查找、校验、随机选择”三种常见需求:

// 按 ID 查找
async function getAvatarById(avatarId: string): Promise<Avatar | null> {
  const avatars = await listAvatars();
  return avatars.find((a) => a.avatar_id === avatarId) || null;
}

// 校验 ID 是否有效
async function isValidAvatarId(avatarId: string): Promise<boolean> {
  const avatar = await getAvatarById(avatarId);
  return avatar !== null;
}

// 随机取一个形象(可选指定性别)
async function getRandomAvatar(gender?: "male" | "female"): Promise<Avatar> {
  let avatars = await listAvatars();

  if (gender) {
    avatars = avatars.filter((a) => a.gender === gender);
  }

  const randomIndex = Math.floor(Math.random() * avatars.length);
  return avatars[randomIndex];
}

在 Agent 自动化流程里,isValidAvatarId 是生成前校验的合适入口;getRandomAvatar 则适合批量 A/B 测试多个形象时的快速取材。

常用公共形象 ID 速查

文档附带的常用公共形象 ID(可用性可能随时间变化):

Avatar ID 名称 性别
josh_lite3_20230714 Josh Male
angela_expressive_20231010 Angela Female
wayne_20240422 Wayne Male
lily_20230614 Lily Female

原文特别提醒:使用前务必先调用 GET /v2/avatars 验证形象是否仍然可用,不要把上表当作长期契约——这也与 SKILL.md “Validate inputs” 的最佳实践呼应。

小结

avatars.md 提供的不只是一份 API 清单,而是一套可落地的选型决策链:

  • 列表与预览GET /v2/avatars 拿到 avatar_idgender 和两个公开预览 URL,先看后定;
  • 类型区分custom_ 前缀识别自训形象,avatar_group.listinclude_public=true)管理分组;
  • 风格匹配normal / closeUp / circle / voice_only 按全屏、特写、画中画、纯音频四类场景对号入座,circle + 绿幕或 WebM 是合成叠加的标准组合;
  • 声音策略:优先 GET /v2/avatar/{id}/detailsdefault_voice_id,为空时再回退到性别手动匹配;
  • 纪律性校验:生成前完成预览确认与 ID 有效性校验,避免积分浪费在错误的形象上。

沿着 SKILL.md 的五步工作流,把本文的形象选择链路接到 video-generation.mdPOST /v2/video/generatevideo-status.md 的轮询逻辑上,即构成 OpenMontage 中一条完整、可复现的 HeyGen 数字人视频生产线。

登录后查看全文
热门项目推荐
相关项目推荐