说明:本文讨论的是 LLM 应用 trace 的字段设计,属于 AI 运维话题,不涉及具体模型版本与价格。AI 领域版本迭代极快,凡涉及版本号、价格、可用性,请以你阅读时的官方页面为准。文中代码为结构示意,请按自己的技术栈调整后再上生产。
一、LLM 应用的 trace 和传统 trace 差在哪
线上出问题时,值班的人第一反应是翻日志。日志里通常不缺东西:请求进来了、模型返回了、耗时多少毫秒,一行行都在。真正卡住的是下一个问题——这次的回答是怎么来的:用了哪一版提示、走了哪条工具链、中途重试过几次、最后是谁判定的。日志按时间戳平铺,回答不了这个。能回答它的是 trace。
一个 span 的输入输出,量级完全不同
传统 APM 里的 span 建模范式是"函数调用":一个 HTTP 请求 span 记方法、路径、状态码,一个数据库 span 记 SQL 模板、耗时、影响行数。这类 span 有两个性质:输入输出确定,同一份输入跑两次字段值一样;体积可控,参数大小由接口签名决定,最坏情况有上限。
模型调用 span 两条都不满足。
输入侧,一次调用带进去的是系统提示、对话历史、检索回来的片段、工具描述,加起来几千到几万 token 是常态,长度随业务数据浮动,没有接口签名约束它。输出侧,产物是自然语言,同一份输入两次执行措辞不同,抽样温度大于零时结论都可能相反。
结果是不能把模型调用的输入输出原样塞进 span,也不能指望用固定字段描述它。一个sql_template字段能覆盖整个数据库层,模型层没有对应的稳定字段。
一次用户请求扇出成一棵树
传统链路里,一次请求的调用深度通常固定:入口、若干服务、若干存储,三四层,每层一个 span。LLM 应用不是固定深度。一次提问会扇出:编排一次、检索若干次、模型调用多次(规划一次、生成动作参数一次、汇总一次)、工具调用若干次,工具返回的信息可能再喂回模型,形成第二轮扇出。深度和宽度都随输入变化。
user_request # 入口 └─ orchestrate # 编排 ├─ retrieve # 检索 │ └─ vector_search ├─ llm.plan # 模型:决定下一步 ├─ tool.call # 工具:查订单 │ └─ http.request ├─ llm.act # 模型:生成动作参数 ├─ tool.call # 工具:发起退款 ├─ llm.summarize # 模型:汇总 └─ postprocess这棵树带来两个直接后果。第一,成本和延迟是子树求和,不是单个 span 的值——只看入口耗时,分不清慢在模型还是慢在检索。第二,父子关系本身是排障信息:同一次 trace 里出现两次llm.plan,说明发生了重试或回退,这在平铺日志里只是两行不相干的记录。
数据模型要能回答四个问题
把上面两点收一下,trace 的数据模型在设计阶段就该回答四件事:这次回答是哪套提示产生的(提示版本);走的哪个模型、哪个部署(模型与部署标识);花了多少(用量与延迟);结果怎么判定的(状态与失败分类)。这四个问题缺一个,trace 就退回成"带结构的日志"——数据都在,问题还是答不上来。
二、该记什么:span 的最小字段集
字段设计的原则是先定最小集,再按需扩展。字段一多,采集成本、存储成本、清洗成本同步上涨,而且没人记得住每个字段的含义,最后字段表变成一份没人读的文档。
关联字段:把一次请求挂到发布和会话上
关联字段解决的是定位问题,至少要覆盖五个标识:
trace_id:一次用户请求的全局标识,同一棵 span 树共用。没有它,父子关系拼不起来。span_id与parent_span_id:当前节点与父节点,用于还原树形结构,定位这次模型调用属于哪个步骤。session_id:多轮会话标识。排障时用它把一次对话的多个请求串起来——只靠trace_id,第三轮出错时看不到第一轮说了什么。release_id:一次发布的整体标识,含提示版本、代码提交与配置项。排障的第一个收敛动作就是按它筛,把范围从"全部流量"压到"这次发的版本"。prompt_version:这一 span 用的具体提示版本。它与release_id是两层粒度:一次发布可能同时改多个提示,release_id说"哪次发的",prompt_version说"这个环节用了哪版"。
release_id有个容易忽略的细节:它必须是字符串标识,不是时间戳。用发布时间当标识,同一分钟内发布的两次改动就分不开——这在"改小东西连着发两次"的场景里很常见。
输入输出的三种表示,默认选哪种
模型调用的输入输出不能原样全存,也不能不存。三种表示各有位置:
| 表示 | 存什么 | 体积 | 适用 |
|---|---|---|---|
| 原文 | 完整输入或输出文本 | 最大,随业务浮动 | 单点排查、构造回归样本 |
| 摘要 | 结构化要点或首尾若干字符 | 中等,可控 | 日常观测、看板聚合 |
| 指纹 | 输入规范化后的哈希值 | 固定且极小 | 判断两次请求输入是否相同 |
默认组合是指纹常驻 + 摘要常驻 + 原文按条件保留。
指纹的用处最容易被低估。提示改版后想知道"新旧两版的输入分布变没变",比指纹就行;同一session_id下两次调用的指纹相同,说明用户重发了同一问题,这是判断重试的有效信号。指纹要对规范化后的输入计算,哈希前先把每次都变的部分剥掉,否则同一份输入每次哈希都不一样。
原文占的体积最大,也是合规风险最集中的地方,不该默认全量落盘。可行的做法是按条件保留:采样命中的请求、判定失败的请求、被人工标记的会话,才把原文写进冷存储,并配一个明确的保留期。
一份最小字段的 span 长这样:
{"trace_id":"<请求标识>","span_id":"<节点标识>","parent_span_id":"<父节点标识>","session_id":"<会话标识>","release_id":"20260930-02","prompt_version":"plan-7","name":"llm.plan","model_id":"<部署时填入的模型标识>","input_fingerprint":"<规范化输入的哈希>","input_tokens":3120,"output_tokens":180,"ttft_ms":640,"total_ms":2380,"status":"ok","retry_count":0,"failure_class":null}用量、延迟与结果判定字段
用量至少记input_tokens、output_tokens、total_tokens。这三个值是成本归因的输入,缺了就只能按调用次数估成本,而调用花费的差异主要来自 token 量而非次数。
延迟要拆成两个:ttft_ms(首 token 延迟)与total_ms(总延迟)。首 token 延迟必须单独记,因为这两个数对应两类用户感知、两类故障。首 token 延迟高,用户感知是"卡住了、没反应",原因通常在排队、网关、或输入过长导致预填充慢;总延迟高而首 token 正常,用户看到的是"字一直在出,就是出不完",原因通常在输出 token 数过多、或长输出中途变慢。两者混成一个latency_ms,就只能知道"慢",不知道慢在哪一段。
结果字段三个:status记终态(成功、失败、取消);retry_count记这一环节重试次数;failure_class记失败归类,取值要有限枚举而不是自由文本,比如超时、限流、上游错误、内容拦截、解析失败、工具报错。自由文本没法聚合,最后还得人肉再分一遍类。
| 字段名 | 类型 | 是否必填 | 用途 |
|---|---|---|---|
| trace_id | string | 必填 | 串起一棵 span 树 |
| span_id / parent_span_id | string | 必填 | 还原树形结构 |
| session_id | string | 必填 | 多轮会话串联 |
| release_id | string | 必填 | 按发布收敛范围 |
| prompt_version | string | 必填 | 归因提示改动 |
| model_id / deploy_id | string | 必填 | 归因模型与部署差异 |
| input_fingerprint | string | 必填 | 判断输入是否重复 |
| input_digest / output_digest | string | 建议 | 日常观测的摘要 |
| input_tokens / output_tokens | int | 必填 | 成本归因 |
| ttft_ms | int | 必填 | 首包性能 |
| total_ms | int | 必填 | 端到端性能 |
| status | enum | 必填 | 终态 |
| retry_count | int | 必填 | 稳定性信号 |
| failure_class | enum | 失败时必填 | 失败归因聚合 |
| tenant_id | string | 多租户必填 | 租户维度切分 |
三、不该记什么:三类高风险数据
这一章讲反面清单。判断标准只有一条:这条数据进了 trace 之后,会不会在一次事故复盘、一次审计、或一次存储泄漏里变成更大的问题。
三类高风险数据
第一类是明文个人敏感信息。手机号、邮箱、证件号、住址、银行卡号,经常原样出现在用户提问和工具返回里。trace 存了这些,等于在观测系统里又建了一份个人信息副本,而观测系统的访问控制通常比业务库松、保留期比业务库长。
第二类是完整凭据。密钥、访问令牌、数据库连接串,最典型的来源是失败堆栈与请求头:一个上游超时的异常信息里可能带着完整请求地址,查询参数里带着令牌。凭据进 trace 的危害是静默的:没人主动去搜,直到观测数据被第三方系统读走。
第三类是全量原始工具返回。工具的响应体动辄几十 KB,里面往往同时夹着上面两类数据。它有双重问题:体积上,一次请求存几份大响应,存储成本按流量线性放大;合规上,无法保证每个工具的返回里没有敏感字段——工具返回结构会随上游接口变化。
| 高风险数据 | 主要来源 | 替代做法 |
|---|---|---|
| 明文个人信息 | 用户输入、工具返回 | 写入前识别并掩码 |
| 完整凭据 | 异常堆栈、请求地址 | 整段丢弃 |
| 全量工具返回 | 接口响应体 | 截断,只留字段名与体积 |
四种可替代的处理
脱敏:对可识别的敏感模式做掩码,保留可读结构,比如把手机号中间四位换成占位符。脱敏后的值仍能看出"这里原本是个手机号",但拿不到内容。
哈希:对只需判断"是否同一个值"、不需读原值的字段(用户标识、输入内容)算稳定哈希。注意加盐,否则短值能被穷举反查——手机号的取值空间很小,不加盐的哈希等于没脱敏。
截断:对长文本设上限,超出部分只记长度与首尾若干字符。截断对排查的损失比想象中小,定位问题通常只需要看开头和结论。
分层保留:敏感度高的原文不落常规存储,只在特定条件下写入受控的冷存储,配一个明确的保留期。这一条与第四章的采样是配合关系:采样规则本身就是一种隐私控制,只对少量流量保留原文,暴露面比全量小一个量级。
脱敏必须在写入前做
这一条单独拿出来说,因为它是整条采集链路上最容易做错的一步。
事后清理补不回来。三个原因:数据已经落盘,冷存储、备份、下游同步可能都复制了一份;清洗脚本只能按已知规则匹配,不认识的敏感模式永远匹配不到;无法确认历史上漏了哪些,因此也给不出"清理完毕"的结论。正确的位置是采集器出口——span 在序列化并发送之前完成脱敏,未脱敏的原文不进入传输管道。落地方式是在采集侧维护一张"字段到处理策略"的映射表,新增字段必须先声明策略,未声明的默认不入库。
⚠️ 代码待验证
importhashlibimportre MASK_RULES=[(re.compile(r"1[3-9]\d{9}"),"phone"),(re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+"),"email"),(re.compile(r"\b\d{17}[\dXx]\b"),"id_card"),]SENSITIVE_KEYS={"authorization","api_key","token","cookie"}defscrub(value:str)->str:forpattern,nameinMASK_RULES:value=pattern.sub("<%s>"%name,value)returnvaluedefscrub_payload(payload:dict)->dict:out={}forkey,valinpayload.items():ifkey.lower()inSENSITIVE_KEYS:out[key]="<dropped>"# 凭据整段丢弃elifisinstance(val,str):out[key]=scrub(val)[:2000]# 先脱敏,再截断elifisinstance(val,dict):out[key]=scrub_payload(val)else:out[key]=valreturnoutdeffingerprint(text:str,salt:str)->str:returnhashlib.sha256((salt+text).encode()).hexdigest()[:16]三点说明:脱敏在截断之前做,顺序反了会切掉手机号后半段导致匹配不上;凭据类字段直接丢弃而不是掩码,因为掩码后的令牌仍占体积且没有排查价值;指纹加盐,避免用户标识被反查。
四、采样策略
全量存 trace 最省事,代价按流量线性放大。采样必须做,但采样策略决定了还能不能排障——采错了,恰恰在最需要的那次错误上什么都没有。
尾采样:先缓冲、后判定、再落盘
头部采样在请求入口就决定采不采,问题是:做决定的那一刻,还不知道这次请求会不会失败。错误和慢请求于是按同样比例被丢掉,而它们恰恰是最该看的。
尾采样把顺序反过来:请求进来时先不判定,span 在内存缓冲里累积;一次 trace 收敛(结束、超时、被取消)之后,按结果决定是否落盘。判定条件三条:失败必留、超延迟阈值必留、其余按比例。
代价要写清楚:缓冲占内存,长会话的 trace 可能几分钟才收敛;多实例部署时同一个 trace 可能跨实例,缓冲要按trace_id归并,需要带过期时间的共享缓冲,或者接受"跨实例的 trace 判定不全"。
⚠️ 代码待验证
fromcollectionsimportdefaultdictclassTailSampler:def__init__(self,sample_rate:float=0.05,slow_ms:int=8000):self.sample_rate=sample_rate self.slow_ms=slow_ms self.buf=defaultdict(list)defadd(self,span:dict)->None:self.buf[span["trace_id"]].append(span)defflush(self,trace_id:str,status:str,total_ms:int)->bool:spans=self.buf.pop(trace_id,[])ifnotspans:returnFalsekeep=status!="ok"ortotal_ms>=self.slow_msifnotkeepandstable_ratio(trace_id)<self.sample_rate:keep=Trueifkeep:write_to_store(spans)returnkeepdefstable_ratio(trace_id:str)->float:# 稳定哈希:同一 trace 的判定可复现,重跑结果一致returnint(hashlib.sha256(trace_id.encode()).hexdigest()[:6],16)/0xFFFFFF比例采样与会话一致性
正常流量按比例采样看起来简单,但有个坑:采样不能按单次请求独立掷骰子。一次多轮会话被采成半截,第 1 轮有 trace、第 2 轮没有,排查时上下文拼不起来——会看到"模型突然改变口径",其实只是缺了中间那轮的信息。
所以采样键要用session_id而不是trace_id:同一会话内所有请求共享同一个采样决定,要么全留,要么全走。代价是采样比例的方差变大——按会话采样,实际留存率围绕目标比例波动,会话越长波动越明显,排障收益大于这点统计精度损失。
尾采样与会话一致性是叠加的,不是二选一:落盘判定先看结果(错误与慢请求必留),剩余的按会话标识做一致性抽样。
策略组合与代价对照
| 策略 | 适用流量 | 代价 | 必须开启的场景 |
|---|---|---|---|
| 全量保留 | 错误、超时、人工标记 | 存储成本最高 | 出现新失败类型时 |
| 按会话比例采样 | 正常成功流量 | 长尾场景可能采不到 | 日常运行 |
| 头部采样 | 超大流量、只做趋势 | 错误样本被平均掉 | 容量统计,不用于排障 |
| 分层采样 | 多租户、多版本 | 实现复杂 | 需要按维度横向对比时 |
组合顺序是:尾采样做第一道闸(错误与慢请求全留),会话一致性做第二道(正常流量按会话抽),分层采样只在需要横向对比时叠加。
五、从 trace 到指标:该聚合出哪几个数
trace 是明细,指标是聚合。聚合口径定错,看板会长期给错误信号。这一章列出必须聚合的几类数以及各自的口径。
失败率要分层看
单一的总失败率是最没用的指标:它把模型错、工具错、内容拦截、用户取消混在一起,涨了也不知道该找谁。至少拆成三个维度:
- 按
prompt_version:哪一版提示的失败率高。这是提示改版后最直接的反馈,也是灰度决策的依据。 - 按工具(
tool_name):哪个工具返回的错误多。工具层的失败率经常掩盖整条链路的健康度。 - 按
tenant_id:哪个租户的问题集中。多租户系统里租户之间的输入分布差异极大,混在一起算等于把最容易出问题的那部分稀释掉。
拆完维度再看失败类型分布,也就是failure_class各取值的占比。全是超时,问题在容量和排队;全是上游错误,问题在下游稳定性;全是解析失败,问题在提示的输出约束没写清;全是内容拦截,问题在输入侧的过滤规则。类型分布比失败率本身更能指向动作。
重试率与每任务成本结构
重试率单看没有意义,要看它和重试成功率的差。两个数分别是重试占请求的比例、重试后成功的比例,组合起来三种情况:
- 重试率高、重试成功率也高:链路不稳定但能自愈。问题在成本——每次重试都是一次模型调用,重试率翻倍,花费可能涨三成以上,排查重点是降低首次失败率。
- 重试率高、重试成功率低:重试基本是浪费。这说明失败不是瞬时抖动,重试策略该收紧,否则只是在放大成本和延迟。
- 重试率低:要确认重试逻辑真的健壮,还是重试分支根本没被触发过。
成本必须归因到任务,不能只看总数。"这个月花得比上个月多"这个结论不可行动。可行口径是每次任务的成本结构:把一次 trace 内所有模型调用的 token 用量加总、换算成成本,再按步骤拆开——检索、规划、动作、汇总各占多少。归因到步骤之后通常会发现某个环节吃掉大头,比如汇总步骤的输入带了全量检索结果,而它只需要摘要,这是可以改的;总数不可改。
延迟分位与告警阈值
延迟不要报平均值。平均值会被大量快请求拉平,把慢请求藏起来。口径用分位:ttft_ms与total_ms各看 P50、P95、P99,且两个指标分开看,理由在第二章。P99 用来找离群点,不定容量;定容量的依据更接近 P95。
告警阈值用分层基线加变化率,不用绝对值。绝对阈值依赖流量规模:同一条链路请求量涨十倍,固定的 P99 阈值就会误报,因为排队时间本身变长。可行做法是先按维度(提示版本、工具、租户)各算一条历史基线,再对"当前窗口相对基线的变化率"设阈值,超过一定比例才告警。这样告警反映的是"相对昨天反常",而不是"绝对值超了某个数",信噪比高得多。
完整版资料清单:本文用到的 trace 字段清单和采样配置都整理在里面了,扫码即可获取:
六、trace、日志、指标三者的分工
三种数据的角色不同,重复存全量等于三份成本、三份合规风险,且没有一份完整。
各存什么
trace存因果链:结构(谁是父子)、字段(第二章的最小集)、判定(状态与失败分类)。核心价值是还原一棵树,所以必须保结构,不必保全文。
日志存离散事件:状态变化、外部依赖返回码、异常与堆栈摘要、投递动作。日志是事件流,时空上是孤立的点,不承载因果。
指标存聚合数值:只存时间窗口上的数,不存个体。价值是趋势与告警,代价是无法回溯到个体——指标涨了只说明"出问题了",说不出"是哪次请求"。
靠什么字段互相关联
三套数据要能互相跳转,靠的是共享标识。trace_id是主线,日志与指标都带上它(指标在聚合前按它取明细)。session_id用于跨 trace 串联多轮会话,release_id用于把三套数据同时收敛到一次发布。
这里有个实践细节:指标本身不存trace_id,但必须支持带trace_id维度的下钻查询——从指标异常出发取一批代表性trace_id,跳到 trace 看明细。做不到这一步,指标与 trace 就是两个孤岛,告警响了还得手工翻日志。
保留期分层
| 数据类型 | 存什么 | 保留期 | 典型用途 |
|---|---|---|---|
| trace 明细 | 结构加字段最小集,原文按条件 | 短期在线,采样后转冷 | 单次排障、会话回放 |
| 日志 | 离散事件与错误摘要 | 中期在线 | 定位异常、看依赖返回 |
| 聚合指标 | 分层计数、分位、成本 | 长期保留 | 趋势、告警、容量规划 |
| 原文快照 | 采样或失败样本的输入输出 | 冷存储,定期清理 | 构造回归样本 |
规则是明细短、聚合长:trace 明细体积最大,在线留短一点;聚合指标体积小,长期保留以支撑同比。关联索引(trace_id、session_id、release_id)在转冷时必须一起保留,否则冷数据等于丢了,能找到记录但拼不出链路。
保留策略写进配置,避免口头约定:
⚠️ 代码待验证
retention:trace_detail:online_days:7# 在线明细,便于即时排障cold_days:90# 转冷保留,含关联索引sample_key:session_id# 采样与关联都用会话标识log:online_days:30metric:online_days:400raw_payload:cold_days:30require:-sampled-failed七、上线顺序与一次实操排查路径
先埋字段,再谈看板
常见的启动顺序是先挑一个观测平台接进去,然后发现没有字段可以画图,于是回头改采集。代价是白做一轮接入,中途流量也没有可回查的痕迹。
正确顺序是反的:先把第二章的字段埋上并验证落盘,再做聚合和看板。验证方法不是"能查到就行",而是拿一次已知结果的请求比对——挑一条明确失败的线上会话,看failure_class是否落在预期类别、prompt_version是否指向实际生效的版本、ttft_ms与total_ms是否都有值。三项对不上,说明埋点位置或字段口径有问题,这时看板画得再好看也是假的。
一次完整的排查路径
把下面的查询串成一条可复用的路径。
⚠️ 代码待验证
# 1. 按发布标识收敛,确认这次发布有没有异常抬升curl-s"http://trace-store/api/spans?release_id=20260930-02&status=error&limit=50"\|jq-r'.items[].failure_class'|sort|uniq-c|sort-rn# 2. 取一个失败会话,按会话标识把多轮请求串起来curl-s"http://trace-store/api/spans?session_id=<会话标识>"\|jq-r'.items[] | [.started_at, .name, .status, .total_ms] | @tsv'# 3. 用 trace 标识拉全树,看是哪一层先失败的curl-s"http://trace-store/api/traces/<trace 标识>/spans"\|jq-r'.items[] | "\(.parent_span_id)\t\(.span_id)\t\(.name)\t\(.status)"'对应五个动作:
- 告警触发:某个分层指标越过基线变化阈值。此时只知道"某一层在变差",不知道原因。
- 定位到发布标识:把失败率抬升的时间窗口对齐发布时间,取出
release_id。这一步把范围从"全部流量"压到"一次发布",是收益最大的一步。 - 收敛到失败分类:按
release_id拉失败样本,统计failure_class分布。集中在一类说明是单点问题,比如某个工具下游挂了;分散说明是系统性问题,比如提示改版导致输出格式普遍不合规。 - 会话级回放:取失败样本的
session_id,把多轮请求按时间排开。很多问题在这个视角下才显形——单看失败那一轮很正常,回放才看到前一轮的回答给了错误前提。这一步依赖会话一致性采样与session_id保留,采错了这里就断了。 - 定位到具体 span:按
trace_id拉全树,找第一个状态非成功的节点,看它的prompt_version、retry_count、failure_class,以及原文快照里保留的输入摘要。
复盘产出两样东西
排查结束要落两样东西,否则同一次故障会再来一遍。
第一样是一条新的回归样本:把出问题的输入和预期输出固化下来,进固定样本集,下次提示改版必须跑过它。第二样是一个新的 trace 字段:绝大多数"查不动"的情况,根因不是数据没了,而是当初没埋那个字段。补字段比补文档有效,因为它下次自动就在那里。
完整版资料清单:本文用到的 trace 字段清单和采样配置都整理在里面了,扫码即可获取:
附表 A:关键取舍一览
| 工程决策 | 原因 | 依据章节 |
|---|---|---|
| 用 trace 而非日志承担排障 | 日志按时间平铺,答不出因果 | 第一章 |
| 模型调用的输入输出不原样全存 | 体积无上限,结果是概率分布 | 第一章 |
| release_id 用字符串而非时间戳 | 同分钟两次发布无法区分 | 第二章 |
| 指纹常驻、原文按条件保留 | 指纹极省且能判断输入重复 | 第二章 |
| 首 token 延迟单独记 | 与总延迟对应不同故障位置 | 第二章 |
| failure_class 用有限枚举 | 自由文本无法聚合 | 第二章 |
| 凭据类字段整段丢弃 | 掩码后仍占体积且无排查价值 | 第三章 |
| 指纹加盐 | 短值可被穷举反查 | 第三章 |
| 脱敏放在采集器出口 | 事后清理补不回来 | 第三章 |
| 尾采样替掉头部采样 | 入口处无法预知是否失败 | 第四章 |
| 采样键用 session_id | 会话被采成半截就拼不出上下文 | 第四章 |
| 失败率拆维度看 | 总失败率把多类问题混在一起 | 第五章 |
| 重试率与重试成功率一起看 | 单看重试率推不出该改什么 | 第五章 |
| 成本归因到步骤而非总数 | 总数不可行动,步骤可改 | 第五章 |
| 告警用分层基线加变化率 | 绝对阈值随流量规模失效 | 第五章 |
| 保留期明细短、聚合长 | 体积与用途不同 | 第六章 |
| 先埋字段再做看板 | 没字段的看板是假的 | 第七章 |
| 复盘补一个新 trace 字段 | 查不动的根因常是字段缺失 | 第七章 |
附表 B:术语速查表
| 术语 | 含义 |
|---|---|
| span | 一次请求链路中的单个节点,含输入输出、耗时与状态 |
| trace | 同一次用户请求下所有 span 组成的树,表达因果 |
| trace_id | 一棵 span 树的全局标识,跨系统关联的主线 |
| session_id | 多轮会话标识,用于把多个 trace 串成一段对话 |
| release_id | 一次发布的整体标识,含提示、代码与配置 |
| prompt_version | 单个环节使用的提示版本,粒度细于 release_id |
| ttft_ms | 首 token 延迟,从请求发出到收到第一个 token |
| failure_class | 失败归类枚举,用于聚合失败原因分布 |
| 指纹 | 输入规范化后的稳定哈希,用于判断输入是否重复 |
| 尾采样 | trace 收敛后按结果决定落盘,错误与慢请求可全留 |
| 分层保留 | 按敏感度与用途把数据分放在不同存储与保留期 |
写在最后:这篇用到的资料
写这篇文章时,我把几个模型的官方文档、参数表和实测记录都对了一遍,顺手整理成几份配套的东西:
- 大模型学习路线图:从 LLM 基础到 Agent 开发,各阶段该学什么、用什么资料
- 大模型全套教程:按主题分好的视频与文档清单
- 大模型实战好书:24 本,附每本适合的阶段
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「大模型」,优先通过。
拿到之后建议先看学习路线图那一份,先定位自己在哪个阶段,再决定学什么,比一上来就啃框架效率高得多。