先看完整模型交互生命周期

一轮交互至少经过六步:应用定义任务与完成条件;Prompt Builder 组合受信指令、动态上下文和用户输入;Adapter 映射成 Provider 请求;应用消费一次性响应或流事件;若模型提出 Tool Call,Runtime 校验并执行,再回注结果;最后系统解析、校验并决定能否提交业务结果。

模型交互不是字符串往返,而是跨输入、传输、行动和验证的契约链
Task目标、输入与完成定义
Prompt指令、Context、示例与工具
Request消息、内容块与执行选项
Events文本、引用、Tool 与终态
Validation完整、语法、Schema、领域
Commit业务状态与可审计证据

这条链上有四种不同责任:Provider 负责按 API 契约产生模型事件,Adapter 负责协议映射,Runtime 负责状态和工具执行,业务系统负责权限、不变量和完成状态。任何一层成功都不能替代下一层验证。

模型 API 的基础对象

Request、Message、Item 与 Content Block

Request 通常包含模型、输入、指令、工具、输出格式、生成参数和追踪元数据。消息式 API 以角色消息序列组织内容;Item 式 API 将文本消息、Tool Call、Tool Result、Reasoning、引用或 Artifact 表达为不同类型。Content Block 进一步表示一条输入或输出中的文本、图像、文件、音频等内容。

这些是 API 抽象,不是 Transformer 内部原生对象。Provider 会把它们转换为模型可见表示,并可能插入自己的系统内容或工具说明。因此跨 Provider Adapter 应统一业务真正依赖的语义,而不能假设字段一一对应。

Response、Usage 与完成语义

Response 不应被压扁成文本。至少需要保留响应 ID、输出 Item、Usage、状态、错误、不完整原因和 Provider 元数据。OpenAI 当前 Responses API 将状态区分为 completed、failed、in_progress、cancelled、queued 或 incomplete,并提供 typed streaming event;这些属于当前 Provider 行为,内部模型应抽象出稳定语义而不是复制全部厂商类型。OpenAI Responses API Reference。

HTTP、协议、模型与业务四层成功

四层成功不能互相替代
层成功表示仍可能失败
HTTP请求被服务接受并返回流中断、限流语义、响应错误
协议事件与字段符合契约拒答、不完整、未知能力
模型输出满足任务质量事实、推理、引用和格式错误
业务外部后置条件成立权限、事务和副作用失败

角色、指令与 Prompt 基础

System、Developer、User、Assistant 与 Tool

角色用于表达消息来源和指令层级。System 或 Developer 通常承载应用政策与行为要求,User 表达当前用户请求,Assistant 保存模型先前输出,Tool 承载外部执行结果。名称、优先级和支持范围因 Provider 与 API 而异;应用应保留内部信任标签,不能仅凭角色字符串判断内容可信。

Tool 返回、网页、文件和检索材料即使放在专用内容块中,仍可能包含恶意或冲突指令。角色和分隔符帮助模型理解,不是权限隔离;服务端策略必须在模型之外执行。

Instruction、Context、Example、Input 与 Output Contract

Instruction 说明要做什么;Context 提供完成任务所需事实;Example 展示边界和期望行为;Input 是本次待处理对象;Output Contract 定义结果形态和无法完成时的语义。把它们混成一段文案会让变量来源、优先级和版本依赖难以审计。

Zero-Shot、One-Shot、Few-Shot 与模板变量

Zero-Shot 只依赖指令与模型既有能力;One-Shot 或 Few-Shot 加入一到多个示例,让模型在当前上下文中归纳任务模式。示例应覆盖真正的决策边界,不是越多越好:过多示例占用窗口、固化偶然格式,并可能压制新分布上的泛化。

Prompt Template 需要声明变量类型、来源、缺失策略、转义方式和敏感级别。分隔符能减少拼接歧义,却不能阻止模型把不可信文本当指令。Anthropic 当前提示实践强调清晰、直接、提供必要上下文并让示例与目标行为一致;这些是模型实践建议,不是跨模型永恒定律。Anthropic Prompt Engineering。

推理引导与可验证过程

系统可以要求模型输出计划、假设、引用、检查结果和最终答案,但不应把隐藏思维链当成审计依据。计划可能被修改,解释可能是事后生成;可靠证据来自真实 Tool Result、来源引用、确定性检查、测试和业务状态。Prompt 应要求“给出可检查产物”,而不是要求披露不可验证的私有推理。

流式响应不是字符串分片

HTTP Streaming、SSE、Event、Delta 与 Token

HTTP Streaming 表示响应体可以增量到达。Server-Sent Events(SSE)在文本流中用事件字段组织服务端到客户端的单向事件。网络 Chunk 是传输分块,SSE Event 是协议消息,Delta 是某个语义对象的增量,Token 是模型内部生成单位;四者可能边界不同。WHATWG HTML Standard 定义了 SSE 线路格式和 EventSource 行为。WHATWG:Server-Sent Events。

Response 与 Item 生命周期

流消费者应按 responseId、itemId、contentIndex 和 callId 归并事件,而不是把所有 Delta 追加到一个字符串。文本、引用、Tool 参数和 Artifact 拥有不同生命周期;参数 Delta 尚未完成时不能执行工具,文本可展示也不代表最终结构已通过校验。

唯一终态与结果未知

Reducer 只接受一个终态。连接中断只说明客户端失去传输,不证明服务端任务失败;服务端可能继续生成或已经触发外部动作。若无法查询真实状态,应标记 incomplete 或 unknown,而不是重跑整轮。终态之后的晚到事件只能进入诊断日志,不能改变已提交结果。

Tool Call 的完整往返

模型只提出工具与参数

Provider 返回 Tool Call 时,模型表达的是“希望调用某工具并给出候选参数”。Runtime 必须等待参数完成,再执行 JSON 解析、Schema 校验、身份授权、业务策略和风险审批。工具名存在不代表当前用户有权调用,参数符合 Schema 也不代表业务允许。

Runtime 执行并生成 Tool Result

执行器在模型之外调用真实系统,并以 callId 关联结果。动作型工具还需要幂等键、执行账本和业务回执:若工具成功后回注中断,恢复流程先查询账本,再决定回注已有结果、补偿或人工处置。直接重新请求模型可能再次提出相同动作。

并行调用与结果回注

多个独立 Tool Call 可以并发,但每个调用有独立状态、错误与超时。结果回注应包含模型决策所需的最小信息;大文档、二进制、凭据和隐私字段不应原样塞入 Context。应保存完整结果的外部引用,并向模型提供结构化摘要和来源元数据。

从自由文本到结构化契约

自由文本、JSON Mode、Structured Output 与 Tool Call

自由文本没有机器可依赖结构;JSON Mode 主要保证语法上是 JSON;Structured Output 使用 Schema 约束模型输出;Tool Call 用结构化参数表达行动提案。以 OpenAI 当前文档为例,json_schema 严格模式只支持 JSON Schema 子集,旧 json_object 模式保证 JSON 语法但仍需指令说明要输出什么。OpenAI:Structured Outputs。其他 Provider 的名称和支持范围需要单独核验。

JSON Schema 基础

type定义值类别,properties描述对象字段,required要求字段存在,enum限制候选值,items约束数组成员,additionalProperties决定是否允许未声明字段。Schema 应表达跨消费者稳定的结构,不要把频繁变化的自然语言政策硬编码成巨大枚举。

完整传输、可解析、Schema 与领域正确

四层正确性完整传输 → 可解析语法 → 符合 Schema → 满足领域不变量。前一层通过不证明后一层。

被输出上限截断的 JSON 可能恰好能解析;Schema 合法的订单 ID 可能不存在;金额类型正确也可能超过退款上限。系统必须按顺序验证,任何一层失败都不能由消费者静默猜测。

TypeScript 类型、运行时校验与领域不变量

TypeScript 类型在编译后不会自动检查外部 JSON。模型输出是不可信输入,应通过 Zod、AJV 或同类运行时校验器建立边界,再调用领域校验确认实时对象、租户、权限、跨字段关系和业务状态。结构化输出减少语法失败,不会把概率模型变成业务规则引擎。

建立可演进的应用内部契约

Canonical Request、Model Event 与 Model Result

type Terminal = 'completed' | 'refused' | 'incomplete' | 'failed' | 'cancelled' | 'unknown'

type ModelEvent =
  | { type: 'response.started'; requestId: string }
  | { type: 'text.delta'; itemId: string; delta: string }
  | { type: 'tool.proposed'; callId: string; name: string; arguments: unknown }
  | { type: 'response.terminal'; status: Terminal; usage?: Usage }
  | { type: 'provider.unknown'; rawType: string; payload: unknown }

这是教学性契约,不是可复制的生产 SDK。内部类型统一业务依赖的公共语义,并用 Provider Extension 或 unknown 事件保留特有能力,避免为了“可移植”静默丢失 reasoning、缓存、内置工具或状态语义。

Reducer 处理重复、乱序、晚到和未知事件

Reducer 以 ID 关联状态,明确每类事件允许出现在哪些阶段。重复 Delta 需要序列号或事件 ID 去重;乱序事件需要缓冲、拒绝或标记协议失败;未知事件必须告警并保存脱敏类型;终态后不再改变业务可见结果。

应用、Provider 与业务系统分别拥有的状态

Provider 可保存 Conversation 或 Response 状态,应用 Session 保存用户、权限、摘要和任务引用,业务系统保存订单、资金等权威状态。客户端重放历史、Provider 托管会话和应用状态库各有生命周期与锁定成本;无论采用哪种方式,都不能把 Provider 对话当业务数据库。

Prompt、Schema 与 Adapter 怎样一起演进

记录模型、Prompt、变量、Schema、Tool 和 Adapter 兼容组合

一次可复现运行需要保存模型快照、推理配置、Prompt 模板、变量 Schema、Context 来源、Tool 版本、输出 Schema 和 Adapter/SDK 版本的依赖摘要。只记录 Prompt 版本无法解释模型升级或 Tool 定义变化造成的回归。

消费者契约、事件回放与能力探测

新增 enum 对生成方看似兼容,但旧消费者的穷举分支可能崩溃;新增 Provider 事件即使最终文本正常,也可能意味着 Usage、引用或工具状态被丢失。通过事件 Fixtures、消费者契约测试和运行时能力探测决定兼容性,不按字段数量猜测。

按失败层定位问题

指令未遵循可能来自 Prompt;无响应可能来自网络、限流或超时;非法 JSON 可能是截断;Schema 通过但结果错误属于领域或事实层;工具拒绝可能是权限策略。把所有问题都归因于 Prompt 会掩盖真正 Owner,也让版本迭代无法验证。

实现一条最小闭合交互链

// 教学性主链:省略 Provider 具体类型和生产基础设施
async function run(request: ModelRequest, adapter: ProviderAdapter, signal: AbortSignal) {
  const state = createState(request.requestId)
  for await (const event of adapter.stream(request, signal)) {
    reduceEvent(state, event)
    trace.record(event, state.snapshot())
  }
  if (!state.terminal) throw new IncompleteStreamError(request.requestId)
  if (state.terminal !== 'completed') return state.toNonSuccessResult()
  const parsed = parseCompleteJson(state.finalText)
  const structured = validateSchema(parsed)
  return validateDomain(structured)
}

主链表达五个顺序约束:先构造受信请求;事件按类型归约;Tool 参数完成后才接受提案;唯一成功终态后才解析最终输出;Schema 与领域验证逐层执行。生产版还需要身份、隐私、幂等、持久状态、超时层级、采样 Trace 和成本核对。

故障推演:SSE 断开后为什么不能直接把任务标记 failed?
传输状态与服务端任务、外部副作用处于不同故障域。先查询真实响应和执行账本;无法确认时使用 incomplete/unknown,再由恢复策略决定回注、补偿或人工。
边界判断:Structured Output 严格匹配 Schema 后,为什么仍不能直接写库?
Schema 约束结构和局部取值,不验证实时对象、租户权限、引用事实、跨字段业务规则和当前状态,仍需领域校验和业务事务。

资料与事实边界

以下以官方文档、标准、论文和原始工程资料为主。厂商 API、价格、限额与模型能力会变化,落地时仍需按目标版本做能力探测和回归。

  1. OpenAI Responses API Reference — 当前请求、输出 Item、状态和响应语义
  2. OpenAI Streaming Events — Typed streaming event 与函数参数增量
  3. OpenAI Structured Outputs — JSON Schema 严格输出、JSON Mode 与能力边界
  4. WHATWG Server-Sent Events — SSE 线路格式和 EventSource 标准
  5. Anthropic Prompt Engineering — 当前 Claude 提示实践与模型特定边界