前八章都在讲模型内部。这一章讲客户端在 API 层能看得见、能调得动的四件事——不懂机制照样能调,但踩坑时你会不知道自己踩在哪。
采样参数:Temperature / Top-k / Top-p 到底在调什么
模型每一步输出的并不是一个 token,而是整个词表上的概率分布——几万个 token 各有一个概率。到底吐哪个字,是"采样"这一步决定的。
- Temperature(温度):过 softmax 前把分数除以一个 T。T=0.1 时高分更高、低分更低,分布变尖,每次几乎都选同一个字,输出稳定;T=1.5 时分布变平,冷门 token 也有机会被选中,输出发散。业务上要复现代码/JSON → 调到 0;要写故事、发散思路 → 调到 0.8–1.2。
- Top-k:只从概率最高的 k 个候选里采样。k=50 就是只有前 50 名有资格被抽中,挡住长尾里的怪词。
- Top-p(核采样):从"累加概率达到 p"的最小候选集里采样。p=0.9 就是凑到 90% 概率覆盖的那几个词里选。相比 Top-k,Top-p 会根据分布形状动态收放——分布尖时候选少,分布平时候选多。
三个参数通常组合使用。需要注意:不同推理引擎对 temperature=0、top-p 和 seed 的处理并不完全一致;即使固定 seed,跨硬件、跨批次或跨服务版本也未必逐 token 相同。严格复现要同时锁定模型、推理引擎、采样参数和运行环境。
Function Call 本质上是模型吐 JSON,客户端自己去调
客户端把一堆函数 schema(名字、参数、描述)注册给模型,模型在生成时会吐一段特殊格式的 JSON,说"我要调用 get_weather(city='北京')"。模型本身什么都没执行,它只是被训练成会在合适的时机吐这种 JSON 字符串出来。真正的执行是客户端拿到 JSON、解析出函数名和参数、自己去调本地或后端服务,然后把结果拼回消息历史,再喂给模型下一轮。
所以 Function Call 的可靠性只取决于两件事:模型训练时见过多少这样的调用样本、你的 schema 描述写得够不够清楚。参数描述含糊、类型不明确,模型就会瞎猜。
幻觉从哪里来
模型的目标是"说得像",从头到尾都不是"说真话"。它在做的事本质是"在这段上下文之后,哪个 token 出现的概率最高"——概率最高的不一定是事实。当模型对某件事没见过、见得少、或者记忆模糊时,它不会停下来说"我不知道",因为它没被训练成这样。它会输出一个"看起来像那么回事"的答案:语法通顺、格式正确、语气自信,内容是编的。
工程上能压幻觉的手段就三条:
- 给它上下文(RAG):把真实答案先塞进 prompt 里,让它照着说
- 让它调工具(Function Call):需要事实的地方去查真实数据,别让模型自己回忆
- 让它先想再答(CoT / o1 那套,第五章讲过):把答案的推导过程展开,减少"张口就来"
别指望换个模型幻觉就没了——这是概率生成的机制病,不是某个模型的 bug。
System Prompt 为什么"有效"
System Prompt 本质就是排在最前面、优先级最高的一段上下文,没什么魔法开关。它有效的原因很朴素:
- 位置在最前:Attention 里,后面每一个 token 都要看它一遍,影响所有后续生成
- 训练时被特殊标记:主流模型训练时,system 消息会带一个特殊 token 或角色标签,模型学到"这段是设定,得遵守"
- 风格锚定:模型输出会向 prompt 的语气、术语、格式靠拢——你 system 里用严肃口吻,它输出也严肃;写"用大白话回答",它就少讲术语
局限也在这:System Prompt 不是硬约束,只是概率上的引导。用户消息里如果反复强推另一种风格,模型可能就跟着漂了。真要硬约束(比如禁止某类内容),得靠后处理,别只靠 prompt。
流式输出(Streaming)为什么天生就能做
顺带说一件天天用但很少细想的事:API 为什么能"一个字一个字往外吐"?
模型本来就是自回归生成的——一次算一个 token,算完立刻拿得到。HTTP 层用 Server-Sent Events(SSE)或者分块传输,服务端每算出一个 token 就 flush 一次推给客户端,不等整段生成完。流式本身就是这套自回归推理的自然延伸,没啥新东西。客户端要做的是解析 SSE 事件流、增量拼接、增量渲染——iOS 上用 URLSession 的 delegate 回调,Web 上用 EventSource 或 fetch + ReadableStream。
流式的好处不只是"体验好",还有:可以在生成中途取消(省钱省算力)、可以边生成边做敏感词检测、可以边生成边切 UI 状态(比如工具调用中的转圈)。