提示

返回博客列表

想查一条三个月前的回复,查不到

问题是客服主管在群里问的:九月中旬有个用户投诉,说自动回复给了一个不对的说法,想看看当时到底回了什么。

我说我查一下,然后打开日志,翻了十分钟,脸色不太好看。

那会儿 AI 调用只记两种东西:成功、失败。logger.info('AI 回复生成成功') 一行,异常时一行 logger.exception。回复正文一个字都没留。用户原话存在 ChatMessage 表里,AI 那句回复是随 chat_send 的响应直接返回给浏览器的,服务端只在内存里过了一遍就没了。

也就是说,除了那个用户的浏览器,世界上没有第二份。

补存储之前先吵了一架

第一反应是"把回复存下来"。真要落库,马上冒出四个问题,每个都不太好答。

存原文还是脱敏后的?原文对复盘最有用,但用户可能贴过手机号、兑换码;脱敏后的看不出当时到底说了什么,等于白存。

存多久?没人能给个准数。客服说投诉追溯一般一两个月,法务那边没给过明确口径,我最后拍了个七天,理由很朴素:先别留太多。

谁能看?回复里可能带用户信息,总不能整个后台都能翻。可我们当时没有细粒度权限,只有"是不是 staff"这一档。

要不要进备份?进了备份,"删除"就不再是真删除,七天保留期形同虚设。不进备份,数据库一恢复,日志整段消失。

要定的事 当时的选择 剩下的别扭
存原文还是脱敏 脱敏后截断 200 字 复盘时看不出用户原话
保留多久 七天 三个月前的投诉查不到
谁能看 staff 一档 没有更细的权限可分
是否进备份 不进 恢复数据库会整段消失

吵到最后定的是一套很将就的方案:

AIAudit.objects.create(
    session_id=session.id,
    prompt_version=SYSTEM_PROMPT_VERSION,
    model=settings.AI_CHAT_MODEL,
    reply=masked_text[:200],
    usage_prompt=usage.prompt_tokens,
    usage_completion=usage.completion_tokens,
    verdict=verdict,          # answer / handoff / failed
    created_at=timezone.now(),
)

脱敏后截断 200 字,按会话 id 索引,保留七天,只有 staff 能看,不进常规备份。七天一到,定时任务批量删。

后来发现最有用的其实不是 reply,是那几个元数据:提示词版本、模型名、token 数、判定类别。主管问"当时为什么这么答",看 prompt_version 和 verdict 比看那 200 字更快定位。文本反而是最容易看走眼的部分。

三个月前那条

当然还是查不到。补存储是十月的事,九月的记录早就不存在了。

最后靠客服自己手机里的聊天截图答的——她当时顺手截了一张发群里吐槽,比我们整套日志都全。这件事我记了挺久:一个花了几周设计的审计方案,被一张截图比下去了。

补完之后倒是赶上过一次用场。十一月有个用户说 AI 让他"清缓存重试",我们按会话 id 查到那条记录,看见 verdict=answer、prompt_version=v3,再对照那版提示词,发现"清缓存"是模型自己编的,提示词里从没写过。要是还只有成功失败两行日志,这事只能不了了之。

对不上的三处

现在数据在三个地方:客服工作台的会话记录、AI 审计表、服务商账单。三边各有各的主键,靠时间勉强能对上,真要追一条完整链路得手工拼。

有次想统计"转人工的会话里有多少最后真被人工回了",分别在两个表里查,数字差了十几个。查了半天发现一边按会话创建时间、一边按审计记录时间,跨天的会话就被算到了不同日期。不是数据错,是口径没统一。

定时任务那个七日清理也出过状况。有回任务卡了两天没跑,表里攒了九天的量,磁盘倒没什么,主要是"我们说保留七天"这句话就不成立了。后来加了个清理延迟告警,才算能自圆其说。

真要做得像样,得给每次 AI 调用发一个贯穿三处的 trace id,工作台、审计、日志全带上。这个改动牵的地方不少,一直排在后面。

VidDown 技术博客里日志相关的还有几篇,口径各有各的乱。

那张九月截图现在还挂在那条群消息里,没人删。我偶尔点开看一眼,主要看当时自己回的那句"我查一下"。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部