跳到主要内容

你的 Prompt 时钟是正确性边界,而非日志字段

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个调度代理将客户的入职电话订在了周二,而不是周三。调查花费了两天时间。Prompt 没问题。模型没问题。日历工具也没问题。错误在于系统 Prompt 携带了一个早一小时的 current_time 字段,当时请求正通过一个在 UTC 午夜前刚刚构建的缓存前缀(cached prefix)进行路由。当代理解析出“明天上午 10 点”并调用预订工具时,“明天”所指的日期对于东京的用户来说已经是“今天”了。

代理根本无法察觉。它没有任何感知手段。LLM 没有时钟。它们只有你在 Prompt 中提供给它们的字符串,并且它们会像对待用户问题一样权威地对待这个字符串——也就是说,完全信任,不加怀疑,也没有第二个来源可以进行交叉比对。

大多数团队在抽象层面都知道这一点,但仍然将注入的时间戳视为日志字段:某种有则更好、渲染到系统 Prompt 中提供上下文、不属于任何人的明确责任、不属于任何人的正确性边界的内容。这种构想是错误的。时间戳是一个正确性边界。每一个依赖于“现在”的代理行为——调度、过期、重试窗口、“最近”、“明天”、“五分钟内”、检索文档的新鲜度检查——都运行在你生成的时间管道之上,并继承了该管道所拥有的每一个 Bug。

你的时钟欺骗代理的四种方式

有四种不同的 Bug 会在模型内部产生错误的“现在”,且它们的失败方式各不相同。修复了其中一个并发布产品的团队通常会认为他们解决了整个类别的问题。

时区默认值。你的服务器运行在 UTC,因为这是明智的服务器默认设置。有人在 Prompt 组装代码中写了 datetime.now(),但没有提供时区参数,因为“服务器是 UTC,所以 UTC 就行”。对于当地时间晚上 10 点的加州用户,UTC 已经是明天了;代理请求“今天的日程”现在会获取错误的日历日期。对于早上 7 点的东京用户,UTC 还是昨天;“我今天完成锻炼了吗”会返回昨天的锻炼记录。这个 Bug 根据一天中的时间和用户位置而具有确定性,这意味着它对某些用户复现,而对另一些用户不复现,这导致它需要很长时间才能暴露出来。

陈旧的缓存 Prompt。出于成本考虑,你会缓存系统 Prompt。Prompt 缓存通过匹配前缀工作;任何字节的变化都会使缓存失效。一个天真的实现会在每次请求时用新鲜的时间戳重新构建系统 Prompt,导致缓存永远无法命中——于是有人将时间戳移到了一个稳定的位置“以保持缓存热度”,现在时间戳成了缓存键的前缀,这意味着它被冻结在了构建前缀时的状态。代理现在得到的是一个看起来权威但实际上已经延迟了数分钟、数小时,甚至在极端情况下延迟了整整一天的 current_time。这里存在真正的架构权衡冲突,团队往往走向相反的方向,而这两个方向都不正确:要么你在每次调用时破坏缓存,要么你提供陈旧的时间。正确的答案是稳定前缀不包含任何时间,而“现在”存在于它所属的逐轮用户消息中——但这需要有人意识到这种冲突的存在。

夏令时(DST)切换。在仍保留夏令时的地区,当地时钟每年会跳动两次,每次一小时。代理推断“将此安排在明天下午 3 点”,它从注入的日期中提取“明天”,加上“15:00”,然后将其交给日历 API,而 API 会根据被告知使用的任何时区来解释 15:00。如果代理的时间字符串是在夏令时切换前构建的,而预订在切换后触发,那么小时数就是错的。同样的 Bug 也适用于过期时间:“此链接 24 小时内有效”如果在夏令时切换的错误一侧打上时间戳,会提前或延后一小时过期,导致会话在用户预期前 40 分钟失效,从而引发支持电话。

长期运行代理中的上下文过期。现代代理不再是简单的请求-响应模式——它们会运行数分钟,有时甚至数小时,经历多次工具调用。系统 Prompt 在第 0 步组装。在第 40 步,工具调用触发。除非你刻意去刷新,否则代理在第 40 步推断所用的 current_time 值就是第 0 步时的值。在第 0 步决定并在第 40 步执行的“5 分钟后重试”,现在变成了 45 分钟前或 45 分钟后,具体取决于代理如何解释它自己的指令。MCP 会话和 OAuth 令牌在这些长期运行中也会过期,原因是一样的:计算“何时失效”是针对一个已不再适用的时间快照进行的。

这里的每一个都是一类独立的事故。“我们修复了时区 Bug”是一个真实的陈述,但并不意味着“我们修复了时间 Bug”。

时间是事实,而非装饰

关键的重构在于:像对待代理预期正确推断的任何其他事实一样对待“现在”。事实有来源,有新鲜度窗口,有明确的类型,并且出现在 Prompt 中代理预期会实际读取而非随眼一扫的位置。

具体而言,这意味着时间上下文应该是:

  • 明确断言,而不是埋在序言中。一行写着 当前时间是 2026-04-23T14:22:00-07:00 (太平洋夏令时间)。用户的当地日期是周四。 是代理可以引用的事实。而在样板代码块中打上的模糊的“今天是 2026 年 4 月 23 日”只是装饰。
  • 带时区限定,同时包含偏移量和时区名称。仅靠偏移量 (-07:00) 无法在夏令时切换期间消除歧义。IANA 时区名称可以,并且它携带了未来日期的转换规则。
  • 分解成代理实际使用的形式。代理询问“今天是星期几”的频率远超你的想象,而 LLM 在根据纯日期计算星期几方面表现极差。在注入的事实中包含星期几,这样模型就不必进行它不擅长的模数运算。
加载中…
References:Let's stay in touch and Follow me for more thoughts and updates