AI 回复比用户提问还早?一个空字符串引发的“时间倒流“

发布时间:2026/10/30 7:24:34

AI 回复比用户提问还早?一个空字符串引发的“时间倒流“ 我今天在查 AI 聊天记录时看到一条很离谱的数据assistant message 的 created_at 竟然比触发它的 user message 还早。AI 难道会时间倒流当然不是。最后查下来根因居然是一个空字符串id 。项目背景:考虑需要快速开发,以及方便定位问题和拓展新需求,所以该项目的技术栈选用的是 Next.js Vercel AI SDK Supabase。服务端持久化消息:用户消息在流式响应前存,assistant 消息在 onEnd 回调里用 upsert(..., { onConflict: id }) 存。UI 一切正常,数据库里却是另一个世界。问题一:数据库里 assistant 消息的 id 是空字符串我在 Postgres 表结构中将 id 设置的属性为 primary key。PRIMARY KEY 隐含 NOT NULL,我以为空值必然被拦住。但是居然出现了毫无报错,但是 assistant 的 id 为空字符串的情况。后面我才发现,PRIMARY KEY 能拦住 NULL但拦不住 。在 Postgres 眼里 是一个合法字符串。想要真正的保护得加 CHECK 约束:ALTER TABLE chat_messages ADD CONSTRAINT id_not_empty CHECK (length(trim(id)) 0);问题二:为什么会出现 id 为空字符串的情况根因:AI SDK 只有在你传了 generateMessageId 时才会生成服务端消息 id。不传的话,SDK 内部直接兜底:messageId: messageId ! null ? messageId : 于是持久化回调里拿到的 responseMessage.id 就是 。start chunk 只有在你传了 generateMessageId 时才会带 messageId。不传的话,服务端这份 id 永远不会被覆盖。问题三:时间倒流的真相每一轮 assistant 消息的 id 都是 ,onConflict: id 的 upsert 让它们全部撞到同一行。用一个时间线看会更明显:事件写入 id数据库动作created_at第一次 assistant 回复INSERT 一行10:00第二次 user 提问msg_user_2INSERT 新行10:05第二次 assistant 回复命中同一个主键,UPDATE 旧行仍然是所以并不是 assistant 真的早于 user,而是第二次 assistant 回复没有创建新记录,而是覆盖了第一次那条 id 的旧记录。created_at 记录的是这行数据第一次 INSERT 的时间,不会因为后面的 UPDATE 自动变成当前时间。这就是时间倒流的真相:表面上是时间戳异常,本质上是所有 assistant 回复都被 upsert 到同一行,历史回复一直在被静默覆盖。这不是展示问题,而是数据丢失。那我们应该怎么办?核心修复是让服务端明确生成 assistant message id。比如:import { createIdGenerator } from ai; createAgentUIStreamResponse({ agent, uiMessages: messages, generateMessageId: createIdGenerator({ prefix: msg, size: 16, }), onEnd: async ({ responseMessage }) { await saveMessage(responseMessage); }, });这样 AI SDK 在创建 assistant response message 时,会给它一个稳定的服务端 id,onEnd 里拿到的 responseMessage.id 就不再是 。如果涉及续写已有 assistant 消息,再配合 originalMessages 使用,让 SDK 正确判断这次是在延续旧消息,还是创建一条新的 assistant 消息。数据库层也要加一道兜底,不要让空字符串 id 再混进来:ALTER TABLE chat_messages ADD CONSTRAINT id_not_empty CHECK (length(trim(id)) 0);前者解决源头,后者防止同类坏数据再次入库。最后这个 bug 反而验证了我当初的选型。我选 Vercel AI SDK 就是看中它够薄——出问题时可以直接读源码。这次从症状 → 持久化回调 → SDK 内部 → 根因,只花了几分钟。换成重型黑盒 Agent 框架,同样的问题可能要查比较久。几条教训:用 AI SDK 做服务端持久化,一定要传 generateMessageId(续写场景再加 originalMessages)PRIMARY KEY / NOT NULL ≠ 非空字符串我正在公开构建一个 AI 会议总结应用,这是开发记录的第一篇,后续会持续分享踩坑实录和从 demo 走向生产的全过程。欢迎关注,一起见证它上线。
延伸阅读

更多相关文章

2026/10/29 11:29:04

框架表示法 vs 产生式规则:5 个维度对比结构化与因果式知识建模

框架表示法与产生式规则:5个维度解析结构化与因果式知识建模的抉择在构建专家系统或业务规则引擎时,知识表示方法的选择往往决定了系统的表达能力、推理效率和维护成本。框架表示法与产生式规则作为两种经典的知识建模范式,分别代表了结构化思…

2026/10/29 17:30:02

pandas多维聚合生产实践:滚动计算、列名扁平化与自定义函数规范

1. 项目概述:为什么多维聚合不是“加个groupby”就能搞定的事我在银行数据平台组干了八年,从最早用SQL写几十行嵌套子查询做客户分层,到后来带团队重构整个风险指标计算引擎,踩过的坑比写的代码还多。今天聊的这个主题——“多维聚…

2026/10/29 17:44:33

NI HIL自动化测试05-测试环境的搭建

软件的下载 NI 还是很Open的,下载相关软件很简单,不像dSPACE管理的那么严格,下个软件都那么费劲。登录NI官网,找到 包管理器下载完成后打开,直接在这里下载或者卸载相关的软件软件的安装软件安装顺序 Labview--…

2026/10/30 7:21:15

Sora视频生成API功能详解与开发实践

1. Sora视频生成API核心功能解析Sora视频生成API提供了两种工作模式,分别针对不同场景的视频生成需求。Version 1经典模式支持10-25秒的视频生成,具备完整的参数控制系统;Version 2合作商模式则专注于短视频场景,提供像素级分辨率…

2026/10/30 7:21:15

IDC、机房与家庭宽带IP的技术特征与安全应用

1. IP归属地类型概述:从机房到家庭的网络身份差异每次我们上网冲浪,设备都会被分配一个独特的IP地址作为网络身份证。但很少有人知道,这个IP背后隐藏着截然不同的使用场景和技术特征。作为从业十年的网络工程师,我经常需要根据IP类…

2026/10/30 7:21:15

华为HCIP路由策略与策略路由核心解析

1. 路由策略与策略路由的核心概念解析在华为HCIP认证体系中,路由策略(route-policy)和策略路由(PBR)是网络工程师必须掌握的两种关键流量控制技术。虽然名称相似,但它们的应用场景和实现原理存在本质区别。…

2026/10/30 7:21:15

四种打开cmd方式与工作目录、权限、编码排错实践

1. 先把话说清楚:cmd不是老古董,它是Windows里最短的一条路刚接触Windows运维或者写脚本的时候,很多人对cmd的印象还停留在"黑框框""过时了"。带了新人之后我发现一个挺有意思的现象:讲PowerShell、讲终端、讲…

2026/10/30 7:21:15

操作系统在干什么:抽象、调度、隔离与性能排查

干了几年系统方向,被问得最多的一个问题不是某个内核函数怎么实现的,而是“操作系统到底在干什么”。这个问题听着像入门课第一章,但真要答好,得同时讲清楚三件事:它抽象了什么、它调度了什么、它在哪些地方偷偷骗了你…

2026/10/30 7:16:15

基于YOLOv11的轻量级无人机检测技术解析

1. 项目背景与核心挑战在无人机技术快速普及的今天,反无人机检测已成为公共安全领域的关键课题。传统基于雷达或无线电侦测的方案存在设备笨重、响应延迟高、易受干扰等问题。我们团队基于改进版YOLOv11开发的轻量级检测方法,在保证精度的同时将模型体积…

2026/10/29 17:05:52

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/29 17:06:02

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/29 17:06:13

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/30 0:00:46

NCP1342高频准谐振反激控制器:从设计约束到验收的完整方案

简介:NCP1342 高频准谐振反激控制器应用介绍译文文档,面向电源设计工程师、硬件研发人员及开关电源学习者,帮助读者跨越英文原版资料的语言门槛,系统理解这款高集成度 QR Flyback 控制器的设计要点。文档围绕芯片核心特性展开&…

2026/10/30 0:00:46

NCP1342准谐振反激电源设计:从选型到验收的全流程解析

简介:这份文档面向电源设计工程师与开关电源学习者,系统梳理NCP1342高频准谐振反激控制器的应用要点,帮助读者快速理解这款高集成度离线电源变换器控制芯片的工作机制与设计方法。内容涵盖芯片核心特性、引脚功能定义、电气特性参数表、最大额…

2026/10/30 0:00:46

Web系统自动登出机制设计与实现全解析

1. 系统自动登出机制的设计初衷在各类Web应用和后台管理系统中,自动登出功能早已成为标配。这个看似简单的功能背后,实际上涉及用户安全、资源管理和体验优化的多重考量。作为从业十多年的老开发,我见过太多因为登出逻辑设计不当导致的安全事…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑