Token、上下文与一次请求结构
这篇是普通人、产品经理、工程师都必须先搞懂的底层概念。很多 AI 使用问题看起来像“模型不聪明”,实际是 Token 预算、上下文装配或请求结构出了问题。
一句话区分
| 概念 | 一句话 | 你真正要关心的事 |
|---|---|---|
| Token | 模型读写内容的计量单位 | 影响上下文上限、费用、速度和截断 |
| 上下文 | 模型这一次回答时能看到的全部信息 | 影响回答是否知道背景、是否被噪声干扰 |
| 请求结构 | 你把任务、材料、工具和输出要求交给模型的方式 | 影响模型能不能稳定执行 |
| 记忆 | 产品或系统长期保存的用户偏好/历史信息 | 不等于本次请求一定可见 |
| 工具调用 | 模型要求外部系统执行某个动作 | 工具结果会再进入上下文 |
Token 不是字数
Token 可以是一个汉字、一个英文词的一部分、一个数字片段、一个标点、一个 JSON 字段名,甚至是图片/文件被转换后的内部表示。
常见误解:
- “我只发了 2000 字,不算长”:中文、英文、代码、表格、JSON 的 token 密度不同。
- “只算我输入的内容”:模型输出也占 token,推理 token、工具 schema、检索片段也会占空间。
- “同一段内容所有模型 token 数一样”:不同 tokenizer 会有差异。
- “上下文窗口大就一定更好”:长上下文会带来成本、延迟和注意力稀释。
实践判断:
| 场景 | 做法 |
|---|---|
| 长文总结 | 先分段摘要,再综合,不要一口气塞满窗口 |
| 文件问答 | 先让 AI 建目录和要点,再围绕具体章节追问 |
| API 调用 | 估算输入、输出、工具 schema、RAG 片段的总 token |
| 高频模板 | 把稳定指令放前面,变量放后面,便于缓存 |
| 成本控制 | 限制输出长度,避免让模型写“完整长报告” |
上下文到底包括什么
一次请求里,模型可能看到:
| 上下文类型 | 内容 | 风险 |
|---|---|---|
| 系统/开发者规则 | 安全边界、风格、工具权限、输出规则 | 写得含糊会导致行为不稳定 |
| 用户当前输入 | 当前问题、目标、限制 | 太短会缺背景,太长会混入噪声 |
| 历史对话 | 前几轮仍被保留的对话 | 长对话会挤占窗口,旧目标可能干扰新目标 |
| 文件/图片 | 上传材料、截图、PDF、表格 | 模型可能只理解部分内容 |
| RAG 片段 | 检索出来的文档片段 | 召回错误会把模型带偏 |
| 工具结果 | 搜索、数据库、代码运行、API 返回 | 工具错误会污染后续推理 |
| 记忆 | 用户偏好、长期事实、项目背景 | 可能不可见、过期或不该用于当前任务 |
上下文工程的核心不是“塞更多”,而是“让模型看到正确、必要、优先级清楚的材料”。
记忆不等于上下文
很多产品会说自己有 Memory、Projects、Knowledge、Workspace 或个人资料,但这些不是同一个东西。
| 名词 | 真实含义 | 使用判断 |
|---|---|---|
| 上下文 | 本次请求实际传给模型的内容 | 决定这次能不能回答 |
| 记忆 | 产品长期保存的信息 | 可能被系统选择性放入上下文 |
| 项目空间 | 一组聊天、文件和说明的组织方式 | 适合长期任务,但仍受上下文窗口限制 |
| 知识库 | 文档被索引后按需检索 | 召回不准时答案仍会错 |
| 会话历史 | 当前对话前面的消息 | 太长会被截断或压缩 |
所以不要说“我之前告诉过它”。更可靠的做法是把当前任务需要的背景重新整理成一段“任务状态摘要”。
一次请求的最小结构
产品界面里的“一句话提问”和 API 里的请求,本质都可以拆成下面几块:
模型选择
+ 指令层:系统规则、角色、边界
+ 用户任务:我要你完成什么
+ 输入材料:文本、文件、图片、表格、代码
+ 上下文:历史、检索片段、工具结果、记忆
+ 工具定义:能调用什么、参数是什么、权限是什么
+ 输出契约:格式、长度、字段、引用、失败处理
+ 控制参数:最大输出、推理强度、温度、是否流式
-> 模型输出:文本 / 结构化结果 / 工具调用请求
一个好请求至少要有 6 个字段:
目标:我要完成什么。
背景:为什么做、给谁用、当前限制是什么。
材料:你可以使用哪些内容。
约束:不要做什么、必须遵守什么。
输出:用什么格式交付。
验收:怎样算好、怎样算不合格。
API 视角的一次请求
不同平台字段名不同,但常见结构相似:
| 字段 | 作用 | 产品侧理解 |
|---|---|---|
| model | 选择模型 | 快、强、便宜、长上下文、多模态之间取舍 |
| messages / input | 对话和输入内容 | 系统、用户、助手、工具结果按顺序进入 |
| content parts | 多模态内容块 | 文本、图片、文件、音频等 |
| tools | 可调用工具定义 | 搜索、数据库、代码执行、MCP、内部 API |
| tool_choice | 是否强制/禁止/自动工具调用 | 控制模型什么时候行动 |
| response_format / schema | 输出结构 | JSON、表格、固定字段、可校验 |
| max output | 最大输出长度 | 防止长篇废话和成本失控 |
| reasoning | 推理强度或思考预算 | 复杂任务用强推理,简单任务不浪费 |
| stream | 是否流式返回 | 影响首包体验 |
| metadata | 业务追踪信息 | trace_id、场景、版本、实验分组 |
工具调用循环
工具调用不是模型自己“真的去做了事”,而是一个循环:
用户任务
-> 模型判断需要工具
-> 模型输出 tool call(工具名 + 参数)
-> 外部系统执行工具
-> 工具结果回填给模型
-> 模型基于结果继续回答或再次调用工具
必须注意:
- 工具描述和参数 schema 也会占 token。
- 工具结果太长会挤占上下文,需要摘要或筛选。
- 工具失败要有错误分类,不能只把错误原文丢给模型。
- 写操作必须分权限:只读、建议写入、人工确认后写入、直接写入。
- 每次工具调用都要能追踪:工具名、参数、结果、耗时、错误、成本。
RAG 如何进入请求
RAG 不是模型训练,而是把检索到的资料片段拼进上下文:
用户问题 -> 查询改写 -> 检索 -> Rerank -> 上下文拼装 -> 模型回答
请求里通常会包含:
- 用户原始问题。
- 改写后的检索 query。
- 若干检索片段。
- 每个片段的标题、章节、更新时间、权限组。
- 回答要求:必须基于片段回答,无法确定就说明无法确定。
- 引用格式:结论后标注依据。
常见失败:
- 召回没命中正确资料。
- 命中了但片段太碎,缺上下文。
- 片段互相冲突,模型没有说明冲突。
- 检索片段覆盖了系统规则,产生 prompt injection 风险。
结构化输出
当结果要进入系统,而不是给人随便读,就要使用结构化输出。
例子:
{
"intent": "refund_request",
"confidence": 0.86,
"need_human_review": true,
"evidence": ["用户提到已付款但未收到商品"],
"next_action": "create_support_ticket"
}
结构化输出的好处:
- 可以被代码解析。
- 可以做字段校验。
- 可以失败重试。
- 可以进入日志和指标。
- 可以和工具参数衔接。
要避免:
- 只说“请输出 JSON”,但不定义字段。
- 字段可以为空却没有说明。
- 让模型输出自由文本再靠正则硬解析。
成本、时延和截断
一次请求的成本和时延通常来自:
- 输入 token:用户输入、历史、文件、RAG、工具 schema。
- 输出 token:模型回答、结构化字段、推理内容。
- 工具耗时:搜索、数据库、代码执行、外部 API。
- 重试:解析失败、工具失败、模型不稳定。
- 多轮:Agent 循环越多,成本越难控。
常见控制方式:
- 给每类上下文设 token 预算。
- 长资料先摘要、再进入主请求。
- 对工具结果做裁剪和字段化。
- 对高频系统提示使用缓存。
- 明确最大输出长度。
- 复杂任务拆阶段,不在一次请求里做完所有事。
最小自测
拿下面这个模糊请求做改写:
帮我分析一下这个竞品。
合格版本应包含:
- 竞品是谁。
- 分析目标是什么。
- 使用哪些资料。
- 输出维度是什么。
- 是否需要联网。
- 输出格式是什么。
- 哪些结论必须标注不确定。
可直接复用:
目标:请分析竞品 A 和竞品 B 在 AI 客服场景下的差异。
背景:我们准备设计面向电商卖家的客服 Agent,需要判断功能优先级。
材料:我会提供官网介绍、价格页和 3 篇用户评价。
要求:按功能、数据接入、自动化程度、人工接管、价格、风险 6 个维度比较。
输出:先给一张表,再给 5 条产品启发。
限制:不要编造材料中没有的信息;不确定的地方标注“待核查”。
验收:结论必须能转成 PRD 的功能优先级建议。
下一站
| 想继续学 | 去这里 |
|---|---|
| 按能力选工具 | AI 工具与能力地图 |
| 看主流工具差异 | 主流 AI 工具能力差异 |
| 学 Prompt/RAG/上下文/MCP | Prompt、RAG、上下文与 MCP |
| 学 Agent 和 Runtime | Agent 核心概念 · 工程化与 Runtime |