Appearance
模型调用与消息结构入门
版本:
v1.1最后更新:
2026-07-08适用对象:刚开始接触大模型 API、已经会发请求但还没有稳定工程心智模型、准备继续进入结构化输出 / 工具调用 / Agent 的读者
很多人一开始学 AI 应用,最容易误判的一件事是:
以为自己在学“神秘模型技巧”,其实真正需要先搞清楚的是一次调用里到底有哪些层。
如果这一层没有建立起来,后面看 Prompt、RAG、Agents、协议、平台工程时,常常会把本来属于不同层的问题混在一起。
这篇文档的目标很明确:
- 帮你先看懂一次模型调用真正由哪些部分组成。
- 帮你分清 Prompt、上下文、结构化输出、工具调用各自负责什么。
- 帮你建立一个最小但可扩展的工程心智模型。
- 帮你把 OpenAI、Anthropic、Gemini 这些官方资料里的共性原则串起来。
1. 先建立一个最小心智模型
你可以先把一次大模型调用理解成下面这条链路:
- 你定义任务目标。
- 你组织规则、输入和上下文。
- 模型在给定上下文里生成结果。
- 应用侧校验结果。
- 需要时再决定是否调用工具、检索知识或进入下一步。
所以,一个 AI 应用从来不只是“发一段 Prompt 给模型”。
更完整地看,通常至少有 7 个组成部分:
任务规格:这次到底要解决什么问题。指令层:稳定规则、边界约束、角色设定、输出协议。动态输入:用户本次真正带来的内容。上下文:历史消息、检索内容、工具结果、状态摘要。执行能力:模型本身、工具调用、检索系统、工作流编排。结果校验:schema 校验、风险检查、人工确认。结果消费:展示给人、写回数据库、触发系统动作或进入下游流程。
只要你先把这几层分开,很多问题就容易定位得多。
2. 一次模型调用里,到底发生了什么
2.1 你不是在“提问”,而是在定义任务
在工程里,我们更关心的是:
- 输入字段是否完整
- 任务边界是否清晰
- 输出协议是否稳定
- 失败时能否回放和修复
比如“帮我总结这段文本”看起来很简单,但在工程里通常还要补这些信息:
- 总结给谁看
- 输出多长
- 是否保留关键数字
- 是否允许模型补充外部知识
- 是否必须输出固定结构
这也是为什么同样一句自然语言,在演示环境能跑,在系统里却可能不稳定。
2.2 指令层和用户输入,最好分开
不同平台对消息结构的命名不完全一样,但核心原则一致:
- 把长期稳定的规则单独放在上层指令里
- 把用户每次变化的输入单独放在动态输入里
- 把外部资料、检索结果、工具输出单独标成上下文
这样做的价值是:
- 规则更容易复用
- 历史更容易回放
- 变更更容易评测
- 安全边界更容易标注
如果把所有内容糊成一大段文本,后面通常会遇到这些问题:
- 不知道到底是哪一层改动导致效果变化
- 难以做版本治理
- 工具结果和用户原话混在一起
- 安全审查时难以区分可信与不可信输入
2.3 模型看到的,不只是“你写的 Prompt”
很多应用最终送进模型的上下文,往往来自多部分拼接:
- 固定行为规则
- 任务描述
- 用户输入
- 检索回来的知识片段
- 工具执行结果
- 历史摘要
- 输出格式说明
所以,输出不稳定时,根因可能在很多地方:
- 用户输入本身含糊
- 上下文太长,被挤掉关键内容
- 检索证据质量差
- 输出字段定义不清
- 工具返回结果不可直接消费
3. 先搞清楚 6 个最基础名词
3.1 token
token 可以粗略理解成模型处理内容时使用的最小计量单位。它不是“字数”,也不是“单词数”,而是模型分词后的计算单位。
你需要关心 token,不是为了背定义,而是因为它会直接影响:
- 上下文窗口能装多少内容
- 请求成本
- 响应延迟
- 历史消息保留策略
OpenAI 当前文档特别强调,真实请求的 token 统计不只包含文本本身,还会包含消息结构、角色边界、工具与 schema 等格式开销,所以不能只靠“字符数 / 4”这种估算方式。Gemini 文档也明确把图片、文件、思考 token、工具 token 分开计量;Anthropic 则把工具定义、消息内容和输出一起纳入上下文预算。
3.2 上下文窗口
上下文窗口不是“无限聊天记录”,而是这次推理能看到的总预算。
通常会包含:
- 当前输入
- 历史消息
- 系统规则
- 检索材料
- 工具返回内容
- 本轮要生成的输出
这意味着只要你不断追加内容,总有一天会遇到:
- 关键信息被截断
- 历史污染当前任务
- 成本和延迟上升
- 长上下文带来的召回下降
Anthropic 的最新文档把这种现象明确提醒为长上下文下的精度衰减问题;这也解释了为什么“上下文越大”不等于“效果越稳定”。
3.3 结构化输出
结构化输出的核心价值不是“格式好看”,而是让结果可以稳定进入程序。
例如下面两种输出相比:
- 自由文本:适合给人看
- 固定字段:适合给系统消费
如果你的结果要进入数据库、工作流、审批流、任务路由、统计报表,通常优先考虑结构化输出,而不是只让模型“尽量返回 JSON”。
3.4 工具调用
工具调用的本质不是“让模型更聪明”,而是让模型把某一步交给外部系统执行。
常见工具包括:
- 搜索
- 数据库查询
- 发邮件
- 调 CRM
- 调内部审批接口
一旦进入工具调用,问题就不再只是 Prompt 问题,还会变成:
- 参数定义是否清晰
- 调用条件是否合理
- 权限是否越界
- 结果是否需要二次校验
3.5 会话状态
多轮对话的难点不是“消息越来越多”,而是如何保留真正有价值的状态。
常见状态包括:
- 用户目标
- 当前步骤
- 已经确认的事实
- 已经执行过的工具结果
- 待用户补充的信息
如果不做状态治理,多轮应用很容易越聊越乱。
3.6 schema
schema 可以理解成你希望模型输出或工具入参满足的结构约束。
它常见于两类场景:
- 结构化输出
- function / tool calling
schema 的价值是把“请尽量按这个格式返回”升级成“结果必须满足这个结构约束,再进入下游程序”。
4. 不同 API 里的消息结构,核心共性是什么
虽然不同平台的字段名不完全一样,但工程上的共性很强。
4.1 OpenAI 视角
OpenAI 当前文档强调:
- 单次请求本身是无状态的
- 多轮对话可以手动传历史
- 也可以用
previous_response_id或conversation持续状态 - 响应里既可以生成文本,也可以生成结构化输出或工具调用
所以在 OpenAI 体系里,你更应该从“请求由哪些块组成”来理解,而不是只盯着一段 prompt string。
4.2 Anthropic 视角
Anthropic 的 Messages 文档更突出“消息块”的概念:
systemmessagestoolstool_result
它的文档也反复强调上下文窗口里不仅有文本,还有工具定义、工具结果、图片、文档,以及在特定模式下的 thinking 块。
4.3 Gemini 视角
Gemini 文档对结构化输出、函数调用、token 计数和工具能力拆得比较清楚:
- Structured Outputs 用来约束最终答案格式
- Function Calling 用来请求外部动作
- Token guide 用来估算输入、输出、thinking、cache、tool use 的预算
4.4 你真正该记住的共识
比起死记每家字段名,更重要的是记住下面这几个稳定原则:
- 稳定规则要和动态输入分开。
- 用户原话要和外部上下文分开。
- 模型输出要和工具执行结果分开。
- 给人看的答案要和给系统消费的结构分开。
- 历史消息不是越全越好,而是要治理。
5. 一个最小但健康的消息分层方式
你可以把一次调用拆成 5 块:
5.1 稳定规则
适合放:
- 角色设定
- 不允许做什么
- 输出风格
- 输出字段要求
- 高风险动作的审批规则
这部分通常更新频率最低。
5.2 当前任务
适合放:
- 本次到底要做什么
- 任务成功标准
- 任务边界
这部分是“这轮为什么发请求”的核心。
5.3 用户输入
适合放:
- 用户原话
- 表单字段
- 上传文本
- 用户本轮新增说明
这一层要尽量保持原始,不要混入系统解释。
5.4 外部上下文
适合放:
- 检索证据
- 历史摘要
- 工具查询结果
- 任务状态
这部分最容易导致上下文膨胀,也最需要治理。
5.5 输出协议
适合放:
- 返回字段
- 类型要求
- 不确定时如何填
- 引用来源是否必须
很多项目失败,就失败在这一层没有明确下来。
6. 为什么“分层”比“写长 Prompt”更重要
当你只是把 Prompt 写得很长,却没有把结构分层,通常会遇到下面这些问题:
6.1 不知道为什么效果变了
你改了一句指令,还是加了一段资料,还是历史消息变了?
如果没有分层,根本没法定位。
6.2 版本治理困难
你以后想做:
- Prompt 版本管理
- 回归评测
- 问题复盘
- 跨团队协作
都会很痛苦。
6.3 安全边界不清
如果用户输入、检索结果、工具结果都混成一段,后面就很难回答:
- 哪些信息是可信的
- 哪些信息可能被 prompt injection 污染
- 哪些内容应该只读不能执行
6.4 程序消费不稳定
如果没有清楚的输出协议,程序端就只能赌模型“这次刚好输出得比较像你要的格式”。
7. token 预算为什么会比你想的复杂
OpenAI 当前的 token counting 文档已经把一个很关键的误区说得很清楚:
- 真实请求的 token 不是只看文本
- 消息角色和结构会消耗 token
- 工具定义与 schema 会增加 token
- 图片、文件、缓存和推理模式也会改变真实计数
Gemini 也提供 count_tokens 以及响应里的 usage 字段来分别看输入、输出、thinking、cache、tool use。
Anthropic 则明确指出:
- system prompt 算
- messages 算
- tool results 算
- tool definitions 算
- output 和某些 thinking token 也算
7.1 所以你要避免什么
- 用字符数粗估成本
- 不算工具 schema 的上下文开销
- 不算图片和文件的输入预算
- 不看输出 token,只盯输入
7.2 更稳的做法
- 在核心链路上做真实 token 计数。
- 把工具定义、schema、上下文块拆开观察。
- 给不同任务设置不同的上下文预算。
- 设计超限时的裁剪、摘要、降级或回退策略。
8. 多轮对话为什么不能只靠“把历史一直追加”
这是很多新手最容易踩的坑之一。
8.1 单次请求是无状态的
OpenAI 当前文档明确说明,单次文本生成请求本身是无状态的;多轮效果来自你是否在下一轮把历史或前一轮响应继续带进去,或者通过 previous_response_id / conversation 这样的机制持久化状态。
也就是说:
- “会话”是你设计出来的
- 不是模型天然无成本替你记住的
8.2 把历史一直追加的问题
如果你机械地保留完整历史,常见后果包括:
- 上下文越来越贵
- 当前任务被旧信息污染
- 关键内容被淹没
- 系统性能越来越差
8.3 更稳的状态管理思路
至少要开始区分:
原始消息历史长期稳定事实当前任务状态本轮临时工具结果可丢弃的中间思考
8.4 新手可先采用的最小方案
- 保留最近几轮原始消息。
- 把更早历史压成摘要。
- 单独维护“已经确认的事实”。
- 工具结果按任务阶段保留,不要永久堆积。
9. 结构化输出、Function Calling、自由文本,到底怎么选
这是一个非常常见的混淆点。
9.1 自由文本
适合:
- 面向人阅读
- 创意表达
- 长段解释
不适合:
- 直接进入数据库
- 直接驱动程序逻辑
- 高一致性要求的流程节点
9.2 结构化输出
适合:
- 结果抽取
- 分类标签
- 路由决策
- 报表字段
- 审批建议
Google 的 Structured Outputs 文档当前就把它定义为“控制最终答案格式”的能力,而不是执行外部动作。
9.3 Function / Tool Calling
适合:
- 要查系统数据
- 要写业务系统
- 要调用外部能力
- 要把决策和执行拆开
OpenAI 和 Gemini 当前文档都明确把 Function Calling 指向“连接外部函数、系统与动作”,而不是仅仅让答案看起来更像 JSON。
9.4 一个简单判断原则
如果你要的是:
给人看:先考虑自由文本给系统消费:先考虑结构化输出让系统执行动作:先考虑 function/tool calling
10. 工具调用真正的生命周期是什么
很多人把工具调用理解成“模型自己去调接口”,但更准确的理解是:
- 你定义工具及参数 schema。
- 模型根据任务决定是否请求某个工具。
- 应用侧执行该工具。
- 应用侧把工具结果传回模型。
- 模型基于结果继续输出最终答案或下一步动作。
也就是说,真正拥有执行权的是你的应用,不是模型。
10.1 这意味着什么
- 工具调用结果要做权限控制
- 入参要做校验
- 执行动作要有审计
- 高风险动作要有人审或双确认
10.2 什么场景不该急着上工具调用
- 只是普通文本改写
- 只是摘要和分类
- 只是离线知识解释
这类任务很多时候单次调用加结构化输出就够了。
11. 为什么很多问题其实不是“模型太弱”
下面这张表很适合新手排查:
| 现象 | 更可能的问题层 | 优先检查什么 |
|---|---|---|
| 输出很散 | 任务规格层 | 目标、边界、输出字段是否写清 |
| JSON 不稳定 | 输出协议层 | 是否使用结构化输出、程序端是否校验 |
| 答非所问 | 输入组织层 | 用户输入是否含糊、示例是否偏移 |
| 明明资料里有却答不出来 | 检索层 | chunk、召回、重排、证据装配 |
| 多轮越聊越乱 | 状态层 | 历史裁剪、状态摘要、记忆分层 |
| 明明只是查数据却做成超复杂 Agent | 架构层 | 是否本来只需要工具调用 |
只要你开始按“层”排查,很多问题就不会一直靠感觉调。
12. 一个最小可落地的工程模板
如果你现在要做第一个正式一点的 AI 功能,建议至少具备下面这些元素:
12.1 输入定义
- 用户输入字段
- 必填项
- 非法值处理
12.2 规则定义
- 稳定行为规则
- 输出格式要求
- 风险边界
12.3 上下文定义
- 需要哪些历史
- 需要哪些知识
- 需要哪些工具结果
12.4 输出定义
- 文本输出还是结构化输出
- 是否需要引用
- 不确定时怎么表达
12.5 校验定义
- schema 校验
- 敏感字段校验
- 风险检查
- 是否需要人工确认
12.6 回放定义
- 保存输入
- 保存输出
- 保存失败样例
- 保存版本信息
13. 给零基础读者的 7 天最小实践路线
第 1 天
- 读完 基础入门总目录
- 看懂一次调用链路分层
- 记录你最想解决的一个真实任务
第 2 天
- 做一个摘要任务
- 明确输入字段、输出字段
- 保存 3 条成功样例和 3 条失败样例
第 3 天
- 做一个信息抽取任务
- 把结果固定成字段而不是自由文本
- 开始建立“输出协议”意识
第 4 天
- 继续练一个分类或路由任务
- 定义“不确定时”的处理策略
- 尝试做最简单的程序端校验
第 5 天
- 补看 提示词工程详解
- 对照你前三天的样例重构输入层次
第 6 天
- 读 LLM 与生产化总目录
- 开始理解 token、上下文、成本和评测
第 7 天
- 用自己的话回答 5 个问题:
- 什么是消息分层?
- 为什么结构化输出比“返回 JSON”更稳?
- 工具调用和自由文本输出的边界是什么?
- 为什么历史消息不能一直无脑追加?
- 为什么失败样例要比“继续拍脑袋调 Prompt”更重要?
14. 学到这里,先别急着跳的 5 个坑
- 还没把消息结构看懂,就直接上多智能体框架。
- 还没做输出校验,就把模型结果直接写进业务系统。
- 还没做失败样例沉淀,就不断重写 Prompt。
- 还没建立 token 和上下文预算意识,就盲目叠资料。
- 还没分清单次调用和 Agent 的边界,就上复杂编排。
15. 看完这篇后,下一步该读什么
如果你现在最缺的是:
总体学习路线:先看 AI学习计划模型为什么能工作:看 Transformer架构详解Prompt 和输出协议:看 提示词工程详解生产化与评测:看 LLM 与生产化总目录Agent 与工作流:看 AI Agents专题
16. 官方资料入口
以下入口在 2026-07-08 检查时可访问,适合和本页对照阅读:
- OpenAI Text generation
- OpenAI Conversation state
- OpenAI Token counting
- OpenAI Structured outputs
- OpenAI Function calling
- OpenAI Prompt engineering
- Anthropic Working with Messages
- Anthropic Context windows
- Anthropic Tool use overview
- Anthropic Prompt caching
- Google Gemini Structured outputs
- Google Gemini Function calling
- Google Gemini Tokens guide
17. 最后给一句判断标准
如果你现在已经能做到下面这些事,说明“模型调用与消息结构”这一关基本算过了:
- 能把一次调用拆成规则、输入、上下文、输出协议几个层次。
- 能区分自由文本、结构化输出、工具调用各自适用的场景。
- 知道上下文窗口为什么是预算问题,不是“能塞多少塞多少”。
- 遇到效果差时,能先按层排查,而不是只怪模型不聪明。
- 知道模型输出只是推理结果,不等于系统可直接执行的事实。
当你能做到这些,再去看 RAG、Agent、协议和平台工程,后面很多内容就会一下子顺起来。