多 Agent 系统有一种很省事的接力方式:把前面所有 messages 原样交给下一个 Agent。
短流程里它能跑,长流程里它会慢慢变成"上下文垃圾车"。旧草稿、工具返回、被否决的结论、无关附件和敏感信息一起进入下一站。接收者看见了很多,却不知道哪一项可以直接使用。
问题不在 Agent 不聪明,而在我们没有定义交付接口。
这篇不讨论再加一个路由 Agent,而是给 Agent 之间的产物加一层 Artifact Envelope:让接收者在执行前验证版本、来源、权限、验收状态和幂等键。
为什么 shared context 不等于 broadcast history
OpenAI 8 月 25 日发布的《The full stack behind abundant intelligence》强调跨基础设施、模型、平台和产品的一体化协同,也指出不同 workload 对能力、速度、可靠性、效率和成本的要求不同。
这里有个容易混淆的工程判断:共享基础设施可以让信息互通,但不代表每个 Agent 都应该接收所有历史。
真正需要共享的是一致的事实源、产物目录、权限策略和验收状态。聊天历史只是这些状态产生过程中的一种日志,不该自动成为业务接口。

一个工作包,六类字段
先看 TypeScript 结构:
ts
type AcceptanceStatus = "passed" | "failed" | "partial";
interface ArtifactEnvelope {
schemaVersion: "1.0";
handoffId: string;
producer: string;
consumer: string;
task: {
id: string;
goal: string;
};
artifact: {
type: string;
uri: string;
version: number;
sha256: string;
};
evidence: Array<{
claimId: string;
source: string;
status: "verified" | "unverified" | "opinion";
}>;
permissions: {
canRead: string[];
canWrite: string[];
canPublish: boolean;
expiresAt: string;
};
acceptance: {
status: AcceptanceStatus;
checks: string[];
};
idempotencyKey: string;
}
为什么不是 summary: string?因为摘要不能稳定回答下面的问题:
artifact:接收者拿的是 v2 还是 v3,内容有没有被改;evidence:哪些句子有官方来源,哪些只是作者判断;permissions:能生成文件,是否也能公开发布;acceptance:模型产出过,还是已经通过事实和格式检查;idempotencyKey:同一次超时重试,会不会产生第二份"最终版"。
把交接拆成 producer、gate、consumer
生产者不直接把聊天记录塞给接收者,而是先写 Envelope;gate 完成验证;只有通过的工作包才进入下游。

ts
type RejectCode =
| "SCHEMA_INVALID"
| "ARTIFACT_MISSING"
| "DIGEST_MISMATCH"
| "UNVERIFIED_CLAIM"
| "UPSTREAM_NOT_ACCEPTED"
| "PERMISSION_EXPIRED"
| "PERMISSION_SCOPE_INVALID";
type GateResult =
| { ok: true; handoffId: string }
| {
ok: false;
stage: "schema" | "content" | "permission";
codes: RejectCode[];
retryable: boolean;
repair?: string;
};
Gate 最好按顺序执行:
ts
async function validateEnvelope(e: ArtifactEnvelope): Promise<GateResult> {
const schemaErrors = validateSchema(e);
if (schemaErrors.length) {
return reject("schema", ["SCHEMA_INVALID"], false);
}
if (!(await artifactStore.exists(e.artifact.uri))) {
return reject("content", ["ARTIFACT_MISSING"], true);
}
const actualDigest = await artifactStore.sha256(e.artifact.uri);
if (actualDigest !== e.artifact.sha256) {
return reject("content", ["DIGEST_MISMATCH"], false);
}
if (e.evidence.some(x => x.status === "unverified")) {
return reject("content", ["UNVERIFIED_CLAIM"], true);
}
if (e.acceptance.status !== "passed") {
return reject("content", ["UPSTREAM_NOT_ACCEPTED"], true);
}
if (Date.parse(e.permissions.expiresAt) <= Date.now()) {
return reject("permission", ["PERMISSION_EXPIRED"], true);
}
if (!policyAllows(e.consumer, e.permissions)) {
return reject("permission", ["PERMISSION_SCOPE_INVALID"], false);
}
return { ok: true, handoffId: e.handoffId };
}
格式检查通过不代表事实正确,事实正确也不代表有权产生副作用。把三道门合成一个 valid=true,排障时很快会失去信息。
Handoff 负责转移控制,Envelope 负责证明可交付
OpenAI Agents SDK 的官方 handoff 文档提供了几个直接可用的机制:
input_type为 handoff 参数声明 schema,模型返回的 JSON 会在本地校验;input_filter可以改变接收 Agent 看到的历史;- 授权依赖解析字段时,应在
on_handoff产生副作用之前检查; - 只需要结构化调用嵌套专家、不转移对话时,可以用
Agent.as_tool(parameters=...)。
Envelope 可以作为 handoff 参数,也可以只传引用:
py
class HandoffRef(BaseModel):
handoff_id: str
artifact_uri: str
async def on_handoff(ctx, input_data: HandoffRef):
envelope = await store.get(input_data.handoff_id)
result = await validate_envelope(envelope, ctx.context.policy)
if not result.ok:
raise PermissionError(result.model_dump_json())
这里不要在授权失败后 return "denied"。官方文档提醒,如果 on_handoff 正常返回,转移仍会继续;需要抛出错误阻止副作用。
Handoff 解决"控制权给谁",Envelope 解决"对方凭什么继续"。把两个问题混在 Prompt 里,通常只会得到越来越长的系统说明。
不要让接收者覆盖上游原件
每个岗位应输出新 artifact 与新 Envelope:
text
research/bundle-v1
-> article/markdown-v3
-> image-set/v1
-> platform-draft/csdn-v1
-> publish-result/csdn-v1
写作 Agent 不修改研究包,配图 Agent 不覆盖文章,发布 Agent 也不把"按钮点过"写回文章文件。它们通过 URI、版本和哈希建立依赖。
这样才能回答:"文章 v4 修了事实错误后,哪些图片和平台草稿已经过期?"如果所有 Agent 都编辑同一份"最终文件",这个问题只能靠人工回忆。
幂等键要包含上游版本
最小键可以是:
ts
const idempotencyKey = `${taskId}:${stage}:${upstreamType}-v${upstreamVersion}`;
// post-42:image-stage:article-v3
同一键重复调用,返回现有结果或当前状态;上游变成 article-v4,才产生新图片任务。
这对浏览器自动化尤其重要。页面超时不等于提交失败,重复点击可能制造两篇内容。没有幂等键与页面结果验证,重试策略就会从容错机制变成重复生产器。
用 pre/post hook 守住副作用
Google Managed Agents 的官方更新介绍了 environment hooks:工具调用前后可以运行脚本,用于 block、lint 或 audit。
本文的 Artifact Envelope 不是 Google 官方标准,但 hook 的位置很适合落验证门:
json
{
"handoff-gate": {
"pre_tool_execution": [
{
"matcher": "write_file|publish_article",
"hooks": [
{
"type": "command",
"command": "python3 /.agents/hooks/validate_envelope.py",
"timeout": 10
}
]
}
]
}
}
pre-hook 阻止过期权限、未核验事实或错误版本进入工具;post-hook 给新产物计算哈希、保存 trace 和输出下一份 Envelope。
数据最小化比"超长上下文优化"更早
很多团队先研究怎么压缩 20 万 Token 的历史,却没问接收 Agent 为什么需要看到这些内容。
Envelope 里不要放 Cookie、密钥、完整客户对话和无关附件。优先传短期资源引用与最小字段;确实需要历史时,再附一段经过筛选的 context slice,并声明:
ts
interface ContextSlice {
uri: string;
purpose: "tone" | "decision_history" | "open_questions";
sensitivity: "internal" | "confidential";
expiresAt: string;
}
这不是永远禁止共享历史,而是让"多传什么、为什么传、传多久"成为显式决定。
在 Tipkay 里,接力不是多个头像
这也是我们做 Tipkay 时的一项取舍。Tipkay 面向小微企业、一人公司和小团队提供按需 AI 员工;不同岗位助手有各自的 Skill、MCP、经验和工作流程,可以从调研、写作继续做到素材、排版、文件与发布准备。
多助手协作时,我们更关心上一个岗位交出什么、下一个岗位能动什么,以及最终产物如何被验收。Agent as a Tool 负责调用关系,岗位协议负责交付关系。按实际使用量计费、不使用时不产生消耗,解决资源弹性;清楚的交接才解决协作稳定性。
一个人的生意,也能有一支专业团队。不是因为屏幕上有很多 Agent,而是任意一步出错后,仍能追溯到具体产物、版本、证据和权限。
先从两岗位开始
不需要一开始建设"Agent 中台"。挑一条最常见的接力,例如"写作 -> 配图":
- 固定
artifact/evidence/permissions/acceptance/idempotencyKey; - 接收前跑 schema、事实、权限三道检查;
- 拒收返回结构化 code 和 repair;
- 接收者输出新版本,不覆盖上游;
- 收集一周拒收记录,再升级 schema。
多 Agent 架构是否进入生产,不看调用链有多长。看的是一句"请继续",能不能被替换成一份可以验证、拒收、重试和追溯的工作包。
参考资料
- OpenAI, The full stack behind abundant intelligence:openai.com/index/the-f...
- OpenAI, Operations solutions:openai.com/business/so...
- OpenAI Agents SDK, Handoffs:openai.github.io/openai-agen...
- Google, Gemini API Managed Agents: 3.6 Flash, hooks, and more:blog.google/innovation-...