用户只会说它胡说:AI 服务的一线报障怎么接
说明本文讨论的是 AI 服务的一线报障受理流程属于工程运维话题不涉及具体模型版本与价格。AI 领域版本迭代极快凡涉及版本号、价格、可用性请以你阅读时的官方页面为准。文中代码为结构示意请按自己的技术栈调整后再上生产。一、它胡说这句话里没有信息周一早上九点四十支持群里进来一句“你们这个 AI 胡说八道。”后面通常没有别的了。你回一句能具体说下吗对方发来一张截图截图里是一段看起来挺正常的回答。再问你问的是什么他说就那个报销的事。到这一步你花了二十分钟手上仍然是零个可查询的条件。这一章只说一件事报障受理的第一步不是判断对错是把一句自然语言变成能塞进检索框的条件。用户给的和他以为给了的用户描述里通常只有三样东西一个结论、一种情绪、一个可能并不存在的例子。“胡说在用户那里等价于输出和我的预期不符”而预期没法查。同一句它乱答可能对应他问的问题本身有歧义可能对应材料里根本没有答案也可能对应他换了入口、而那个入口的配置不一样。这几种在受理单上长得一样在日志里一行都对不上。情绪是有用的信号但不是判据。很生气说明影响面不说明该查哪张表。例子最值钱可用户给的往往是转述。他写它说报销要找财务原文可能是报销申请需经财务部门复核后提交。这两句丢进全文检索命中率不是一个量级。所以要原文我发了什么、它回了什么。用户说的工程师要的差在哪“它胡说”一段原文问答对结论对不上可检索的文本“就刚才”带时区的时间戳相对时间无法对齐日志“你们那个网页”entry 枚举值口语名与字段名不同源“一直这样”重放三次的结果印象替代不了记录工程师要的是可查询条件工程师能开工的前提是手上有四个能直接用的东西时间、会话、输入、入口。时间落到分钟级把窗口从全部历史缩到那一次会话 ID 是唯一能把人带进日志的钩子没有它只能靠时间加关键字碰运气原始输入决定能不能重放转述过的输入重放不出同一个问题入口决定你看哪一套日志、哪一份配置四样凑齐第一动作可以是查缺一样就退化成你再试一次给我看看响应时间从十分钟拉成一天。缺口不该由用户来补用户不知道你会记会话 ID也不知道日志只保留一段时间。要求他提供不知道存在的东西是把系统设计的债转嫁给用户收回来的还是一堆没法用的描述。正确的补法在三个地方界面上放一个复制本次会话的按钮报障入口自动带上时间、入口、请求 ID表单只问系统拿不到的东西。都是一次性投入做完每一单省十几分钟。这一章可以带走的一句用户没有义务提供工程信息但系统有义务在他开口的时候顺手把信息收下来。二、一线要收的最小信息包最小这两个字有约束力多一个字段用户多一分放弃率少一个字段工程师多一次来回。下面六个是压不下去的下限。六个字段各自的作用会话 ID 或任务 ID。它是索引键不是给人看的。要求是能直接粘进检索框长度对、字符集对、没被人为截断。发生时间带时区。精确到分钟就够但必须能和你日志的时间轴对齐。跨时区团队最容易在这翻车用户说昨天下午三点日志按 UTC 记一减就是八小时。原始输入。原文不是摘要。概括会丢掉标点、空格、换行和附件名而这些恰好影响上下文拼接。期望与实际的差。写成两句话“我以为它会做 X”“它给了 Y”。写成答案不对等于没写因为不对没有方向。是否可复现。分级的主要输入。三值就够每次、偶尔、只出现过一次。“还没试要单独留一项不要塞进只出现过一次”。入口。网页、客户端、API、批处理。入口写错后面所有查询都白做。每个字段的合格线字段定义里最容易漏的是什么算填对。只写必填没用用户会填一个字形正确、内容错误的字符串然后在受理单里躺三天。字段合格线能直接用于查询不合格的典型样子会话 ID可直接粘贴检索、长度与字符集符合规则只截了后六位、截图有反光发生时间带时区的 ISO 时间误差 ±5 分钟“昨天下午”“刚刚”“上周”原始输入用户实际发送的完整文本可复制一句概括、语音转文字后的残句期望与实际的差两句话X 和 Y 都可判定“答得不对”“胡说八道”是否可复现四值枚举之一重放动作真实做过空着、或者填应该是每次入口枚举值和日志里的 entry 字段同名“网页版”“就是你们那个”表单里的入口选项要和日志里的entry一一对应。写网页版、记web中间就得有人翻译一次翻译就会出错。收不到的时候怎么兜第一类用户把会话删了。退一步收输出里的一段原文用那段原文做全文反查通常能定位到唯一一条响应。要跟用户说明为什么需要否则他会觉得你在刁难。第二类走的是 API没有界面。这类用户一般能给请求 ID 或调用时间以请求 ID 为主键时间只作辅助。第三类不敢贴原文里面可能有客户名、金额、证件号。要给可操作的替代只贴结构、脱敏后贴、或者授权工程师按会话 ID 查看。授权要落在产品里不能落在群聊里的我同意。把六个字段固化成受理单⚠️ 代码待验证ticket:id:t-20261024-0007entry:web# 与日志 entry 字段同名session_id:s_9f2c7a41# 用户可复制直接进检索框happened_at:2026-10-24T09:38:0008:00# 必须带时区raw_input:|帮我看下这张差旅报销单能不能过附件是行程单和发票。expected:逐条列出不符合项actual_quote:|您的报销单符合规定可以提交。reproducible:true# 四值true / false / once / untestedself_check:replay:reproduced# reproduced / not_reproduced / changedother_entry:not_triedshrunk_input:reproduced每一行都要能翻译成一条查询条件翻译不出来的字段不该出现在表单里。三、做成一句话模板让用户填对表单不是问卷是检索条件的生成器判断一个字段该不该留只有一个标准它会不会进入查询条件。不会的删掉。“您的公司规模”您是哪个部门这类字段在工单系统里很常见对统计有用对受理没用。它让用户觉得在走流程填写质量跟着下降最后连该认真填的也敷衍了。还有一条更硬的系统能自己拿到的东西一律不要问用户。浏览器 UA、入口、请求 ID、会话 ID、提交时间、用户标识提交那一刻全都拿得到。把它们做成输入框等于把自动化外包给最不可靠的一环。按这条砍一刀十几项的表单通常剩三四个必填。第一屏只放三个框用户的耐心只够填三个框。第一屏放这三样你发了什么多行文本必填它回了什么多行文本必填只要一两句原话什么时候默认当前时间可改必填其余放进补充信息折叠区。代价是首轮信息不完整收益是提交率一个没提交的报障等于不存在。字段定义写成配置改起来不用发版⚠️ 代码待验证{form_id:ai_incident_intake,version:3,fields:[{name:raw_input,type:textarea,required:true,min_len:8,label:你发给它的内容,hint:粘贴原文不要概括},{name:actual_quote,type:textarea,required:true,min_len:4,label:它回答的原话,hint:一两句即可不要截图},{name:happened_at,type:datetime,required:true,auto_fill:now},{name:entry,type:select,required:true,auto_fill:detect,options:[web,app,api,batch]},{name:expected,type:text,required:false,max_len:120,label:你原本预期它做什么},{name:reproducible,type:radio,required:false,options:[every_time,sometimes,once,untested]}]}auto_fill的两个字段仍要显示只是不让改让用户看见系统已经知道他在哪个入口比藏起来更让人放心。校验该拦的拦该提示的提示校验的尺度分三档全都硬拦会把用户赶走。情况处置理由输入为空、时间在未来硬拦不许提交提交了也查不了是无效工单输入少于 8 个字软提示可继续有人真的只发了一个词出现胡说“不对”“有问题”追加必填项引用一句原话这类词没有方向必须补方向时间早于日志保留期硬拦并说明保留天数免得用户白填也免得多一轮解释会话 ID 格式不符软提示允许留空有些用户确实拿不到第三行是这套表单里最关键的一条它是条件必填。平时引用原话是选填用户一旦用了那些没信息量的词它变成必填。用户不觉得被拦只觉得系统在帮他把话说清楚。实现上就是一个返回错误列表的函数不要抛异常——错误要能一次全显示而不是让用户改一条提交一次⚠️ 代码待验证fromdatetimeimportdatetime,timedelta,timezone VAGUE_WORDS(胡说,不对,有问题,乱答,答非所问)SUMMARY_HINTS(它说,大概,类似,好像,意思是)defvalidate(payload:dict,log_retention_days:int30)-list[str]:errors[]raw(payload.get(raw_input)or).strip()ifnotraw:errors.append(请输入你发给它的内容)eliflen(raw)8:errors.append(输入很短确认一下是不是只发了一个词)elifsum(winrawforwinSUMMARY_HINTS)2:# 转述的典型特征连着出现多个它说/好像这类词errors.append(这段看起来是转述请粘贴你实际发送的原文)quote(payload.get(actual_quote)or).strip()ifany(winrawquoteforwinVAGUE_WORDS)andnotquote:errors.append(请引用一句它的原话这样我们才能定位到具体回答)tsparse_ts(payload.get(happened_at))iftsisNone:errors.append(时间格式不对需要带时区)eliftsdatetime.now(timezone.utc)timedelta(minutes5):errors.append(时间在未来检查一下时区)eliftsdatetime.now(timezone.utc)-timedelta(dayslog_retention_days):errors.append(f这个时间已经超出日志保留期{log_retention_days}天)returnerrors最后一个分支不是拦住用户是提前告诉他这条查不到了——否则他会提交然后等一个查不到的回复。四、自助诊断三个动作让用户先排除一半三个动作按成本排序自助诊断不是让用户替工程师干活是让他在两分钟内把三种最可能的分岔走掉。动作用户要做什么结果怎么记能分掉哪一类原样重放点一下再问一次稳定复现 / 偶发 / 换了个错法稳定性与内容问题换一个入口同一句在另一个入口再问复现 / 不复现 / 没权限入口之间的配置差异缩小输入去掉附件、去掉前半段、缩短指令仍出错 / 变正常与输入长度或形态相关顺序不能颠倒重放最便宜一秒做完缩小输入最贵用户得重新组织问题。让用户先做贵的他多半直接放弃。三个动作各自的读法原样重放。关键是原样同一段输入、同一个入口、不改一个字。所以产品上要提供按钮不要让用户手工复制粘贴——手工重放十有八九会顺手改一两个字。结果只有三种每次都错和输入内容强相关偶尔错和采样或并发有关换了个错法说明这段输入踩在边界上。换入口。同一份能力在不同入口上往往差着系统提示、超时、附件解析开关、检索是否开启。换入口能复现说明现象不是某个入口独有换入口不复现说明差异在入口配置里。这一条能挡掉很多你们模型不行的误报。缩小输入。三种砍法去掉附件、去掉前半段对话、把长文档换成一段摘要。三种结果短输入正常和长度或截断有关短输入也错和内容有关怎么砍都正常和当时的并发或时间有关。这里有个容易忽略的点缩小后正常不等于问题消失了。它只说明触发条件包含长度。受理单上要如实记这个结果而不是记成用户误报。结果要能回到受理单自助做完了结果必须变成结构化字段回传否则自助只是把问题又推回给用户还多花了他两分钟。三个字段就够每个都是三值枚举replayreproduced / not_reproduced / changedother_entryreproduced / not_reproduced / not_triedshrunk_inputreproduced / normal / not_tried这三个字段直接决定分级。replayreproduced且shrunk_inputnormal的单子比一个什么都没试过的值钱得多接手的人第一眼就知道往哪查。自助也有边界。涉及计费、权限、数据删除的现象不要让用户自己试——他每试一次都可能产生真实副作用。这类直接进人工别省那两分钟。五、分级与升级路径三级判据写死分级的难点不在分级本身在什么算严重这句话没有共识。所以判据必须是可判定的条件不能是形容词。级别判据满足任一响应时限谁接一级核心入口有请求但无任何输出或 30 分钟内 3 个以上不同用户报同一现象15 分钟内有人回应当班工程师 负责人二级单用户、可复现、有替代路径可用当日工作时间内当班工程师三级单次、不可复现、用户已自行绕过每周归并时统一看受理人登记即可核心入口有请求但无任何输出和答得不对是两件事。前者是服务没回后者是回了但内容不合预期。放进同一个级别真正该立刻处理的那类会被淹没。30 分钟内 3 个以上不同用户有两个限定词不同用户排除同一个人反复提交30 分钟内排除跨越一周的偶发。少任何一个这条判据都会误报。判据写成代码比写成文档可靠因为代码不会在不同人的嘴里变成不同意思⚠️ 代码待验证fromdatetimeimportdatetime,timedelta REQUIRED(entry,happened_at,reproducible,has_output)LEVEL_1,LEVEL_2,LEVEL_3L1,L2,L3defgrade(ticket:dict,same_phenomenon_users:int,now:datetime|NoneNone)-tuple[str,str]:missing[kforkinREQUIREDifticket.get(k)isNone]ifmissing:# 缺字段不猜级别直接打回补信息raiseValueError(f受理单缺字段:{missing})nownowordatetime.now()ifticket[entry]coreandticket[has_output]isFalse:returnLEVEL_1,核心入口有请求无输出ifsame_phenomenon_users3andticket[happened_at]now-timedelta(minutes30):returnLEVEL_1,30 分钟内多用户同一现象ifticket[reproducible]isTrue:returnLEVEL_2,单用户可复现returnLEVEL_3,单次不可复现那个raise是有意为之。缺字段时按默认值猜一个级别等于把一个信息不完整的单子伪装成完整的后面所有人都被这个假级别骗。允许跳级不允许随手降级往上跳要容易任何人都能标一级代价是必须填一段理由。这条不是防滥用是防沉默——宁可多几个误报也不要一个被压在三级里的真故障。往下调要难只能由接手人看过之后调并写清原因。最常见的坏习惯是先标三级等有空再看这一压往往就是两天。还有一条时限从提交时刻算不从接单时刻算。从接单算的话一直没人接的单子永远不会超时时限形同虚设。超时之后自动往上走一级 15 分钟没人回应自动通知上一层二级到当日结束还没人接次日自动升为一级并附上已积压一天。这套动作是自动的不依赖任何人记得。只有超时未回应才升回应了但没解决不升前者是流程问题后者是技术问题处理的人手不一样。完整版资料清单本文用到的受理单模板、分级判据表和术语对照都整理在里面了扫码即可获取六、工程师接手后的第一条动作把胡说翻译成三个查询条件接手后的第一件事不是看模型答得对不对是确认用户说的那一次到底是哪一次。拿三个条件去定位时间窗用户报的时间前后各 15 分钟、会话 ID精确匹配、入口枚举值。三个里至少两个要落在索引上否则查询会退化成全表扫描。这一步必须放在最前面原因是受理单上的时间是用户记得的时间不是请求发生的时间。人会记错半小时会把昨天晚上说成昨天下午会把自己在另一个入口的操作记成这个入口。先把那一次请求找出来后面的讨论才有共同对象。这一步还常带来一个意外发现用户说的那次根本不在他填的入口里。到这儿问题就从内容不对变成了受理单填错入口处置动作完全不同。一条能跑的查询查询本身没技巧技巧在条件上。下面这条带上租户条件是因为多租户下session_id有可能重复——两个租户各自生成了一样的短 ID不带租户就会拉出别人的会话既查错也越权。⚠️ 代码待验证-- 按时间窗拉一条会话的全部请求-- tenant 条件不能省session_id 在多租户下可能重复SELECTr.request_id,r.turn_index,r.entry,r.created_at,r.status,r.finish_reason,r.input_chars,r.output_charsFROMrequest_log rWHEREr.tenant_id:tenant_idANDr.session_id:session_idANDr.created_at:from_tsANDr.created_at:to_tsORDERBYr.created_atLIMIT200;ORDER BY created_at是为了还原对话顺序少了顺序你会看到一堆并列的请求判断不出上下文是怎么被拼起来的。LIMIT 200是保险——长时间挂着的会话里上千轮请求并不罕见不设上限会把结果集撑爆。受理单上由接手人填的四个字段受理单分两半用户填的那半和接手人填的那半。后一半只有四个字段但每个都能被追问。字段填什么为什么必须有首查条件实际用了哪几个条件、命中几条让别人能原样复现你的检索定位到的请求request_id 与 turn_index把讨论对象钉死在一个请求上信息完整度六个字段里缺哪几个缺字段的单子结论要打折看下一步归属转给谁、还是退回补信息只写归属不写结论第四个字段要克制。受理人写应该是模型幻觉“估计是检索没召回”看起来有帮助实际是在没有证据时给接手人预设方向。“查到 0 条也是有效结果。它说明三件事之一入口填错、时间窗错、或者这次请求根本没落日志。三种的下一步完全不同所以要当成正常分支记下来而不是当成没查到再问问”。七、把重复报障变成规则一周一次归并按现象不按人单看一条报障什么规律都看不出来。攒一周再看重复的部分会自己浮出来。归并的三个维度是现象、入口、输入形态。不按用户归并因为同一个用户可能报三件不同的事三个用户也可能报同一件事。“现象要归一化。用户写胡说”“答非所问”“牛头不对马嘴”归并时要落到同一个标签上。这一步靠人做不要指望关键词自动聚类——中文里同一个意思的说法太多自动聚出来的组通常没法看。阈值建议是 5同一类一周内到 5 条才升级成待处理类不到的留在池子里下周继续累计。低于阈值的强行归类会得到一堆只出现过一两次的类改完表单也没人用。归并之后要改三样东西归并结果如果只写进周报等于没做。它必须回写到三个地方而且最好是同一个人改表单选项把高频现象做成下拉项。用户点一下分类就带上了比让他用自然语言描述准确得多。自助话术这一类如果有稳定的自助解法写进自助诊断的提示语。比如这类问题多数和附件解析有关可以先去掉附件试一次。知识库条目一条现象、一条判据、一条处置动作三行写完。不要写长文长文没人看也没法在受理时快速对照。三样必须同步。最常见的破败样子是表单里多了一个选项知识库里没有对应条目接手人看到这个选项也不知道该干什么最后还是回去问用户。什么不该归并第一类是时间上高度集中的。一小时内进来的 20 条很可能是同一次故障的 20 个用户。归并成 1 条等于把影响面从 20 改成 1级别也跟着从一级掉到三级。这类要合的是处置动作不是计数——20 条一起处理但 20 这个数字必须留着。第二类是处置动作不同的。两条描述几乎一样但一条要改配置、一条要补数据它们就不是同一类。归并的粒度是处置动作相同不是关键词相同。统计脚本可以自动做完候选分组剩下的判断留给人⚠️ 代码待验证fromcollectionsimportdefaultdictdefcluster(tickets:list[dict],min_count:int5)-tuple[list[dict],list[dict]]:bucketsdefaultdict(list)fortintickets:key(t[phenomenon],t[entry],t[input_shape])buckets[key].append(t)ready,pending[],[]forkey,itemsinbuckets.items():row{phenomenon:key[0],entry:key[1],input_shape:key[2],tickets:len(items),users:len({i[user_id]foriinitems}),ticket_ids:[i[id]foriinitems],}(readyiflen(items)min_countelsepending).append(row)ready.sort(keylambdar:r[tickets],reverseTrue)returnready,pending输出里特意带了users条数多但用户数只有 1说明是同一个人在反复提交不该进待处理类该去看他为什么反复提交。完整版资料清单本文用到的受理单模板、分级判据表和术语对照都整理在里面了扫码即可获取附表 A关键取舍一览取舍本文结论判断依据位置受理第一步做什么先转成查询条件不判断对错没有条件就没有可查对象第一章信息缺口谁来补系统补不追问用户用户不知道哪些东西存在第一章表单首屏只放三个必填框提交率优先于首轮完整度第三章模糊描述怎么处理条件必填引用原话硬拦会赶走用户放任则无法定位第三章自助动作顺序重放 → 换入口 → 缩小输入按用户操作成本排序第四章分级判据写法可判定条件不写形容词严重没有共识无法执行第五章降级权限只有接手人能降且写原因防止先压三级再说第五章时限从哪算从提交时刻算从接单算则无人接单永不超时第五章接手第一条动作先确认是哪一次请求用户记的时间不等于请求时间第六章受理人写不写结论只写归属不写结论无证据的预设会带偏后续第六章归并按什么聚类现象 入口 输入形态按用户聚类会把不同问题混在一起第七章密集报障怎么处理合处置不合计数合计数会把影响面算小第七章附表 B术语速查表术语含义最小信息包让工程师能开始检索的最少字段集合本文定为六个会话 ID一次连续对话的标识是定位日志的主键入口用户实际使用的接入方式如网页、客户端、API、批处理可查询条件能直接落进检索或数据库条件的值如时间窗、精确 ID原样重放同一输入、同一入口、不改一字地再执行一次分级判据用来判定报障级别的可判定条件不含形容词超时升级超过响应时限仍无人回应时自动提升级别并通知上一层现象归一化把不同说法归到同一个现象标签通常由人完成写在最后这篇用到的资料写这篇文章时我把几个模型的官方文档、参数表和实测记录都对了一遍顺手整理成几份配套的东西大模型学习路线图从 LLM 基础到 Agent 开发各阶段该学什么、用什么资料大模型全套教程按主题分好的视频与文档清单大模型实战好书24 本附每本适合的阶段资料是我自己整理的放在下面这个码上扫码即可获取添加时备注「大模型」优先通过。拿到之后建议先看学习路线图那一份先定位自己在哪个阶段再决定学什么比一上来就啃框架效率高得多。