标签 分类 下的文章

Claude又双叒叕修好了!

刚刚,Anthropic发布声明,称已经找到并解决了两个影响Claude响应质量的问题,并承诺会继续监控任何潜在的质量问题。

这已经是短短10天内,Anthropic第二次承认并修复模型质量问题了。

两个bug,一个月的煎熬

根据Anthropic在状态页面公布的详细信息:

这次发现的问题比之前更复杂:

第一个bug影响了Claude Sonnet 4的一小部分请求,从8月5日持续到9月4日,其中8月29日到9月4日期间影响加剧。

第二个bug则同时影响了Claude Haiku 3.5和Claude Sonnet 4,时间跨度为8月26日到9月5日。

Anthropic特别强调:

我们从不会因为需求或其他因素而故意降低模型质量。

显然,这句话是在回应社区中广泛流传的「降智阴谋论」,很多用户怀疑Anthropic在高峰期故意让模型变笨来节省算力。

积怨已久的用户

此次降智事故也让Claude失去了一批订阅用户。

Katie 'Monsieur Clicky' Nied(@KatieNiedz)就称:

请让Claude恢复到以前的样子。我会立刻重新订阅的。 (8月的改动太严重了。我最终放弃了)

38 Trilly Incoming(@rrektcapital)也吐槽:

嗯,感觉你们确实故意降智了。

Kolsonos(@Kolsonos):

好吧朋友,但我该联系谁来延长我的订阅以补偿我在Claude Code中遇到的缓慢响应时间?

信任危机

这已经不是Anthropic第一次承认模型质量问题了。

图片

早在上个月8月30日,Anthropic曾确认Opus 4.1和Opus 4出现质量下降,当时的问题是由于推理堆栈的更新导致的。

用户遇到了智能水平下降、响应格式错误以及Claude Code中工具调用失败等问题。

更让用户不满的是透明度问题。

上次Opus的问题已经存在好几天,但Anthropic只在事后才告知用户。

这种「先瞒后报」的做法,让许多重度用户感到被背叛。

并且,也只是声称故障,并没提及任何补偿措施。

不过,我又恢复了Max订阅……

但这种反复的质量波动,确实让人感到疲惫。谁知道你这次真好假好……

最后,Kolsonos说到:

老板,我累了……


[1]

上一次的官方事件报告: https://status.anthropic.com/incidents/h26lykctfnsz

[2]

本次官方事件报告: https://status.anthropic.com/incidents/72f99lh1cj2c




关于 Claude Code 和 Codex 的使用/交流,欢迎进《Claude Codex》群交流,任何相关问题都有热心群友第一时间解答(禁广告,中转谢绝入内)~
图片
由于群满(超200人)了不能直接进,请先进中转群(见评论区)后加我,备注"CC" 即可,我稍后会拉你进群。


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

刚刚,Claude 发布了一个重磅更新:可以直接生成Excel和PPT了!

现在,Claude可以直接创建和编辑各种文件:

Excel表格、Word文档、PPT幻灯片、PDF文件,通通不在话下。

官方演示视频:

Anthropic 用户关系负责人Alex 特别强调:

代码智能体为软件工程做的事情,很快就会扩展到所有知识工作领域,这只是开始

能做的很多

要注意的是,这次的更新,并不是说像之前那样用前端代码写点蓝紫渐变的样式就完了,而是会输出真正可用的文件

用你的Office 办公软件就可以直接打开的那种。

技术方案上,Anthropic给Claude配备了一个私有计算机环境,让它能在里面写代码、运行程序,最终生成你需要的各种格式文件。

这个环境让Claude能做很多很酷的事情:

高级数据分析:上传原始数据,返回清洗后的数据、统计分析、图表和书面洞察报告

图像视频处理:裁剪、调整、各种操作都能搞定

处理各类文件:GIF动图、LaTeX文档、ZIP压缩包,什么格式都能处理

甚至是,跨格式转换

你可以上传PDF报告让它生成PPT,分享会议记录让它整理成格式化文档,上传发票让它整理成带计算功能的Excel表格。

Claude处理所有繁琐的技术工作,按你需要的方式呈现信息。

开启方式

目前这个功能作为预览版提供给Max、Team和Enterprise用户,Pro用户还需要等几周。

具体开启步骤:

  1. 进入设置页面,找到「实验性功能」部分

  2. 开启「升级的文件创建和分析」选项

选中后会默认关掉Analysis tool 的实验功能(相对新功能而言,这个过时了)。

然后,你就可以上传相关文件或描述你的需求了。

Claude会在后台完成所有工作,你可以下载完成的文件,或者直接保存到Google Drive。

实测

有Max账号的我,自然也第一时间测了一把这个新功能。

我直接Claude的更新公告内容全选后贴进去,并说:帮我把这次更新的内容做成一个PPT介绍

然后,它就咔开始整活了……

先是一顿分析 + 执行各种命令:

然后,就开始生成ppt 了:

很快就生成了一份pptx 的文件出来,可以直接预览,也可以点击下载后用办公软件打开:

来看一眼:

还不错啊!

但,有个问题是:

我明明用中文和你对话,你怎么给我生成了英文版PPT呢……

我告诉它「用中文」,于是:

点击,就能播放演示了。

质量还不错,和我花一小时做的ppt 相比,好像也没太多差别。

但……有点太朴素了,有人可能喜欢更花哨一些?

于是我让它浮夸一些:

结果我得到了这个:

过于浮夸了……(也没有加上过渡动画)

相信仔细调一调prompt,应该能有更好的质量。

其实对我来说,朴素版就很好了。

背后则是:又一批创业公司要完了

这次更新的背后,则是:又有一大批公司要被干死了。

首当其冲的是那些AI PPT生成公司。

过去一年涌现出的各种「一键生成PPT」的产品,现在Claude直接就能做了,而且还能处理Excel、Word、PDF等各种格式。

那些做AI文档处理、数据分析可视化、格式转换的创业公司,恐怕都要重新思考自己的定位了。

以及,让人心疼的还有Manus。

在禁止这家中国背景的公司使用API 后,Anthropic 今天又放出了Manus 主打的办公系列功能直接对标。

从现在起,职场打工人们在Claude 中就能完成几乎所有任务了。

从模型到应用

值得注意的是,Claude背后的Anthropic,正在将触手从模型伸向应用

自从今年5月全面推出的Claude Code之后,其已然成为开发者的首选工具(暂不算其作死降智被codex 薅走了的用户)。

而仅仅三个月时间,Claude Code的使用量就增长了10倍以上,目前已经产生超过5亿美元的年化收入。

这个数字实在是过于惊人:

一个工具在三个月内就达到了许多独角兽公司需要数年才能达到的收入规模。

而更为惊人的则是:

Claude Code干死Cursor等AI编程工具只是第一步。

其目标,显然是要将在Claude Code中的成功方法论,scale 至全系列应用中去——

最终打造无数个垂类Claude Code 应用来。

而结合此前的130亿美元暴力融资,外加近期的模型莫名降智事件……随着这次的功能发布,也许一切也都能说得通了。

可以说,Anthropic的野心,已经昭然若揭了。

而留给创业者的,还有多少空间呢

创业公司们,你们要小心了




[1]

功能开启页面: https://www.claude.ai/settings/features

[2]

官方公告: https://www.anthropic.com/news/create-files

[3]

Alex Albert推特原文: https://twitter.com/alexalbert__/status/1965429651662327928


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

Mira Murati 的新公司终于发声了!

Thinking Machines Lab 今天正式推出了他们的研究博客 Connectionism,第一篇文章就直接瞄准了 LLM 推理中让人头疼的「非确定性」问题。

这家由前 OpenAI CTO(及前临时 CEO) Mira Murati 创立的公司,在今年 7 月刚完成了约 20 亿美元的种子轮融资,估值达到 120 亿美元。投资方包括 Andreessen Horowitz(领投)、Nvidia、AMD、Cisco 等科技巨头。

值得注意的是:在拿到如此巨额融资之前,公司还没发布任何产品。

LLM「不确定性」的真相

这第一篇博文《击败大语言模型推理中的非确定性》直击要害。

如果你是算法相关从业者,你应该有发现:同样的输入,LLM 有时会给出不同的输出

即使设置了相同的随机种子,结果还是会变化。

很多人以为是 GPU 并发执行和浮点数运算的锅。

但 Thinking Machines 的研究发现:真正的罪魁祸首是批次不变性缺失

什么意思?当你向 LLM 发送请求时,服务器会根据当前负载情况,把你的请求和其他请求打包成不同大小的批次处理。问题就出在这里——

相同的输入在不同批次大小下会产生不同的结果

这就像你去餐厅点菜,你点的菜味道竟然会因为厨房同时在做几道菜而改变。

听起来很荒谬?

但这就是现在 LLM 推理系统的现状。

浮点数的「蝴蝶效应」

根本原因在于浮点数的非结合性:(a+b)+c ≠ a+(b+c)。不同的加法顺序会产生微小差异,这种差异在深度神经网络中层层放大。

具体到 LLM 推理中,矩阵乘法、RMSNorm、注意力机制等核心操作,在不同批次大小下会采用不同的约简策略。你的请求结果竟然依赖于服务器同时在处理多少其他请求——

这太魔幻了。

让内核「批次不变」

Thinking Machines 提出的解决方案很直接:实现批次不变的内核。

RMSNorm:采用数据并行策略,避免分割约简。

矩阵乘法:使用固定内核配置,避免 Split-K 策略。

注意力机制:采用固定分割大小策略,确保约简顺序一致。

实验结果可谓是令人惊讶:

在 1000 次采样中,原本会产生 80 个不同的完成结果

但在启用批次不变内核后,所有结果完全一致

当然,这种确定性是有代价的。未优化版本性能下降约 2 倍,但经过改进后性能损失已经可以接受。

Connectionism:不只是一个名字

有意思的是,博客名「Connectionism」是 1980 年代研究神经网络与生物大脑相似性的 AI 子领域名称。

Mira Murati(@miramurati)表示:

Thinking Machines 使命的重要部分是提高人们对 AI 的科学理解,并与更广泛的研究社区合作。今天推出 Connectionism 来分享我们的一些科学见解。

联合创始人 Lilian Weng(@lilianweng)补充了一个有趣的历史细节:

除了 Connectionism 与 AI 领域早期的联系,以及强调神经网络与人类大脑的相似性这个有趣的事实外,第一代 Thinking Machines 的旗舰产品就叫 Connection Machine。

豪华团队阵容

除了 Mira Murati,核心团队还包括 OpenAI 联合创始人 John Schulman、前研究 VP Barret Zoph、前 AI 安全与机器人 VP Lilian Weng 等人。

而 Andrew Tulloch 甚至拒绝了 Zuckerberg 15 亿美元回 Meta 的邀请,选择继续与 Murati 一起创业。

团队约 30 人,其中三分之二来自 OpenAI。技术岗位年薪高达 45-50 万美元

Bob McGrew 和 Alec Radford 等 OpenAI 核心研究者担任顾问。

Thomas Ip(@_thomasip)精辟总结道:

LLM 推理非确定性不只是浮点数非结合性或 GPU 并发执行,核心罪魁祸首是批次方差,服务器负载不可预测地改变了数值计算。批次不变内核解锁了真正的可重复性,终于让强化学习『在线策略』变得可行。

这项工作的意义不仅在于解决了一个技术难题,更重要的是为 LLM 的可重复性和可靠性提供了科学方法。尤其是对强化学习等对一致性要求极高的应用场景,该文具有重要价值。

科学确实在分享中变得更好。




下为全文

击败大语言模型推理中的非确定性

来源[1] https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/

发布时间: 2025年9月10日

目录

  • 引言
  • 原罪:浮点数非结合性
  • 为什么内核不总是按相同顺序相加数字?
  • 什么时候需要原子加法?
    • 批次不变性和"确定性"
  • 如何使内核批次不变?
    • 批次不变的RMSNorm
    • 批次不变的矩阵乘法
    • 批次不变的注意力机制
  • 实现
  • 实验
    • 生成结果的非确定性程度如何?
    • 性能
    • 真正的在线策略强化学习
  • 结论
  • 引用


可重复性是科学进步的基石。然而,从大语言模型中获得可重复的结果极其困难。

例如,你可能观察到向ChatGPT多次提出同一个问题会得到不同的结果。这本身并不令人惊讶,因为从语言模型获得结果涉及"采样"过程——

将语言模型的输出转换为概率分布并概率性地选择一个token。

更令人惊讶的是,即使我们将温度调整到0(这意味着LLM总是选择概率最高的token,称为贪婪采样),使采样理论上变为确定性,LLM API在实践中仍然不是确定性的(见过往讨论这里[2]这里[3]这里[4])。即使使用vLLM或SGLang等开源推理库在自己的硬件上运行推理,采样仍然不是确定性的(见这里[5]这里[6])。

但是为什么LLM推理引擎不是确定性的呢?

一个常见的假设是浮点数非结合性和并发执行的某种组合导致了基于并发核心谁先完成的非确定性。我们将这称为LLM推理非确定性的"并发+浮点数"假设。例如,最近的一篇arXiv预印本[7]写道:

GPU中的浮点运算表现出非结合性,意味着(a+b)+c≠a+(b+c),这是由于有限精度和舍入误差造成的。这一特性直接影响transformer架构中注意力分数和logits的计算,其中多个线程的并行操作可能基于执行顺序产生不同的结果。

你也可以在其他地方找到重复的"并发+浮点数"假设,比如这里[8]有速度权衡,为了使端点快速,使用了GPU,它们进行并行[非确定性]计算。任何现代GPU神经网络计算都会受到这些影响。),或这里(https://x.com/hosseeb/status/1773146428594090473 非确定性计算。任何现代GPU神经网络计算都会受到这些影响。)这里因为GPU高度并行化,每次执行时加法或乘法的顺序可能不同,这可能级联为输出的微小差异。

虽然这个假设并非完全错误,但它没有揭示全貌。例如,即使在GPU上,对相同数据重复运行相同的矩阵乘法总是会提供按位相等的结果。我们确实在使用浮点数。我们的GPU确实有很多并发性。为什么在这个测试中我们没有看到非确定性?

A = torch.randn(20482048, device='cuda', dtype=torch.bfloat16)
B = torch.randn(20482048, device='cuda', dtype=torch.bfloat16)
ref = torch.mm(A, B)
for _ in range(1000):
    assert (torch.mm(A, B) - ref).abs().max().item() == 0

要理解LLM推理非确定性的真正原因,我们必须深入研究。

不幸的是,即使定义LLM推理确定性的含义也很困难。或许令人困惑的是,以下陈述都同时为真:

  1. GPU上的某些内核是非确定性的
  2. 然而,语言模型前向传播中使用的所有内核都是确定性的
  3. 此外,LLM推理服务器(如vLLM)的前向传播也可以声称是确定性的
  4. 尽管如此,从使用推理服务器的任何人的角度来看,结果是非确定性的

在这篇文章中,我们将解释为什么"并发+浮点数"假设没有抓住要点,揭露LLM推理非确定性背后的真正罪魁祸首,并解释如何击败非确定性并在LLM推理中获得真正可重复的结果。

原罪:浮点数非结合性

在讨论非确定性之前,解释为什么会有数值差异是有用的。毕竟,我们通常认为机器学习模型是遵循结构性规则(如交换律或结合律)的数学函数。难道不应该有一个"数学上正确"的结果,我们的机器学习库应该提供给我们吗?

罪魁祸首是浮点数非结合性。也就是说,对于浮点数:

(a+b)+c≠a+(b+c)

(0.1 + 1e20) - 1e20
>>> 0
0.1 + (1e20 - 1e20)
>>> 0.1

讽刺的是,破坏结合律正是使浮点数有用的原因。

浮点数有用是因为它们允许"动态"的精度级别。为了解释起见,我们将使用十进制(而不是二进制),其中浮点数的格式为尾数×10^指数。我们还将为尾数使用3位数字,为指数使用1位数字。

例如,对于值3450,我们可以精确地表示为3.45×10³。我们也可以表示更小的值,如0.486为4.86×10⁻¹。通过这种方式,浮点数允许我们表示非常小和非常大的值。在科学中,我们可能说浮点数允许我们保持恒定数量的"有效数字"。

如果你将两个具有相同指数的浮点数相加,它看起来类似于整数加法。例如,123(1.23×10²)+ 456(4.56×10²)结果为579(5.79×10²)。

但是当我们将两个具有不同指数的浮点数相加时会发生什么,比如1230和23.4?在这种情况下,精确结果是1253.4。然而,我们一次只能保持3位数字的精度。因此浮点加法会丢弃最后2位数字并获得值1.25×10³(或1250)。

我们需要3位精度来表示1230,需要3位精度来表示23.4。然而,将这两个数字相加的结果需要5位精度来表示(1253.4)。我们的浮点格式必须丢弃末尾的34。在某种意义上,我们在相加之前实际上将原始的23.4舍入为20.0。

然而,此时我们已经破坏了信息。注意,每次我们将两个具有不同"尺度"(即不同指数)的浮点数相加时,这种情况都可能发生。实际上,将具有不同指数的浮点数相加一直在发生。事实上,如果我们能保证永远不需要不同的指数,我们就可以只使用整数!

换句话说,每次我们以不同的顺序将浮点数相加时,我们可能得到完全不同的结果。举一个极端例子,根据顺序的不同,对这个数组求和有102种不同的可能结果。

import random

vals = [1e-101e-51e-21]
vals = vals + [-v for v in vals]

results = []
random.seed(42)
for _ in range(10000):
    random.shuffle(vals)
    results.append(sum(vals))

results = sorted(set(results))
print(f"There are {len(results)} unique results: {results}")

# 输出:
# There are 102 unique results: [-8.326672684688674e-17, -7.45931094670027e-17, ..., 8.326672684688674e-17]

虽然这是非相同输出的根本原因,但它并没有直接回答非确定性来自哪里。它没有帮助我们理解为什么浮点值会以不同的顺序相加,何时发生这种情况,以及如何避免。

答案在于内核是如何实现的。

为什么内核不总是按相同顺序相加数字?

如上所述,对于内核为什么以不同顺序相加数字的一个常见解释是"并发+浮点数"假设。该假设声称,如果并发线程完成的顺序是非确定性的,并且累积顺序依赖于并发线程完成的顺序(比如原子加法),我们的累积顺序也将是非确定性的。

令人困惑的是,虽然这可能导致非确定性内核,但并发性(和原子加法)最终完全不涉及LLM推理非确定性!为了解释真正的罪魁祸首是什么,让我们首先理解为什么现代GPU内核很少需要原子加法。

什么时候需要原子加法?

通常,GPU会在许多"核心"(即SM)上并发启动程序。由于核心之间没有固有的同步,如果核心需要彼此通信,这就带来了挑战。例如,如果所有核心都必须累积到同一个元素,你可以使用"原子加法"(有时称为"fetch-and-add[9]")。原子加法是"非确定性的"——结果累积的顺序纯粹取决于哪个核心先完成。

例如,想象你正在用100个核心约简一个100元素的向量(例如torch.sum())。虽然你可以并行加载所有100个元素,但我们最终必须约简到单个元素。实现这一点的一种方法是使用某种"原子加法"原语,硬件保证所有加法都会被处理,但不保证顺序。

原子加法确保每个核心的贡献都会反映在最终和中。然而,它不保证贡献被相加的顺序。顺序完全取决于哪个核心先完成,这是一个非确定性属性。因此,多次执行相同的并行程序可能导致非确定性输出。

这通常是人们所说的"非确定性"——你用完全相同的输入执行同一个内核两次,得到不同的结果。这被称为运行到运行的非确定性,即你用完全相同的依赖项运行同一个python脚本两次,但得到不同的结果。

虽然并发原子加法确实使内核非确定性,但绝大多数内核都不需要原子加法。实际上,在LLM的典型前向传播中,通常没有一个原子加法存在

考虑到并行化约简可以从原子加法中受益,这可能令人惊讶。原子加法最终不被需要有两个主要原因。

  1. 沿着"批次"维度通常有足够的并行性,我们不需要沿着约简维度并行化。例如,假设我们不是约简单个100维向量,而是并行约简500个向量。在这种情况下,我们可以在每个核心中约简整个向量,并允许每个核心操作不同的向量。

  2. 随着时间的推移,大多数神经网络库都采用了各种策略来在不牺牲性能的情况下实现确定性。例如,我们可以执行"分割"(或树)约简,将100元素约简分割为五个20元素约简(从而实现五路并行性)。然后,为了组合剩余的五个元素,我们可以执行单独的"清理"约简(不并行化,但操作的元素足够少以保持廉价)或利用信号量(确保每个并发线程块将以确定性顺序累积)。

由于这两个因素,对于绝大多数神经网络操作来说,避免原子加法的性能损失是微不足道的。

仍然有几个常见操作避免原子加法会有显著的性能损失。例如,PyTorch中的scatter_adda[b] += c)。然而,在LLM中常用的只有FlashAttention反向传播。

然而,LLM的前向传播不涉及需要原子加法的操作。因此,LLM中的前向传播实际上是"运行到运行确定性的"。

从推理服务器的角度来看,它确定性的。给定完全相同的用户请求,它总是提供相同的确定性输出。

维基百科写道,"确定性算法是一种算法,给定特定输入,总是产生相同输出。"在这种情况下,给定完全相同的输入(即推理服务器正在处理的确切请求),前向传播总是产生完全相同的输出。

然而,前向传播本身是"确定性的"并不足以确保包含它的系统是确定性的。例如,如果我们请求的输出依赖于并行用户请求(例如批量归一化)怎么办?由于每个单独的请求无法知道并行请求将是什么,从他们的角度来看,我们的整体LLM推理也是非确定性的!

事实证明,我们请求的输出确实依赖于并行用户请求。不是因为我们以某种方式在批次间泄漏信息——而是因为我们的前向传播缺乏"批次不变性",导致我们请求的输出依赖于前向传播的批次大小

批次不变性和"确定性"

为了解释批次不变性,让我们简化系统,仅查看矩阵乘法。你可以假设所有矩阵乘法实现都是"运行到运行确定性的"。然而,它们不是"批次不变的"。换句话说,当批次大小改变时,批次中的每个元素可能得到不同的结果。

从数学角度来看,这是一个相当不寻常的属性。矩阵乘法应该沿着批次中的每个元素"独立"——批次中的其他元素或批次有多大都不应该影响批次中特定元素的计算结果。

然而,正如我们可以实验性观察到的,这并不是真的。

import torch
torch.set_default_device('cuda'

B = 2048
D = 4096
a = torch.linspace(-10001000, B*D).reshape(B, D)
b = torch.linspace(-10001000, D*D).reshape(D, D)
# 通过取批次的第一个元素进行矩阵向量乘法
out1 = torch.mm(a[:1], b)
# 进行矩阵矩阵乘法然后取批次的第一个元素
out2 = torch.mm(a, b)[:1]
print((out1 - out2).abs().max()) # tensor(1669.2500, device='cuda:0')

注意这"运行到运行确定性的"。如果你多次运行脚本,它将确定性地返回相同的结果。

然而,当非批次不变内核用作更大推理系统的一部分时,系统可能变得非确定性。当你向推理端点发出查询时,服务器承受的负载量从用户的角度来看实际上是"非确定性的"。负载决定了内核运行的批次大小,从而改变每个单独请求的最终结果!

虽然推理服务器本身可以声称是"确定性的",但对于单个用户来说情况不同。从单个用户的角度来看,其他并发用户不是系统的"输入",而是系统的非确定性属性。这使得LLM推理从每个用户的角度来看都是"非确定性的"。

如果你将内核不具有不变性的某些属性(即批次大小)与该属性的非确定性(即服务器承受的负载)组合起来,你就得到了一个非确定性系统。

换句话说,几乎所有LLM推理端点都是非确定性的主要原因是负载(因此批次大小)非确定性地变化! 这种非确定性并不是GPU独有的——从CPU或TPU提供的LLM推理端点也会有这种非确定性来源。

所以,如果我们想在推理服务器中避免非确定性,我们必须在内核中实现批次不变性。为了理解如何实现这一点,让我们首先看看为什么内核一开始就没有批次不变性。

如何使内核批次不变?

为了使transformer实现批次不变,我们必须使每个内核批次不变。幸运的是,我们可以假设每个逐点操作都是批次不变的。因此,我们只需要担心涉及约简的3个操作——RMSNorm、矩阵乘法和注意力机制。

方便的是,这些也按难度递增排序。每一个都需要一些额外的考虑来以合理的性能实现批次不变性。让我们首先讨论RMSNorm。

批次不变的RMSNorm

数据并行RMSNorm 理想情况下,我们希望避免在并行化策略中核心之间的通信。实现这一点的一种方法是将一个批次元素分配给每个核心,从而保证每个约简完全在单个核心内完成。这就是所谓的"数据并行"策略,因为我们只是沿着不需要通信的维度并行化。在这个例子中,我们有四行和四个核心,饱和了我们的核心。

RMSNorm可以实现为:

# x: [batch_size, hidden_dim]
# weight: [hidden_dim]
def rms_norm(x, weight):
    return x * torch.rsqrt(torch.mean(x ** 2, dim=-1, keepdim=True)) * weight

批次不变性的要求是每个元素的约简顺序必须固定,无论内核的批次大小如何。注意这并不意味着我们必须总是使用相同的约简策略。例如,如果我们改变要约简的元素数量,即使约简策略发生变化,我们仍然可以是批次不变的。

因此,我们只有在批次大小影响约简策略时才会破坏批次不变性。

让我们看看RMSNorm的标准并行化策略。通常,并行算法受益于最小化核心间的通信。对于本讨论的目的,你可以假设当我们提到"核心"时,我们指的是SM。更具体地说,这里重要的属性是我们内核启动的线程块数量大于SM的数量。所以,我们可以开始的一个策略是将每个批次元素分配给一个核心,如上图所示。

增加批次大小不会影响我们的约简策略;如果批次大小为200为我们的内核提供了足够的并行性,那么批次大小为2000肯定会提供足够的并行性。

更大批次的数据并行RMSNorm 将数据并行策略扩展到更大的批次相当简单——不是让每个核心处理一行,而是允许每个核心顺序处理不同的行。这保持了批次不变性,因为每个批次元素的约简策略保持相同。

另一方面,减少批次大小可能带来挑战。因为我们将每个批次元素分配给一个核心,减少批次大小最终会导致核心数量多于批次元素,使一些核心闲置。

遇到这种情况时,一个好的内核工程师会使用前一节提到的解决方案之一(原子加法或分割约简),保持良好的并行性,从而获得良好的性能。不幸的是,这改变了约简策略,阻止了这个内核成为批次不变的。

分割约简RMSNorm 如果我们有小的批次大小,我们的数据并行策略可能不再有足够的并行性来饱和我们的核心。在这种情况下,在多个核心之间"分割"约简可能更有效,允许我们充分利用GPU。然而,这失去了批次不变性,因为我们不再以相同的顺序约简每个元素。

最简单的解决方案是完全忽略这些情况。这并非完全不合理——小批次大小意味着内核可能执行得很快,所以减速可能不是灾难性的。

如果我们被迫优化这种用例,一种方法是始终使用一个约简策略,即使对于非常小的批次大小也有足够的并行性。这样的约简策略会导致较大批次大小的过量并行性,但允许我们在整个大小范围内实现不错(但不是峰值)的性能。

批次不变的矩阵乘法

数据并行矩阵乘法 类似于RMSNorm,矩阵乘法的标准并行化策略是"数据并行"策略,将整个约简保持在一个核心中。最直接的思考方式是将输出张量分割为2D块,并将每个块分配给不同的核心。然后每个核心计算属于该块的点积,再次在一个核心内执行整个约简。

从本质上讲,你也可以将矩阵乘法视为逐点操作后跟约简。然后,如果我们通过将输出分块来并行化矩阵乘法,我们就有了一个类似的"数据并行"内核策略,将每个约简保持在一个核心内。

同样类似于RMSNorm,我们的"批次"维度(M和N)可能变得太小,迫使我们沿着约简维度(K)分割。尽管有两个"批次"维度,矩阵乘法也要求我们每个核心有更多的"工作",以便有效地利用张量核心。例如,如果你有一个[1024, K] x [K, 1024]矩阵乘法和标准的2D块大小[128, 128],数据并行策略只能将这个矩阵乘法分割为64个核心,不足以饱和GPU。

在矩阵乘法中沿约简维度分割被称为Split-K矩阵乘法[10]。就像RMSNorm一样,使用这种策略会破坏批次不变性。

Split-K矩阵乘法 如果我们的批次维度相当小,我们可能没有足够的并行性,需要split-k矩阵乘法。在这个例子中,我们将每个约简分割到两个核心上,它们会分别累积然后在最后合并结果。然而,将每个约简分割到两个核心上允许我们仍然利用八个核心。

然而,还有一个额外的复杂性——张量核心指令。与约简不同,我们可以简单地一次操作一行,高效的矩阵乘法内核必须一次操作整个"块"。

每个张量核心指令(比如`wgmma.mma_async.sync.aligned.m64n128k16`[11])内部可能有不同的约简顺序。使用不同张量核心指令的一个原因可能是批次大小非常小。例如,如果我们使用操作长度为256的块的张量核心PTX指令,但批次大小只有32,我们几乎浪费了所有计算!在批次大小为1时,最快的内核通常根本不使用张量核心。

填充的张量核心指令 如果批次大小太小,我们可能处于无法在输出中放入甚至一个2D块的情况。在这种情况下,切换到较小的张量核心指令或完全放弃张量核心是最有效的!然而,这两个选项都阻止了我们的内核成为批次不变的。

所以,确保矩阵乘法批次不变性的最简单方法是编译一个内核配置并将其用于所有形状。虽然我们会失去一些性能,但这在LLM推理中通常不是灾难性的。特别是,当M和N都很小时最需要split-k,而幸运的是,在我们的情况下,N(即模型维度)通常相当大!

尽管获得了批次不变性,我们与cuBLAS相比只损失了大约20%的性能。注意这也不是优化的Triton内核(例如没有TMA)。然而,性能中的一些模式说明了我们的批次不变要求在哪里损失性能。首先,注意我们在非常小的批次大小时由于过大的指令和不足的并行性损失了大量性能。其次,随着批次大小的增加,有一个"拼图"模式,这是由通常通过改变块大小来改善的量化效应(块和波)引起的。

批次不变的注意力机制

FlashAttention2策略 我们沿Q并行化,同时沿K/V约简。这意味着我们的整个约简可以保持在单个核心内,使其成为另一个数据并行策略。

在为矩阵乘法获得批次不变性后,注意力机制引入了两个额外的复杂性——恰如其分,因为它包含两个矩阵乘法。

  1. 与只沿特征维度约简的RMSNorm和矩阵乘法不同,我们现在沿特征维度序列维度约简。
  2. 由于上述原因,注意力机制必须处理影响序列处理方式的各种推理优化(分块预填充、前缀缓存等)。

因此,为了在LLM推理中实现确定性,我们的数值必须对一次处理多少请求每个请求在推理引擎中如何分片都保持不变。

让我们首先介绍注意力机制的标准并行化策略,首次在FlashAttention2中引入。类似于RMSNorm和矩阵乘法,默认策略是"数据并行"策略。由于我们沿着key/value张量约简,数据并行策略只能沿着query张量并行化。

例如,根据推理引擎的选择,一个序列可能被分几部分处理(如在分块预填充中)或一次全部处理(如果预填充没有分割)。为了实现"批次不变性",必须确保给定token的约简顺序不依赖于其序列中同时处理多少其他token。如果你分别约简KV缓存中的K/V值和当前处理的token中的K/V值(如vLLM的Triton注意力内核[12]),这无法实现。例如,在处理序列中的第1000个查询token时,无论KV缓存中有0个token(预填充)还是999个token(解码),约简顺序必须相同。

带KV缓存的FlashAttention 为什么显式地将KV缓存与当前KV值分开处理会破坏批次不变性有点微妙,这与"边界条件"有关。特别是,想象你的块大小是32,但我们当前在KV缓存中有80个元素。然后我们计算另外48个未缓存的元素。在这种情况下,我们需要三个块(两个完整的和一个掩码的)来计算"P缓存",另外两个块(一个完整的和一个掩码的)来计算"P"。因此,当我们只有四个总块(即128)元素要计算时,这是五个总块来计算我们的约简,这肯定会改变我们的约简顺序。

为了解决这个问题,我们可以在注意力内核本身之前更新KV缓存和页表,确保我们的键和值总是一致地布局,无论正在处理多少token。

有了这个额外的细节(以及前一节提到的所有内容,如一致的块大小),我们能够实现批次不变的注意力实现!

然而,这里有一个重大问题。与矩阵乘法不同,我们在LLM推理中看到的注意力形状通常确实需要分割约简内核,通常称为Split-KV或FlashDecoding。这是因为如果我们不沿约简并行化,我们只能沿批次维度、头维度和"查询长度"维度并行化。在注意力的解码阶段,查询长度非常小,所以除非我们有非常大的批次大小,否则我们通常无法饱和GPU。

不幸的是,忽略这种情况不像RMSNorm和矩阵乘法那样容易。例如,如果你有非常长的KV缓存,尽管只处理一个请求,注意力内核可能需要很长时间。

固定#Split-KV策略(即FlashDecode) 如果我们的查询长度变得非常小(如在解码期间),我们可能最终处于内核中几乎没有并行性的情况。在这些情况下,我们需要再次沿约简维度分割——这次是KV维度。沿KV维度分割的典型策略是确定我们需要多少并行性,然后平均分割KV维度。例如,如果我们的KV长度是1000,需要4个分割,每个核心将处理250个元素。

这不幸地也破坏了批次不变性,因为我们的精确约简策略取决于我们在任何给定请求中从序列处理多少查询token。

此外,注意力机制常用的分割约简策略也对批次不变性构成挑战。例如,FlashInfer的"平衡调度算法"选择仍能饱和GPU所有核心的最大分割大小,从而使约简策略不是"批次不变的"。然而,与RMSNorm/矩阵乘法不同,仅选择固定数量的分割而不考虑批次大小是不够的。

相反,为了实现批次不变性,我们必须采用"固定分割大小"策略。换句话说,不是固定分割的数量,我们固定每个分割的大小,然后得到不同数量的分割。通过这种方式,我们可以保证无论我们处理多少token,我们总是执行相同的约简顺序。这需要一些内部FlexAttention更改,这些更改不包含在我们的代码发布中。我们将在不久的将来上游它们!

固定大小Split-KV策略 这个策略与前一个策略的唯一区别是我们的分割现在是"固定大小的"。例如,如果我们的KV长度是1000,不是将其分割为四个长度为250的均匀分割,我们会将其分割为三个固定大小长度为256的分割和一个长度为232的分割。这允许我们保持批次不变性,因为我们的约简策略不再依赖于我们一次处理多少查询token!

实现

我们通过利用vLLM的FlexAttention后端以及torch.Library,在vLLM之上提供了确定性推理的演示。通过torch.Library,我们能够以非侵入式的方式替换大部分相关的PyTorch操作符。你可以在thinking-machines-lab/batch-invariant-ops[13]找到"批次不变"内核库,以及在"确定性"模式下运行的vLLM示例。

实验

生成结果的非确定性程度如何?

我们使用Qwen/Qwen3-235B-A22B-Instruct-2507并在温度为0的情况下使用提示"Tell me about Richard Feynman"(非思维模式)采样1000个完成,每个生成1000个token。令人惊讶的是,我们生成了80个独特的完成,其中最常见的出现了78次。

查看完成在哪里不同,我们看到完成实际上在前102个token是相同的!第一次出现分歧的完成发生在第103个token。所有完成都生成序列"Feynman was born on May 11, 1918, in",然而,992个完成继续生成"Queens, New York",而8个完成生成"New York City"。

另一方面,当我们启用批次不变内核时,我们所有的1000个完成都是相同的。这是我们从采样器数学上期望的,但如果没有批次不变内核,我们无法实现确定性结果。

性能

我们没有在这里大力优化批次不变内核的性能。然而,让我们运行一些实验来验证我们的性能仍然可用。

我们将用一个GPU设置运行Qwen-3-8B的API服务器,并请求1000个输出长度在90到110之间的序列。

配置
时间(秒)
vLLM默认
26
未优化的确定性vLLM
55
+ 改进的注意力内核
42

大部分减速来自vLLM中的FlexAttention集成尚未进行大量优化。尽管如此,我们看到性能不是灾难性的

真正的在线策略强化学习

正如研究人员所注意到的[14],训练和推理之间的不同数值隐含地将我们的在线策略RL转变为离线策略RL。

当然,如果我们甚至无法从两个相同的推理请求中获得按位相同的结果,就不可能在训练和推理之间获得按位相同的结果。然后,确定性推理使我们也能够修改我们的训练堆栈,以在采样和训练之间获得按位相同的结果,从而产生真正的在线策略RL。

我们在Bigmath[15]上的RLVR设置中运行实验,RL策略从Qwen 2.5-VL指令8B初始化,最大展开长度为4096。

如果我们在没有离线策略校正(即重要性加权)的情况下训练,我们的奖励在训练过程中崩溃,而添加离线策略校正项允许训练顺利进行。但是,如果我们在采样器和训练器之间实现按位相同的结果,我们是完全在线策略的(即0 KL散度),也可以顺利训练。

我们还可以绘制采样器和训练器之间logprobs的KL散度,其中所有3次运行都有明显不同的行为。使用重要性加权运行时,它保持在0.001左右,偶尔有峰值。然而,不使用重要性加权运行最终会在奖励崩溃的同时导致KL散度峰值。当然,运行"真正的在线策略RL"时,我们的KL散度保持在0的平线,表明训练策略和采样策略之间没有散度。

注意没有重要性加权的运行在步骤318左右有显著的损失峰值,这伴随着logprobs的相应KL散度峰值。同时,使用离线策略校正或运行"真正的在线策略"都允许RL继续顺利进行。显示"真正在线策略"的蓝线不是错误——它只是在0处的平线。

结论

现代软件系统包含许多抽象层。在机器学习中,当我们遇到非确定性和微妙的数值差异时,往往很容易掩盖它们。毕竟,我们的系统已经是"概率性的",那么再多一点非确定性有什么问题呢?在失败的单元测试上提高atol/rtol有什么问题?训练器和采样器之间logprobs的差异可能不是真正的错误,对吧?

我们拒绝这种失败主义。通过一点工作,我们可以理解非确定性的根本原因,甚至解决它们!我们希望这篇博客文章为社区提供了如何解决推理系统中非确定性的坚实理解,并启发其他人获得对他们系统的完全理解。

引用

请引用这项工作为:

He, Horace and Thinking Machines Lab, "Defeating Nondeterminism in LLM Inference", 
Thinking Machines Lab: Connectionism, Sep 2025.

或使用BibTeX引用:

@article{he2025nondeterminism,
  author = {Horace He and Thinking Machines Lab},
  title = {Defeating Nondeterminism in LLM Inference},
  journal = {Thinking Machines Lab: Connectionism},
  year = {2025},
  note = {https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/},
  doi = {10.64434/tml.20250910}
}




[1]

来源: https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/

[2]

这里: https://152334h.github.io/blog/non-determinism-in-gpt-4/

[3]

这里: https://community.openai.com/t/a-question-on-determinism/8185/2

[4]

这里: https://cookbook.openai.com/examples/reproducible_outputs_with_the_seed_parameter

[5]

这里: https://docs.vllm.ai/en/v0.7.0/getting_started/faq.html

[6]

这里: https://docs.sglang.ai/references/faq.html

[7]

最近的一篇arXiv预印本: https://arxiv.org/abs/2506.09501

[8]

这里: https://community.openai.com/t/a-question-on-determinism/8185

[9]

fetch-and-add: https://en.wikipedia.org/wiki/Fetch-and-add

[10]

Split-K矩阵乘法: https://github.com/NVIDIA/cutlass/blob/main/media/docs/cpp/efficient_gemm.md#parallelized-reductions

[11]

wgmma.mma_async.sync.aligned.m64n128k16https://docs.nvidia.com/cuda/parallel-thread-execution/#asynchronous-warpgroup-level-matrix-instructions-wgmma-mma

[12]

Triton注意力内核: https://github.com/vllm-project/vllm/blob/0ae43dbf8cb28a299ae724fc742b0c5bcddea868/vllm/attention/ops/prefix_prefill.py#L36

[13]

thinking-machines-lab/batch-invariant-ops: https://github.com/thinking-machines-lab/batch_invariant_ops

[14]

研究人员所注意到的: https://fengyao.notion.site/off-policy-rl

[15]

Bigmath: https://arxiv.org/abs/2502.17387



👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

现在,Claude可以直接操作 iOS 的提醒事项了:

只需要直接告诉他对应的任务,他就会申请系统提醒事项的权限(首次使用时),并为你设定合适的日程。

看着很简单,对不对?

但我想说:从现在起,所有 todo 软件们都可以去死了。

——至少对我而言是这样。

以前我还会为了实践最佳 GTD 精神而用了好久的 OmniFocus,但后来我才体会到:最好的 GTD 应用,其实就是你真正会用的那个

只要你用、一直用,它就是你的最佳 GTD 应用。

所以我最后都直接用 iOS 的提醒事项了。

而现在,Claude 将先 Siri 一步,成为我的智能日程助理。

我还可以用它来提醒我别错过订机票:

不用说的多么准确,随性着说就好。

Claude 就会根据我的本地时间,设定合适的提醒时间点,并真正放到系统的提醒事项中去。

并且,买机票设置成为 high 的优先级——这事确实比买杯咖啡要重要得多啊。

属实细节了。

不像 ChatGPT 只是个应用内的消息提醒(push 通知):

豆包也一样:

元宝则说:对不起我还不会这个技能。

除了添加,Claude 还能查看:

管理(以删除为例):

早几年前,我还为了类似这样随性又智能的体验而开发过一款自用的 iOS app:

语音或文字输入非结构化的内容,通过简单的 NLP 模型 + 各种智能规则识别出对应的时间点,再设置好提醒。

怎么说呢,没有AI 辅助的代码写得是真辛苦,而效果也是真的一般。

也就我自用着还凑合,给人用确实不太行……

后来就没有后来了,改用其他软件去了……

而从现在起,我想我的 todo 软件就直接是 Claude 了。

什么 Toki 啥啥的,估计又都可以死了……

建议各位还是做点离模型远点儿的事吧,并在做之前,想清楚远的真实定义。

而至于这个功能是否是今天的新更新,我也不确定。上周应该还没有,或者,又是给 Max 用户的灰度功能?

总之,非常好用!

快去试试吧!


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

99% 的 Agent 创业公司,都可以扔掉你的代码了转用 Claude Code SDK 来实现了。

刚刚,Claude Code SDK 发布了支持自定义工具和钩子函数的更新:

Claude Code 开发者 Thariq(@trq212) 宣布:

Claude Code SDK 现在支持直接在代码中使用自定义工具和钩子。此外,我们刷新了所有文档,包含完整的参考和 10 个新指南。

虽然 Claude Code 并不开源,甚至还莫名降智,但这不妨碍它性能强大,我每天都会用来做各种编程之外的事。

而基于 Claude Code SDK,再结合 MCP、工具、命令、钩子等周边功能,可以说,这能帮我们解决绝大多数在电脑上需要做的事情,和绝大多数所谓 Agent 公司们在做的事情。

自定义工具的实现

自定义工具的实现方式很简单:定义一个函数,将其注册为 SDK 的 in-process MCP 服务器,Claude Code 就能调用它。

这种「进程内 MCP」的设计让扩展变得异常优雅。

来看实现代码。

(又是这个获取天气的示例……,好在后面有更多例子)

TypeScript 版本

import { query, tool, createSdkMcpServer } from"@anthropic-ai/claude-code";
import { z } from"zod";

// 创建一个带有自定义工具的 SDK MCP 服务器
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "get_weather",
      "Get current weather for a location",
      {
        location: z.string().describe("City name or coordinates"),
        units: z.enum(["celsius""fahrenheit"]).default("celsius").describe("Temperature units")
      },
      async (args) => {
        // 调用天气 API
        const response = await fetch(
          `https://api.weather.com/v1/current?q=${args.location}&units=${args.units}`
        );
        const data = await response.json();
        
        return {
          content: [{
            type"text",
            text: `Temperature: ${data.temp}°\nConditions: ${data.conditions}\nHumidity: ${data.humidity}%`
          }]
        };
      }
    )
  ]
});

Python 版本

from claude_code_sdk import tool, create_sdk_mcp_server
from typing import Any
import aiohttp

# 使用装饰器定义自定义工具
@tool("get_weather", "Get current weather for a location", {"location": str, "units": str})
asyncdef get_weather(args: dict[str, Any]) -> dict[str, Any]:
    units = args.get('units''celsius')
    asyncwith aiohttp.ClientSession() as session:
        asyncwith session.get(
            f"https://api.weather.com/v1/current?q={args['location']}&units={units}"
        ) as response:
            data = await response.json()
    
    return {
        "content": [{
            "type""text",
            "text"f"Temperature: {data['temp']}°\nConditions: {data['conditions']}\nHumidity: {data['humidity']}%"
        }]
    }

# 创建服务器
custom_server = create_sdk_mcp_server(
    name="my-custom-tools",
    version="1.0.0",
    tools=[get_weather]
)

使用自定义工具

重要提示:自定义 MCP 工具需要流式输入模式。必须使用异步生成器作为 prompt 参数,简单的字符串不能与 MCP 服务器配合使用。

工具名称遵循特定格式:mcp__{server_name}__{tool_name}。例如,my-custom-tools 服务器中的 get_weather 工具会变成 mcp__my-custom-tools__get_weather

TypeScript 调用示例

import { query } from"@anthropic-ai/claude-code";

// 使用异步生成器进行流式输入
asyncfunctiongenerateMessages({
yield {
    type"user"asconst,
    message: {
      role: "user"asconst,
      content: "What's the weather in San Francisco?"
    }
  };
}

forawait (const message of query({
  prompt: generateMessages(),  // 使用异步生成器
  options: {
    mcpServers: {
      "my-custom-tools": customServer  // 作为对象传递,不是数组
    },
    // 可选:指定 Claude 可以使用哪些工具
    allowedTools: [
      "mcp__my-custom-tools__get_weather",
    ],
    maxTurns: 3
  }
})) {
if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Python 调用示例

from claude_code_sdk import query, ClaudeCodeOptions

asyncdef message_generator():
    yield {
        "type""user",
        "message": {
            "role""user",
            "content""What's the weather in San Francisco?"
        }
    }

asyncfor message in query(
    prompt=message_generator(),  # 使用异步生成器
    options=ClaudeCodeOptions(
        mcp_servers={"my-custom-tools": custom_server},
        allowed_tools=[
            "mcp__my-custom-tools__get_weather",
        ],
        max_turns=3
    )
):
    if hasattr(message, 'result'):
        print(message.result)

权限系统架构

SDK 提供了四层互补的权限控制机制,让我们能够精确控制工具的使用。

权限模式

模式
描述
工具行为
default
标准权限行为
正常权限检查
plan
规划模式
只能使用只读工具,执行前展示计划
acceptEdits
自动接受文件编辑
文件编辑和文件系统操作自动批准
bypassPermissions
绕过所有权限检查
所有工具无需权限提示运行(谨慎使用)

设置权限模式的代码:

// 初始配置
const result = await query({
  prompt: "Help me refactor this code",
  options: {
    permissionMode: 'default'
  }
});

// 动态更改(仅流式模式)
asyncfunctionstreamInput({
yield { 
    type'user',
    message: { 
      role: 'user'
      content: "Let's start with default permissions"
    }
  };
}

const q = query({
  prompt: streamInput(),
  options: {
    permissionMode: 'default'
  }
});

// 动态切换模式
await q.setPermissionMode('acceptEdits');

canUseTool 回调

canUseTool 回调在 Claude Code 需要显示权限提示时触发,可以实现交互式工具批准:

async function promptForToolApproval(toolName: string, input: any{
console.log("\n🔧 Tool Request:");
console.log(`   Tool: ${toolName}`);

// 显示工具参数
if (input && Object.keys(input).length > 0) {
    console.log("   Parameters:");
    for (const [key, value] of Object.entries(input)) {
      let displayValue = value;
      if (typeof value === 'string' && value.length > 100) {
        displayValue = value.substring(0100) + "...";
      } elseif (typeof value === 'object') {
        displayValue = JSON.stringify(value, null2);
      }
      console.log(`     ${key}${displayValue}`);
    }
  }

// 获取用户批准
const approved = await getUserApproval();

if (approved) {
    console.log("   ✅ Approved\n");
    return {
      behavior: "allow",
      updatedInput: input
    };
  } else {
    console.log("   ❌ Denied\n");
    return {
      behavior: "deny",
      message: "User denied permission for this tool"
    };
  }
}

// 使用权限回调
const result = await query({
  prompt: "Help me analyze this codebase",
  options: {
    canUseTool: async (toolName, input) => {
      return promptForToolApproval(toolName, input);
    }
  }
});

钩子函数

钩子提供了对工具执行各个阶段的程序化控制:

const result = await query({
  prompt: "Help me refactor this code",
  options: {
    hooks: {
      PreToolUse: [{
        hooks: [async (input, toolUseId, { signal }) => {
          console.log(`Tool request: ${input.tool_name}`);
          
          // 自定义验证逻辑
          if (input.tool_name === "Bash") {
            const command = input.tool_input.command;
            if (command.startsWith("rm -rf")) {
              return {
                decision: "block",
                reason: "Dangerous command blocked"
              };
            }
          }
          
          return { continuetrue };
        }]
      }],
      PostToolUse: [{
        hooks: [async (input, toolUseId, { signal }) => {
          console.log(`Tool completed: ${input.tool_name}`);
          // 记录或审计工具结果
          return { continuetrue };
        }]
      }]
    }
  }
});

Python 版本钩子实现:

from claude_code_sdk import query, ClaudeCodeOptions, HookMatcher, HookContext

asyncdef pre_tool_hook(
    input_data: dict[str, Any], 
    tool_use_id: str | None, 
    context: HookContext
)
 -> dict[str, Any]:

    print(f"Tool request: {input_data['tool_name']}")
    
    if input_data['tool_name'] == 'Bash':
        command = input_data['tool_input'].get('command''')
        if command.startswith('rm -rf'):
            return {
                'hookSpecificOutput': {
                    'hookEventName''PreToolUse',
                    'permissionDecision''deny',
                    'permissionDecisionReason''Dangerous command blocked'
                }
            }
    
    return {}

options = ClaudeCodeOptions(
    hooks={
        'PreToolUse': [
            HookMatcher(matcher='Bash', hooks=[pre_tool_hook])
        ]
    }
)

权限规则

在 settings.json 中配置声明式权限规则:

{
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test:*)",
      "Read(~/.zshrc)"
    ],
    "deny": [
      "Bash(curl:*)",
      "Read(./.env)",
      "Read(./secrets/**)",
      "WebFetch"
    ],
    "ask": [
      "Bash(git push:*)",
      "Write(./production/**)"
    ]
  }
}

规则语法说明:

  • Bash 规则:使用前缀匹配。例如 Bash(npm:*) 匹配任何以 "npm" 开头的命令

  • 文件规则:支持 glob 模式。例如 Read(./src/**/*.ts) 匹配 src 目录下的所有 TypeScript 文件

  • 工具规则:省略括号控制整个工具。例如 WebFetch 阻止所有网络获取

实用工具示例

数据库查询工具

const databaseServer = createSdkMcpServer({
  name: "database-tools",
  version: "1.0.0",
  tools: [
    tool(
      "query_database",
      "Execute a database query",
      {
        query: z.string().describe("SQL query to execute"),
        params: z.array(z.any()).optional().describe("Query parameters")
      },
      async (args) => {
        const results = await db.query(args.query, args.params || []);
        return {
          content: [{
            type"text",
            text: `Found ${results.length} rows:\n${JSON.stringify(results, null2)}`
          }]
        };
      }
    )
  ]
});

API 网关工具

这个工具可以调用多个外部服务:

const apiGatewayServer = createSdkMcpServer({
  name: "api-gateway",
  version: "1.0.0",
  tools: [
    tool(
      "api_request",
      "Make authenticated API requests to external services",
      {
        service: z.enum(["stripe""github""openai""slack"]).describe("Service to call"),
        endpoint: z.string().describe("API endpoint path"),
        method: z.enum(["GET""POST""PUT""DELETE"]).describe("HTTP method"),
        body: z.record(z.any()).optional().describe("Request body"),
        query: z.record(z.string()).optional().describe("Query parameters")
      },
      async (args) => {
        const config = {
          stripe: { baseUrl: "https://api.stripe.com/v1", key: process.env.STRIPE_KEY },
          github: { baseUrl: "https://api.github.com", key: process.env.GITHUB_TOKEN },
          openai: { baseUrl: "https://api.openai.com/v1", key: process.env.OPENAI_KEY },
          slack: { baseUrl: "https://slack.com/api", key: process.env.SLACK_TOKEN }
        };
        
        const { baseUrl, key } = config[args.service];
        const url = new URL(`${baseUrl}${args.endpoint}`);
        
        if (args.query) {
          Object.entries(args.query).forEach(([k, v]) => url.searchParams.set(k, v));
        }
        
        const response = await fetch(url, {
          method: args.method,
          headers: { 
            Authorization: `Bearer ${key}`
            "Content-Type""application/json"
          },
          body: args.body ? JSON.stringify(args.body) : undefined
        });
        
        const data = await response.json();
        return {
          content: [{
            type"text",
            text: JSON.stringify(data, null2)
          }]
        };
      }
    )
  ]
});

计算器工具

包含基础运算和复利计算:

const calculatorServer = createSdkMcpServer({
  name: "calculator",
  version: "1.0.0",
  tools: [
    tool(
      "calculate",
      "Perform mathematical calculations",
      {
        expression: z.string().describe("Mathematical expression to evaluate"),
        precision: z.number().optional().default(2).describe("Decimal precision")
      },
      async (args) => {
        try {
          // 生产环境使用安全的数学计算库
          const result = eval(args.expression); // 仅示例!
          const formatted = Number(result).toFixed(args.precision);
          
          return {
            content: [{
              type"text",
              text: `${args.expression} = ${formatted}`
            }]
          };
        } catch (error) {
          return {
            content: [{
              type"text",
              text: `Error: Invalid expression - ${error.message}`
            }]
          };
        }
      }
    ),
    tool(
      "compound_interest",
      "Calculate compound interest for an investment",
      {
        principal: z.number().positive().describe("Initial investment amount"),
        rate: z.number().describe("Annual interest rate (as decimal)"),
        time: z.number().positive().describe("Investment period in years"),
        n: z.number().positive().default(12).describe("Compounding frequency per year")
      },
      async (args) => {
        const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);
        const interest = amount - args.principal;
        
        return {
          content: [{
            type"text",
            text: `Investment Analysis:\n` +
                  `Principal: $${args.principal.toFixed(2)}\n` +
                  `Rate: ${(args.rate * 100).toFixed(2)}%\n` +
                  `Time: ${args.time} years\n` +
                  `Compounding: ${args.n} times per year\n\n` +
                  `Final Amount: $${amount.toFixed(2)}\n` +
                  `Interest Earned: $${interest.toFixed(2)}\n` +
                  `Return: ${((interest / args.principal) * 100).toFixed(2)}%`
          }]
        };
      }
    )
  ]
});

多工具协同

当 MCP 服务器有多个工具时,可以选择性地允许它们:

const multiToolServer = createSdkMcpServer({
  name: "utilities",
  version: "1.0.0",
  tools: [
    tool("calculate""Perform calculations", { /* ... */ }, async (args) => { /* ... */ }),
    tool("translate""Translate text", { /* ... */ }, async (args) => { /* ... */ }),
    tool("search_web""Search the web", { /* ... */ }, async (args) => { /* ... */ })
  ]
});

// 只允许特定工具
asyncfunctiongenerateMessages({
yield {
    type"user"asconst,
    message: {
      role: "user"asconst,
      content: "Calculate 5 + 3 and translate 'hello' to Spanish"
    }
  };
}

forawait (const message of query({
  prompt: generateMessages(),
  options: {
    mcpServers: {
      utilities: multiToolServer
    },
    allowedTools: [
      "mcp__utilities__calculate",   // 允许计算器
      "mcp__utilities__translate",   // 允许翻译器
      // "mcp__utilities__search_web" 不被允许
    ]
  }
})) {
// 处理消息
}

错误处理

优雅地处理错误,可以提供有意义的反馈:

tool(
  "fetch_data",
"Fetch data from an API",
  {
    endpoint: z.string().url().describe("API endpoint URL")
  },
async (args) => {
    try {
      const response = await fetch(args.endpoint);
      
      if (!response.ok) {
        return {
          content: [{
            type"text",
            text: `API error: ${response.status} ${response.statusText}`
          }]
        };
      }
      
      const data = await response.json();
      return {
        content: [{
          type"text",
          text: JSON.stringify(data, null2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type"text",
          text: `Failed to fetch data: ${error.message}`
        }]
      };
    }
  }
)

Python 类型安全

Python 版本支持多种模式定义方法:

# 简单类型映射 - 推荐用于大多数情况
@tool(
    "process_data",
    "Process structured data with type safety",
    {
        "name": str,
        "age": int,
        "email": str,
        "preferences": list  # 可选参数可以在函数中处理
    }
)
asyncdef process_data(args: dict[str, Any]) -> dict[str, Any]:
    name = args["name"]
    age = args["age"]
    email = args["email"]
    preferences = args.get("preferences", [])
    
    print(f"Processing {name}'s data (age: {age})")
    
    return {
        "content": [{
            "type""text",
            "text"f"Processed data for {name}"
        }]
    }

# 对于更复杂的模式,可以使用 JSON Schema 格式
@tool(
    "advanced_process",
    "Process data with advanced validation",
    {
        "type""object",
        "properties": {
            "name": {"type""string"},
            "age": {"type""integer""minimum"0"maximum"150},
            "email": {"type""string""format""email"},
            "format": {"type""string""enum": ["json""csv""xml"], "default""json"}
        },
        "required": ["name""age""email"]
    }
)
asyncdef advanced_process(args: dict[str, Any]) -> dict[str, Any]:
    return {
        "content": [{
            "type""text",
            "text"f"Advanced processing for {args['name']}"
        }]
    }

完整功能支持

SDK 提供了对所有 Claude Code 默认功能的访问,通过相同的文件系统配置:

  • 子智能体:存储在 ./.claude/agents/ 的专用智能体

  • 钩子:在 ./.claude/settings.json 中配置的自定义命令

  • 斜杠命令:定义在 ./.claude/commands/ 的 Markdown 文件

  • 记忆(CLAUDE.md):通过 CLAUDE.md 文件维护项目上下文

这些功能通过读取相同的文件系统位置来工作,与 Claude Code 对应功能完全一致。

可以构建什么

根据文档,基于 Claude Code SDK 我们可以构建各类 Agent,包括但不限于:

编码智能体

  • SRE 智能体诊断和修复生产问题

  • 安全审查机器人审计代码漏洞

  • 值班工程助手分类事件

  • 代码审查智能体执行风格和最佳实践

业务智能体

  • 法律助手审查合同和合规性

  • 财务顾问分析报告和预测

  • 客户支持智能体解决技术问题

  • 营销团队的内容创建助手

现在,所有这些 Agent 都可以通过 Claude Code SDK 轻松实现,而不需要从零开始构建复杂的基础设施了。

封装一下业务 API,弄弄数据,搞搞 UI,就可以了。

顺便,我还让 Claude 给做了个 《基于 Claude Code SDK 开发 Agent》的PPT,贴上来供参考:




[1]

自定义工具文档: https://docs.anthropic.com/en/docs/claude-code/sdk/custom-tools

[2]

SDK 权限文档: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-permissions

[3]

SDK 概览: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-overview

[4]

子智能体指南: https://docs.anthropic.com/en/docs/claude-code/sdk/subagents

[5]

斜杠命令指南: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-slash-commands

[6]

TypeScript SDK 参考: https://docs.anthropic.com/en/docs/claude-code/sdk/typescript

[7]

Python SDK 参考: https://docs.anthropic.com/en/docs/claude-code/sdk/python

[8]

MCP 文档: https://modelcontextprotocol.io

[9]

SDK 配置: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-configuration


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

编程新王者真的要来了!

刚刚,OpenAI 发布了 GPT-5-Codex:一个专门为 Agent 编程优化的全新模型。

并且,该模型同步在 Codex CLI、IDE 扩展、网页端、移动端以及 GitHub 代码审查中全面可用。

动态思考

GPT-5-Codex 最具革命性的特性是沿用了 GPT-5 的动态调整思考时间

它会根据任务复杂度自动决定投入多少计算资源:简单任务秒回,复杂任务深度思考。

在 OpenAI 员工的实际使用数据中,处理最简单的 10% 任务时,GPT-5-Codex 比 GPT-5 减少了 93.7% 的 token 使用量。

而面对最复杂的 10% 任务,它会花费两倍时间进行推理、编辑、测试和迭代。

测试中,GPT-5-Codex 曾独立工作超过 7 小时处理大型复杂任务,不断迭代实现、修复测试失败,最终交付成功的实现。

这种能力让 Codex 在交互式编程会话中反应迅速,同时又能独立完成需要长时间思考的复杂任务。

性能全面碾压

基准测试成绩:

在 SWE-bench Verified (500 个任务)上,GPT-5-Codex 达到 74.5% 的准确率,超过 GPT-5 的 72.8%。

代码重构任务上表现更是亮眼:GPT-5-Codex 准确率达到 51.3%,大幅领先 GPT-5 的 33.9%。这个评估包含了来自大型成熟代码库的重构任务,涵盖 Python、Go 甚至 OCaml。

其中一个示例任务来自 Gitea,需要修改 232 个文件和 3,541 行代码。

代码审查能力突破:

GPT-5-Codex 被专门训练用于代码审查和发现关键缺陷。它会导航代码库、推理依赖关系、运行代码和测试来验证正确性。

在评估中:

  • 错误评论率仅 4.4%(GPT-5:13.7%)

  • 高影响力评论占比 52.4%(GPT-5:39.4%)

  • 平均每个 PR 0.93 条评论(GPT-5:1.32 条)

GPT-5-Codex 在前端任务上也表现出色。

除了创建美观的桌面应用,在创建移动网站时的人类偏好评估中也显示出显著改进。在云端工作时,它可以查看你提供的图片或截图输入,视觉检查进度,并向你展示工作截图。

Codex 平台大升级

Codex CLI 0.36 重大更新:

A screenshot of a social media post about Codex-CLI 0.36 release by OpenAI. Text includes highlights like GPT-5-Codex model, resume and compaction features, auth and login improvements, TUI onboarding, and core platform updates. A watermark from X is visible.

新版本完全重建了 CLI 架构,专门针对 Agent 编程工作流优化。主要特性包括:

  • 图片支持:可以直接在 CLI 中附加和分享截图、线框图、设计图

  • 进度追踪:复杂工作时用待办事项列表追踪进度

  • 工具集成:包含网页搜索和 MCP(Model Context Protocol)连接外部系统

  • UI 升级:工具调用和 diff 格式更清晰易读

  • 简化审批模式:三个级别——只读模式(需要显式批准)、自动模式(工作区内完全访问但工作区外需要批准)、完全访问模式

  • 会话管理:支持压缩会话状态,让长时间会话更易管理

  • 恢复功能:可以通过 codex resume 恢复旧会话

IDE 扩展全新体验:

新的 IDE 扩展将 Codex Agent 带入 VS Code、Cursor 和其他 VS Code 分支。

它能利用你打开的文件或选中的代码作为上下文,让你写更短的提示词,获得更快的结果。

更重要的是,IDE 扩展实现了云端和本地的无缝切换

你可以在 IDE 中创建云任务、追踪进行中的工作、审查已完成的任务,而 Codex 会保持完整上下文。

云端基础设施优化:

通过容器缓存,新任务和后续任务的中位完成时间缩短了 90%

Codex 现在会自动扫描常见的设置脚本并执行它们来配置环境,还可以通过可配置的互联网访问运行 pip install 等命令来获取依赖。

GitHub 集成更新

一旦为 GitHub 仓库启用,Codex 会在 PR 从草稿转为就绪时自动进行审查,并将分析结果发布在 PR 上。

如果它建议编辑,你可以在同一个线程中要求 Codex 实施这些更改。

你也可以通过提及「@codex review」来明确请求审查,还可以给出额外指导,如「@codex review for security vulnerabilities」或「@codex review for outdated dependencies」。

在 OpenAI 内部,Codex 现在审查绝大多数 PR,每天捕获数百个问题——

通常在人类审查开始之前。

安全与隐私

GPT-5-Codex 默认在沙盒环境中运行,禁用网络访问,无论是本地还是云端。这确保 Codex 不会在你的计算机上执行有害操作,并降低来自不可信源的提示注入风险。

开发者可以根据风险承受能力自定义安全设置。

在云端,可以将网络访问限制在可信域名。在 CLI 和 IDE 扩展中,开发者可以批准命令以完全访问权限运行,或允许 Agent 使用网页搜索和连接 MCP 服务器。

与 GPT-5 的处理方式一致,OpenAI 将 GPT-5-Codex 在生物和化学领域视为高能力模型,并实施了相应的保护措施。

定价与可用性

Codex 包含在 ChatGPT Plus、Pro、Business、Edu 和 Enterprise 计划中:

  • Plus、Edu、Business:可支持每周几次集中的编程会话

  • Pro:可支持跨多个项目的完整工作周

  • Business:可购买额外积分超出限制使用

  • Enterprise:提供共享积分池,按实际使用付费

对于通过 API key 使用 Codex CLI 的开发者,OpenAI 计划很快在 API 中提供 GPT-5-Codex。

Dan Shipper(@danshipper) 表示已经用了一周,并给出了两个重要趋势:

动态思考时间:他们将这个模式从 ChatGPT 移植到了编程模型,这将成为未来的标准。

本地到网页的交接:你的 Agent 应该在任何地方都能带着完整上下文陪伴你。

面对 Claude Code 最近频繁出现的「降智」之谜,越来越多开发者开始考虑迁移。

众多开发者询问能否提供 100 美元的计划,让从 Claude Code 切换过来的成本不那么痛苦?

作为 AGI 最核心的一环,编程正成为各模型厂商新的战场——

我先前一直是 20 Claude Max,现在看来,或许——

是时候将 200$ 从 Claude Code 转向 Codex 了!




[1]

OpenAI Codex 介绍页面: https://openai.com/index/introducing-upgrades-to-codex/

[2]

Codex CLI GitHub: https://github.com/openai/codex

[3]

Codex IDE 快速入门: https://developers.openai.com/codex/ide

[4]

Codex 云端文档: https://developers.openai.com/codex/cloud

[5]

代码审查快速入门: https://developers.openai.com/codex/cloud/code-review

[6]

GPT-5 系统卡片附录: https://openai.com/index/gpt-5-system-card-addendum-gpt-5-codex/

[7]

Codex 定价说明: https://developers.openai.com/codex/pricing

[8]

Codex 安全操作指南: https://developers.openai.com/codex/security

[9]

Agent 网络访问文档: https://platform.openai.com/docs/codex/agent-network

👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

终于,AI Agent 们可以直接转账了!

刚刚,Google 和 Coinbase 刚刚联手搞出了一个大动作:

Agentic Payments Protocol(AP2),配合 x402 稳定币支付轨道,让 AI Agent 不仅能相互对话,还能直接完成支付交易。

从现在起,Agent 经济正式开启了

AI 也有钱包了

以前的 AI Agent 只能帮你查查信息、写写代码,现在不一样了。

通过 Google Cloud 的 Agent2Agent(A2A)协议,不同平台的 Agent 已经能够相互通信协作。而 AP2 的出现,让这些 Agent 拥有了真正的经济行为能力

x402 作为 AP2 的首批扩展之一,也是唯一的稳定币支付方案,让 Agent 可以:

  • 为自己的服务收费

  • 向其他 Agent 付款

  • 代表用户自动处理微支付

那些原本需要人工审核的任务,比如数据抓取付费、微任务结算,现在 Agent 可以自动完成了。

这和美团抖音搞个支持可不是一回事,而是一个全新金融系统的开启

当 Agent 有了钱包,它就不再只是一段代码,而将成为经济网络中的一个真正独立实体。

有点像一个养大的孩子,除了能交流、工作,也将开始自由支配财务了。

买冰箱不用人了

为了展示这项技术的威力,Google 和 Coinbase 给 Lowe's Innovation Lab 做了个演示:一个 Agent 从发现需求到完成购买,全程自动化

整个流程只需要五步:

  1. 咨询诊断:AI Agent 理解自然语言和图片,判断项目需求

  2. 推荐商品:调取本地库存,展示价格和品牌

  3. 确认订单:在聊天界面展示购物车,用户一键确认

  4. 支付结算:Agent 使用 x402 + 稳定币完成支付,不需要信用卡信息

  5. 履约交付:API 触发取货或配送,区块链收据作为购买凭证

视频中,用户只需要说「我的预算是 1000 美元,你推荐哪个选项?」,Agent 就自动找到了一台 749 美元的海信冰箱,确认后直接完成了 USDC 支付。

整个过程不到一分钟

微支付将爆发

这项技术最激动人心的地方在于微支付场景的爆发

可以想象的包括但不限于下面这些场景:

学术研究:研究 Agent 自动向档案 Agent 按文档付费,拉取最新数据生成报告,用户完全不用操心支付环节

代码审查:代码审查 Agent 按发现的 bug 数量收费,开发者只为实际使用的洞察付费

全球协作:客服 Agent 即时向翻译 Agent 支付费用处理小语种请求,用稳定币实时结算

x402 bazaar 已经让 Agent 能够自动发现并与生态系统中的任何服务交互,开发者甚至不需要升级代码

机器经济时代开启

Coinbase CEO Brian Armstrong 分享的信息显示,x402 是作为 Google AP2 协议内的稳定币支付轨道运行的。

这套系统建立在 Google 的 A2A 框架之上,让 Agent 能够与其他 Agent(比如预算或配送 Agent)协调,做出实时决策。

对开发者来说,这带来了全新的可能性:

  • 按使用付费的低摩擦支付

  • 创建 Agent 运营的服务

  • 探索完全由 Agent 驱动的微观经济

不过,值得注意的是,Google 似乎还没有正式宣布 AP2,Armstrong 提前透露了消息。这个发布可能还有更多内幕。

有兴趣的可以继续蹲一下 Google 的公告。

改写商业世界

支付只是开始。

随着 Agent 承担越来越复杂的责任:获取信息、完成任务、跨平台协调,无缝交易将成为自主工作流的核心推动力

Google 和 Coinbase 的此次合作,并不仅仅只是给 AI Agent 加了个支付功能那么简单。

而是机器经济时代的真正开启。

从 Agent 会说话到 Agent 会花钱,这一步的跨越,让 AI 真正成为了经济参与者,可以说是意义重大。

而 AI 和 web 3,也终于,走到了一起。

当 Agent 能够自主交易,整个商业世界的运行方式,或将从此改写。




[1]

Coinbase 官方发布: https://www.coinbase.com/developer-platform/discover/launches/google_x402

[2]

演示视频: https://www.youtube.com/watch?v=vtB9YyC73yc


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

Claude 再次解释:八月到九月初,它确实出问题了。

刚刚,Anthropic 今天发布了一份详细的技术报告,解释了三个基础设施 bug 如何让 Claude 的回答质量断崖式下降。

虽然他们像是说了些实话,但这份报告来得有点太晚了。

Claude 到底怎么了?

从八月初开始,用户就开始抱怨 Claude 的回答变差了。

起初 Anthropic 很难分辨这到底是正常的用户反馈波动,还是真的出了问题。

但随着投诉越来越多,他们终于在八月底开始调查。

Anthropic 在报告中强调:

我们从不会因为需求量、时间段或服务器负载而降低模型质量。

用户遇到的问题完全是基础设施 bug 导致的

调查发现了三个相互重叠的 bug,这让诊断变得异常困难。

Anthropic 声称:现在,这三个 bug 都已经修复了。

三个让人头疼的 Bug

Illustrative timeline of events on the Claude API. Yellow: issue detected, Red: degradation worsened, Green: fix deployed.
Illustrative timeline of events on the Claude API. Yellow: issue detected, Red: degradation worsened, Green: fix deployed.

第一个 bug:路由错误

8 月 5 日,部分 Sonnet 4 的请求被错误地路由到了为即将推出的 100 万 token 上下文窗口配置的服务器。

这个 bug 最初只影响 0.8% 的请求。

但 8 月 29 日的一次常规负载均衡调整,意外地让更多短上下文请求被路由到了长上下文服务器。

最严重的时候,8 月 31 日某个小时内,16% 的 Sonnet 4 请求都受到了影响

更糟的是,路由是「粘性的」:一旦请求被错误的服务器处理,后续的对话也会继续被同一个错误的服务器处理。

第二个 bug:输出损坏

8 月 25 日,他们在 Claude API 的 TPU 服务器上部署了一个错误配置。

这导致模型会莫名其妙地输出一些不该出现的 token,比如在英文对话中突然蹦出泰文或中文字符,或者在代码中产生明显的语法错误。

有用户可能会在英文回答中看到「สวัสดี」这样的泰文问候语。

这个问题影响了 8 月 25-28 日的 Opus 4.1 和 Opus 4,以及 8 月 25 日到 9 月 2 日的 Sonnet 4。

第三个 bug:XLA:TPU 编译器错误

8 月 25 日,他们部署了改进 token 选择的代码,但无意中触发了 XLA:TPU 编译器中的一个潜在 bug。

这个 bug 确认影响了 Claude Haiku 3.5,可能也影响了部分 Sonnet 4 和 Opus 3。

编译器 bug 的技术细节

Code snippet of a December 2024 patch to work around the unexpected dropped token bug when temperature = 0.

这个 bug 最为棘手。

Claude 生成文本时,会计算每个可能的下一个词的概率,然后随机选择。

在 TPU 上,模型运行在多个芯片上,概率计算发生在不同位置,需要在芯片之间协调数据。

问题出在混合精度算术上。

模型用 bf16(16 位浮点数)计算概率,但 TPU 的向量处理器原生支持 fp32,所以编译器会把某些操作转换为 fp32 来优化性能。

这造成了精度不匹配:本该在最高概率 token 上达成一致的操作,因为运行在不同精度级别而产生分歧。最高概率的 token 有时会完全消失。

Code snippet showing minimized reproducer merged as part of the August 11 change that root-caused the “bug” being worked around in December 2024; in reality, it’s expected behavior of the xla_allow_excess_precision flag.

他们在修复精度问题时,暴露了一个更底层的 bug:approximate top-k 操作的问题。

这是一个性能优化,用来快速找到最高概率的 token,但有时会返回完全错误的结果。

Slack message showing reproducer of the underlying approximate top-k bug shared with the XLA:TPU engineers who developed the algorithm. The code returns correct results when run on CPUs.
Reproducer of the underlying approximate top-k bug shared with the XLA:TPU engineers who developed the algorithm. The code returns correct results when run on CPUs.

这个 bug 的行为令人抓狂。

它会根据无关因素而改变,比如前后运行了什么操作,是否启用了调试工具。

同一个提示词,这次可能完美运行,下次就失败了。

最终他们发现 exact top-k 操作已经没有以前那么大的性能损失了,于是改用精确算法,并将一些操作标准化为 fp32 精度。

为什么这么难发现?

Anthropic 的验证流程通常依赖基准测试、安全评估和性能指标。

工程团队会进行抽查,先部署到小型「金丝雀」组。

但这些问题暴露了他们本该更早发现的关键缺陷。

他们的评估根本没有捕捉到用户报告的质量下降,部分原因是 Claude 往往能从孤立的错误中很好地恢复。

隐私实践也造成了调查困难:内部隐私和安全控制限制了工程师访问用户与 Claude 交互的方式和时间。

这保护了用户隐私,但也阻止了工程师检查那些识别或重现 bug 所需的问题交互。

每个 bug 在不同平台上以不同速率产生不同症状,创造了令人困惑的混合报告,没有指向任何单一原因。

看起来就像是随机的、不一致的质量下降。

改进措施

Anthropic 承诺将做出以下改变:

更敏感的评估:开发能更可靠地区分正常和异常实现的评估方法。

更多地方的质量评估:将在真正的生产系统上持续运行评估,以捕捉类似上下文窗口负载均衡错误这样的问题。

更快的调试工具:开发基础设施和工具来更好地调试社区反馈,同时不牺牲用户隐私。

他们特别强调,用户的持续反馈至关重要。

用户可以在 Claude Code 中使用 /bug 命令,或在 Claude 应用中使用「thumbs down」按钮来提供反馈。

网友反应

虽然 Anthropic 的透明度值得赞赏,但用户们的反应却可以说是相当复杂。

Denis Stetskov(@razoorka) 表示能感受到巨大的改进:

我已经能感受到巨大的改进。无论你们修复了什么,它都起作用了。

Rajat(@DRajat33) 赞赏了透明度:

感谢澄清和细节。透明度是让公司与众不同的东西,无论他们的产品如何。

但更多用户对没有补偿表示不满。

Alexandr Os(@iamavalex) 直接要求:

发布受影响账户列表并立即退款。我就是其中之一。

Conor Dart(@Conor_D_Dart) 质疑:

你们会给受影响的用户退款或补偿吗?报告影响了很多人,你们的价格可不便宜。

The City Keeps Building(@TheCity777) 简单直接:

我们的退款呢?

peermux(@peermux) 认为:

如果你承认在八月到九月之间没有交付商定的产品,那么你应该提供退款,或至少提供一个月的免费服务。这将展示诚意并有助于维持信任。

Baby Yoda(@grogu836) 表示失望:

我们不会因此获得退款?难以置信。再也不用 Claude Code 了。

还有用户指出问题可能还没完全解决。

tuna(@tunahorse21) 说:

它很明显还有 bug,你们等了一个月才承认这个问题。

Daniel Lovera(@dlovera) 则提出了更进一步的质疑,认为短上下文请求在长上下文服务器上表现变差,说明 Anthropic 实际上是在根据需求间接降低模型质量。

Thomas Ip(@_thomasip) 则总结了三个 bug:

tldr: 

bug 1 - 一些请求被路由到测试服务器 

bug 2 - 性能优化 bug 给稀有 token 分配了高概率 

bug 3a - 精度不匹配导致最高概率 token 被丢弃 

bug 3b - approximate top-k 算法完全错误




[1]

技术后期诊断报告: https://www.anthropic.com/engineering/a-postmortem-of-three-recent-issues


👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

AI 写代码爽归爽,但删库跑路也是真的会发生!

Andrew Ng Launches A Campaign For Data-Centric AI

吴恩达最新分享了他们团队使用 AI 编程助手的血泪史:

一个 Agent 竟然执行了 rm *.py 命令,把整个项目的代码全删了!

更离谱的是,当被质问时,这个 AI 还道歉说:「那确实是个极其愚蠢的错误。」

虽然道歉多少让人感觉好了一点,但,代码已经没了啊!

在 AI Fund 和 DeepLearning.AI 最近举办的 Buildathon 活动上,吴恩达分享了他对 Agentic Testing(智能体测试)的最新思考。

他认为,在 AI 辅助编程时代,自动化测试正变得前所未有的重要。

网友 David(@DavidSHolz) 预言:

AI 将重写所有软件库、编程语言和硬件子单元,清除掉人类文明的工程债和技术债。我称之为「大重构」——再见 JavaScript,欢迎回归三进制处理器!

但……

如果 Agent 写的代码不可靠,它们写的测试就真的会可靠吗?

反正我目前是没信心的。

我的 Claude Code 就曾经干过把没通过的测试 case 删除来达到通过的目标(之前的文章有写)。

测试很重要,但代码 review 也同样重要。

就目前而言,我仍然会 review 几乎每一行在生产环境中运行的代码。



吴恩达原文:

自动化软件测试在 AI 辅助编程时代正变得越来越重要。

智能体编程系统加速了开发,但也不可靠。

智能体测试(让 AI 编写测试并检查你的代码)正在发挥作用。

自动测试你打算在其之上构建的基础设施软件组件特别有帮助,能够带来更稳定的基础设施和更少的下游调试。

软件测试方法论如测试驱动开发(TDD:一种测试密集型方法,先编写严格的正确性测试,然后通过编写能通过这些测试的代码来推进)是发现 bug 的重要方式。

但编写测试可能需要大量工作(我个人因为这个原因从未采用 TDD)。由于 AI 非常擅长编写测试,智能体测试正受到越来越多的关注。

首先,编程 Agent 确实会出问题! 

我的团队大量使用它们,我们见过:

  • Agent 引入的大量 bug,包括需要人类花费数周才能发现的微妙基础设施 bug
  • 当编程 Agent 为了简化开发而让密码重置变得更容易时,在我们的生产系统中引入了安全漏洞
  • 奖励黑客攻击,编程 Agent 修改测试代码使其更容易通过测试
  • Agent 在工作目录中运行「rm *.py」,导致删除了项目的所有代码(幸运的是,在 GitHub 上有备份)

在最后一个例子中,当被追问时,Agent 道歉并同意:那是一个极其愚蠢的错误」。这让我们感觉好了一些,但损害已经造成了!

尽管有这些错误,我仍然喜欢编程 Agent,并看到它们让我们的生产力大幅提升。

为了让它们更可靠,我发现优先考虑在哪里进行测试很有帮助

我很少编写(或指导 Agent 编写)前端代码的大量测试。

如果有 bug,希望它很容易被看到,并且造成的持久损害很小。例如,我发现生成代码的前端 bug,比如网页上信息的显示问题,相对容易发现。当网站的前端看起来不对时,你会立即看到,你可以告诉 Agent 并让它迭代修复。

更高级的技术:使用 MCP 让 Agent 与 Playwright 等软件集成,自动截图,这样它可以自主查看是否有问题并进行调试。)

相比之下,后端 bug 更难发现

我见过微妙的基础设施 bug,例如,只在某些特殊情况下导致数据库记录损坏的 bug,这需要很长时间才能发现。

为你的基础设施代码设置严格的测试可能有助于更早发现这些问题,并为你节省许多小时的艰难调试。

你打算在其之上构建的软件组件中的 bug 会导致难以发现的下游 bug。

此外,深入软件栈中的组件(你在其上构建多个抽象层)的 bug 可能只在几周或几个月后才浮现,远在你忘记构建这个特定组件时在做什么之后,并且真的很难识别和修复。

这就是为什么测试软件栈深处的组件特别重要

Meta 的座右铭「快速移动,保持稳定的基础设施」(取代了「快速移动,打破常规」)今天仍然适用。

智能体测试可以帮助你确保你有良好的基础设施供你和他人构建!

在 AI Fund 和 DeepLearning.AI 最近的 Buildathon 活动中,我们举行了一场与智能体编程专家的小组讨论(Michele Catasta,Replit 总裁;Chao Peng,Trae 首席研究科学家;Paxton Maeder-York,Anthropic 风险投资合作伙伴;由 AI Fund 的 Eli Chen 主持),演讲者分享了最佳实践。

测试是讨论的主题之一。

那次小组讨论是我在 Buildathon 的亮点之一,你可以在 YouTube 上观看视频。

参考资料

[1] 

原文链接: https://www.deeplearning.ai/the-batch/issue-319/

[2] 

youtube讨论: https://www.youtube.com/watch?v=9VxB8ewCHN0


关于 Claude Code 和 Codex 的使用/交流,欢迎进《Claude Codex》群交流,任何相关问题都有热心群友第一时间解答(禁广告,中转谢绝入内)~
图片
由于群满(超200人)了不能直接进,请先进临时群(见评论区)后加我,备注"CC" 即可,我稍后会拉你进群。

👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。

想必你已经看到了 Meta Reality Labs 在昨天 Meta Connect 大会现场演示翻车的尴尬之事了。

来看视频:

小扎当时一脸尴尬到脚趾抠地了,试了无数次后……终于放弃了。

当时他的内心估计也是一脸懵,属实是整不明白:

彩排的 100 次,不都全是成功的吗?!!!

心疼小扎一秒钟……

现在,原因找到了

Meta 开发者倡导者 Jake Steinerman(@jasteinerman) 无情地揭露了这场翻车背后的真相:

当厨师说「Hey Meta start Live AI」时,它同时激活了房间里每个人的 Meta AI,并有效地对我们的服务器进行了 DDOS 攻击 🤣

这,就是现场翻车的真实原因!

Ian Rumac(@IanIsSoAwesome) 调侃:

哦,看,我找到你们的服务器了

更让人哭笑不得的是,整个演示居然跑在开发服务器上

Jake Steinerman 解释道,他们本来想把 Live AI 的流量路由到开发服务器,以避免影响生产环境。

毕竟现场演示嘛,没多大流量,稳定更重要。

但没想到的是,MPK(Meta总部)的所有人都被路由到了这个服务器

自然,也包括所有参会者。

这就意味着,当语音命令响起时,现场数百台设备将会同时向一个本不该承载如此流量的开发服务器发起请求。

开发服务器:我太难了……

除了服务器过载,WhatsApp 通话也出了岔子。

Jake 表示,这是由于眼镜显示屏过早进入睡眠状态的意外 bug 造成的。

不过好消息是,他们已经修复并打了补丁。

两个问题叠加,让这场原本应该震撼全场的演示变成了「大型社死现场」。

无法想象会议结束后后台的气氛

不过,事故的背后,也暴露了一个潜在的安全问题。

网友 tpae(@tpae) 质疑道:

所以你的声音可以激活别人的设备?这听起来像是设计缺陷

Adam MacBeth(@adamac) 也提出了同样的疑问:

为什么「Hey Meta」会激活其他人的设备?

Lee Callender(@leefcallender) 作为 Meta 的多模态 AI 负责人回应说:

不,我们对此有防护措施,但在回声室中效果不佳。

看来在嘈杂的会议室环境中,声音识别的防护机制失效了。

这有点像早年 Alexa 被电视广告触发的尴尬往事。

2018 年,一个小女孩通过电视学会了向 Alexa 订购玩具,结果新闻报道这件事时,播音员说出的「Alexa,给我订一个娃娃屋」又触发了无数家庭的设备下单。

现在,历史以另一种方式重演了……

Jarrod(@jarrodxmartian) 也安抚到:

Jake,我认为 Meta RL 团队做得很好,看到一个不是预先录制的现场演示真是令人耳目一新。向你和你的团队致敬。墨菲定律真的很喜欢现场演示,你们处理得很好。

Brandon Tyler(@BrandonTyler) 则感谢透明度:

实际上,喜欢这种透明度,谢谢

JP(@jpchen__) 则从技术角度分析了这次事故:

视频通话的竞争条件非常微妙,但有点惊讶这没有提前预料到,这几乎不算是边缘情况。开发服务器没有只接受舞台上设备的请求是草率的,无意冒犯。

好吧,虽然透明,但这确实值得反思。

作为一家市值万亿的科技巨头,在如此重要的发布会上使用开发服务器,且没有做好请求过滤,确实显得准备不足。

这世界光鲜的 AI 背后,果然还依旧是一个巨大的草台班子。

包括我们自己,谁没有个尴尬傻 X 的时候啊……

Cherelynn(@Cherelynn) 则是友善地给出了鼓励:

你们尽力了——你们学到了经验,下次会很棒的!继续加油!

这次翻车给整个行业上了一课:现场演示的墨菲定律永远存在,而当 AI 遇上现场演示,情况可能更加不可预测。

这就是现场演示的魅力所在,你永远不知道下一秒会发生什么。

Jake 自己说到:

这就是现场演示的代价!

Meta 也是用一次「大型社死」为行业贡献了宝贵经验了。

各位做 AI 硬件的朋友注意了,以后在现场演示中,请不要再踏入这条 Meta 踩过的尴尬河流了!

👇

👇

👇

另外,我还用AI 进行了全网的AI 资讯采集,并用AI 进行挑选、审核、翻译、总结后发布到《AGI Hunt》的实时AI 快讯群中。

这是个只有信息、没有感情的 AI 资讯信息流(不是推荐流、不卖课、不讲道理、不教你做人、只提供信息、希望能为你节省一些时间)

欢迎加入!

图片

也欢迎加群和5000+群友交流。