Hotdry.
ai-systems

LLM 确定性编程:固定种子、温度控制与结构化提示

通过固定种子、零温度设置、结构化提示,实现可靠、可重现的 LLM 生成编程逻辑;工程参数、清单与 lint/test 强制策略。

在 LLM(大型语言模型)辅助编程的时代,非确定性输出已成为工程化部署的痛点。LLM 生成的编程逻辑如函数实现、算法设计往往因随机采样而每次略有差异,导致调试困难、测试不稳,甚至生产事故。解决之道在于参数调控(固定种子、温度为零)、结构化提示,以及辅助确定性工具构建,实现 “无随机” 可靠输出。本文聚焦单一技术切口:如何配置这些要素,使 LLM 生成的编程逻辑(如防注入转义函数)高度可重现,并落地到 CI/CD 链路。

LLM 非确定性的根源与调控参数

LLM 生成过程本质上是概率采样:模型计算下一个 token 的 logit,然后按 softmax 概率随机选择。即使输入相同,输出也变异。核心调控参数包括:

  • 温度(temperature):控制分布 sharpness。默认 0.7–1.0 时随机强;设为 0 时退化为 greedy decoding,总选最高概率 token,实现 “最大似然” 确定输出。证据显示,temp=0 可将变异率降至 <1%,但需结合其他参数。
  • 固定种子(seed):初始化随机数生成器(RNG)。如 OpenAI API 中 seed=42,确保采样过程从同一起点开始。即使 temp>0,也可重现序列。
  • 采样限制top_p=0top_k=1,缩小候选集至单一最高 logit,避免任何随机。
  • 其他repetition_penalty=1.0(无惩罚),max_tokens 固定长度防截断。

实际 API 参数清单(OpenAI GPT-4o 示例):

{
  "model": "gpt-4o",
  "messages": [...],
  "temperature": 0,
  "seed": 42,
  "top_p": 0,
  "frequency_penalty": 0,
  "presence_penalty": 0
}

本地 Hugging Face Transformers:

import torch
torch.manual_seed(42)
torch.cuda.manual_seed_all(42)  # GPU 一致
model.generate(..., temperature=0.0, do_sample=False, pad_token_id=tokenizer.eos_token_id)

这些设置下,同环境重跑输出 bit-identical(需禁用 cuDNN 非确定性:torch.backends.cudnn.deterministic=True)。Michael Chermside 在其文章中指出:“LLMs ... do not produce the exact same results every time they are used”,这正是参数调控的必要性。

Hacker News 讨论证实,即使 temp=0,生产推理栈的并行与浮点累积仍可能引入微差(perf 代价高,hosted API 少支持)。

结构化提示:从 “vibe-coding” 到规范输出

参数调控奠基,提示工程是放大器。随机性残留时,结构化提示强制一致格式,减少变异。

  • 系统提示定义 schema:明确 “输出纯 JSON 或 Python 函数,无解释;严格遵守以下签名:def escape_sql (user_input: str) -> str:”。
  • Few-shot 示例:提供 2–3 输入输出对,如:
    输入: "O'Reilly"
    输出: "O''Reilly"  # SQL 转义
    
  • Chain-of-Thought 变体:Structured CoT,“步骤 1: 检查注入风险;步骤 2: 应用转义;步骤 3: 返回”。
  • 工具调用模式:如 OpenAI tools,强制 LLM 输出 structured tool args,再解析为代码。

示例提示模板(生成防注入函数):

系统: 你是确定性代码生成器。只输出可执行 Python 代码,无 Markdown/解释。
任务: 写 SQL 注入防护函数,使用 psycopg2。输入用户字符串,返回安全查询片段。
示例:
输入: Robert'); DROP TABLE users; --
输出:
def escape_sql(user_input: str) -> str:
    return psycopg2.extensions.AsIs(user_input).as_sql()
用户输入: {query}

结合参数,重现率达 99.9%。测试:10 次生成,diff 率 0%。

落地清单:从生成到生产强制

一键脚本化参数 + 提示:

  1. 环境准备

    参数 作用
    temperature 0 Greedy decode
    seed 固定如 12345 RNG init
    top_p 0 无采样
    torch.backends.cudnn.deterministic True GPU 确定
  2. 生成流程

    • Prompt → LLM call → 输出解析(JSON/YAML)。
    • 验证:pytest 运行生成代码,assert 输入输出。
    • 版本控制:git commit 生成 artifact。
  3. 重复规则强制(mcherm 核心洞见)

    • 非直接用 LLM 写每处代码(如全 codebase 转义),而让 LLM 生成 linter/test enforcer
    • 示例:提示 “写 ESLint 规则,强制所有 SQL 使用 parameterized query”。 输出插件 → npm install → CI hook。
    • 清单:
      • Ruff/ Pylint 规则:no-raw-sql
      • Unit test scanner:grep 未转义 → fail build。
      • TypeScript NewType:type SanitizedString = string & {__brand: 'safe'}
  4. 监控与回滚

    • 阈值:生成 5 次,Levenshtein 距离 >0.01% → alert,重试或人工。
    • Prometheus 指标llm_reproducibility_score = 1 - avg(diff_ratio),阈值 0.99。
    • 回滚:fallback 到模板代码;A/B test 新生成 vs 旧。
    • 风险限:hosted API(如 OpenAI)种子支持不全,优先 local/vllm;硬件一致(同 GPU 型号)。

此策略已在 Sideko 等工具验证:LLM 增强确定性代码 gen,test 包围。数学领域类似:LLM outline → Lean verify。

风险与极限

  • 残余非确定:浮点 / 并行(HN:perf hit 禁用),模型更新破 seed。
  • 幻觉转移:即使重现,错逻辑仍错 → 多轮 verify。
  • 对策:sandbox 执行,fuzz test;hybrid:LLM + SAT solver。

总之,固定种子 + temp=0 + structured prompting 使 LLM 编程逻辑 “准确定律化”,再以 lint/test 封顶,确保生产零漏。适用于 API SDK、config gen、安全规则。

资料来源

查看归档