SemIf 跑语义决策时输出不一致,先固定输入和环境再对比记录

文章导读
同一份输入跑 SemIf 得到不同的语义决策结果时,先不要改 prompt 或换模型。两次运行之间只要有一处输入、配置或调用顺序变了,输出就可能不一样。可行的顺序是:先把输入和环境钉死,再用同一份输入重复跑并逐轮记录,最后用对照表判断差异到底出在哪一层。
📋 目录
  1. 一 在运行记录里标出同输入不同输出的位置
  2. 二 对照 SemIf 实际暴露的配置项固定随机性
  3. 三 用最小输入重复运行并保存原始输出
  4. 四 把输入快照、配置快照、输出快照落成对照表
  5. 五 根据差异判断是输入、环境还是调用顺序变化
A A

同一份输入跑 SemIf 得到不同的语义决策结果时,先不要改 prompt 或换模型。两次运行之间只要有一处输入、配置或调用顺序变了,输出就可能不一样。可行的顺序是:先把输入和环境钉死,再用同一份输入重复跑并逐轮记录,最后用对照表判断差异到底出在哪一层。

判断差异是否真实存在是第一步:把输入原文、运行时间、输出摘要、调用方标识记下来,先排除把两次不同输入当成同一次的情况。确认同输入后,固定随机种子、采样开关、并行度和模型与模板版本,用最小输入重复运行并保存原始输出。若这些全部固定后仍不稳定,才考虑模型或服务侧的非确定性,此时应保留日志向提供方确认,而不是继续调 prompt。

在运行记录里标出同输入不同输出的位置

跑两次结果不一样,先别接受“同输入”这个前提。常见的误判来自输入里字段顺序变化、上游拼接时多了一个时间戳、会话 ID 或历史轮次不同、文本被截断、空白与换行差异。这些在日志里看起来很像同一段输入,实际不是。

建议每次调用至少落下面这些字段,存成结构化记录或一行 JSON:

trace_id:
input_raw:            # 完整输入原文,不要只留摘要
input_hash:           # 按固定归一化规则计算后的哈希
run_at:               # 含时区的运行时间
caller:               # 调用方标识:服务名 / 用户 / 任务 ID
config_version:       # 本次实际生效的配置或快照文件名
output_summary:       # 决策结果摘要,如标签加分数
output_hash:

input_hash 之前要先写清归一化规则,例如是否排序键、是否去首尾空白、是否保留大小写。规则不写进记录,哈希本身也会变成新的误判来源。

对照 SemIf 实际暴露的配置项固定随机性

把下面这些候选配置逐项确认。名称按你本地的配置页或启动参数实际叫法替换,不要假设框架的默认值等于固定值:

SemIf 跑语义决策时输出不一致,先固定输入和环境再对比记录
  • 随机种子:seed / random_seed / SEMIF_SEED
  • 采样开关:sample / do_sample / sampling_enabled
  • 采样参数:temperature / top_p / top_k
  • 并行度与批大小:max_workers / concurrency / batch_size
  • 超时与重试:timeout / max_retries,重试会改变实际调用顺序
  • 模型与模板版本:model_version / prompt_template_version / config_version
  • 会话与缓存:session_id、cache_enabled、cache_ttl

确认方式有三条:先从配置页导出一次完整配置快照;再在启动命令里显式传参,而不是依赖默认值;最后检查环境变量是否覆盖了配置,例如用 env | grep -i semif 看一遍。部分框架的优先级是环境变量高于启动参数、高于配置文件,具体顺序需要结合本地环境确认。

用最小输入重复运行并保存原始输出

挑一条最短、字段最少的输入,去掉业务上下文和长历史,再重复跑若干轮。目的是看差异在干净输入下是否仍然稳定出现。下面的骨架可按本地命令替换:

mkdir -p runs snapshots
./semif config dump > snapshots/config_before.yaml

for i in 1 2 3 4 5; do
  ./semif decide \
    `--input` cases/min_case.json \
    `--config` snapshots/config_before.yaml \
    `--seed` 42 \
    `--no-sample` \
    `--concurrency` 1 \
    > runs/run_${i}.out 2> runs/run_${i}.err
  sha256sum runs/run_${i}.out >> runs/hashes.txt
done

需要替换的是命令名、子命令和参数名。关键点是每轮除轮次编号外参数完全一致,并且保存原始输出,不要只保存格式化或截断后的展示结果,否则后面的比对会丢字段。

SemIf 跑语义决策时输出不一致,先固定输入和环境再对比记录

把输入快照、配置快照、输出快照落成对照表

每跑一轮就往表里加一行,历史行不修改。列名可以这样定:

轮次输入快照文件输入哈希种子采样开关并行度模型与模板版本输出快照文件输出摘要输出哈希是否与上一轮一致

填写方式:一行对应一次运行,输入快照和输出快照都存成独立文件并记下文件名,哈希从文件内容算出。当输入哈希相同而输出哈希不同,这才是要继续查的差异;如果输出哈希相同但摘要看着不同,通常是比较了不同层级的展示结果,需要回到原始输出重新核对。

根据差异判断是输入、环境还是调用顺序变化

把结论收敛到单一原因,可用下面三类判定条件:

  1. 输入变化:输入哈希不同,或原文里存在字段顺序、空白、截断、时间戳、会话历史差异。下一步动作是按归一化规则重排、裁剪后重跑,确认输出是否回到一致。
  2. 环境变化:输入哈希一致,但配置快照里的种子、采样开关、版本、并行度或缓存状态有差异。下一步动作是把两轮都指向同一份配置快照重跑。
  3. 调用顺序变化:输入与配置都一致,差异只在并发或批处理、多轮会话、缓存命中情况不同的场景出现。下一步动作是改成并发 1、单条调用,清空会话与缓存后再跑。

如果这三类都固定后,同一输入仍然给出不同输出,那属于模型或服务侧的非确定性。此时应保留 trace_id、原始输入输出和时间戳,带上对照表去跟提供方确认,而不是继续用调 prompt 的方式掩盖问题。