海域重启礼包码汇总 海域重启最新可用兑换码分享
2026-07-21
2026-07-22 0
今天上手跑通了第一个 LangChain 应用——用不同温度参数控制模型风格输出。这篇文章沿着我实际学习的路径,从"大模型为什么能随机说话"一直讲到"LangChain 怎么把 AI 工作流串成一条链"。

先看文件全貌和它们的依赖关系:
复制代码readme0721.md(参数理论:Temperature、Top-k、Top-p 是什么)
↓ 理论落地
main.js(实践代码:双温度模型 + PromptTemplate + pipe 串联)
↓ 框架展开
langchain-explained/readme.md(LangChain 全模块生态概览)
教学逻辑是 概念 → 落地 → 全景:先搞懂三大随机性参数怎么控制输出,再用 LangChain 把它们写进代码,最后俯瞰整个框架的能力边界。
大模型每生成一个词,本质是从一个概率分布里做一次"抽奖"。输入「你好」,模型会说:
复制代码下一个词候选:
「吗」35% 「啊」20% 「世界」15% 「我是AI」10% 「呀」7% 「哈哈」5%
从这个概率分布出发,有三个参数可以玩。
底层公式很简单:
复制代码调整后分数 = logits / Temperature
最终概率 = softmax(调整后分数)
Temperature < 1(低温)——除以一个小数放大差距,强者更强:
复制代码T=0.3: 吗 72% 啊 18% 世界 6% 我是AI 3%
↑ 几乎锁死在「吗」
Temperature > 1(高温)——除以一个大数拉平差距,人人有机会:
复制代码T=2.0: 吗 22% 啊 18% 世界 17% 我是AI 15% 呀 13%
↑ 百花齐放
不是——它只调整概率分布的"陡峭度",最终还是从新分布里随机采样。T=0.3 时「吗」占 72%,但依然有 28% 的概率抽到别的词。
结论:Temperature 是"马太效应调节阀"。写代码/合同设 0.2,搞文艺创作设 0.8。
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 太大 = 候选虽多但全都挤向同一个词,输出保守没有想象力。要根据业务场景调。
直接调 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 是"低温大池"。
复制代码const storyPrompt = PromptTemplate.fromTemplate(
`请写一篇短篇散文,主题:{theme}
风格治愈温柔,篇幅200字左右,不要分段,文字细腻有画面感。`
)
字符串拼接时,prompt 的结构逻辑和业务数据混在一起,换个主题就得改代码。PromptTemplate 把**不变的结构(模板)和可变的数据(变量)**拆开——同一个模板,换不同的 {theme} 就直接复用。Agent 应用里,同一套 AI 逻辑换不同用户身份(诗人 vs 律师),变的只是参数,代码完全不动——这就是模板化的价值。
复制代码const outputParser = new StringOutputParser()
// 内部等价于:result.content ?? result.toString()
单独用确实不值。但当你把它挂在 chain 末尾时,价值就出来了——链条外面拿到手直接就是干净的字符串,不用再 .content。管道里的最后一道工序。
复制代码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。
走完最简工作流,整个框架的全景也就清晰了:
| 模块 | 职责 | 一句话 |
|---|---|---|
| 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——正是这一切的基础。
今天按"概念 → 落地 → 全景"的顺序覆盖了:
ChatOpenAI 构造函数里 temperature / topK 的实际配置.content.pipe() 管道串联——自动传递,代码即流水线下一步可以沿 Tools → Agent 方向深入自主决策型应用,或走 RAG 路线做私有知识库问答。
#LLM #LangChain #Temperature #Node.js #学习笔记