消息、配置与版本意识
本节目标
设计稳定的应用请求合同,把角色、内容、模型选择和供应商特性留在明确的适配边界。
供应商无关合同
应用层可以先定义自己真正需要的最小字段:
{
"operation_id": "ticket-42-attempt-group-1",
"prompt_version": "ticket-router-1.3.0",
"model_profile": "fast-structured-classifier",
"required_capabilities": ["structured_final"],
"messages": [
{"role": "user", "content": "……"}
],
"output_schema_id": "ticket-label-1.1.0"
}字段阅读:
operation_id把同一业务意图的多次网络尝试关联起来,不能把每次请求 ID 当作业务唯一键。prompt_version让日志、评测和回归可以定位到实际使用的指令版本。model_profile是内部选择角色;部署配置再映射到具体 Provider 和模型 ID。required_capabilities列出正确性不可缺少的能力,adapter 应在调用前验证支持情况。messages保存应用层规范化输入;角色和内容块仍需要由 adapter 显式映射。output_schema_id关联下游预期的结构化合同及其版本。
model_profile 是内部逻辑配置,不是供应商模型名。部署配置再将它映射为供应商、模型标识、输出上限和受支持功能。这样可以审计和切换,但不能假装所有模型的参数语义一致。
内部合同还应区分“必需能力”和“偏好”。例如 schema 严格遵循、工具调用或图片输入若是正确性的前提,就必须在发送前做 capability check;延迟档位或缓存则可能只是优化。adapter 遇到必需能力不支持时返回 unsupported_capability,不能静默降级为纯文本再让下游误以为合同仍成立。
角色与内容映射
不同 API 对系统/开发者/用户/助手角色、内容块、图片、工具结果和对话状态有不同约束。adapter 应做显式映射并拒绝无法表达的功能,而不是静默降级。高层指令是否跨响应链继承、历史如何计费、服务端状态保留多久,都属于动态事实。
当前三家 API family 的核心差异如下;这张表只描述 2026-07-21 核验的 family,不代表同一供应商的其他 API:
| API family | 高层指令与本轮输入 | 多轮状态 | 必须显式处理的边界 |
|---|---|---|---|
| OpenAI Responses | instructions 与 input | 可用 previous_response_id,也可手工重放 Items | instructions 不随 previous ID 继承;链上先前输入 token 仍计费;store=false 手工历史要重放每个 response.output Item,不能只留可见文本 |
| Anthropic Messages | 通常用顶层 system + messages | 调用方重放完整消息历史 | 顶层 system 是覆盖最广的做法;mid-conversation system 只对 Fable 5、Mythos 5、Opus 4.8 等已声明模型并满足位置规则时启用 |
| Gemini Interactions v1 | system_instruction、input/Steps | 可用 previous_interaction_id 或提交统一 Steps | previous interaction 不继承 tools、system instruction 或生成配置,续接时必须显式重发 |
“服务端记住历史”不等于“配置也继承”,更不等于“历史免费”。adapter 应为每个请求构造完整 caller-owned controls,并把服务端句柄是否可检索当作显式前置条件。不能在句柄失效后悄悄退化为缺少 reasoning/thought/tool blocks 的文本摘要。
有状态与无状态续接
两种方式的工程责任不同:
- 有状态续接:保存 Provider response/interaction ID,核对前序是否已存储、保留期、数据治理和不继承字段;句柄过期或删除时显式失败或从可信快照重建。
- 无状态续接:应用保存 canonical provider items/blocks/steps,按原顺序重放所有续接所需对象;必须有大小上限、加密、完整性和版本迁移策略。
不要只存一段 assistant 文本。工具调用身份、工具结果、reasoning/thinking 签名、拒绝/截断状态和托管工具步骤都可能影响下一轮合法性。需要摘要时,把摘要作为新输入,并明确它不是原始 Provider 对话的无损恢复。
配置要可追溯
记录:
- 供应商 adapter 版本;
- 逻辑模型配置 ID 与实际模型标识;
- 提示、schema、工具定义和上下文选择器版本;
- 关键生成参数及其“未设置/显式设置”状态;
- 请求发起时间和应用 operation ID。
不要从某个供应商复制 temperature、top_p 或推理参数到所有模型。先查支持情况,再用任务评测证明设置的价值。模型别名可能漂移;需要强复现时使用供应商提供的稳定版本机制并保留上线评测。
配置记录要同时保留“请求的模型配置”和“响应实际报告的模型/版本”。别名、路由或后端更新可能让两者不同;只有内部 model_profile 而没有实际响应标识,无法解释回归。
对动态合同保存两种版本:人类可读的 prompt_version/schema_id/toolset_id,以及规范化内容的 digest。版本号说明发布意图,digest 检测“同名内容被改写”。不要把包含秘密或个人数据的原文直接塞进高基数 metric label;digest 也不是脱敏万能药,低熵敏感值仍可能被枚举。
输出上限和停止状态
输出达到上限、被安全策略拒绝、工具调用待处理和正常完成不是同一种成功。adapter 应把供应商停止原因映射为有限的内部状态,同时保留原始类型,未知新类型要显式暴露而不是当成完成。
练习与自测
为“结构化工单分类”设计一个最小内部请求/响应 dataclass。列出换供应商时必须适配的字段。自测:若新供应商不支持所需 schema 子集,系统会报能力不匹配,还是悄悄改用纯文本?
掌握检查
- 应用合同只包含业务需要,供应商字段由 adapter 显式映射。
- 必需能力与性能偏好分开;无法表达的必需能力会失败关闭。
- 请求和响应都保留实际模型、adapter、提示、schema、工具和上下文版本。
- 我能区分有状态句柄与无状态重放,并知道哪些指令/配置不会继承、哪些历史仍计费。
- 对话快照保存 Provider 身份与必要 block/item/step,不把可见文本误当无损历史。
- 未设置与显式设置参数可区分,不把某家供应商参数机械复制到另一家。
- 完成、拒绝、截断、等待工具和未知终止原因映射为不同内部状态。
下一步
进入 结构化输出与流式响应。
参考资料
- OpenAI:Conversation state(状态、存储、计费与手工 Items,访问于 2026-07-21)
- OpenAI:Function calling(工具 Items 与续接,访问于 2026-07-21)
- Anthropic:Using the Messages API(访问于 2026-07-21)
- Anthropic:Mid-conversation system messages(模型与位置门禁,访问于 2026-07-21)
- Google:Gemini Interactions overview(续接与非继承配置,访问于 2026-07-21)
- Google:Interactions API v1 reference(访问于 2026-07-21)