Skip to content

广告创意审查 Agent

本页说明广告创意审查 Agent 如何在只读委托下读取广告平台或创意库中的草稿,对照版本化的品牌与合规规则给出待人确认的审查意见。读完本页,你能理解这个场景需要哪些模块、权限边界如何收窄,以及品牌与合规规则为什么应该放在规则库而不是 Memory。

适用场景

Marketing 团队需要在投放前检查图片、标题、描述、目标页面和 claims 是否符合品牌和合规要求。创意数量随渠道和 A/B 测试成倍增长,人工逐条比对品牌规则和平台政策容易遗漏;而给自动化脚本一个广告平台账号,它同时也拿到了改预算、提交投放的能力。

典型触发时机:

  • 新 campaign 的一批创意进入投放前审查,需要在投放窗口前完成。
  • 品牌规则或合规禁用词更新后,需要复查在库和待投的存量创意。
  • 某条创意被平台拒审,需要排查同批次创意是否存在相同问题。

工程挑战

  • 审查量随渠道与 A/B 测试成倍增长,而投放窗口固定:一批创意必须在窗口前审完,一条越界 claim 漏到线上就是平台拒审或合规事故。
  • 意见必须可复核且前后一致:同一句文案在不同平台政策和目标页语境下结论不同,每条意见都要标明创意来源和依据的规则版本,否则既无法复查,批次之间的判定也会漂移。
  • 借用投放账号权限过宽:能读草稿的账号通常也能改预算、提交投放——审查只需要"读取指定账户的草稿"这一件事,误触任何写操作都是真实资损。

模块组合

模块角色说明
GenAuth核心广告平台与创意库的只读委托、撤销与审计链;投放窗口内的审查任务用分钟级凭证。
Web Agent核心受控会话登录广告平台(Profiles 可复用登录态),逐条抽取素材、文案、目标页链接和 claims,每条留截图与来源。
GUMem可选仅保存审查者确认的长期偏好(例如意见措辞的口吻)。品牌与合规规则是版本化规则,放在你的规则库(policy store)按版本注入;历史拒审记录归档在你的审查系统。两者都不属于 Memory。

广告创意审查 Agent 场景架构

权限与委托边界

Agent 本身不持有任何固有权限。每次审查任务的实际权限是三个集合的交集:用户真实权限 ∩ 本次显式委托范围 ∩ 企业批准边界。落到这个场景:

  • 委托范围只覆盖"读取指定广告账户的创意草稿、creative library 和投放规则",不包含提交投放、修改预算、编辑创意或下线广告。
  • 委托凭证短时效,单次审查任务建议分钟级有效期,过期后需重新委托。
  • 用户或管理员可随时撤销授权;撤销后新的草稿读取请求立即失败。
  • 越权尝试(例如访问委托范围外的其他广告账户)会被拒绝并留痕——审计链覆盖全部尝试,不只是成功行为。

注意:SDK 示例申请的是产品级 scope(如 webagent.do_anything:read)。广告账户清单、页面范围和动作白名单这类细粒度边界由 GenAuth 的 Agent Profile 或策略层配置强制执行,不由任务 prompt 承担;本页示例未展示该配置。完整语义见 Delegate Token 与缩权

工作流程

广告创意审查 Agent 工作流程

  1. 用户选择要审查的广告系列或创意草稿清单,并在 Qoni Console 确认本次交互式授权。

  2. GenAuth 为本次任务签发最小权限的只读委托凭证。

  3. 应用从规则库读取当前版本的品牌与合规规则,连同平台政策要点注入任务描述。

  4. Web Agent 登录广告平台或创意库,逐条抽取素材、文案、目标页链接和 claims,每条保留截图与来源。

    检查点:广告平台出现登录墙、验证码或风控页时,Web Agent 应升级给人处理,而不是静默绕过。

  5. Agent 对照规则逐条审查创意,标注风险项、疑似违规 claims 和与目标页不一致的表述,每条附创意 ID 和触发的规则编号。

  6. 应用侧校验输出契约:缺少创意 ID 或规则编号的意见直接丢弃。

  7. Agent 输出审查意见:风险分级、修改建议和待确认 claims,附规则版本号与 audit id,交由人工确认;确认结果归档到你的审查系统。

    检查点:每条风险项都应能回溯到具体创意来源和触发的规则版本;无来源支撑的结论不应进入交付物。

示例代码

下面的示例使用官方 Qoni SDK@qoniai/qoni)把这个场景接到你的服务端:交互式委托(含完整回调)→ 从规则库读取品牌与合规规则 → 一次 doAnything.run() 完成逐条审查 → 解析并校验审查意见。

ts
import { Qoni, QoniScopes } from '@qoniai/qoni'

const qoni = new Qoni({
  accessKey: process.env.QONI_ACCESS_KEY!,
  secretKey: process.env.QONI_SECRET_KEY!,
})

// 1. 交互式委托:涉及广告平台登录,让用户在 Qoni Console 确认授权
export async function startCreativeReview(userId: string, taskId: string) {
  const { data: authorization } = await qoni.delegateToken({
    mode: 'interactive',
    agent: 'ad-creative-review',
    scopes: [QoniScopes.DO_ANYTHING_READ, QoniScopes.DO_ANYTHING_MANAGE],
    redirectUri: 'https://app.example.com/qoni/callback',
    state: taskId,
    user: { id: userId },
    expiresIn: 900, // 单次审查任务给分钟级有效期
  })
  redirectUserTo(authorization.authorizationUrl)
}

// GET /qoni/callback —— 用户同意后在服务端兑换 grant,继续执行任务
export async function handleQoniCallback(request: Request) {
  const query = new URL(request.url).searchParams
  const { data: grant } = await qoni.completeDelegateToken({
    grantId: query.get('grantId')!,
    code: query.get('code')!,
    state: query.get('state')!,
  })
  return runReviewTask(grant, await loadReviewTask(query.get('state')!))
}

async function runReviewTask(
  grant: { token: string; auditId: string; grantedScopes: string[] },
  task: { campaigns: string[] },
) {
  // 2. 任务前:从你的规则库读取当前版本的品牌与合规规则(不是 Memory)
  const policy = await loadCreativeReviewPolicy() // 例如 { version: '2026-08', forbiddenClaims: [...], brandVoice: ... }

  // 3. 一次调用完成审查:登录平台、逐条抽取、只输出审查意见
  const run = await qoni.doAnything.run({
    token: grant.token,
    prompt: `
      Review the creative drafts in these campaigns: ${task.campaigns.join(', ')}.
      Extract each creative's image, headline, description, landing page link
      and claims, then flag risks against the policy below. Return findings as
      a JSON array of { creativeId, risk, quote, ruleId, sourceUrl } objects.
      Review only — never submit, change budgets, edit or take ads down.

      Creative review policy (version ${policy.version}):
      ${JSON.stringify(policy)}
    `,
    capture: { screenshots: true },
  })

  const result = await run.wait({
    // 登录墙 / MFA / 风控页:升级给人处理
    onInteraction: (interaction) => notifyUserActionRequired(interaction),
  })

  // 4. 应用侧校验输出契约:缺创意 ID 或规则编号的意见直接丢弃
  const opinions = parseOpinions(result.output).filter(
    (o) => o.creativeId && o.ruleId,
  )

  return {
    opinions, // 待人工确认;确认结果归档到你的审查系统
    artifacts: result.artifacts,
    policyVersion: policy.version,
    audit: { auditId: grant.auditId, permissionBoundary: grant.grantedScopes },
  }
}

输出结构由任务描述约定:这里约定返回 { creativeId, risk, quote, ruleId, sourceUrl } 数组,应用侧 parseOpinions 负责解析与校验,任何缺少 creativeIdruleId 的条目被直接丢弃。SDK 顶层只返回通用的 RunResultrunIdstatusoutputartifacts 等)。

数据与记忆边界

这个场景涉及四类数据,只有最后一类属于 GUMem:

  • 版本化规则:品牌规范、合规禁用词、平台政策要点——放在规则库(policy store)里按版本管理,每条审查意见引用规则版本号。
  • 业务状态:审查意见、人工确认结果、历史拒审记录——归档到你的审查系统,供后续批次对照与追溯。
  • 审计记录:grantIdauditId 构成的委托与行为链——由 GenAuth 维护。
  • 用户 Memory(可选):审查者确认的长期偏好(例如意见措辞的口吻)——这才是 GUMem 的位置;单次审查默认不召回也不写回。

失败处理

情况推荐处理
广告平台登录态失效任务挂起,通知用户重新登录,从断点继续。
创意库页面结构变化导致抽取失败按失败处理并回放会话记录,不输出无证据的风险项。
委托范围外的广告账户请求直接拒绝并记录,事后可在审计链中查到未遂访问。
输出条目缺少创意 ID 或规则编号应用侧校验直接丢弃该条目,并在意见汇总中标注丢弃数量。

生产注意点

Agent 不应自动提交投放、修改预算或发布广告。高风险 claims 应交给人工确认。审查意见只作为投放决策的输入,不直接触发创意下线;每条意见都应带规则版本号,规则更新后旧意见不追溯改判。对广告平台的抽取频率应设置上限,避免触发平台风控。

下一步