本地化 Messaging Agent
本页说明本地化 Messaging Agent 如何在交互式委托下读取源 campaign 和区域市场页面实况,对照版本化的术语表与禁译词逐市场核对 messaging 一致性,并以事件流形式返回巡检进度和差异清单。读完本页,你能理解这个场景需要哪些模块、逐市场巡检的进度如何流式返回,以及术语表这类数据为什么应该放在本地化配置库而不是 Memory。
适用场景
国际化 marketing 团队需要把 campaign、landing page 或广告文案改写成适合目标地区的版本,并核对已上线的多语言页面是否与源 messaging 保持一致。区域页面由本地团队各自维护,术语翻译漂移、禁译词误用和源文案更新后的滞后很难靠人工逐市场发现。
典型触发时机:
- 源 campaign 文案更新后,需要核对各语言市场页面是否同步。
- 进入新市场前,需要对照当地竞品和市场惯例校准 messaging。
- 术语表或禁译词更新后,需要排查各区域页面的存量翻译。
工程挑战
- 多市场 × 多页面的核对量随市场数线性增长:每个市场都要抽取实况文案、对照术语表逐条比对,串行人工核对在源文案更新后的时间窗口内根本做不完,而巡检进行到哪、卡在哪个市场需要实时可见。
- 差异判定依赖版本化规则:术语表和禁译词更新频繁,一条差异是"真漂移"还是"依据了旧版术语表"必须可追溯到规则版本,否则当地 reviewer 无法复核。
- 借用员工账号读取区域 workspace 权限过宽:借来的登录态能看到全部市场的 campaign 资料,而单次核对只需要指定源文案和目标区域的只读访问。
模块组合
| 模块 | 角色 | 说明 |
|---|---|---|
| GenAuth | 核心 | 区域 workspace 与 campaign 资料的只读委托、撤销与审计链;发布译文和修改页面留在委托范围之外。 |
| Web Agent | 核心 | 受控会话逐市场抽取当地已上线页面的实况文案,保留来源 URL 与截图,并查询当地竞品页面作措辞对照。 |
| GUMem | 不使用 | 术语表、禁译词属于版本化规则,放在你的本地化配置库里按版本注入;差异清单与 reviewer 决策属于业务状态,归档到你的本地化记录——都不属于 Memory。 |
权限与委托边界
Agent 本身不持有任何固有权限。每次核对任务的实际权限是三个集合的交集:用户真实权限 ∩ 本次显式委托范围 ∩ 企业批准边界。落到这个场景:
- 委托范围只覆盖"读取指定 campaign 资料、区域 workspace 和当地公开页面",不包含发布译文、修改区域页面或改动术语表。
- 委托凭证短时效,单次核对任务建议分钟级有效期,过期后需重新委托。
- 用户或管理员可随时撤销授权;撤销后新的资料读取请求立即失败。
- 越权尝试(例如读取委托范围外的其他市场 workspace)会被拒绝并留痕——审计链覆盖全部尝试,不只是成功行为。
注意:SDK 示例申请的是产品级 scope(如 webagent.do_anything:read)。域名清单、页面范围和动作白名单这类细粒度边界由 GenAuth 的 Agent Profile 或策略层配置强制执行,不由任务 prompt 承担;本页示例未展示该配置。完整语义见 Delegate Token 与缩权。
工作流程
用户选择源文案、目标地区和要核对的当地页面清单。
GenAuth 发起交互式委托;用户在 Qoni Console 确认后,服务端回调兑换出最小权限的只读凭证。
应用从本地化配置库读取当前版本的术语表、禁译词和区域措辞规范,注入任务描述。
Web Agent 逐市场抽取当地已上线页面的实况文案,保留来源 URL 与截图;巡检进度以事件流实时返回。
检查点:区域 workspace 或当地页面遇到登录墙、验证码或风控页时,Web Agent 应升级给人处理,而不是静默绕过。
Web Agent 查询当地竞品和公开市场资料,补充措辞惯例对照。
Agent 对照源 messaging、术语表和禁译词逐条比对当地页面,标注翻译漂移、禁译词误用和滞后未同步项,每条附页面来源和依据的规则版本。
Agent 输出本地化差异清单、修正建议草稿、改写理由和来源,附 audit id;应用侧校验后交当地 reviewer 确认。
检查点:每条差异和建议都应能回溯到具体页面来源或术语表条目;无来源支撑的结论不应进入交付物。
示例代码
下面的示例使用官方 Qoni SDK(@qoniai/qoni)把这个场景接到你的服务端:交互式委托(完整 callback)→ 从本地化配置库读取术语表 → 一次 doAnything.run() 完成多市场核对,用 run.events() 事件流实时转发逐市场巡检进度 → 解析并校验差异清单。
import { Qoni, QoniScopes } from '@qoniai/qoni'
const qoni = new Qoni({
accessKey: process.env.QONI_ACCESS_KEY!,
secretKey: process.env.QONI_SECRET_KEY!,
})
export async function startLocaleCheck(userId: string, taskId: string) {
// 1. 交互式委托:涉及区域 workspace 登录,让用户在 Qoni Console 确认授权
const { data: authorization } = await qoni.delegateToken({
mode: 'interactive',
agent: 'localization-messaging',
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')!,
})
const task = await loadLocaleCheckTask(query.get('state')!) // 你的任务存储
return runLocaleCheck(grant, task)
}
async function runLocaleCheck(
grant: { token: string; auditId: string; grantedScopes: string[] },
task: { region: string; localPages: string[]; sourceMessaging: string },
) {
// 2. 任务前:从你的本地化配置库读取当前版本的术语表与禁译词(不是 Memory)
const policy = await loadLocalizationPolicy(task.region) // 例如 { version: '2026-08', glossary: [...], forbiddenTranslations: [...] }
// 3. 一次调用完成核对:抽取当地实况、比对源 messaging,只输出草稿
const run = await qoni.doAnything.run({
token: grant.token,
prompt: `
Verify the live pages for market ${task.region}:
${task.localPages.join(', ')}.
Capture the live copy, compare it against the source messaging,
glossary and forbidden translations, then flag drift, misused
terms and unsynced copy. Return diffs as a JSON array of
{ page, diff, suggestion, sourceUrl, glossaryRef } objects.
Never publish, edit pages or change the glossary.
Source messaging: ${task.sourceMessaging}
Localization policy (version ${policy.version}):
${JSON.stringify(policy)}
`,
capture: { screenshots: true },
})
// 4. 事件流:逐市场巡检的进度、截图和需要人参与的步骤实时转发给前端
let output: unknown
for await (const event of run.events()) {
if (event.type === 'progress') appendTrace(event.data) // 巡检到哪个页面
if (event.type === 'screenshot') renderScreenshot(event.image) // 每页取证截图
if (event.type === 'interaction') handleInteraction(event.data) // 登录墙 / 验证码升级给人
if (event.type === 'done') output = event.data.output
}
// 5. 应用侧解析并校验输出契约:缺少来源或术语表条目引用的差异不进交付物
const diffs = parseLocaleDiffs(output).filter(
(d) => d.sourceUrl && d.glossaryRef,
)
return {
diffs,
policyVersion: policy.version,
audit: { auditId: grant.auditId, permissionBoundary: grant.grantedScopes },
}
}输出结构由任务描述约定:这里约定返回 { page, diff, suggestion, sourceUrl, glossaryRef } 数组,应用侧 parseLocaleDiffs 负责解析与校验,缺少 sourceUrl 或 glossaryRef 的条目被直接丢弃。事件流断线时 SDK 使用 Last-Event-ID 自动重连续传;事件类型常量见 QoniEventTypes。
数据与记忆边界
这个场景涉及四类数据,本场景不使用 GUMem:
- 版本化规则:术语表、禁译词、区域措辞规范——放在你的本地化配置库里按版本管理,每条差异引用规则版本号。
- 业务状态:差异清单、修正建议、页面截图、reviewer 决策——归档到你的本地化记录,供复核与追溯。
- 审计记录:
grantId与auditId构成的委托与行为链——由 GenAuth 维护。 - 用户 Memory(可选):只有用户明确确认的长期个人偏好才属于 GUMem;术语表和区域规范是团队级规则,不是个人记忆,本场景默认不召回也不写回。
失败处理
| 情况 | 推荐处理 |
|---|---|
| 区域 workspace 登录态失效 | 任务挂起,通知用户重新登录,从断点继续。 |
| 当地页面结构变化导致抽取失败 | 按失败处理并回放会话记录,不输出无证据的差异项。 |
| 委托范围外的市场 workspace 请求 | 直接拒绝并记录,事后可在审计链中查到未遂访问。 |
| 输出差异缺少页面来源或术语表条目引用 | 应用侧校验直接丢弃该条差异,并标注丢弃数量和依据的规则版本。 |
生产注意点
不要把本地化建议当作法律、文化或合规最终判断。发布前应由当地 reviewer 确认。Agent 只输出差异清单与修正建议草稿,不直接发布译文或修改区域页面;对当地竞品页面的抽取频率应设置上限。术语表更新后应在配置库中发布新版本,避免旧版规则继续判定新差异。
下一步
- 阅读 快速开始 跑通 Agent 身份与委托的最短路径。
- 阅读 授权与浏览器沙盒 了解受控会话的安全边界。
- 继续查看 品牌一致性 Agent 了解相邻场景。