一、大模型为什么会"随机说话"?

1.1 从"幻觉问题"说起

如果你用过 ChatGPT、DeepSeek 这类大模型,一定遇到过这种情况:同一个问题问两遍,得到的答案居然不一样。有时候它答得头头是道,有时候却一本正经地胡说八道——这就是我们常说的"幻觉"(Hallucination)。

这不是 Bug,而是大语言模型(LLM)的设计特性。LLM 本质上是一个"下一个词预测器"(Next Token Prediction),它每次输出的不是一个确定的词,而是一张概率分布表

理解这一点,是控制 AI 行为的第一步。

1.2 概率分布:LLM 的底层运作机制

大模型在生成每个词时,内部会计算出一个概率分布(Probability Distribution)——即"接下来最可能出现的词是哪些,各自的概率是多少"。

举个例子,当模型看到上文 “你好” 之后,它内部可能计算出这样一张表:

候选词概率得分
0.60
0.15
0.10
0.05
0.01

关键认知:模型不是"知道"下一个词该是什么,而是"猜测"下一个词可能是什么。这个"猜测"的过程,就是从一个概率分布中采样(Sampling)

如果没有人为干预,模型默认会倾向于选概率最高的词(这里是"吗"),但并不总是选它。这正是 AI 输出"不可控"的根源——对于开发者来说,我们需要理解并控制这个采样过程,让 AI 在"靠谱"和"有创意"之间取得平衡。


二、控制随机性的两大关键参数

2.1 Temperature:控制"创造力"的温度旋钮

Temperature(温度) 是控制采样随机性最核心的参数,取值范围通常是 0 ~ 1(部分模型支持 >1,但很少用到)。

原理(用人话讲)

在采样之前,模型会把概率分布中的每个得分都除以 Temperature:

调整后得分 = 原始得分 / Temperature
  • Temperature = 0.2(低温):原始得分 0.6 ÷ 0.2 = 3.0,得分被放大,高低分之间的差距被急剧拉大。概率最高的词(“吗”)几乎必然被选中,输出稳定、保守、可预测
  • Temperature = 0.8(高温):原始得分 0.6 ÷ 0.8 = 0.75,得分间的差距被缩小。原本概率很低的词(“坏”=0.01 ÷ 0.8 = 0.0125)和高概率词的差距变小了,被选中的机会大大增加,输出多样、发散、有创意
一张图帮你理解
原始概率分布:  吗 ████████████ 0.60  |  啊 ███ 0.15  |  呀 ██ 0.10  |  美 █ 0.05  |  坏 ▏0.01

Temperature=0.2(低温):
  吗 ████████████████████████████  → 几乎必选
  其他词几乎无机会

Temperature=0.8(高温):
  吗 ██████████  |  啊 █████  |  呀 ████  |  美 ██  |  坏 █
  → 各词都有机会被选中,结果更随机
场景选择建议
Temperature 值特点适用场景
0.0 ~ 0.3高度确定性,输出几乎不变代码生成、法律文书、合同审查、数学推理
0.4 ~ 0.6平衡型,有一定灵活性通用对话、翻译、摘要
0.7 ~ 1.0高随机性,创意丰富文学创作、广告文案、头脑风暴、AI 漫剧脚本

⚠️ 常见误区:Temperature 不是越高越好,也不是越低越好。生成代码时用高 Temperature 会让代码"放飞自我"满屏 Bug写诗时用低 Temperature 会让文字像机器人一样干巴巴

2.2 Top-K:划定"候选池"的筛选器

如果说 Temperature 控制的是"随机程度",那 Top-K 控制的就是"选择范围"。

原理

Top-K 的做法非常直接:把概率分布按得分从高到低排序,只保留前 K 个词,其余全部丢弃,然后在这 K 个词里重新归一化概率再采样。

还是用上面的例子:

原始分布(排序后): 吗 0.60 > 啊 0.15 > 呀 0.10 > 美 0.05 > 坏 0.01 > ...

Top-K=3: 只保留 [吗, 啊, 呀],其余词概率归零
  → 吗 0.60/(0.60+0.15+0.10) ≈ 0.71
  → 啊 0.15/(0.60+0.15+0.10) ≈ 0.18
  → 呀 0.10/(0.60+0.15+0.10) ≈ 0.12
  → 美、坏 等被直接排除,不可能被选中
Top-K 的作用
  • K 较小(如 2~4):只保留最靠谱的几个候选词,过滤掉跑偏的低概率词,保证输出质量的下限。
  • K 较大(如 8~20):给更多候选词机会,保留更多可能性和多样性。
  • 默认值通常是 8,这是一个经过大量实践验证的平衡点。

2.3 Temperature + Top-K 的协同配合(核心重点)

这是整个随机性控制中最关键的知识点。两个参数并不是独立工作的——它们配合使用,分两步操作:

Step 1(Top-K 过滤): 从概率分布中筛选出前 K 个高分词,丢掉低分"噪音"
       ↓
Step 2(Temperature 缩放): 对这 K 个词的得分做温度调节,控制随机性
       ↓
    最终采样 → 输出一个词

这个两步流程可以用一句话概括:Top-K 划定"靠谱的范围",Temperature 决定"在靠谱范围内有多大胆"

黄金组合矩阵
场景TemperatureTop-K为什么这样配?
🧑‍⚖️ 代码 / 法律 / 合同0.2(低)8(大)低温保证精准,大 Top-K 保证不漏掉正确的候选词
✍️ 创意写作 / 文案0.8(高)3~4(小)高温激发创意,小 Top-K 防止发散到完全不靠谱的词
💬 通用对话0.5(中)8(默认)平衡准确性和自然度
🎨 AI 漫剧 / 多模态创作0.8~1.0(高)3~5(小)需要创意但也要保证内容可用
⭐ 黄金法则(务必记住)

Temperature 和 Top-K 不可能都太大,也都不需要都很小。

  • Temperature 小 + Top-K 大 = 精准且全面(严谨场景)
  • Temperature 大 + Top-K 小 = 靠谱的创造性(创作场景)
  • Temperature 大 + Top-K 大 = 输出乱码风险极高
  • Temperature 小 + Top-K 小 = 输出死板毫无变化

三、LangChain:把 AI 工作流"链"起来

3.1 什么是 LangChain?

LangChain = Lang(uage) + Chain(链)

它的核心思想很简单:AI 应用不是"调一次 API 就完事"的,它往往是一个多步骤的工作流(Workflow)——接收输入 → 套用提示词模板 → 调用 LLM → 解析输出 → 执行下一步操作。LangChain 做的事情,就是让这个工作流中的每一步都可复用、可组合、可维护

为什么需要 LangChain?

在没有 LangChain 之前,你可能这样写:

// 😢 硬编码方式:提示词写死在代码里,模型参数散落各处
const prompt = "请写一篇短篇散文,主题:秋日山野晚风,风格温柔治愈...";
const response = await fetch("https://api.deepseek.com/v1/chat/completions", {
  body: JSON.stringify({
    model: "deepseek-v4-pro",
    temperature: 0.8,
    messages: [{ role: "user", content: prompt }],
  }),
});
// 每换一个主题就要改代码,每换一个业务场景就要重新写一遍...

有了 LangChain 之后,Prompt 是独立的模板,模型是可配置的实例,整个流程是搭积木式的。对于需要频繁迭代的 AI Agent 应用来说,这种工程化能力至关重要。

3.2 核心模块速览(@langchain/core

模块作用一句话理解
Prompts提示词模板把"变化的部分"(用户输入)和"不变的部分"(系统指令)分离,方便复用
Messages对话消息列表管理多轮对话的上下文,HumanMessage / AIMessage / SystemMessage
Output Parsers输出解析器把 LLM 的原始输出自动解析成你需要的格式(纯文本 / JSON / 结构化数据)
Tools工具定义让 LLM 能调用外部函数(查数据库、调 API、读文件),这是 Agent 的基础

在本文的实战中,我们重点使用 PromptsOutput Parsers 两个模块。


四、实战:构建一个可控随机性的 AI 写作工作流

4.1 项目初始化

# 创建项目目录
mkdir temperature-demo && cd temperature-demo

# 初始化项目
npm init -y

# 安装依赖
npm install @langchain/openai @langchain/core dotenv

# 创建环境变量文件
echo 'DEEPSEEK_API_KEY=你的API密钥' > .env

4.2 完整代码与逐行解析

创建文件 main.mjs,完整代码如下:

// ============================================
// 第 1 步:导入依赖
// ============================================
import 'dotenv/config'                                  // 自动读取 .env 中的环境变量
import { ChatOpenAI } from '@langchain/openai'           // LangChain 封装的 OpenAI 兼容 LLM
import { StringOutputParser } from '@langchain/core/output_parsers'  // 把 LLM 输出解析成纯文本
import { PromptTemplate } from '@langchain/core/prompts'              // 提示词模板,让 prompt 可复用

// ============================================
// 第 2 步:配置两个不同"性格"的 LLM 实例
// ============================================

// 🔥 创意型模型:高 Temperature + 小 Top-K
// 思路:用高温激发发散性,用小 Top-K 框住下限,防止"太放飞"
const creativeModel = new ChatOpenAI({
  model: 'deepseek-v4-pro',
  temperature: 0.8,   // 高温 → 随机性大,适合创意发散
  topK: 4,            // 小 Top-K → 只从概率前 4 的词里采样,过滤掉低分"噪音词"
  maxToken: 600,      // 限制最大输出长度
  apiKey: process.env.DEEPSEEK_API_KEY,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  }
})

// 🧑‍⚖️ 严谨型模型:低 Temperature + 大 Top-K
// 思路:用低温保证确定性,用大 Top-K 保证不遗漏正确的候选词
const preciseModel = new ChatOpenAI({
  model: 'deepseek-v4-pro',
  temperature: 0.2,   // 低温 → 近乎确定性输出,每次结果几乎一样
  topK: 8,            // 大 Top-K → 保留更多候选,确保信息完整不丢失
  maxToken: 600,
  apiKey: process.env.DEEPSEEK_API_KEY,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  }
})

// ============================================
// 第 3 步:创建可复用的提示词模板
// ============================================
// PromptTemplate 把"变化的输入"({theme})和"固定的指令"分离
// 不同用户、不同主题,只需替换 {theme} 变量,模板本身不用改
const storyPrompt = PromptTemplate.fromTemplate(
  `请写一篇短篇散文,主题:{theme}
风格温柔治愈,篇幅200字左右,不要分段,文字细腻有画面感。`
)

// ============================================
// 第 4 步:创建输出解析器
// ============================================
// StringOutputParser 自动从 LLM 返回的复杂对象中提取纯文本内容
// 避免手动写 response.choices[0].message.content 这种繁琐代码
const outputParser = new StringOutputParser()

// ============================================
// 第 5 步:用 pipe() 组装 AI 工作流(Chain)
// ============================================
// pipe() 是 LangChain 的核心方法,类似工厂流水线:
// PromptTemplate → LLM → OutputParser,数据依次流过每个环节

// 创意写作流水线
const creativeChain = storyPrompt
  .pipe(creativeModel)    // 把填好变量的 prompt 送入创意型 LLM
  .pipe(outputParser)     // LLM 原始输出 → 纯文本字符串

// 严谨写实流水线(流程一模一样,只是 LLM 配置不同)
const preciseChain = storyPrompt
  .pipe(preciseModel)     // 把填好变量的 prompt 送入严谨型 LLM
  .pipe(outputParser)

// ============================================
// 第 6 步:执行工作流,对比输出
// ============================================
async function runWriteDemo() {
  const theme = '秋日山野晚风'

  console.log('========== 🎨 创意写作模式 ==========')
  console.log(`参数: temperature=0.8, topK=4`)
  console.log('---')
  const creativeText = await creativeChain.invoke({ theme })
  console.log(creativeText)
  console.log('')

  console.log('========== 🧑‍⚖️ 严谨写实模式 ==========')
  console.log(`参数: temperature=0.2, topK=8`)
  console.log('---')
  const preciseText = await preciseChain.invoke({ theme })
  console.log(preciseText)
}

// 启动
runWriteDemo().catch(err => console.error('运行出错:', err))

4.3 代码设计思路(关键理解)

整段代码的设计体现了一个核心思想:“同一套 AI 业务逻辑,通过调整参数适配不同场景”

                    ┌─────────────────┐
                    │  PromptTemplate  │  ← 同一套提示词,{theme} 是唯一变量
                    └───────┬─────────┘
                            │
            ┌───────────────┴───────────────┐
            ↓                               ↓
   ┌────────────────┐             ┌────────────────┐
   │ creativeModel  │             │  preciseModel  │
   │ temp=0.8,k=4   │             │  temp=0.2,k=8  │
   └───────┬────────┘             └───────┬────────┘
           ↓                              ↓
   ┌────────────────┐             ┌────────────────┐
   │ OutputParser   │             │  OutputParser  │
   └───────┬────────┘             └───────┬────────┘
           ↓                              ↓
    创意散文 🌈                       写实散文 📐

这就是 LangChain 被称为 “Chain” 的原因——它让你像搭积木一样,把 Prompt 模板、LLM 实例、输出解析器pipe() 串联起来,形成一条端到端的 AI 工作流水线。

4.4 运行结果对比

运行 node main.mjs,你会看到两份同样主题但风格完全不同的散文:

  • 创意模式(temp=0.8, topK=4) 的输出:每次都不一样,用词更大胆、比喻更意外,读起来像不同的人写的。
  • 严谨模式(temp=0.2, topK=8) 的输出:每次几乎一样,用词平稳、结构工整,但缺少惊喜感。

这就是 Temperature + Top-K 在真实场景中的威力——同样的 Prompt,不同的参数,产出完全不同风格的文本


五、全文总结

本文从"大模型为什么会随机说话"这个日常问题出发,深入讲解了背后的核心机制:

  1. LLM 的本质是概率预测,不是确定性计算。它输出的每个词都是从概率分布中采样得来的,这是随机性的根源。
  2. Temperature 通过缩放概率分布来控制随机性的大小——低温让模型"保守",高温让模型"大胆"。
  3. Top-K 通过截断候选词范围来保证质量下限——只从得分最高的 K 个词里选,过滤噪音。
  4. 两者配合使用,先在 Top-K 阶段过滤不合格词,再在 Temperature 阶段调节随机程度,实现"靠谱的创意"或"全面的精准"。
  5. LangChain 用 Chain(链)的思想将这些参数和模块工程化,让 AI 工作流可组装、可复用、可维护。

六、核心知识点复盘

序号知识点一句话总结
1LLM 输出机制基于概率分布的采样,而非确定性选择
2Temperature 原理原始得分 ÷ Temperature,低温拉大差距、高温缩小差距
3Temperature 取值0~0.3 严谨场景,0.7~1.0 创意场景
4Top-K 原理只保留概率最高的 K 个候选词,其余丢弃后重新归一化
5Top-K 默认值通常为 8,是一个经过验证的通用平衡点
6黄金组合(严谨)Temperature 小(0.2)+ Top-K 大(8)→ 精准全面
7黄金组合(创意)Temperature 大(0.8)+ Top-K 小(3~4)→ 靠谱的创意
8LangChain 核心PromptTemplate → pipe(LLM) → pipe(OutputParser) 的链式工作流
9PromptTemplate分离"固定指令"和"动态输入",提升复用性
10StringOutputParser自动从 LLM 返回对象中提取纯文本,简化代码

七、常见问题 / 避坑指南

❓ 问题 1:Temperature 和 Top-K 到底先执行哪个?

:在大多数 LLM 实现中,先 Top-K 过滤,再 Temperature 缩放。流程是:

原始概率分布 → [Top-K 筛选] → 保留 K 个候选词 → [Temperature 调节] → 采样输出

先框定范围,再调随机性——这样能保证即使 Temperature 很高,也只在"靠谱候选池"里浪,不会彻底跑偏。

❓ 问题 2:Temperature 设为 0 会怎样?

:Temperature = 0 意味着模型总是选概率最高的那个词(贪婪解码 / Greedy Decoding)。每次同样的输入必然得到完全一样的输出。这在代码生成等场景是好事,但在对话中会显得非常死板。

❓ 问题 3:为什么我的模型明明设了低 Temperature,输出还是不稳定?

:检查三点:

  • Top-K 是否被忽略了? 有些 API 的 Top-K 需要显式设置;
  • 是否还有其他随机性参数? 比如 Top-P(Nucleus Sampling)可能同时生效;
  • 服务端是否有默认覆盖? 部分云服务会在后端强制调整参数。

❓ 问题 4:为什么不直接用 Temperature=0(贪婪解码),而要费劲调参?

:因为真实世界的语言不是"唯一解"。同一个问题可以有不同的好答案——“今天天气真好"后面接"适合出去玩"和"阳光很温暖"都是对的。贪婪解码会抹杀掉这种多样性,让 AI 变成一个"复读机”。

❓ 问题 5:Top-K 和 Top-P 有什么区别?该用哪个?

  • Top-K:固定保留 K 个词,简单粗暴,但 K 值不好调(太小可能漏掉好词,太大可能包含噪音)。
  • Top-P(Nucleus Sampling/核采样):动态保留词,直到累计概率达到 P(如 0.9)。比 Top-K 更灵活——概率分布集中时只选很少的词,分散时选更多词。

一般来说,入门阶段先理解并调好 Temperature + Top-K 就够用了。Top-P 可以后续深入学习。

❓ 问题 6:LangChain 封装了一层,和直接调 API 比有什么优劣?

对比维度直接调 API使用 LangChain
上手难度简单直接有学习成本
代码量少(简单场景)少(复杂场景)
可维护性差(prompt 和逻辑耦合)好(模块化,模板复用)
扩展性差(换模型要大量改代码)好(换模型只需改一个配置)
适用场景简单的一次性调用Agent、多步推理、RAG 等复杂工作流

一句话建议:写 Demo 验证想法时可以裸调 API,但做正式项目建议用 LangChain 或同类框架,工程化带来的收益远大于学习成本。


📌 延伸思考:控制随机性不只是调参——在实际项目中,你还需要考虑 Prompt 设计(指令越明确、随机性影响越小)、输出校验(用正则/JSON Schema 检查 LLM 输出是否符合预期)、以及多轮对话中的上下文管理。Temperature 和 Top-K 只是整个 AI 工程化链条中的一环,但它们是最基础、最直接影响输出质量的一环。


本文基于 DeepSeek API + LangChain 实战编写,代码完整可运行。欢迎交流与指正。

更多推荐