同一段 Prompt,在开发环境里回答得不错,到了线上却突然变长、变慢、变贵,甚至换了模型。很多团队第一反应是继续调 temperature

这通常调错了方向。

模型参数真正难的地方,不是背住一长串字段,而是知道每个参数属于哪一层,谁可以修改它,修改后怎样被追踪。没有这层边界,配置会慢慢散落到请求处理、业务函数和环境变量里,最后没有人知道某一次结果为什么不一样。

本文会建立一套参数分层方法,并通过三个小实验理解随机性、输出预算和运行时覆盖。示例中的模型名仅用于说明调用形式,实际运行请替换为自己可访问的服务。

参数不是一堆旋钮,而是三类责任

连接与可靠性

api_key、base_url、timeout、max_retries

生成行为

model、temperature、max_tokens、stop

运行时治理

run_name、tags、metadata、callbacks、max_concurrency

模型实例默认值

单次调用

连接参数决定请求怎样抵达服务端。生成参数决定模型怎样生成。运行时参数则描述本次调用怎样被追踪、限制和归类。

timeout 当成生成参数,或把用户可以控制的模型名直接塞进请求参数,都会带来稳定性和成本问题。

实验一, temperature 改变的是采样,不是事实性保证

低温度适合抽取、分类和固定格式输出。较高温度适合需要多个不同候选的创意任务。

from langchain.chat_models import init_chat_model

extractor = init_chat_model(
    "openai:gpt-5.5",
    temperature=0,
    max_tokens=300,
)

writer = init_chat_model(
    "openai:gpt-5.5",
    temperature=0.9,
    max_tokens=800,
)

print(extractor.invoke("提取这句话中的城市和日期,北京团队将在周五开会。").content)
print(writer.invoke("为一款安静的机械键盘写三个不同风格的短标题。").content)

不要把温度当作「回答质量」按钮。低温度让采样更稳定,不会让错误知识变正确。高温度也不等于更有创意,它只是增加候选变化。

更重要的是,temperature=0 也不承诺绝对一致。模型版本、服务端实现、系统更新和并行请求都可能改变输出。业务如果要求严格一致,应把关键判断交给规则、Schema 校验或数据库约束。

温度

采样随机性

结果变化范围

事实正确性

知识来源、检索、校验

格式正确性

Schema 与程序校验

实验二, max_tokens 是输出预算,不是上下文总长度

模型的上下文窗口要同时容纳系统提示、对话历史、检索内容、用户输入和模型输出。max_tokens 通常约束的是最后一项。

short_answer = init_chat_model(
    "openai:gpt-5.5",
    max_tokens=80,
)

response = short_answer.invoke("解释向量数据库的工作原理,并举一个业务例子。")
print(response.content)

如果输出被截断,不能机械把 max_tokens 调大。需要检查三个问题。

  1. 任务是否可以拆成提纲、分段生成和汇总。
  2. 输入上下文是否塞入了不相关的历史或检索片段。
  3. 业务究竟需要一段长文本,还是几个可验证字段。

上下文窗口

系统提示

消息历史

检索片段

用户输入

预留输出空间

max_tokens

长输入加长输出,往往同时提高延迟和成本。对于报告类任务,先让模型生成结构,再逐段填充,通常比一次生成全部内容更可控。

实验三, 初始化默认值与运行时 config 不能混用

初始化参数表达长期稳定的默认策略。config 表达一轮调用的上下文、追踪信息和经过明确允许的临时变化。

from langchain.chat_models import init_chat_model

model = init_chat_model(
    "openai:gpt-5.5",
    temperature=0.2,
    timeout=30,
    max_retries=3,
    configurable_fields=("model", "temperature", "max_tokens"),
)

result = model.invoke(
    "将下面这段说明压缩为三条要点。",
    config={
        "run_name": "policy_summary",
        "tags": ["summary", "production"],
        "metadata": {"request_id": "req_123"},
        "configurable": {
            "temperature": 0.4,
            "max_tokens": 300,
        },
    },
)

这里有一条重要边界。只有被 configurable_fields 显式允许的字段,才应当由运行时覆盖。否则,一个普通用户请求可能意外切换到高成本模型,或者绕开稳定性设置。

模型初始化默认值

最终生效配置

本次调用 config

字段已被明确允许?

拒绝或忽略覆盖

结构化输出的可靠性,不能只靠低温度

提取姓名、日期、金额、分类标签时,最常见的错误是要求模型「以 JSON 返回」,然后用字符串或正则去解析。

更稳妥的方式是先定义数据契约,再选择模型支持的结构化输出策略。

from pydantic import BaseModel, Field


class Invoice(BaseModel):
    vendor: str
    amount: float = Field(ge=0)
    currency: str


structured_model = model.with_structured_output(Invoice)
invoice = structured_model.invoke("发票来自 Acme,金额 1280.50 美元。")
print(invoice.model_dump())

通过

失败

定义 Schema

模型生成结构化结果

字段和类型校验

进入业务流程

修复、重试或转人工

不同服务商可能使用原生结构化输出或工具调用策略。它们的限制和失败形态不同。上线前要针对真实样本测试缺字段、类型错误、额外字段和模型拒答,而不是只测试一次成功样例。

四个生产参数,不应该留给默认值

参数建议做法原因
timeout显式设置防止慢请求长期占用连接
max_retries设置有限预算网络错误、429、5xx 可恢复,401 不可恢复
max_concurrency与服务商配额一起测试防止批量任务把错误率推高
metadata记录请求和业务场景标识便于追踪成本、延迟和故障

重试也需要克制。401 通常是凭证或权限问题,404 通常是模型名、Endpoint 或路径错误,这两类问题反复重试只会浪费时间。429 和部分 5xx 才适合有限次指数退避。

把调参变成实验,不要靠感觉

为每个关键任务准备一组固定输入,记录模型、参数、输出是否通过、延迟和 token 用量。一次只改一个变量。

任务, 发票信息抽取
成功标准, Schema 校验通过且金额正确
对照项, temperature 0 与 0.5
记录项, 通过率、延迟、输入输出 token、失败类型

这会让参数讨论从「我觉得 0.7 比较好」变成可复查的工程决策。模型可以变,实验和业务标准不应该丢。

还应把实验结果和发布配置分开保存。实验允许快速试不同温度和模型,生产配置则应经过评审,并限制哪些字段允许请求覆盖。否则一次临时调试很容易变成无人知晓的线上默认值。

延伸阅读

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐