上一章 洞察型评分与 LLM-as-Judge "洞察好不好"也能评吗?能,但要先把维度拆开:方向相关性、证据充分性、可操作性、表达清晰度。以及一个必须警惕的东西——机器打分的四类偏差。 III · 评测工程 · 第 04 章 · 深入 · 约 34 分钟
Agent 工程学习站 做棵大树 出品 主站 beatree.cn 免费 · 无需登录 · 进度存本机
III 版 · 评测工程 ◆ 第 05 章 ◆ Closing the Loop
III · 评测工程 05 / 22 进阶

Trace、Replay 与线上闭环

Closing the Loop
预计阅读 28 分钟
难度 进阶
关键词 Trace · Replay
本机状态 未读

出了问题查不到原因,是因为没有 trace;改了一版不敢上线,是因为没有 replay。这一章把「线上 badcase → 评测集 → 回归门禁 → 灰度发布」这条闭环接起来。接上之后,评测才从一份报告变成一套能挡住问题的机制。

编辑部注 · 本章是全站最有「系统感」的一章。面试里讲清这条闭环,等于证明你做过完整的质量工程,而不只是写过评测脚本。

前面四章分别解决了「评什么维度」「用哪些样本」「指标怎么算」「机器打分怎么可信」。但还有一个更根本的问题:这套东西怎么才能真的挡住问题,而不是变成每季度产出一份没人看的报告。

一、闭环的五个环节

质量闭环:五个环节,一个都不能断 ① Trace 全链路记录 每次请求记录: · 完整上下文(脱敏后) · 每次工具调用的参数与返回 · token 数、延迟、重试次数 要求:能完整重放(replay) ② 归因 定位到具体环节 按环节切分失败原因: · 理解错(意图识别) · 选错工具 / 填错参数 · 工具本身故障 / 数据问题 产出:归因分布,而非「失败率」 ③ 入集 沉淀为回归样本 只纳入「工程问题」类: · 标注期望行为 · 写明加入原因与来源 · 研究类问题单独归档 否则回归集永远修不完 ④ 门禁 把评测接进 CI 提交前(每次 PR,2 分钟内必须跑完): · 冒烟集 100% 通过(硬性) · 关键单测(解析器、错误分类) 发版前: · 回归集不得低于基线;保留池结果作为决策依据 ⑤ 灰度 用小流量验证真实分布 1% → 5% → 20% → 全量,每个档位观察: · 任务完成率、平均轮数、成本 / 次 · 用户主动重试率、中断率(最有价值的负向信号) 回滚条件要事先写死,不能临时决定 · 例:完成率跌幅 > 3pct 或成本涨幅 > 20% → 立即回滚 灰度中发现的新 badcase 回到 ① Trace —— 闭环成立 闭环断在哪,问题就出在哪 断在 ① → 出了问题只能靠猜(最常见,也最致命) 断在 ② → 知道有多少失败,但不知道该改哪一层,改进靠碰运气 断在 ③ → 修过的问题反复出现(回归集没长起来) 断在 ④ → 评测只是一份报告,不构成约束力
图 1 评测闭环的五个环节。最容易断的是 ① 和 ④:没有可重放的 trace,一切归因都是猜;评测没接进 CI,它就没有约束力,改动照样能合进去。

这五个环节各自解决一个具体问题:全链路 Trace 让失败可复现,归因(Attribution) 把失败落到具体环节,入集把一次性问题变成永久约束,回归门禁(Regression Gate) 让评测拥有否决权,灰度发布(Canary Release) 用小流量在真实分布上做最后一次验证。断掉任何一个,后面的环节都会退化——这正是「明明做了评测,线上却还在出同样的问题」的最常见原因。

二、Trace 的设计:为「重放」而记录

Trace 的价值不是「记录发生了什么」,而是「能在本地重放(Replay)当时发生了什么」。这个区别决定了你要记录什么。

Trace 必须记录的七类字段(按重要性排序)
#字段为什么必须
1完整的请求体(脱敏后)没有它就无法重放。这是 trace 的核心,其余都是辅助
2模型与版本标识换模型/换版本后的行为差异只有对比才能发现
3每次工具调用的名称、参数、返回、耗时归因的最主要依据——多数失败发生在工具环节
4上下文各部分的大小(指令/知识/状态各占多少)定位「上下文膨胀」类问题的唯一手段
5重试与失败的完整序列(含错误分类)区分「一次就对」与「重试三次才对」——后者是隐患
6关键时间戳(TTFB、每次 chunk、总时长)定位卡死与性能问题的唯一依据
7用户后续行为(是否重试、是否中断、是否手动修正)这是最强的质量信号——用户用脚投票比任何评分都真实
第 7 项被严重低估

「用户重试率」和「用户中断率」是最接近真相的质量指标。原因很简单:模型评分再准也只是代理指标,用户行为是真实结果。一个完成率 90% 但用户重试率 30% 的系统,实际体验远差于完成率 85%、重试率 8% 的系统。

建议把这两个信号当作一等指标,与完成率并列观察。它们还能自动帮你挖掘 badcase——所有重试请求的原始 trace,就是一份高质量的问题样本来源。

这两个信号值得单独说清楚。用户重试率(User Retry Rate) 是「同一件事被问第二次」的比例,用户中断率(Abort Rate) 是中途放弃的比例;它们比任何离线评分都更接近真相,而且天然自带 badcase 挖掘功能——每一次重试都意味着上一次输出没被接受。

三、动手:Trace 与重放

trace_replay.pypython
import json, time, hashlib
from dataclasses import dataclass, field, asdict
@dataclass
class ToolCall:
    turn: int
    name: str
    args: dict
    status: str                     # ok | empty | bad_args | timeout | ...
    duration_ms: int
    result_digest: str              # 结果指纹,而不是全文(全文另存)
@dataclass
class Trace:
    trace_id: str
    started_at: float
    model: str
    request_body: dict              # 脱敏后的完整请求体 —— 重放的依据
    tool_calls: list[ToolCall] = field(default_factory=list)
    context_sizes: dict = field(default_factory=dict)   # {"instructions":1200,...}
    ttfb_ms: int | None = None
    total_ms: int = 0
    retries: list[dict] = field(default_factory=list)
    outcome: str = "unknown"        # done | budget_exhausted | failed | need_human
    user_signal: str = "none"       # none | retried | aborted | corrected
    def to_json(self) -> str:
        return json.dumps(asdict(self), ensure_ascii=False)
def trace_id_for(request_body: dict, model: str) -> str:
    """
    trace id 用「请求内容 + 模型」派生。
    好处:同一个输入重复出现时能自动聚类,便于统计高频问题。
    """
    key = json.dumps(request_body, sort_keys=True, ensure_ascii=False) + model
    return hashlib.sha256(key.encode()).hexdigest()[:16]
def replay(trace: Trace, run_once) -> dict:
    """
    重放:用当时的请求体重新跑一遍,对比结果差异。
    这是「改了代码到底有没有改善」的最直接验证方式。
    """
    result = run_once(trace.request_body)          # 用同一份请求体
    diffs = {
        "outcome_changed": result.get("outcome") != trace.outcome,
        "tool_call_count": (len(result.get("tool_calls", [])), len(trace.tool_calls)),
        "retry_count": (len(result.get("retries", [])), len(trace.retries)),
        "latency_ms": (result.get("total_ms"), trace.total_ms),
    }
    return {"trace_id": trace.trace_id, "improved": not diffs["outcome_changed"]
            or result.get("outcome") == "done", "diffs": diffs}
def classify_failure(trace: Trace) -> str:
    """
    归因:把一次失败定位到具体环节。
    这一段逻辑是「评测报告」与「评测工具」的分界线 ——
    有归因,报告才能直接变成改动清单。
    """
    if trace.outcome == "budget_exhausted":
        if trace.context_sizes.get("state", 0) > 0.6 * sum(trace.context_sizes.values()):
            return "上下文膨胀:状态占比过高,需要加强压缩或状态外置"
        return "轮数/预算上限不足,或陷入无进展循环(检查调用签名重复度)"
    bad = [c for c in trace.tool_calls if c.status == "bad_args"]
    if bad:
        return f"参数错误({len(bad)} 次):检查工具描述与参数约束"
    to = [c for c in trace.tool_calls if c.status == "timeout"]
    if to:
        return f"工具超时({len(to)} 次):检查超时设置与退避策略"
    if trace.retries:
        return f"重试 {len(trace.retries)} 次后成功:属隐患,应查清根因"
    if trace.ttfb_ms and trace.ttfb_ms > 15000:
        return "首字节延迟过高:可能需要换 provider 或降级流式"
    return "未归因:需要人工查看 trace"
def attribution_report(traces: list[Trace]) -> dict:
    """归因分布:这份报告比「失败率 12%」有用得多"""
    from collections import Counter
    failed = [t for t in traces if t.outcome != "done"]
    reasons = Counter(classify_failure(t) for t in failed)
    return {
        "total": len(traces),
        "failed": len(failed),
        "failure_rate": len(failed) / len(traces) if traces else 0,
        "by_reason": reasons.most_common(),
        "user_retry_rate": sum(1 for t in traces if t.user_signal == "retried") / len(traces)
                           if traces else 0,
    }

重放的产出不是「这次跑通了」,而是一份按环节切分的 归因分布(Attribution Report)——参数错占几成、工具超时占几成、上下文膨胀占几成。这份分布才是后续改动的优先级清单:它把「失败率 12%」这个没有信息量的数字,换成了「本周该先修哪一层」。

四、回归门禁:让评测有约束力

这是闭环里最容易被省略、也最关键的一环。没有门禁的评测只是报告。

阶段跑什么耗时预算不通过的后果
本地提交前解析器与错误分类的单元测试< 10 秒开发者自己发现问题,不浪费 CI 资源
PR 创建后冒烟集(10-20 条)+ 静态检查< 2 分钟阻塞合并——没有例外
合并到主分支后回归集 + 边界集< 15 分钟产生告警,并自动创建 issue
发版候选回归 + 边界 + 对抗 + 保留池可到 1 小时阻塞发布;主指标回归必须人工确认才能放行
上线后线上指标监控(完成率、重试率、成本)持续触发回滚条件则自动回滚
门禁分层:越频繁跑的层越轻 从下往上看——跑的频率越来越低,门槛越来越严,代价只花在少数几次上 ④ 发版候选 覆盖:回归 + 边界 + 对抗 + 保留池 ≤ 1 小时 不通过则阻塞发布(主指标回归须人工确认) ③ 合并到主分支后 覆盖:回归集 + 边界集 ≤ 15 分钟 产生告警并自动创建 issue,不阻塞合并 ② PR 创建后 覆盖:冒烟集 10-20 条 + 静态检查 ≤ 2 分钟 不通过则阻塞合并,没有例外 ① 本地提交前 覆盖:解析器与错误分类的单元测试 ≤ 10 秒 开发者自己发现问题,不占用 CI 资源 门槛的高度,决定它是被遵守还是被绕过 任何一层只要耗时超过开发者能忍受的阈值,团队就会加 skip-eval 标签绕过它——门禁一旦可以被绕过,等于没有。 所以严格性必须与频率成反比:越频繁跑的层越轻(秒级),越接近发版的层越重(小时级)。 不允许下降的分层指标(尤其是对抗集)要写进配置,而不是靠人记得。
图 2 门禁的四层结构:越靠下越频繁、越轻;越靠上越严格、越贵。判据是「这一层跑一次要多久,会不会让人想绕开」——把全量评测压在 PR 阶段,换来的一定是 skip-eval 标签,而不是更好的质量。
门禁设计的两个坑

坑一:把门槛设得太高,导致人人都想办法绕过它。如果 PR 阶段要跑 40 分钟,团队很快就会加 skip-eval 标签。正确做法是分层:PR 只跑最关键的冒烟集(2 分钟内),重的评测放到合并后与发版前。

坑二:只卡「总体指标」。这样很容易被「总体提升、局部退化」的改动骗过去(见第 2 章)。正确做法是把哪些分层指标不允许下降写进配置——尤其是对抗集,安全类的退步不能因为总体分数上升而被容忍。

门禁的另一半在线上:回滚条件(Rollback Condition) 必须在发版前写死,而不是出事时临时决定。常用的三条是完成率跌幅超过 3 个百分点、单次成本涨幅超过 20%、用户重试率翻倍——命中任意一条即自动回滚,不等人开会。写出可自动判定的数值条件,才算写完了发版流程;需要人来解释才知道该不该触发的条件,等于没有。

灰度爬坡:每一档都要有回滚条件 流量按 1% → 5% → 20% → 全量推进,每档留出观察窗口再放量 流量占比 ↑ 1% 5% 20% 全量 阶段一 · 观察 2 小时 阶段二 · 观察 1 天 阶段三 · 观察 3 天 全量 · 持续监控 回滚条件必须在发版前写死 完成率跌幅 > 3 个百分点,或单次成本涨幅 > 20%,或用户重试率翻倍——命中任意一条即自动回滚。 小流量意味着信号弱:档位越小越安全,也越难看出问题,所以每一档都要留出观察窗口再放量。
图 3 灰度不是「先放 1% 试试」,而是一条带观察窗口的爬坡路径。真正起作用的不是档位本身,而是事先写死的回滚条件——没有它,灰度只是把全量故障推迟了几天发生。

五、常见误区与追问

5.1 误区:Trace 记录得越全越好(其实标准是「能不能重放」)

错在哪:把「留痕」当成目标,结果日志里堆满了好看但用不上的字段。为什么自然:出问题时第一反应总是「当时记的东西不够」,于是下一次什么都记。正确做法:判据只有一个——把这条 trace 拿回来,能不能不改一行代码就在本地跑出同样的失败?不能,说明字段缺了;能,但你还想加字段,那属于过度记录。做法:优先保证完整请求体、工具调用参数与返回、上下文各部分大小这三项,其余字段按「它能让哪一类问题可归因」来决定去留。

5.2 误区:门禁越严格越好(其实门槛过高会诱导团队绕过它)

错在哪:把门禁的严格程度当成质量的唯一变量。为什么自然:「宁可多拦一点」听起来永远政治正确。正确做法:门禁的可用性和严格性必须一起设计。数字:PR 阶段如果要求跑 40 分钟全量评测,团队很快会加 skip-eval 标签;一旦出现第一个例外,门禁的约束力就开始归零。做法:让耗时与频率成反比——每次提交跑的层控制在 2 分钟内,重的评测放到合并后与发版前。

5.3 误区:灰度就是「小流量上线」,回滚条件到时候再定

错在哪:把回滚当成应急响应,而不是发布流程的一部分。为什么自然:谁都不想在发版前花时间写一份「可能用不上」的条款。正确做法:回滚条件必须在发版前写死,并且是可自动判定的数值条件。数字:完成率跌幅超过 3 个百分点、单次成本涨幅超过 20%、用户重试率翻倍——命中任意一条即自动回滚,不等人开会。判据:如果一条条件需要人来解释才知道该不该触发,那它写得还太模糊,等于没有。

5.4 误区:归因到「失败率 12%」就算做完归因了

错在哪:把总量指标当成归因结论。为什么自然:失败率是最容易算、也最容易向上汇报的数字。正确做法:失败率只回答「有多少」,不回答「为什么」;归因分布才回答「该改哪一层」。判据:如果一份失败报告读完,你说不出「这周该优先修哪一个环节」,那它就是一份没做完的归因。数字:把失败按参数错、工具超时、上下文膨胀、无进展循环四类切开,通常会看到某一类占到一半以上——那一类就是本周的改动清单。

5.5 误区:用户重试率是体验问题,不该混进质量指标

错在哪:把用户行为信号归到「产品侧」,让它和数据指标分家。为什么自然:质量指标通常由工程团队定义,用户行为由产品团队看,两者天然被切在不同的报表里。正确做法:用户重试率与中断率是最接近真相的质量指标,因为模型评分只是代理指标,用户行为才是真实结果。数字:完成率 90%、重试率 30% 的系统,实际体验远差于完成率 85%、重试率 8% 的系统。判据:把它和完成率并列观察;只提升完成率而重试率上升的改动,应当视为失败。

5.6 误区:所有 badcase 都该进回归门禁

错在哪:把「收藏问题」和「设成门槛」当成同一件事。为什么自然:每一条 badcase 看起来都值得防住。正确做法:只有能通过 Harness 改动解决的工程问题才进回归集;需要模型侧改进的研究问题单独归档,作为改进输入而不是门槛。判据:如果一条样本注定长期失败,团队就会为它开白名单、加例外;而一旦开始加例外,门禁就废了。

六、自测

本章自测第 2 题为高区分度题
Q1为什么「用户重试率」和「中断率」是很有价值的质量信号?
B。一个完成率 90% 但重试率 30% 的系统,体验远差于完成率 85%、重试率 8% 的系统——这个例子能很好说明代理指标与真实结果的差距。而且这两个信号自带 badcase 挖掘功能:所有重试请求都值得看一眼。
Q2PR 阶段的门禁应该跑多少评测?
D。这是很实用的工程经验:门禁的可用性和严格性需要平衡。让开发者每次提交等 40 分钟,结果一定不是「质量更好」,而是「大家想办法跳过」。分层设计让每一层的耗时与其约束力匹配,门禁才能长期存活。
Q3为什么要把 badcase 分成「工程问题」与「研究问题」分别处理?
C。关键在「门禁的可维护性」:如果回归集里混着一批「模型能力不足导致」的样本,这些样本会长期失败,团队就不得不为它们开白名单、加例外——一旦开始加例外,门禁就废了。研究类问题应该单独归档,作为模型侧改进的输入,而不是回归门槛。

七、小结

环节关键要求
Trace为「可重放」而记录:完整请求体、工具调用、上下文大小、重试、时间戳、用户行为
归因定位到具体环节(参数错 / 超时 / 上下文膨胀 / 无进展),产出归因分布而非单一失败率
入集只纳入工程问题;标注期望行为;写清来源与原因
门禁分层设计,PR 只跑冒烟(2 分钟内),发版前跑全量;不允许下降的分层指标要写进配置
灰度回滚条件事先写死;关注完成率、重试率、成本三项
最强信号用户重试率 / 中断率——真实结果,且自带 badcase 挖掘

评测没有接进 CI,就只是文档。文档不会挡住任何一个坏改动。本刊编辑部

评测工程部分结束。最后一部分回到「回答必须有据可查」这个问题:知识怎么建模、怎么检索、怎么让人信。

八、参考与延伸

闭环这件事没有单一权威文档,下面几份材料各自补一块:规范、基准、编排原则,以及线上监控的实践。

先看图(建立直觉)

  • Anthropic · Building effective agents —— 讲 Agent 循环该在什么地方停下来交给人,对应本章「归因之后该改哪一层」的判断。如果团队正在争「这个失败该改提示词还是改流程」,先读它关于工作流与 Agent 分界的部分。

再看代码(动手实现)

  • tau-bench —— 多轮 Agent 基准,把用户建模成模拟器、把工具建模成真实接口,它的评测协议本身就是一套 replay。想理解「重放为什么必须固定外部依赖」,看它怎么把用户与工具都做成可复现的受控对象。

最后读论文(对齐一手定义)

  • OpenTelemetry · Generative AI semantic conventions —— 目前唯一在推进「LLM 与 Agent 调用该记哪些字段」标准化的官方规范。本章第二节那张 trace 字段表,可以直接拿去和它的字段命名对照,省掉自己造一套私有 schema。
  • SWE-bench —— 用「真实仓库的测试能不能跑通」当门禁的极端形态。想知道把门禁彻底程序化会变成什么样,看它的任务构造与判定方式。

延伸阅读

  • Hamel Husain 的博客 —— 线上监控与离线评测怎么接成闭环,以及「评测不接进流程就等于没做」的多次讨论。本章的门禁分层与告警阈值,可以拿他的实践清单逐条核对。

◇ 面试官会怎么问

共 6 条 · 其中 2 条高频 · 先自己答一遍,再展开对照

Trace 你会记录哪些字段? 高频
目标是让任何一次失败都能被完整复现,所以按"能 replay"的标准来设计:
任务级——任务 ID、用户、入口、目标与约束、开始/结束时间、最终状态、总 token 与成本。
轮次级——轮次编号、模型与参数、完整的 prompt 组成(含系统提示版本号、注入的上下文片段及其来源、裁剪了什么)、模型原始输出、解析后的工具调用、耗时、输入/输出 token、缓存命中情况。
工具级——工具名与版本、参数、执行耗时、返回结果摘要与原始结果指针、错误分类、是否重试。
变更级——本次运行使用的 prompt / 工具 / 模型配置版本号。
两个容易被漏掉但很关键的字段:prompt 的各段来源与版本(否则改了提示词就再也复现不了旧结果)、以及裁剪/压缩的日志(否则你不知道模型当时"没看到"什么)。

追问链

  1. 存原始 prompt 全文会不会太大?
  2. 怎么按任务链路把多 Agent 的 trace 串起来?
Replay 有什么用?
Replay 是"把一次线上运行在本地原样重放"的能力,它解决三个具体问题:
① 复现——线上失败很难在开发环境重现(输入随机、上下文巨大、依赖外部状态),replay 让你用当时的完整输入重跑,把不可复现变成可调试。
② 对比——在同一个测试用例上跑旧版本与新版本(A/B replay),直接看出行为差异,这是判断改动是否有效的核心手段。
③ 回归——把有代表性的 trace 固化成回归用例,每次改动自动重放这批用例,形成门禁。
实现要点是把"可重放"作为架构约束而不是事后补的功能:所有外部依赖(模型、工具、检索)都要能在 replay 模式下用录制结果替换(mock/replay 层),否则外部状态一变,重放就不成立。
加分点:"把可重放做成架构约束而非事后补功能",是有系统设计经验的人才会说的。
从线上 badcase 到回归门禁,完整闭环怎么建?
六步闭环:
① 发现——通过用户反馈信号(重试、纠错、放弃、点踩)与系统指标异常(成功率下降、超时率上升)自动捞取候选 badcase。
② 归因——按失败原因打标分类(意图理解 / 参数生成 / 工具选择 / 上下文缺失 / 表达 / 系统故障),并区分"模型问题"与"系统问题"。
③ 固化——把可复现的案例整理成评测用例入库,保留原始 trace。
④ 修复——针对原因改对应的层(提示 / 工具描述 / 上下文策略 / 代码逻辑),而不是一律改提示词。
⑤ 回归——在固定评测集上跑,既有全量指标也要看新用例;不能有回归才允许进入下一步。
⑥ 灰度与回滚——按用户或租户灰度,监控线上指标与失败率,劣化自动回滚,正常后放量。
这个闭环能持续运转的前提是第 ③ 步要自动化一部分,否则人工整理会成为瓶颈,闭环很快就断了。
加分点:指出"闭环的瓶颈通常在人工整理用例这一步,所以必须部分自动化",非常贴近真实工程。
PR 阶段的门禁要求跑 40 分钟全量评测,团队开始加 skip-eval 标签。你怎么改? 高频
把单层门禁改成分层门禁,让耗时与频率成反比。
① 本地提交前:只跑解析器与错误分类的单元测试,10 秒级;② PR 创建后:只跑冒烟集(10 到 20 条)加静态检查,控制在 2 分钟内,不通过就阻塞合并;③ 合并到主分支后:跑回归集与边界集,15 分钟级,失败产生告警并自动建 issue;④ 发版候选:跑全量(回归、边界、对抗、保留池),可以到 1 小时,不通过阻塞发布。
关键判断是:门禁的价值不是「跑得多」,而是「跑得久」——一个总被绕过的门禁,价值等于零。宁可让 PR 阶段只拦最粗的低级错误,也不要让它变成必须跳过的流程。

追问链

  1. 冒烟集只跑 10 到 20 条,会不会漏掉真正的回归?
  2. skip-eval 标签要不要允许存在?如果允许,怎么加约束?
加分点:加分点:主动说出「门禁一旦被绕过就等于没有」,这是被真实流程教育过的人才会讲的。
系统 A:完成率 90%、用户重试率 30%;系统 B:完成率 85%、重试率 8%。你选哪个上线?
选 B。
完成率是代理指标,重试率是真实结果。用户重试一次,等于对上一次输出投了一张反对票;30% 的重试率意味着三成请求没有被一次接受——这通常就是「答得像但不对」的那类失败,而它恰好是完成率最难捕捉的:系统给出一个看似合理的答案,评测算通过,用户不满意。
把两个数一起读:A 的「一次就满意」大约是 63%(90% 乘 70%),B 大约是 78%(85% 乘 92%),B 明显更好。
还有一个附带收益:所有重试请求的原始 trace 天然就是一批高质量 badcase,B 的改进闭环会转得更快。如果必须在两者间取舍,我会把重试率写进发版门禁,而不是只盯完成率。

追问链

  1. 完成率用的是哪个口径,会影响你的判断吗?
  2. 如果 A 的重试集中在少数几个场景,你会改变结论吗?
Trace 里最容易被漏掉、但重放时最致命的是哪一类字段?
「模型当时看到了什么」的那一类字段:系统提示的版本号、注入的上下文片段及其来源、以及裁剪与压缩的日志。
大多数团队会记请求体、工具调用和耗时——这些能让你知道发生了什么,但不够让你复原为什么。最常见的三种无法重放是:① 提示词改过了,只存了最终渲染出来的字符串,没存版本号,旧 trace 无法判断当时用的哪一版;② 上下文是动态拼的,检索片段、记忆、用户画像每轮都不同,不存来源就只能看到一个巨大的字符串;③ 裁剪没有留痕,你只知道模型没答对,不知道它当时没看到哪一段。
判据很简单:拿一条三个月前的 trace 出来,不改一行代码跑一遍,能不能复现同样的失败?不能,缺的就是这一类字段。

追问链

  1. 存全量提示词体积很大,有什么工程上的折中?
  2. 合规要求不能存原文时,怎么保证可重放?
答这类题的通用结构

结论先行(一句话给出取舍)→ 机制(为什么是这样,涉及哪条链路)→ 代价或边界(这么做放弃了什么)→ 你的实践或数字(真实场景里怎么落地)。 只讲机制不讲代价,是背题;只讲取舍没有数字,是空谈。

本章收尾 · Wrap up
掌握度自评
点一下给自己打分;低于 3 分建议加入复习队列
个人笔记 · Notes
    下一章 知识建模:实体、事实、推断 把业务知识拆成三层——实体是可锚定的对象,事实是可溯源的关系,推断是带依据链的衍生结论。这一章讲清三层为什么必须分开,混在一起会出什么事。 IV · 知识引擎 · 第 01 章 · 进阶 · 约 30 分钟