开头
经常有读者在后台问我:LLM 到底是怎么“读懂”我输入的那段话的?为什么我多问几句,它的回答就变飘了?为什么有人说“上下文塞太满会爆”,背后到底爆的是什么?
我一般会把问题拆成三件事讲:Token、上下文窗口、采样参数。这三者构成了所有大语言模型运行机制的底层骨架,也是你排查一切 LLM 使用困惑——比如输出被截断、回答文不对题、越聊越傻、API 账单莫名飙升——时最先要检查的三个地方。
这篇文章我会用一篇完整的长文,把这三块彻底拆开,每一块都讲清楚“它是什么、底层怎么运作、实际使用中最容易踩什么坑”,最后再给一套我自己实测过的参数配置建议和问题排查表。不管你是刚开始用 ChatGPT/Claude 的普通用户,还是在自己接 API 做应用开发的工程师,这篇文章都能帮你省下大量试错时间。
1. Token:为什么它是计费单位,也是“理解”的最小颗粒
1.1 语言模型不识字,只认数字
要理解 Token,你先得接受一个事实:大语言模型并不像人一样“读字”。它接收和输出的全部内容,本质上都是数字序列。那文字怎么变成数字?中间这层转换,就是 Token 化(Tokenization)。
Token 可以粗略理解成“把一段文本切成若干个小块,每个小块对应一个唯一 ID”。这个 ID 就是模型词汇表(Vocabulary)里的一个编号。比如英文单词the可能是一个 Token,中文的“深”可能是一个 Token,“度”又是一个 Token。模型处理文本时,实际上是在处理一串 Token ID——你可以把它想象成把一整篇文章拆成了乐高积木里的一个个标准颗粒,模型学的就是这些颗粒之间的排列规律和组合概率。
这里有个容易误解的地方:Token 不是“词语”,也不完全是“字”。它是一种分词算法切出来的结果,边界由词频和字节组合决定。同一个句子,用不同的分词器(Tokenizer)切,得到的结果可能完全不一样。目前主流模型用的基本都是 BPE(Byte Pair Encoding,字节对编码)或其变体,核心逻辑就是从字节级别开始,反复合并出现频率最高的相邻片段,最后形成一个词表。
1.2 中英文 Token 消耗差异:为什么中文“更贵”
很多刚接触 API 的同学会有一个疑惑:为什么同样意思的一句话,用中文问比用英文问消耗的 Token 数要多?这不是心理作用,而是分词器的真实行为。
原因很简单:绝大多数模型的词表是以英文为主构建的,英文单词在 BPE 合并中能形成大量高频完整词块,一个 Token 往往就能覆盖一个常见单词,比如token、model、context都是一整个 Token。但中文没有天然空格分词,分词器在处理中文时,绝大多数单字只能独立成 Token,高频双字词有时能合并成一个,但整体而言,平均一个汉字大约要消耗 0.6 到 1 个 Token——也就是说,一句 100 个汉字的句子,消耗的 Token 数量往往多于同样信息量的英文句子。
这对开发者的直接影响是:在做 API 计费预估和成本优化时,不能按“字数”去估算,必须按 Token 数估算。我在实际项目中习惯的做法是,在代码里缓存一份tiktoken或对应模型的分词器离线表,每次请求前先对本轮要发送的内容做一次本地计数,这样既能做成本预警,也能提前发现“会不会超过上下文限制”。这个习惯帮我省下的冤枉钱,保守估计也有几千块了。
1.3 token 失效、token 用量、token 上限:三种“token”别混淆
搜索热词里反复出现“token 失效”“token 用量”“已达到输出 token 上限”“token exchange failed”这类说法。这里其实混了三件完全不同的东西,我一次性帮大家理清:
第一是语言模型 Token,就是上面说的文本最小单元,它是模型计费和上下文长度计算的单位。
第二是接口鉴权 Token,比如你调用某个 API 时拿到的 Access Token、JWT,或者登录时返回的会话 Token。这类 Token 是字符串凭证,用于身份验证和权限控制,跟模型本身一毛钱关系都没有。你在各种工具里遇到的 “sign-in could not be completed: token exchange failed”“your access token could not be refreshed”,说的都是这类鉴权凭证失效或刷新失败,对应的解决方式是重新登录、检查 API Key 权限、刷新凭证,而不是去调模型参数。
第三是输出上限(max_tokens)。这是模型生成回答时的最大 Token 数限制。后面讲采样参数的时候我会专门展开。
把这三者分开,你排查问题时就能少走 70% 的弯路。很多人一看报错带 “token” 两个字,就跑去改模型的 temperature 参数,这完全是在错误的方向上使劲。
1.4 控制 Token 用量的几个实操技巧
既然 Token 直接等于钱,也有很多人问“AI 编码如何指定上下文了”“Claude Code 如何用省 Token”,我分享几个亲测有效的做法:
- 压缩历史记录:不是每次请求都把全部对话历史发过去。对一段超过 N 轮的对话,我会用“摘要+最近几轮原文”的结构替代完整历史,相当于让模型记笔记,而不是每次重读整本小说。这一步能把长对话的 Token 消耗降低 40% 到 60%。
- 精简系统提示词:系统提示词每请求都会重复计费,精炼表达、去掉冗余修饰能实打实省钱。一句话能说清楚的要求,不要写满半屏。
- 善用结构化输入:用 Markdown 或 JSON 格式组织内容,让模型更快理解你的意图,减少因误解导致的反复追问和重试。
- 按需设置 max_tokens:如果只需要模型输出几个关键词或代码片段,就把输出上限设小一点,防止它“自由发挥”写篇小作文,白白烧掉额外 Token。
2. 上下文窗口:模型的“工作记忆”与它的物理边界
2.1 什么是上下文窗口,为什么它会影响回答质量
上下文窗口(Context Window)指的是模型在处理一次请求时,最多能“同时看到”的 Token 数量。它相当于模型的工作记忆空间:既包括你输入的提示词、历史对话、参考文档,也包括模型正在生成的回答。
如果说 Token 是模型理解世界的“词汇颗粒”,上下文窗口就是模型在特定时刻能摆在桌面上的所有卡片数量。桌面就这么大,能摆的卡片有上限,一旦超出,模型就必须丢弃或忽略一些卡片。
这里有一个重要的认知:模型的“长期记忆”并不存在。它每次回答,都只基于这次请求送入上下文窗口的内容。关掉对话窗口之后,模型不会记得你,除非你每次把需要它记住的信息重新放进上下文里。这也是为什么很多人觉得“同一个问题换个新对话问,模型就变傻了”——不是模型变了,而是上下文里没有承载之前对话的信息。
上下文窗口为什么是个硬限制?因为 Transformer 架构的核心是注意力机制(Attention),它需要计算输入序列中任意两个 Token 之间的关系。这个计算量随序列长度呈平方级增长。窗口越长,显存占用和计算延迟都急剧上升。所以厂商在模型设计和部署时,会对上下文长度做一个明确的硬边界,比如 128K、200K 等。
2.2 超过上下文限制到底会发生什么:四种后果
很多人搜“Claude 超过上下文限制会怎么样”,我来系统说清楚。不同产品对超限的处理方式不一样,但底层逃不出四种情况:
- 直接报错:API 请求返回错误,提示输入超过上下文限制。这是最“干净”的失败方式,至少你知道原因了。
- 自动截断:有些应用会静默丢弃对话历史中最旧的内容,只保留最近的部分。后果是模型“失忆”,忘了你最开始提的需求,回答变得莫名其妙。
- 回答截断:模型正在生成时达到输出 Token 上限,回答中断在半句话上。很多产品会提示“已达到输出 token 上限,回答被截断,发送‘继续’可让模型接续”。这说明前面的输入已经占用了大量窗口,留给输出的空间不够了。
- 成本飙升后失败:部分系统在超限时自动丢弃中间内容但保留首尾(比如保留系统提示词和最近对话),通过摘要压缩来硬塞进窗口,但这通常意味着你要额外付出摘要生成的 Token 成本。
我在本地跑开源模型时,最常遇到的是第二种和第三种。尤其在用长文档做问答时,如果把十几页文档一次性塞进上下文,模型要么报错,要么生成到一半就断了。后来我给自己定了一条红线:输入内容不要超过上下文窗口的三分之一。留出足够空间给模型输出和推理,回答质量会稳定很多。
2.3 上下文工程:比“调参”更值得投入的方向
最近有一个词很火,叫“上下文工程”(Context Engineering)。热词里也有“上下文建设 亮点”“上下文数据流图的分解”等说法。在我看来,上下文工程不是玄学,而是研究如何把有限上下文窗口的价值发挥到最大——在窗口受限的前提下,哪些信息该放进去、以什么顺序放、用什么格式放,直接决定模型输出的上限。
这个方向最常见的落地方式是 RAG(检索增强生成)。原理不复杂:你有一个很大的知识库,但不可能全部塞进上下文,于是先根据用户问题做一次检索,只把最相关的几段内容拿出来,拼到提示词里,再把拼好的内容送给模型。这样既绕开了上下文窗口的限制,又让模型“基于资料回答”,显著减少幻觉。
我做过一个内部知识库问答系统,最初就是一股脑把所有相关文档拼接起来送进模型,结果上下文频繁超限,回答质量也差。后来改成 RAG 流程:先向量检索 Top 5 相关片段,每段控制在 500 字以内,拼完后整体不超过 3000 Token。同样的知识库,回答准确率肉眼可见地提升了,上下文超限的报错也几乎绝迹。
另一个被低估的上下文工程技巧是信息顺序。模型对上下文不同位置的敏感度不一样:开头(primacy effect)和结尾(recency effect)的信息更容易被模型记住,中间部分容易被忽略。我习惯把最关键的要求放在系统提示词里反复强调,把最新指令放在用户消息末尾,长文档只取核心段落放在中间偏后位置。这个细节在长文档问答场景下,提升效果相当明显。
2.4 AI 编码场景下,怎么“给上下文”才省力又有效
热词里有一类高频问题:“Cursor 怎么把上下文给到 AI”“AI 编码如何指定上下文”。做 AI 辅助编程的同学应该都有体会:代码文件越长,越容易把不相关的代码塞给模型,既浪费 Token 又稀释注意力。
我的经验是:显式圈定上下文,而不是把整个仓库交给 AI。在 Cursor、Claude Code、Codex CLI 这类工具里,尽量不要用那种“自动获取全部文件”的模式,而是手动指定当前任务涉及的文件、函数或类。比如你要改某个模块的接口,就把这个接口的定义、调用它的几个关键位置、对应的测试用例给到模型,其他无关模块一概不写进上下文。
还有个不少人忽略的点:让模型先输出“对问题的理解”,再输出代码。这在编码场景中特别有用。你可以要求模型先把任务拆解成要点、列出改动文件清单,确认无误后再生成具体实现。这本质上是在上下文里建立“共识区”,避免模型越过需求直接写代码,导致方向跑偏。这个习惯也帮我在代码评审时省了大量返工时间。
3. 采样参数:决定模型“性格”的旋钮
3.1 从概率到文本:模型是怎么“选”下一个词的
前面讲了模型如何把文本变成 Token,但模型真正神奇的地方在于:它能预测下一个 Token 是什么。具体来说,模型会根据当前上下文,为词表中的每个 Token 计算一个分数(Logits),再通过 Softmax 函数转成概率分布。然后在这个概率分布上,用不同的策略选出“下一个 Token”。
这里的关键是:模型天然不是一个“只会选最大概率”的机器。它在概率分布上做“采样”,也就是带有一定随机性。采样参数就是控制这个随机性方式和强度的旋钮。
我常用一个比喻:模型像一个知识渊博但有点选择困难症的人。如果让他每次都说最标准、最保险的答案,他会比较无聊;如果给他一点自由发挥的空间,他可能会说出很有创意的观点,但也可能跑题。采样参数就是用来调节他“无聊”和“跑题”之间平衡的。
3.2 核心采样参数逐个拆解:temperature、top_p、top_k、惩罚项
这一节是很多人“调了半天参数没感觉”的重灾区。我给每个参数一个清晰的定义,附上使用建议。
temperature(温度):最核心的随机性参数,取值范围通常是 0 到 2。温度越低,概率分布越尖锐,模型越倾向选高概率 Token;温度越高,低概率 Token 也有机会被选中,输出更多样、更有“创造力”。数学上,它是把 Logits 除以温度值后再做 Softmax。当 temperature=0 时,概率分布尖锐到极限,模型每次都选最高概率的 Token,输出几乎完全确定。经验值:需要稳定事实回答的场景用 0 到 0.3,创意写作、头脑风暴用 0.7 到 1.0,再高就容易胡言乱语了。
top_k:只从概率最高的前 K 个 Token 里采样,其余全部排除。比如 top_k=50,就是先把概率排前 50 的 Token 挑出来,再按各自概率采样。它的作用是防止模型偶尔抽中一个概率极低的冷门 Token。实际操作中,top_k 通常设 40 到 50 是比较稳的区间。太小的 top_k 会让输出变得保守,太大则失去了限制的意义。
top_p(核采样):从累计概率超过 p 的最小 Token 集合里采样。比如 top_p=0.9,就把概率从高到低累加,直到累加值超过 0.9,然后在这一组 Token 中采样。它的逻辑是“只在高概率的候选里做选择”,比 top_k 更动态,因为候选数量会随概率分布的形状变化。标准做法是:top_p 和 temperature 只调其中一个,不要两个同时大幅调整,否则容易互相打架,输出变得难以控制。
frequency_penalty(频率惩罚):对已经出现过的 Token 施加减分,出现次数越多,分越低,从而降低模型重复同一词汇的概率。适合需要减少复读机效果的场景。范围通常是 -2 到 2,正值代表惩罚重复,负值反而鼓励重复。我一般设 0.3 到 0.6 就够用了,太大会让句子变得生硬不连贯。
presence_penalty(存在性惩罚):只要某个 Token 出现过,就给一次固定减分,跟出现次数无关。作用是鼓励模型谈论新话题、引入新概念。它和 frequency_penalty 的差别在于:frequency 惩罚“反复说”,presence 惩罚“说过就减分”。两者可以同时使用,但要注意整体输出风格的变化。
3.3 为什么模型“有幻觉”:采样参数和幻觉得关系
热词里有一条“大模型能力边界,幻觉、上下文、温度”,直接把幻觉和温度并列,很有洞察。幻觉的本质原因很复杂,包括训练数据噪声、模型压缩、知识截止日期等,但采样参数是幻觉的直接触发器之一——如果你把 temperature 调得过高,模型就会在低概率 Token 上“放飞自我”,一本正经地编造事实。
我在实际测试中遇到过非常典型的例子:用同一个事实类问题分别测试 temperature=0.1 和 temperature=0.9,前者回答准确率在 9 成以上,后者虽然偶尔有惊艳表达,但错误率也明显上升。如果你在做客服问答、知识库问答这类对准确性要求极高的场景,我的建议是 temperature 不要超过 0.3,最好在 0.1 到 0.2 之间。
但有一点要提醒:temperature=0 并不能完全消除幻觉。因为模型“知道什么”和“确认什么”在训练时就固定了,采样参数只是决定它能否说出不那么确定的内容。就算设置为 0,模型也可能在知识盲区上编一个听起来合理的答案。要真正减少幻觉,必须回到上下文工程——给它可靠的参考资料,让它在有限范围内作答。
3.4 “让模型不输出思考过程”:这个需求怎么用参数满足
热词里有一条“dify llm 怎么让模型不输出思考过程”,这也是很多人问过的。首先要分清模型是否真的“会思考再输出”。现在很多推理模型(比如带 reasoning 能力的模型)默认会在回答前输出一段内部推理过程,这在某些产品里是显式的,会出现在界面上,占用你的输出 Token。
怎么让它不输出思考过程?没有单一的采样参数能完全开关这个行为,但我有几个亲测有效的方法:
一是修改系统提示词,明确要求“只输出最终答案,不要展示推理步骤,不要解释过程”。多数模型会听话,省掉那部分冗长的思考文本。
二是在 API 层面关闭推理输出。不少平台提供reasoning或thinking相关开关,把详细推理内容关掉,只保留最终结果。如果你用的是这类能力,优先找这个开关而不是调 temperature。
三是把输出上限调低。如果模型的思考过程很长,而你把 max_tokens 设置得较小,推理过程就可能被截断,最终答案自然变短。这个方法比较粗暴,不推荐,因为它可能让最终答案也一起被砍掉。
四是换用非推理模型。如果你的任务不需要复杂推理,只是想快速拿到答案,直接选用不带推理能力的模型,反而响应更快、成本更低。不要什么任务都上最强模型。
3.5 max_tokens 与输出截断的实战经验
“已达到输出 token 上限,回答被截断”这个问题,我估计被它坑过的人不在少数。要解决它,得先搞清楚上下文窗口 = 输入 Token + 输出 Token。当你请求时,系统会预留出 max_tokens 这个输出额度,剩下的才给输入用。如果输入太长,留给输出的空间自然就少了。
我踩过的一个具体坑是:在一个长文档问答系统里,用户上传一篇 5000 Token 的文档,我把 max_tokens 设成 2000,上下文窗口是 8000,看起来没问题。但系统提示词、对话历史、检索结果加起来其实已经超过 6000 Token,实际留给输出的只有不到 2000,而模型生成到一半就到达上限,回答被截断。后来我做了两道防线:一是在发送前计算整个输入的长度,如果接近上限就自动压缩历史或提示用户;二是把 max_tokens 根据任务类型动态设置——摘要类任务给 1500 到 2000,选择题给 200 到 500,代码生成给 2000 以上。
另一个技巧是:遇到模型回答到一半断了,不要重新问一遍,直接发“继续”或“接着上文继续”,让模型接着已有的回答继续生成。这也是热词里“发送‘继续’可让模型接续”的用法来源。但要注意,“继续”也占用上下文和输出额度,如果输入已经把窗口占满了,继续也救不回来,这时候只能先精简输入或手动拆分任务。
4. 三者联动:从一次生成事故看参数协作与排查思路
4.1 一个真实的失败案例复盘
今年早些时候,我帮朋友排查一个 AI 写作助手的问题:用户上传一篇约 1 万字的营销长文,要求模型“改写成更有吸引力的版本”,结果模型频繁报错,偶尔成功但输出质量也很差。
我打开日志一看,问题一目了然:整个请求的输入 Token 已经接近 1.5 万,而上下文窗口是 8000,系统自动截断了文档开头部分;同时 temperature 被前端写死成 0.95(为了“更有创意”),导致模型在信息不全的情况下高随机性地发挥;max_tokens 设的是 4096,窗口又不够用,经常生成一半就被截断。
三个参数同时出问题,结果就是:输入被截断→模型看不到全文→高温度放飞自我→输出又被截断。用户看到的就是“报错+答非所问+生硬结尾”的三连击。
修复方案也简单:把文档拆分成长文分段改写,每次只处理 3000 字左右;temperature 从 0.95 降到 0.7;max_tokens 设置为 1500,让每次输出都能完整包含改写结果和必要的上下文总结。改完之后,同样一篇长文,处理时间变短了,输出质量也稳定了。
这个案例说明了一个重要原则:Token、上下文、采样参数不是三个独立旋钮,它们是一条生产链上的三个环节。任何一个环节出问题,都可能让整体效果崩掉。
4.2 常见问题速查表:一图定位问题源头
很多人来问我“为什么我的模型回答越聊越笨”时,我给的排查思路就是先查这三个维度。整理成一个速查表,方便你对照自己的情况快速定位:
| 现象 | 最先排查的环节 | 常见原因 | 解决思路 |
|---|---|---|---|
| 回答中断、半截话 | 上下文窗口+max_tokens | 输入太长挤占输出空间;max_tokens 设太小 | 压缩输入、降低文档长度、动态调整 max_tokens |
| 上下文报错(超限) | 上下文窗口 | 输入超过模型硬限制 | 精简提示词、做历史摘要、改用 RAG 检索 |
| 回答越来越笨、前后矛盾 | Token 消耗+上下文窗口 | 历史对话被截断,模型“失忆” | 缩短对话轮次、保留最近关键信息、每轮重建上下文 |
| 天马行空、胡说八道 | 采样参数 | temperature 过高 | 降到 0.1 到 0.3,或在接入层开启检索引用 |
| 输出重复、复读机 | 采样参数 | 缺少频率惩罚;temperature 过低 | 加 frequency_penalty 0.3 到 0.6,适当提高 temperature |
| 输出保守、缺乏创意 | 采样参数 | temperature 过低 | 适中调高到 0.7 到 1.0,注意配合 top_p |
| API 报错 token 失效/未授权 | 接口鉴权 | 凭证过期、权限不足 | 重新登录、刷新 token、检查 API Key 权限 |
| 账单费用超标 | Token 用量 | 发送大量冗余内容、超长历史、高 max_tokens | 精简每次请求、启用上下文压缩、缓存响应 |
你在排查时,可以按“先查上下文窗口是否充足→再查采样参数是否合理→最后查接口鉴权和配额”这个顺序来。90% 的异常都能在第三步之前解决。
4.3 一套可以直接抄的 LLM 应用参数配置
最后分享一套我在多个实际项目中验证过的配置模板,覆盖几类最常见的任务。注意,这是起点,不是终点,具体到你的场景还需要微调。
| 任务类型 | temperature | top_p | top_k | frequency_penalty | max_tokens | 关键上下文策略 |
|---|---|---|---|---|---|---|
| 知识库问答(RAG) | 0.1 | 0.3 | 40 | 0.0 | 500-1000 | 只送入检索到的 Top 5 段落 |
| 创意写作/头脑风暴 | 0.9 | 0.9 | 50 | 0.4 | 1500-3000 | 提供写作方向+示例,不设限 |
| 代码生成 | 0.2 | 0.5 | 40 | 0.0 | 2000+ | 明确函数签名、输入输出、约束条件 |
| 摘要总结 | 0.3 | 0.6 | 45 | 0.3 | 800-1500 | 传入全文或拆分分批摘要 |
| 客服对话 | 0.2 | 0.4 | 40 | 0.5 | 500 | 保留最近 5 轮对话+用户订单信息 |
| 翻译 | 0.1 | 0.3 | 40 | 0.0 | 1000-2000 | 保留原文和被翻译的部分,提供术语表 |
这套模板的关键思路是:事实类任务温度低,创意类任务温度高;输出长度按任务实际需要,而不是越大越好。至于 top_k 和 top_p,我建议新手先用 top_p 就够了,top_k 作为辅助微调手段,不要一上来两个参数都乱动。
4.4 优化收益最大化的个人心得:把“每次请求”当一份精心准备的简报
踩过足够多的坑之后,我发现真正拉开使用效果差距的,往往不是选哪款模型或调哪个参数,而是一个视角的转变:把每次发给模型的请求,当成一份给高管的简报——信息经过筛选、按优先级排序、控制篇幅、目标明确。
这意味着你在写提示词时要想清楚几个问题:模型需要哪些信息才能完成这个任务?这些信息以什么顺序给最不容易被忽略?哪些信息其实是干扰项可以省略?执行标准应该用多少 token 能说清?当你的思维从“我要把能想到的都告诉模型”转变成“我要让模型在有限上下文里最高效地完成任务”,Token 成本、上下文超限、输出截断这些问题都会自动缓解。
另外,我始终建议你在本地维护一份自己的“提示词模板库”和“参数配置记录”。每次测试完一组任务,就把用的参数、输入长度、输出质量、成本记下来。积累一段时间后,你会形成一套属于自己的“手感”,到那时再回头看什么 temperature、top_p,它们不再是抽象的概念,而是你手里的工具。