用 LangChain 初始化一个聊天模型,看起来只是 new ChatOpenAI({ ... }) 或 initChatModel("deepseek:deepseek-chat", { ... }) 这么简单,但花括号里能填的参数其实相当多。它们大致可以分为五类:连接与身份、生成与采样、输出控制、可观测与工程、运行时高级能力。搞清楚每一类的作用,你就能既不被参数淹没,又能在需要时精准调参。
下面以 OpenAI 兼容的聊天模型(ChatOpenAI、ChatDeepSeek 等)为主来说明,大多数参数在各家模型上都是相通或近似的。
一、连接与身份类
这一类的参数决定“请求发去哪、以谁的身份发”。
| 参数 | 作用 |
|---|---|
model | 使用的模型名,如 deepseek-chat、gpt-4o。是必填的核心参数。 |
apiKey | API 密钥。未显式传入时,OpenAI 系默认读 OPENAI_API_KEY,DeepSeek 读 DEEPSEEK_API_KEY。别名 openAIApiKey。 |
configuration | 底层客户端配置。最常用的是 configuration.baseURL,用来把请求指向不同厂商或自建服务。也可配超时、自定义 header、代理等。 |
timeout | 单次请求的超时时间(毫秒)。网络不稳或调用大模型时建议显式设置。 |
maxRetries | 请求失败时的最大重试次数。适合应对偶发的限流或网络抖动。 |
示例:
const model = new ChatOpenAI({
model: "deepseek-chat",
apiKey: process.env.DEEPSEEK_API_KEY,
timeout: 30_000,
maxRetries: 2,
configuration: { baseURL: "https://api.deepseek.com" },
});
二、生成与采样类
这一类控制“模型怎么生成内容”,是调参最常打交道的部分。
| 参数 | 作用 |
|---|---|
temperature | 采样温度,控制随机性。越低越确定、越保守(适合事实问答),越高越有创造性(适合写作头脑风暴)。通常取值 0~2。 |
topP | 核采样,只从累积概率达到 topP 的候选词中采样。与 temperature 一般二选一调整,不建议同时大改。 |
maxTokens | 生成的最大 token 数。用于限制回复长度、控制成本。推理模型常用别名 maxCompletionTokens。 |
stop | 停止序列,遇到这些字符串就停止生成。别名 stopSequences。 |
frequencyPenalty | 频率惩罚,按词出现频率降低其再次出现的概率,减少重复。 |
presencePenalty | 存在惩罚,只要词出现过就降低其概率,鼓励涉猎新话题。 |
n | 为每个输入生成几个候选回复。多用于对比或投票场景。 |
seed | 随机种子。设置后有助于复现相近的输出(是否完全确定取决于服务端)。 |
调参经验:先用默认值,只有在效果不理想时才动 temperature / topP;需要压缩成本或长度时用 maxTokens;需要稳定复现时试 seed。
三、输出控制类
| 参数 | 作用 |
|---|---|
streaming | 是否以流式方式返回。开启后可以用 stream() 逐块接收,带来更好的交互体验,但会影响一次性获取 token 用量。 |
streamUsage | 流式返回时是否附带 token 用量信息,默认 true。 |
logprobs / topLogprobs | 是否返回 token 的对数概率及前 N 个候选,用于分析模型置信度。 |
modelKwargs | 透传厂商特有、LangChain 未显式暴露的参数。兜底利器。 |
四、可观测与工程类
这一类不改变输出内容,但影响开发、调试、监控和成本。
| 参数 | 作用 |
|---|---|
callbacks | 回调处理器,用于日志、追踪、流式回调等。 |
tags | 给调用打标签,便于在追踪系统里归类筛选。 |
metadata | 附加元数据,随调用一起上报,方便定位问题或做统计。 |
verbose | 是否输出详细日志,调试时开启。 |
cache | 模型结果缓存,相同请求可复用,节省成本、加快速度。 |
五、运行时高级能力
有些能力通常不在构造时确定,而是通过专门的方法或调用参数挂载:
- 工具调用:用
model.bindTools([...])绑定工具,模型即可返回结构化的工具调用请求。 - 结构化输出:用
model.withStructuredOutput(schema)让模型按给定 schema 返回,方便程序解析。 - 运行时覆盖:通过
initChatModel的configurableFields,可以在调用时用configurable覆盖model、temperature等,实现动态切换。
六、参数该放哪里:构造时还是调用时
这是初学时容易混淆的一点。大多数参数既可以在构造模型时统一设置,也可以在某次调用时单独覆盖:
// 构造时设默认值
const model = new ChatOpenAI({
model: "deepseek-chat",
temperature: 0.7,
});
// 调用时临时覆盖
const res = await model.invoke("写一句广告语", {
temperature: 1.2,
maxTokens: 50,
stop: ["\n"],
});
调用时的参数优先级更高,适合“个别请求需要不同行为”的场景;构造时的参数则适合作为全局默认值。
七、注意别名与厂商差异
- 别名:
apiKey≈openAIApiKey;maxTokens≈maxCompletionTokens;stop≈stopSequences。知道别名可以避免“参数明明写了却没生效”的困惑。 - 厂商差异:像 DeepSeek 的
deepseek-reasoner、OpenAI 的推理模型等会有一些专属参数(如推理强度相关设置)。这些参数如果 LangChain 没直接暴露,可以用modelKwargs透传,或使用对应厂商的专属包。 - 不支持的参数:并非所有厂商都支持所有采样参数,传了不支持的参数可能被忽略或报错,接入新服务时最好先看其文档。
八、小结
初始化模型时的参数可以按五类来记:连接与身份(model、apiKey、configuration.baseURL、timeout、maxRetries)、生成与采样(temperature、topP、maxTokens、stop、惩罚项)、输出控制(streaming、logprobs、modelKwargs)、可观测与工程(callbacks、tags、metadata、cache)、以及运行时高级能力(工具、结构化输出、动态覆盖)。
记住两点就够了:一是大多数参数都能在调用时覆盖构造时的默认值;二是优先使用默认值,按需微调。掌握这些参数,你就能在效果、成本、速度之间找到合适的平衡点。