首页
/ OpenMontage 人脸替换(Face Swap)实战指南:基于 HeyGen FaceswapNode 工作流的换脸视频生成

OpenMontage 人脸替换(Face Swap)实战指南:基于 HeyGen FaceswapNode 工作流的换脸视频生成

2026-09-07 09:52:43作者:昌雅子Ethen

换脸(Face Swap)是 AI 视频生产管线中最常用的"二次创作"能力之一:把一张来源照片中的人脸,无缝替换到目标视频中的原有人脸上。本指南以 OpenMontage 仓库内 .agents/skills/faceswap/SKILL.md 技能文档为核心,系统讲解通过 HeyGen /v1/workflows/executions 接口完成人脸替换的完整链路——从 HEYGEN_API_KEY 鉴权、任务提交、状态轮询到结果取回。读者学完后,既能用 curl / TypeScript / Python 独立调用换脸 API,也能把换脸任务与数字人(Avatar)视频生成串成"先生成、再换脸"的个性化管线。

技能定位:OpenMontage 里的"换脸"角色

在 OpenMontage 的 Agent 技能体系中,人脸替换隶属于 HeyGen 云端能力簇。仓库的 AGENT_GUIDE.md 在「Avatar / lip-sync」分组中列出了 avatar-videoheygencreate-videofaceswap 等技能,而 skills/INDEX.md 进一步把 faceswap 与 Lip Sync、HeyGen AI Video 场景归为一类。也就是说:这个技能解决的问题是——拿一张来源人脸图片,替换到一段目标视频上,得到一段全新的人物出镜视频

技能清单(frontmatter)给出了 Agent 触发它时应该满足的条件:

触发条件 说明
用 AI 在视频中替换人脸 用另一张脸替换视频中的人脸
从来源图片向目标视频换脸 source_image_urltarget_video_url 的单向注入
制作个性化视频 把某人的脸换进通用出镜视频,实现千人千面
处理 HeyGen /v1/workflows/executions 统一走该执行端点的 FaceswapNode 工作流

该技能声明 allowed-tools: mcp__heygen__*,且其运行前提是通过环境变量注入 HEYGEN_API_KEY

鉴权准备:统一使用 HEYGEN_API_KEY

所有换脸请求都需要在 HTTP Header 中携带 X-Api-Key,密钥统一来自环境变量 HEYGEN_API_KEY

export HEYGEN_API_KEY=your_key_here

这一约定与 OpenMontage 全仓库的 HeyGen 接入方式保持一致:docs/PROVIDERS.md 在环境变量清单中登记了 HEYGEN_API_KEY= # HeyGen avatar video gateway;而仓库自带的 HeyGen 视频工具在 tools/video/_shared.py 中同样以 os.environ.get("HEYGEN_API_KEY") 读取密钥(缺失时直接判定工具不可用)。因此,无论你是通过 MCP 技能调用,还是像下面这样直接用 HTTP 调用,密钥的注入方式都是同一个环境变量。

验证鉴权链路最简单的方式是一次直接的 POST:

curl -X POST "https://api.heygen.com/v1/workflows/executions" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workflow_type": "FaceswapNode", "input": {"source_image_url": "https://example.com/face.jpg", "target_video_url": "https://example.com/video.mp4"}}'

默认工作流:四步完成一次换脸

换脸任务是典型的异步云端作业,完整生命周期只有四步:

  1. 调用 POST /v1/workflows/executions,提交 workflow_type: "FaceswapNode"、一张来源人脸图、一段目标视频;
  2. 从响应中拿到 execution_id
  3. 每 10 秒轮询一次 GET /v1/workflows/executions/{id},直到状态变为 completed
  4. 从输出中取出结果视频地址 video_url

之所以要轮询而不是同步等待,是因为人脸替换属于 GPU 密集型计算。根据技能文档的说明,单次换脸处理通常需要 1~3 分钟,官方推荐以 10 秒为轮询间隔。下面的各个小节将逐一拆解每一步的请求构造与响应解析。

发起换脸任务

端点与请求字段

  • Endpoint: POST https://api.heygen.com/v1/workflows/executions

请求体结构如下:

字段 类型 必填 说明
workflow_type string Y 必须为 "FaceswapNode",用于选择换脸执行节点
input.source_image_url string Y 被换入的人脸图片 URL(来源脸)
input.target_video_url string Y 应用换脸的目标视频 URL(被替换的视频)

注意 workflow_type 是区分"这次执行到底跑哪个节点"的开关:换脸用 FaceswapNode,而后续示例里生成数字人则用 AvatarInferenceNode

curl 完整示例

curl -X POST "https://api.heygen.com/v1/workflows/executions" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_type": "FaceswapNode",
    "input": {
      "source_image_url": "https://example.com/face-photo.jpg",
      "target_video_url": "https://example.com/original-video.mp4"
    }
  }'

TypeScript 实现

把请求封装成函数,返回 execution_id 供后续轮询使用:

interface FaceswapInput {
  source_image_url: string;
  target_video_url: string;
}

interface ExecuteResponse {
  data: {
    execution_id: string;
    status: "submitted";
  };
}

async function faceswap(input: FaceswapInput): Promise<string> {
  const response = await fetch("https://api.heygen.com/v1/workflows/executions", {
    method: "POST",
    headers: {
      "X-Api-Key": process.env.HEYGEN_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      workflow_type: "FaceswapNode",
      input,
    }),
  });

  const json: ExecuteResponse = await response.json();
  return json.data.execution_id;
}

Python 实现

import requests
import os

def faceswap(source_image_url: str, target_video_url: str) -> str:
    payload = {
        "workflow_type": "FaceswapNode",
        "input": {
            "source_image_url": source_image_url,
            "target_video_url": target_video_url,
        },
    }

    response = requests.post(
        "https://api.heygen.com/v1/workflows/executions",
        headers={
            "X-Api-Key": os.environ["HEYGEN_API_KEY"],
            "Content-Type": "application/json",
        },
        json=payload,
    )

    data = response.json()
    return data["data"]["execution_id"]

响应格式

提交成功后,服务端立即返回一个已受理的任务(同步返回、任务后台异步执行):

{
  "data": {
    "execution_id": "node-gw-f1s2w3p4",
    "status": "submitted"
  }
}

execution_id 形如 node-gw-...,是后续所有状态查询的凭证,请务必保存。

查询任务状态

端点

  • Endpoint: GET https://api.heygen.com/v1/workflows/executions/{execution_id}
curl -X GET "https://api.heygen.com/v1/workflows/executions/node-gw-f1s2w3p4" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

完成时的响应格式

{
  "data": {
    "execution_id": "node-gw-f1s2w3p4",
    "status": "completed",
    "output": {
      "video_url": "https://resource.heygen.ai/faceswap/output.mp4"
    }
  }
}

statuscompleted 时,换脸结果视频地址位于 data.output.video_url,可直接下载或交给下游(如配音、字幕、切片)继续处理。

轮询等待完成的完整实现

把"提交 + 轮询 + 取结果"收拢为一个函数,并对 completed / failed / not_found 三种终态以及超时分别处理:

async function faceswapAndWait(
  input: FaceswapInput,
  maxWaitMs = 600000,
  pollIntervalMs = 10000
): Promise<string> {
  const executionId = await faceswap(input);
  console.log(`Submitted face swap: ${executionId}`);

  const startTime = Date.now();
  while (Date.now() - startTime < maxWaitMs) {
    const response = await fetch(
      `https://api.heygen.com/v1/workflows/executions/${executionId}`,
      { headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
    );
    const { data } = await response.json();

    switch (data.status) {
      case "completed":
        return data.output.video_url;
      case "failed":
        throw new Error(data.error?.message || "Face swap failed");
      case "not_found":
        throw new Error("Workflow not found");
      default:
        await new Promise((r) => setTimeout(r, pollIntervalMs));
    }
  }

  throw new Error("Face swap timed out");
}

这段轮询有几个工程要点值得关注:

  • 默认超时 600000ms(10 分钟):与文档估计的 1~3 分钟 GPU 处理时间相比留足余量,避免在视频较长、排队拥堵时误判失败;
  • 默认间隔 10000ms(10 秒):官方推荐的轮询节奏,既不会过度占用 API 配额,也不会让用户等太久;
  • 状态机完备:把 failednot_found 也纳入显式分支并抛出带原因的错误,而不是静默无限循环。

使用示例

基本换脸:把个人大头照换进演讲视频

curl -X POST "https://api.heygen.com/v1/workflows/executions" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_type": "FaceswapNode",
    "input": {
      "source_image_url": "https://example.com/headshot.jpg",
      "target_video_url": "https://example.com/presentation.mp4"
    }
  }'

这个场景对应技能触发条件里的"Replacing a face in a video with another face"——例如把通用演讲模板视频中的人物脸替换成自己的照片,得到一段"本人出镜"的定制内容。

链式用法:先生成 Avatar 视频,再换入自定义人脸

这是换脸最有价值的组合玩法:先让 HeyGen 生成一段数字人口播视频,再用自定义人脸去替换,实现"人人是自己形象的数字人"。

import time

# Step 1: Generate avatar video
avatar_execution_id = requests.post(
    "https://api.heygen.com/v1/workflows/executions",
    headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"], "Content-Type": "application/json"},
    json={
        "workflow_type": "AvatarInferenceNode",
        "input": {
            "avatar": {"avatar_id": "Angela-inblackskirt-20220820"},
            "audio_list": [{"audio_url": "https://example.com/speech.mp3"}],
        },
    },
).json()["data"]["execution_id"]

# Step 2: Wait for avatar video to complete
while True:
    status = requests.get(
        f"https://api.heygen.com/v1/workflows/executions/{avatar_execution_id}",
        headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"]},
    ).json()["data"]
    if status["status"] == "completed":
        avatar_video_url = status["output"]["video"]["video_url"]
        break
    time.sleep(10)

# Step 3: Swap in a custom face
faceswap_execution_id = faceswap(
    source_image_url="https://example.com/custom-face.jpg",
    target_video_url=avatar_video_url,
)

三段式结构非常清晰:

  1. 生成数字人AvatarInferenceNode 工作流,指定 avatar_id(示例为 Angela-inblackskirt-20220820)与配音音频 audio_list[].audio_url
  2. 等待完成:同样是 10 秒间隔轮询,完成后从 data.output.video.video_url 取视频(注意此处数字人任务的输出结构是 output.video.video_url,与 FaceswapNode 直接返回 output.video_url 不同);
  3. 换入自定义脸:把第 2 步得到的数字人视频当作 target_video_url,换脸任务只需追加一次 faceswap() 调用即可。

这套链式用法在 OpenMontage 里可以继续下沉到生产工具链中:仓库已把 HeyGen 作为云端视频网关接入(参见 docs/PROVIDERS.md 中 "HeyGen — Avatar Video Gateway" 的说明,以及 tools/video/heygen_video.pytools/video/_shared.py 中基于 HEYGEN_API_KEY 的请求封装、预设上传与结果轮询实现),Agent 可以在统一的环境变量鉴权下复用同一套任务编排思路。

最佳实践清单

技能文档给出了 6 条实战准则,逐条展开如下:

  1. 使用清晰、正对镜头的人脸照片——来源图应只含一张脸、光线良好、角度正面,过大的侧脸或遮挡会显著降低换脸质量;
  2. 认清换脸是 GPU 密集型计算——单次处理预计耗时 1~3 分钟,请以 10 秒为间隔轮询,并合理设置客户端超时(前文示例中的 10 分钟上限即为此设计);
  3. 来源图分辨率越高越好——高分辨率人脸照片能保留更多五官细节,换脸结果更自然;
  4. 来源图只允许出现一张脸——多张脸会让算法无法判断"该换谁",必须在送入任务前裁剪或挑选;
  5. 目标视频几乎没有限制——目标视频可以是数字人视频、真人录屏、或者任何"画面里存在可见人脸"的视频,算法负责跟踪并替换对应人脸;
  6. 积极与其它工作流链式组合——先跑 AvatarInferenceNode 生成数字人、再做 FaceswapNode 换脸,是实现"自定义形象 + 任意文案出镜"类个性化视频的标准路径。

小结

.agents/skills/faceswap/SKILL.md 为参照,Face Swap 的调用范式可以概括为一句话:提交一个 workflow_type: "FaceswapNode" 的执行任务,用 10 秒间隔轮询 execution_id,在 completed 后消费 output.video_url。配合 OpenMontage 中 HeyGen 云端网关的既有接入方式(同一 HEYGEN_API_KEY 环境变量),开发者或 Agent 既可以独立执行换脸,也能无缝把它串进"数字人生成 → 换脸个性化 → 下游剪辑"的完整视频生产管线中。

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