发布时间:2026/7/13 3:20: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/7/13 3:20:34

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

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

2026/7/13 3:20:34

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

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

2026/7/13 3:20:34

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

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

2026/7/13 6:40:47

Qt 6.5 .pro/.pri 配置实战:3个模块化项目构建与 $$PWD 路径管理

Qt 6.5 模块化工程实战:.pro/.pri 配置与 $$PWD 路径管理精要当Qt项目从简单的Demo演变为包含多个子模块的复杂系统时,如何优雅地组织工程结构成为每个开发者必须面对的挑战。本文将带你深入Qt 6.5的工程配置体系,通过三个典型模块的实战案例…

2026/7/13 6:40:47

LayerNorm与RMSNorm对比:大模型归一化技术原理与LLaMA实现

在深度学习模型训练中,归一化技术一直是稳定训练过程、加速收敛的关键组件。LayerNorm(层归一化)作为Transformer架构中的标准配置,多年来在自然语言处理领域占据主导地位。然而,随着大模型时代的到来,RMSN…

2026/7/13 6:40:47

bitArt 系列 01:架构

最近整理一个 HarmonyOS 像素画编辑器项目 bitArt,发现它很适合作为复杂 ArkTS 应用的拆解案例。它不是一个只有按钮和列表的 Demo,而是一个完整的移动端创作工具:中间是像素画布,周围有工具栏、图层面板、调色板、动画帧时间轴、…

2026/7/13 6:40:47

专业铸就口碑!细数黑龙江移远科技的核心服务优势

在黑龙江无线通信行业,供应商数不胜数,但能长期稳定服务政企、景区、林场、油田、市政、工程企业的本土品牌,黑龙江移远科技始终凭借专业、靠谱、本土化的服务优势,赢得市场认可与客户信赖。第一大优势:深耕本土&#…

2026/7/13 6:40:46

AI视频生成技术实战:从扩散模型到工程化应用全解析

最近在技术圈里,一个名为"2026红尘CK冲榜宣传片"的项目引起了广泛讨论。很多开发者第一眼看到这个标题时都会感到困惑——这到底是游戏宣传片、影视项目,还是某种新型的技术应用?实际上,这个项目背后涉及的是当前最热门…

2026/7/13 6:35:46

蓝牙5.4音频模块开发实战:低功耗LC3编码与射频设计

1. 项目背景与核心组件选型在无线音频传输领域,蓝牙5.4标准的推出标志着LE Audio技术正式进入实用阶段。我们选择的IDC777-1模块作为射频前端,搭配STM32L152RE主控的方案,能够实现专业级无线音频传输质量。这套组合的核心优势在于&#xff1a…

2026/7/13 6:38:38

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/12 0:01:29

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/12 0:01:29

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/13 0:00:24

广氟 PTFE 高速线缆膜 —— 高端线缆绝缘材料新选择

PTFE高速线缆膜的基本概念与特点 PTFE 高速线缆膜是以聚四氟乙烯树脂为原料,经膨化双向拉伸制成的多孔绝缘薄膜,作为高速高频通信线缆的核心介质材料,内部形成均匀连通的微孔结构,兼具极低介电常数与介电损耗,能有效降…

2026/7/12 11:21:32

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…