一文讲透 Temperature 与 LangChain:从控制模型随机性到组装 AI 工作流
今天我们来深入探讨一个非常实用的话题——如何借助 LangChain 将大模型的随机性参数灵活运用,并真正构建出一条可落地的 AI 工作流。本文会沿着一条清晰的学习路径展开:首先理解大模型为何能够“随机生成内容”,接着将这些参数配置落实到代码实践中,最后全面了解 LangChain 这一框架的核心能力与生态模块。

先看整体学习脉络。整个学习路径包含三个文件,它们之间的依赖关系非常清晰:
复制代码readme0721.md(参数理论:Temperature、Top-k、Top-p 核心概念)
↓ 理论落地实践
main.js(实践代码:双温度模型 + PromptTemplate + pipe 串联)
↓ 框架全景展开
langchain-explained/readme.md(LangChain 全模块生态概览)
教学逻辑遵循 概念 → 落地 → 全景:先吃透三大随机性参数如何控制模型输出,再用 LangChain 将它们集成到代码中,最后俯瞰整个框架的能力边界与应用场景。
一、大模型是如何实现"随机"输出的?
大模型每生成一个词,本质上是从一个概率分布中进行一次"抽样"。输入「你好」,模型会给出如下候选:
复制代码下一个词候选:
「吗」35% 「啊」20% 「世界」15% 「我是AI」10% 「呀」7% 「哈哈」5%
基于这个概率分布,有三个关键参数可以调控。
Temperature:马太效应的调节阀
底层公式非常简洁:
复制代码调整后分数 = logits / Temperature
最终概率 = softmax(调整后分数)
Temperature < 1(低温)——除以一个小数放大差距,强者愈强:
复制代码T=0.3: 吗 72% 啊 18% 世界 6% 我是AI 3%
↑ 几乎锁定在「吗」
Temperature > 1(高温)——除以一个大数拉平差距,各候选均有机会:
复制代码T=2.0: 吗 22% 啊 18% 世界 17% 我是AI 15% 呀 13%
↑ 百花齐放,多样性丰富
需要注意的是——Temperature 并不直接决定输出结果,它只调整概率分布的"陡峭程度",最终仍从新分布中随机采样。T=0.3 时「吗」虽然占 72%,但仍有 28% 的概率抽到其他词汇。
结论:Temperature 本质上是一个"马太效应调节阀"。编写代码或合同时建议设为 0.2,从事文艺创作则设为 0.8 更合适。
Top-k 和 Top-p:过滤低概率词的裁剪工具
Temperature 调高之后,那些原本只占 1%-2% 的低概率词也会被一并拉高——输出会不会变得混乱?这就引出了第二个参数 Top-k。
Top-k 的做法非常直接:只保留概率最高的 k 个词,其余的全部剔除。
复制代码用户输入「你好」:
原始 → 吗 35% 啊 20% 世界 15% 我是AI 10% 呀 7% 哈哈 5% 哦 4%...Top-k=4 → 只保留:吗、啊、世界、我是AI,其余概率归零,不再参与采样
而 Top-p(核采样)则采用另一种裁剪策略——从高到低累加概率,直到达到你指定的 p 值为止。p=0.7 时,35%+20%+15%=70%,刚好在「世界」这里停住,后面的全部砍掉。
一句话概括:Top-k 是"固定名额制"(无论分布如何都选 k 个),Top-p 是"动态名额制"(候选数量随分布变化——分布集中时可能只留 2 个,分散时可能留 10 个)。
两个参数如何协同配合?
实际使用中遵循先裁剪再调节的顺序:Top-k 划定安全范围,Temperature 在范围内调整概率分布。
复制代码原始概率 → ① Top-k 剔除低概率词 → ② Temperature 拉平或拉陡 → ③ 随机采样
以 k=4, T=0.5 为例走一遍流程:
复制代码原始:吗35% 啊20% 世界15% 我是AI10% ...① Top-k=4 → 保留前4个,重新归一化:吗50% 啊29% 世界21%
② T=0.5 → 加剧马太效应,分化更明显:吗78% 啊16% 世界6%
③ 随机采样 → 大概率输出「你好吗」
搭配原则:temperature 过高 + top-k 过小 = 候选池内随机扰动,输出容易千篇一律;temperature 过低 + top-k 过大 = 候选虽多但全部趋向同一个词,输出保守缺乏创意。需要根据具体业务场景灵活调参。
二、LangChain 实战:将参数配置落地到代码中
为什么要使用 LangChain?
直接调用 OpenAI API 时,代码通常是这样写的:
复制代码const prompt = '请写一篇散文,主题:' + theme + '...' // 字符串拼接,换主题需改代码
const res = await fetch('...', { body: JSON.stringify({ model, temperature }) })
const data = await res.json()
const text = data.choices[0].message.content // 手动解析多层嵌套
Prompt 散落在代码各处,返回结果需要手动提取 .content,步骤一多代码就变得混乱。LangChain 将这些环节全部模块化,让流程更清晰。
第一步:创建两个不同温度的大模型实例
复制代码// 创意型:高温 + 小 Top-k = 发散但不偏离主题
const creativeModel = new ChatOpenAI({
model: 'deepseek-v4-flash', // 轻量、响应速度快
temperature: 0.8, // 高温 → 输出更丰富多样
topK: 4, // 仅从概率前4的词汇中采样
maxToken: 600,
})// 严谨型:低温 + 中 Top-k = 准确且信息完整
const preciseModel = new ChatOpenAI({
model: 'deepseek-v4-pro', // 更强模型,质量优先
temperature: 0.2, // 低温 → 输出更确定
topK: 8, // 更大的候选池,确保信息完整性
maxToken: 600,
})
代码中的 temperature 和 topK 与前面的理论一一对应:creative 是"高温小池"配置,precise 是"低温大池"配置。
第二步:用 PromptTemplate 将提示词转化为模板
复制代码const storyPrompt = PromptTemplate.fromTemplate(
`请写一篇短篇散文,主题:{theme}
风格治愈温柔,篇幅200字左右,不要分段,文字细腻有画面感。`
)
使用字符串拼接时,prompt 的结构逻辑与业务数据混在一起,换主题就需要改代码。PromptTemplate 将不变的结构(模板)和可变的数据(变量)分离开来——同一个模板,换不同的 {theme} 即可直接复用。在 Agent 应用中,同一套 AI 逻辑换不同用户身份(诗人 vs 律师),变化的只是参数,代码完全不动——这就是模板化的核心价值。
第三步:用 OutputParser 自动提取结果
复制代码const outputParser = new StringOutputParser()
// 内部等价于:result.content ?? result.toString()
单独使用看起来价值不大,但当你把它挂在 chain 末尾时,优势就体现出来了——链条外面拿到的直接就是干净的字符串,无需再手动 .content。这就是管道中的最后一道工序。
第四步:用 .pipe() 组装传送带式工作流
复制代码const creativeChain = storyPrompt // 1️⃣ 填入 {theme},生成完整 prompt 字符串
.pipe(creativeModel) // 2️⃣ LLM 推理,输出消息对象
.pipe(outputParser) // 3️⃣ 提取 content,输出纯字符串const preciseChain = storyPrompt
.pipe(preciseModel)
.pipe(outputParser)
pipe 的核心机制非常简单——上一个 .invoke() 的输出,自动成为下一个 .invoke() 的输入,省去了手动从中间环节取结果再传递的步骤。执行顺序就是顺着代码从上到下、从左到右:
复制代码{ theme: '秋日山野晚风' }
→ ① storyPrompt.invoke() → 完整 prompt 字符串
→ ② creativeModel.invoke() → { content: "晚风轻拂...", ... }
→ ③ outputParser.invoke() → "晚风轻拂..."
最终只需一句 creativeChain.invoke({ theme }),整条链即可自动流转。
第五步:启动流水线
复制代码async function runWriteDemo() {
const theme = "秋日山野晚风" console.log('创意写作模式')
const creativeText = await creativeChain.invoke({ theme })
console.log(creativeText) // 散文风格,文字细腻富有画面感 console.log('严谨写实模式')
const preciseText = await preciseChain.invoke({ theme })
console.log(preciseText) // 更克制、更准确的表达
}runWriteDemo().catch(err => console.error(err))
顶层的 .catch() 能够兜住所有异常——API Key 未配置、网络超时、{theme} 忘记传递——避免 Node 进程直接因 UnhandledPromiseRejection 而崩溃。
三、LangChain 还能实现哪些功能?
走完最简工作流之后,整个框架的全景也就清晰了:
| 模块 | 职责 | 一句话总结 |
|---|---|---|
| Prompts | 模板化提示词管理 | 结构与变量分离,复用无需重写 |
| Messages | 标准化对话格式 | System / Human / AI 三类,兼容所有 LLM |
| Output Parsers | 解析模型返回内容 | String / JSON / Structured 三种解析器可选 |
| Tools | 为模型挂载外部能力 | 模型自主决定调用工具(查天气、搜资料等) |
| Vector Stores | 向量化存储与检索 | RAG 核心——让模型"读取"海量文档 |
| Document Loaders | 加载各类文件格式 | PDF、TXT、CSV → 统一文档对象 |
| Text Splitters | 切分长文本 | 按 chunkSize 分块,overlap 保留上下文 |
Agent 正是这些模块的有机组合:Messages 管理对话历史 → Tools 提供外部能力 → PromptTemplate 设定角色人设 → 模型自主规划何时调用什么工具。而我们今天走通的最简链——PromptTemplate → LLM → OutputParser——正是构建这一切的基础框架。
学习回顾
今天按照"概念 → 落地 → 全景"的顺序系统覆盖了:
- Temperature(概率分布缩放)、Top-k(固定名额裁剪)、Top-p(动态阈值裁剪)及三者搭配策略
ChatOpenAI构造函数中temperature/topK的实际配置方法- 为什么需要 LangChain——从手动拼接字符串到模块化工作流的演进
- PromptTemplate 实现"结构"与"数据"的分离
- StringOutputParser 自动提取
.content .pipe()管道串联——自动传递参数,代码即流水线- 同一模板 + 不同温度配置 → 生成不同风格的 AI 输出
- LangChain 全模块:从 Prompts 到 Agent 的完整生态全景
下一步可以沿 Tools → Agent 方向深入探索自主决策型应用,或走 RAG 路线构建私有知识库问答系统。
