广告位的交互一直是"看一眼、点一下、跳走",疑问留在落地页表单里,销售链路被切得很碎。Sponsored Agents 把这一段缩短了:在 ChatGPT 里点击广告之后,可以和企业赞助的智能体直接对话,该智能体带有明确标注。这一期按接入方视角拆工程问题——上下文怎么隔离、事件怎么回传、账怎么分两本记;接入层的中转与配额我挂在 4sapi(https://4sapi.com)的网关上跑。

一、开篇痛点:广告只能点,不能问

一条广告成交链路原本有三处断裂:曝光到兴趣、兴趣到疑问、疑问到留资。过去这三段基本都压给落地页,而落地页只能做单向陈述。用户真正卡住的问题往往很具体——这套东西能不能对接现有系统、换个地区报价怎么变、账期和合同周期多长——这些问题在落地页上没有入口,只能跳出到客服队列,跳出一次就掉一批人。

Sponsored Agents 补的正是第二段。点击广告后进入一段可追问的对话,企业用自己的知识、话术和边界来回答;用户准备采取下一步时,点击链接前往企业网站。对企业侧的价值也很直白:通过个性化对话帮助感兴趣的客户了解产品与服务,而不是把所有人塞进同一张表单。

对做接入的人来说,真正需要盯住的不是"多了一个对话框",而是会话从平台侧长出了一个新的边界。这个边界决定三件事:会话历史落在哪、转化事件由谁记账、每一轮对话的成本算在谁头上。三件事里任何一件没想清楚,上线之后都会变成对账纠纷,而且是跨团队、跨系统、很难取证的那种。

二、原理速览:这一批更新到底改了什么

Sponsored Agents 目前在美国与部分精选广告主进行测试。同一批更新还包括广告创建、集成伙伴、广告主工具与创意辅助几块,逐个看:

把上面这些翻译成接入侧的工作项,关系会更清楚:

平台能力 接入侧要落的东西 容易漏的点
Sponsored Agent 可对话 企业侧应答服务、知识检索、会话状态 把主对话内容带进商务会话
广告创建走向提示词化 广告结构可被程序化描述、模板化 提示词生成物没有版本管理
HubSpot 作为首个 CRM 合作伙伴 CRM 对象映射、潜在客户去重、跟进流 事件重复入库导致线索重复
Shopify 作为首个电商合作伙伴 Catalog 同步、商品与投放地区对齐 价格与库存漂移
建议文案与图像 人审位、审阅记录、回滚 建议直接进活动、无人复核
可选 AI 文本定制与翻译 多语言版本治理、术语表 机器翻译扛价格与法律措辞

这张表里的右列,基本就是后面几节要展开的内容。左列是平台给的能力,右列是自建系统的责任,两者之间没有自动衔接。

三、上下文隔离为什么是生死线

有一句话值得抄进接入设计文档:与 Sponsored Agent 的对话不同于 ChatGPT 的独立回答,也独立于用户在 ChatGPT 中发起的原始对话。也就是说存在两条隔离线——一条隔开模型侧的通用回答,一条隔开用户自己的主对话。这两条线同时成立,商业会话才是一个可管理的对象。

从工程角度看,隔离带来三层价值。

第一层是可审计。会话边界清楚,意味着每一次商务对话都可以有自己的会话标识、自己的消息序列、自己的开始与结束时间。出现争议时能回放"当时用户问了什么、智能体答了什么、依据是哪条商品或政策",而不是在混在一起的上下文里猜。审计要能追溯到具体会话和具体轮次,光有一份总日志没有用。

第二层是数据边界与免责。主对话里可能有用户的私人内容、别的品牌的咨询、和本次广告完全无关的信息。如果接入侧把主对话上下文直接拼进商务会话,就会出现越界引用:智能体可能回答出用户没在这段对话里说过的事。这既是体验事故,也是合规事故。反过来,商务会话的内容也不应该回流去影响模型对用户的通用回答——包括不该回流去影响 ChatGPT 的独立回答。

第三层是可计量。只有会话独立、轮次可数,按对话轮次计费的口径才成立。会话粘连在一起,轮次归属就说不清,广告账本和模型账本都没法闭合。这一点在第七节展开。

一个常见的错误做法是"上下文越多越好",把用户画像、历史订单、主对话摘要全部塞进系统提示词。隔离线一旦被自己拆掉,再想恢复就只能靠事后补救,而事后补救的成本往往高于重做一次接入。

四、请求流与四类事件

把点击到转化的路径画出来,比在文档里争论接口命名有效得多:

用户点击广告
      |
平台侧创建 Sponsored Agent 会话(带明确标注)
      |
独立会话:不继承用户主对话,也不混入模型独立回答
      |
企业侧接入层:鉴权 / 租户映射 / 会话白名单 / 配额
      |
      +--> 知识与商品检索(政策、规格、Catalog 快照)
      |
      +--> 模型调用(经 4sapi 网关统一中转与计量)
      |
      v
生成回复 --> 用户追问(同一会话内可多轮)
      |
用户准备采取下一步 --> 点击链接前往企业网站
      |
企业侧事件回传(曝光 / 点击 / 会话开始 / 轮次 / 留资 / 转化)
      |
归因与对账:广告投放口径一本账,模型调用口径一本账

这条链路上,接入方真正拥有并要负责的是中间那一段:鉴权、检索、模型调用、事件回传。两端的会话生命周期由平台侧管理,不要试图在自家系统里再伪造一套会话状态。

事件模型建议固定成四类,字段不要在项目中途改名:

事件类型 触发时机 必需字段 幂等键建议
曝光 广告被展示 广告标识、会话标识、时间戳 广告标识 + 展示位 + 分钟粒度
点击 用户点击进入会话 广告标识、会话标识、入口位置 广告标识 + 会话标识
会话轮次 每完成一轮问答 会话标识、轮次序号、模型用量、语言 会话标识 + 轮次序号
留资与转化 用户提交或到达企业网站完成动作 会话标识、线索标识、转化类型 线索标识 + 转化类型

第四类事件最容易被重复回传。用户在会话里点了两次链接、企业网站又触发一次跳转、重试逻辑再补一次请求,都可能让同一条线索落库三次。所以幂等键不是可选项,是回传接口的组成部分。

五、接入 CRM:HubSpot 侧该做什么

HubSpot 是首个 CRM 合作伙伴。管理客户的企业可以连接 ChatGPT Ads 账户,直接在 HubSpot 中创建广告、跟踪效果并跟进潜在客户,由 HubSpot 上下文支持。对已经用 HubSpot 管客户的企业,这条路的好处是不用新建一套投放后台,广告对象和客户对象本来就住在一起。

接入时值得先定清楚的是三组映射关系。

第一组是账户与权限。企业侧连接 ChatGPT Ads 账户之后,谁来创建广告、谁只能看效果、谁可以跟进潜在客户,应该在 CRM 的权限模型里有对应角色。广告创建权限和下发给销售团队的线索跟进权限不是一回事,混在一个角色里,后面很难收紧。

第二组是对象映射。广告活动、广告、会话、线索、联系人这五个对象之间的父子关系要在 CRM 里显式落下来。尤其是会话到线索的映射:一段对话可能不产生任何线索,也可能产生多条线索(用户先问 A 产品再问 B 产品),映射关系设计成一对一会让数据失真。

第三组是去重与跟进顺序。线索落库之后谁先跟进、多久算超时、未接通如何回流,这些属于业务流程,但字段必须在回传阶段就带上,例如渠道标识、会话标识、首次咨询商品、偏好的语言。字段缺失的线索,在 CRM 里基本等于聋子耳朵。

顺序上建议这样排:会话结束触发线索对象生成,线索对象关联到联系人,联系人上写回渠道与归因字段,然后才进入销售的跟进队列。把归因字段放在最后补,就会出现一批线索永远没有渠道信息,报表只能靠估算。

六、接入电商:Shopify 侧与 Catalog 同步

Shopify 是首个电商合作伙伴。位于美国的商家可以在 Shopify App Store 使用新的 ChatGPT Ads 应用创建与管理广告活动;产品已通过 Shopify Catalog 集成,商家可立即投放并跟踪效果;该应用将于 9 月 23 日起在 ChatGPT Ads 可用的国际市场推出。

电商这条路的工程重心在 Catalog 一致性,而不是广告后台的操作。商品已经通过 Shopify Catalog 集成,这意味着一份商品数据同时在两个地方生效:店铺里和广告里。数据一旦漂移,智能体就会一本正经地报出错误的价格或库存。

同步字段 漂移后果 建议做法
商品标识 会话推荐了不存在的商品 以 Catalog 主键为准,不做二次编码
价格与币种 报价与结算不一致 价格变更触发快照失效,不沿用旧快照
库存与可售状态 会话仍在推荐已售罄商品 检索层加可售过滤,不靠模型判断
可售地区 向非投放地区展示 地区白名单在检索层做,不由模型兜底
商品描述与卖点 建议文案与实物不符 描述变更走审阅,不自动进会话

上线节奏也要按平台侧来:美国商家可以先接,国际市场上从 9 月 23 日起随应用推出。多市场铺开时,产品文案、币种、退换政策、计量单位都要一起过一遍。把美国市场的会话脚本原样搬到别的市场,是最省事也最容易出事的一种做法。

七、计费口径:广告成本与模型调用成本分两本账

这里的坑几乎全部来自把两本账合成一本。广告投放成本走的是投放口径:花费、曝光、点击、转化,观察面板在 Ads Manager 以及 HubSpot、Shopify 侧。模型调用成本走的是推理口径:输入输出用量、缓存命中、工具调用、每轮对话的延迟。两者币种不同、归集主体不同、结算周期也不同,硬合成一个数字之后,既不能优化投放,也不能优化推理。

按对话轮次计的账可以写成这个式子:

单次会话的模型侧成本 ≈ 每轮推理成本 × 期望轮次 + 检索与工具调用成本 + 多语言版本带来的额外用量

转化成本 ≈ 广告花费 ÷ 转化数

真正要比较的是这两个数:单次会话的模型侧成本,和单次会话带来的毛利。前者是自己能优化的,后者取决于商品与定价。只盯转化成本会得出"投放贵"的结论,只盯推理成本会得出"对话便宜、可以无限开放"的结论,两种结论都不完整。

成本项 计费口径 观察位置 优化手段
广告花费 投放口径,按曝光与点击计数 广告后台、CRM、电商后台 创意与人群调整
会话轮次用量 推理口径,按用量与轮次计数 自建网关面板 提示词瘦身、缓存复用、会话轮次上限
检索与工具调用 内部资源口径,按调用次数计数 接入层面板 缓存商品快照、限制工具调用深度
多语言版本 推理口径叠加创意维护成本 创意版本库 术语表、只对必要语种开启定制
归因与回传 工程口径,按事件量计数 事件管道 幂等去重、批量回传、限制重试次数

轮次上限这个手段容易被忽略。商务对话天然开放,但工程上要设一个软上限:超过若干轮之后把对话引导到留资或跳转,而不是无限追问。这既控制成本,也避免把对话拖成没有结论的长尾。

多语言那个可选能力也要算进账里。按对话语境调整已有标题与描述,并自动把广告文案翻译成用户偏好的语言,会让同一份创意长出多个语言版本。版本数一上去,创意维护成本、审阅成本、回滚成本都会同步上涨,这部分不体现在推理账单里,但确实发生在团队身上。

八、教程:接入应答服务与幂等回传

这一段是可直接照抄的部分。应答服务做三件事:用会话标识和轮次拼出稳定的请求,调用模型生成回复,拒绝跨会话的上下文注入。接入层走 OpenAI 兼容接口,凭据从环境变量读取,不落进代码库:

import os
import time
import hashlib
from openai import OpenAI

# 凭据只从环境变量读取,严禁硬编码进仓库或镜像
client = OpenAI(
    api_key=os.environ["FOURSAPI_API_KEY"],
    base_url=os.getenv("FOURSAPI_BASE_URL", "https://4sapi.com/v1"),
    timeout=30.0,
)

SYSTEM_PROMPT = (
    "只在本次广告会话范围内回答,不引用会话之外的信息;"
    "价格、库存、政策必须来自检索结果;无法确认时明确说明并引导留资。"
)


def session_id_of(ad_id: str, platform_chat_id: str) -> str:
    """会话标识由广告与会话共同决定,保证隔离且可追溯。"""
    raw = f"{ad_id}:{platform_chat_id}".encode("utf-8")
    return hashlib.sha256(raw).hexdigest()[:24]


def build_messages(session_id: str, history: list[dict], user_text: str,
                   retrieved: list[dict]) -> list[dict]:
    """只带入本次会话的历史,绝不拼接用户主对话内容。"""
    facts = "\n".join(f"- {r['title']}: {r['snippet']}" for r in retrieved)
    scoped = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "system", "content": f"会话标识 {session_id}\n可用事实:\n{facts}"},
    ]
    return scoped + history[-8:] + [{"role": "user", "content": user_text}]


def reply(session_id: str, history: list[dict], user_text: str,
          retrieved: list[dict], locale: str) -> dict:
    messages = build_messages(session_id, history, user_text, retrieved)
    started = time.time()
    resp = client.chat.completions.create(
        model=os.getenv("FOURSAPI_MODEL", "gpt-4o-mini"),
        messages=messages,
        temperature=0.3,
    )
    return {
        "session_id": session_id,
        "text": resp.choices[0].message.content,
        "locale": locale,
        "latency_ms": int((time.time() - started) * 1000),
        "usage": getattr(resp, "usage", None) and resp.usage.total_tokens,
    }

回传这一段的关键是幂等。事件在进入队列之前先算出幂等键,服务端查到键已经成功处理过就直接返回 200,不再写第二遍:

import json
import time
import hashlib

RETRY_BACKOFF = [1, 2, 4, 8]


def idempotency_key(event: dict) -> str:
    """同一事件无论重试多少次,键必须一致。"""
    if event["type"] == "impression":
        basis = f"{event['ad_id']}:{event.get('slot', '')}:{event['ts'] // 60}"
    elif event["type"] in ("click", "session_start"):
        basis = f"{event['ad_id']}:{event['session_id']}"
    elif event["type"] == "turn":
        basis = f"{event['session_id']}:{event['turn']}"
    else:
        basis = f"{event['lead_id']}:{event['conversion_type']}"
    return hashlib.sha256(basis.encode("utf-8")).hexdigest()


class EventSink:
    """先查幂等键,再落库;重试使用固定退避表,次数封顶。"""

    def __init__(self, store, post):
        self.store = store      # 例如 Redis / 数据库唯一索引
        self.post = post        # 企业侧事件接收端

    def emit(self, event: dict) -> dict:
        key = idempotency_key(event)
        if self.store.seen(key):
            return {"status": "duplicate", "key": key}
        payload = json.dumps({**event, "idempotency_key": key}, ensure_ascii=False)
        for index, delay in enumerate(RETRY_BACKOFF):
            try:
                self.post(payload)
                self.store.mark(key, ttl_sec=7 * 24 * 3600)
                return {"status": "ok", "key": key, "attempts": index + 1}
            except Exception:
                if index == len(RETRY_BACKOFF) - 1:
                    break
                time.sleep(delay)
        return {"status": "failed", "key": key}

两个实现细节要强调。其一,历史只取最近若干轮,并且只取本次会话的消息,任何来自主对话或其它会话的内容一律不进请求体。其二,幂等键必须由事件自身的业务字段推导,不能带随机数、不能带重试次数、不能带服务器时间,否则重试一次就变成一条新事件。

九、广告主侧:Ads Manager 与创意辅助怎么接

广告主侧的变化是操作方式变了。通过 Ads Manager 插件,可以在 ChatGPT 里用自然语言提示词创建、更新和分析广告活动;可以把网站或简报转成广告活动、了解效果、获得下一步行动建议。也就是说,"把一份网站或简报变成一组投放"这件事,从手工填表变成了给输入、审输出。

产出要能被审阅,链路才算完整。起草广告时,依据落地页与广告活动目标会给出建议的文案与图像,广告主仍掌握控制权,可以在决定加入广告活动前审阅并编辑这些建议。这句"决定加入之前"是整个流程的闸门,接入侧要把它落成系统里的一个人审位,而不是一句口头约定。

可选启用的 AI 文本定制更需要在流程上留痕:按对话语境调整广告主已有的标题与描述,并自动把广告文案翻译成用户偏好的语言。定制意味着同一份创意会随语境和语言分叉,分叉之后必须有版本号和回滚点。否则某一种语言的表述出了问题,很难定位是哪次定制产生的。

给接入侧的建议是把创意资产按三层管理:原始素材(落地页、简报)、平台建议(文案与图像草稿)、已投放版本。三层之间保留引用关系,任何一层变更都能回答"这次改动影响了哪些在投活动"。

十、对照表:三条接入路径怎么选

把三类企业放在一起对照,选择会清楚很多:

维度 自建应答层 走 HubSpot 走 Shopify
适用对象 有自有系统与知识库的企业 用 CRM 管客户的企业 有商品目录的商家
接入重心 会话隔离、检索、网关计量 对象映射、线索去重、跟进流 Catalog 一致性、地区与库存
归因粒度 可自定义,最灵活 中等,跟随 CRM 对象 中等,跟随商品与订单
主要风险 上下文越界、成本失控 线索重复、字段缺失 价格与库存漂移
上线节奏 自行排期 随账户连接推进 美国先行,国际市场自 9 月 23 日起

三条路并不互斥:HubSpot 管客户关系,Shopify 管商品与订单,自建应答层管对话质量与计量。企业规模一旦上去,通常是三条并存,再在事件层做一次统一去重。

如果只选一条先跑,建议以"事件层能不能统一"作为判断标准。会话隔离做得好、事件字段齐、幂等键稳定的那条路,扩起来最省事;反过来,先上一条没有幂等回传的路,后面每加一条都要还一次债。

十一、商业 agent 上线的避坑清单

按上线顺序过一遍,每一条都能在验收时打分:

  1. 标注合规:Sponsored Agent 在 ChatGPT 中带明确标注,接入侧不得隐藏、不得把商业会话伪装成普通回答。
  2. 上下文边界:会话独立于模型的通用回答,也独立于用户在 ChatGPT 中发起的原始对话,禁止回填主对话内容。
  3. 语言本地化:偏好语言会触发自动翻译与语境定制,价格、法律措辞、计量单位必须人工确认,不能只依赖机器翻译。
  4. 幂等回传:事件由业务字段推导幂等键,服务端先去重再落库;重复点击与重试不得重复计数。
  5. Catalog 一致性:商品标识、价格、币种、库存、可售地区与投放地区一致,检索层做白名单过滤,不靠模型兜底。
  6. 归因口径:转化定义先写死一份文档,广告账本与模型账本分开,报表口径变更走评审。
  7. 权限最小化:平台凭据与模型凭据只从环境变量注入,日志脱敏,线索可见范围按角色收敛。
  8. 灰度与回滚:先在美国与精选广告主的口径内跑通,国际市场上线前完成多市场回归与回滚演练。
  9. 人审位:建议文案与建议图像在加入广告活动之前必须经过审阅与编辑,审阅动作留痕。
  10. 留存策略:会话记录与线索记录的保存期限、脱敏方式、删除流程提前落定,不留"以后再说"。

清单里第 3 条和第 9 条最容易被低估。翻译与创意分叉带来的不是技术难题,而是流程难题:谁有权改、改完谁复核、出问题回滚到哪一版。这三问没有答案,多语言和 AI 创意工具就只能在单个语种、单个市场里小范围使用。

十二、成本与风险提示

十三、总结

这一期把 ChatGPT 广告位上的智能体当成一个可接入的商业会话系统来拆:会话与用户主对话隔离、也与模型独立回答隔离,这是审计、数据边界和计费的共同前提;HubSpot 方向的重心在对象映射与线索去重,Shopify 方向的重心在 Catalog 一致性与投放地区,美国商家先行、国际市场上自 9 月 23 日起随应用推出;成本上把广告投放和模型调用分两本账,按轮次算模型侧成本,再和单会话毛利比,才有决策价值;上线前按标注合规、数据边界、语言本地化、幂等回传这四项逐条验收。应答与回传的示例代码可以直接改,接入层统一走 4sapi(https://4sapi.com)中转与计量,广告账本与模型账本在同一个请求标识下对得上。这些取舍在各自业务里怎么落地,欢迎在评论区聊聊。