每隔一段时间,开发圈都会重新争一次"什么语言最好"。到了 AI 时代,这个问题又多了一层:Python 是不是已经赢了?Rust 会不会吃掉 C++?Go 适不适合做 AI?Java、PHP 这种传统后端语言还有没有必要?
只看 GitHub 示例,很容易得到一个简单结论:AI 就是 Python。可把一个真正运行的大模型系统拆开,会发现事情完全不是这样。训练脚本可能是 Python,Tensor Runtime 大量是 C++,GPU 上跑的是 CUDA Kernel;线上入口可能是 Go 或 Java,浏览器还是 TypeScript,某些本地 Runtime、网关、沙箱开始出现 Rust。所谓"一个 AI 项目",实际上经常是一串不同语言通过 ABI、FFI、RPC 和数据格式拼起来的系统。
这也是今天再聊编程语言比较有意思的地方:重点已经不是哪门语言能不能做某件事,而是哪门语言适合占据哪一层,以及跨层的成本到底是什么。
Python
Python 在 AI 里的地位很高,但原因经常被说错。它不是因为计算快。CPython 的动态对象模型、解释器开销、引用计数,都决定了它不适合亲自承担大规模数值计算。真正让 Python 成为 AI 主语言的,是它很适合做"控制面":定义模型、组织数据、发起计算、拼接组件、做实验,然后把重活交给下面的 native code。
PyTorch 是最典型的例子。写下:
python
y = torch.matmul(a, b)
看起来是 Python 在算矩阵乘法,实际上 Python 主要负责发起调用。PyTorch 的底层建立在 C++ Tensor 库 ATen 之上,算子会根据设备、数据类型等条件分发到 CPU、CUDA 等不同 backend。PyTorch 官方 C++ 文档也明确提到,Python 前端并不必然比 C++ 前端慢,因为绝大多数昂贵的数值运算本来就会进入 C++。
所以 Python 在 AI 中最成功的地方,不是把 C++ 干掉了,而是把 C++ 藏起来了,这其实是非常重要的工程能力。研究人员可以在 Python 中写:
python
loss.backward()
optimizer.step()
不需要同时处理模板、指针、显存分配和底层算子实现;真遇到性能热点,又可以通过 C/C++/CUDA Extension 把局部沉下去。Python 官方本身也长期提供 C API:既可以让 C/C++ 写 Python 扩展,也可以把 Python 解释器嵌进其他程序。因此 Python 很像 AI 技术栈里的"总控台"。它的性能上限并不完全由 Python 自己决定,而是取决于能否尽快越过 Python 边界,把工作交给 NumPy、PyTorch、CUDA 或其他 native runtime。这也解释了一个常见现象:同样是 Python,代码性能可能差几个数量级。一个 Python for 循环逐元素计算,和一次调用底层向量化算子,虽然表面都是 Python,执行路径完全不是一回事。
Python 真正的问题也在边界上。一旦程序包含大量细粒度 Python 调用、频繁对象创建、复杂并发或严格的尾延迟要求,解释器和运行时成本就会重新出现。此时继续"所有东西都用 Python"未必划算。
官方资料:Python C/C++ 扩展文档、PyTorch C++ Frontend
C++
如果只做 API 调用,可能很久都碰不到 C++;但越接近模型 Runtime,C++ 越难绕开。原因不是历史包袱这么简单。Tensor 本质上不是一个普通业务对象,它背后有 dtype、shape、stride、device、storage、layout 和生命周期。一次看似简单的算子调用,下面可能涉及 CPU/GPU backend 选择、线程池、向量化指令、内存分配、异步执行以及不同设备之间的数据移动。PyTorch 的 ATen 就处在这个位置。官方把它定义为基础 Tensor 和数学运算库,Python 与 C++ 的大量上层能力都建立在它之上。Autograd 再在 Tensor 操作之上记录计算图,用反向模式自动微分求梯度。到了推理系统,问题还会更底层。模型服务真正关心的往往是:
text
权重怎么装载?
KV Cache 怎么分配?
Batch 怎么合并?
不同请求怎么调度?
CPU 到 GPU 有没有多余复制?
显存碎片如何控制?
量化后的数据如何布局?
一个算子是否值得融合?
这些问题都要求程序对内存和执行过程有比较强的控制。C++ 的优势就在这里:抽象能力足够强,同时又能一路向下碰到地址、布局、SIMD、线程、ABI 和设备 API。
C++ 的代价也很明显。语言本身太大,资源管理和并发安全高度依赖工程纪律。RAII、智能指针、现代 C++ 已经解决了很多问题,但"可以写得很安全"和"语言强制你安全"仍然不是一回事。
所以在 AI 时代,C++ 并没有因为 Python 流行而退场。恰恰相反,Python 越成功,下面越需要有人把高层调用变成高效的 native execution。
CUDA
CUDA 更适合单独拿出来说,因为到了这一层,"哪门通用语言更好"的讨论已经开始失效。
GPU 和 CPU 的执行模型差别很大。NVIDIA 当前 CUDA Programming Guide 中,线程以 block 组织,block 再组成 grid;同一 warp 中以 32 个线程为一组执行 SIMT。GPU 还有 global memory、shared memory、local memory、register 等不同层级的存储空间。写一个能运行的 Kernel 不难,写一个真正快的 Kernel,考虑的却是另外一套东西。
例如矩阵计算性能可能受到这些因素影响:
text
线程块如何划分
warp 是否发生严重分支分歧
global memory 访问能否合并
数据是否能复用到 shared memory
寄存器压力是否降低 occupancy
Kernel launch 是否过于碎片化
是否能做 operator fusion
Host / Device 之间是否发生无谓传输
这里最值得注意的是内存。现代 GPU 的算力增长很快,但数据必须及时送到计算单元。NVIDIA 官方文档也把 global memory 的访问效率列为 Kernel 性能的重要因素,并专门讨论 coalesced memory access。很多时候,程序不是"算得不够快",而是"数据喂不进去"。
这也是为什么大模型优化不能简单理解成"把 Python 换成 C++"。如果瓶颈已经在 GPU 上,真正需要看的可能是 Kernel、显存带宽、通信、量化、Batch、KV Cache,甚至硬件拓扑。
官方资料:NVIDIA CUDA Programming Guide
Rust
Rust 在模型训练生态里远没有 Python、C++ 那么强,但在 AI 基础设施里很值得看。它解决的是一个很老的问题:如果既想像 C/C++ 一样控制资源,又不想把大量内存安全问题交给程序员自觉,怎么办?
Rust 的答案是 ownership 和 borrowing。一个值有明确的 owner,引用受到借用规则约束,很多悬垂引用、重复释放、数据竞争会在编译阶段被拒绝。这里真正关键的不是"Rust 不会出 bug"------当然会------而是它把一类原本需要运行时或人工保证的约束移到了类型系统和编译器里,同时不依赖传统 GC。这对 AI 应用正在变得更有价值,因为 Agent 已经开始从"调用模型"变成"执行环境"。
一个 Agent Runtime 可能允许模型访问:
text
Filesystem
Shell
Browser
Network
MCP Server
Credential
Local Process
Remote Tool
这时候真正麻烦的已经不只是 Prompt,而是权限、隔离、资源生命周期、并发任务、取消、超时、崩溃恢复和不可信输入。一个会执行工具的 Agent,本质上已经开始接近小型操作系统 Runtime,而不是普通的聊天机器人。
Rust 很适合进入这些地方:本地 Runtime、沙箱外围、高性能代理、网络服务、CLI、数据处理组件、Tokenizer,以及一些对内存占用和尾延迟敏感的服务。
当然,Rust 也有成本。Ownership 带来的安全性不是免费的午餐,它把一部分运行时问题变成了编译期复杂度。生命周期、trait、async 生态以及 FFI 都会增加开发门槛。所以"Rust 更安全"不能直接推出"所有 AI 基础设施都应该用 Rust"。
官方资料:The Rust Programming Language - Ownership
Go
Go 在模型本身这一层没什么存在感,但在模型周围很舒服。一个线上 AI 产品除了推理,还需要 API Gateway、鉴权、计费、限流、任务队列、模型路由、流式输出、WebSocket、日志、监控和服务发现。这些东西并不需要直接操作 Tensor,却要处理大量网络连接和并发任务。
Go 的优势就在这里:语言小、部署简单、goroutine 的并发模型容易使用,标准库的网络能力成熟。它还有 GC,所以不像 Rust/C++ 那样要求开发者管理对象生命周期。
GC 当然也不是没有代价。Go 官方 GC Guide 很直接地讨论了 CPU 与内存之间的 trade-off:GC 越频繁,通常越省内存但消耗更多 CPU;降低 GC 频率可以减少 GC CPU 成本,但会允许 heap 增长。Go 还提供 GOMEMLIMIT,让服务在容器这类固定内存环境里给 runtime 一个软内存上限。这点很适合拿来理解不同语言的设计取舍。Rust 倾向于在编译期解决生命周期问题,Go 则接受 runtime 和 GC 的存在,换取更简单的开发模型。两边都能写高性能服务,但成本落在不同地方。
对于 AI Gateway、模型代理、任务系统、控制面服务,Go 往往是很实用的选择;如果一个组件对极致内存控制、确定性延迟或 native integration 要求更高,再考虑 Rust/C++ 可能更合适。
官方资料:Go Garbage Collector Guide
Java
Java 在 AI 讨论里经常显得"不够新",但生产系统不是从 2022 年才开始建设的。大量企业核心业务仍然运行在 JVM 上。订单、支付、风控、库存、供应链、CRM、ERP,这些系统不会因为多了一个 LLM 就整体迁到 Python。更常见的情况是原来的 Java 服务继续承担业务一致性、事务和领域逻辑,把模型作为新的外部能力接进来。
例如:
text
Java Order Service
│
├── MySQL
├── Redis
├── MQ
└── Model Gateway
│
└── LLM / Embedding / Reranker
一旦模型通过 HTTP、gRPC 或消息系统暴露,调用方是什么语言其实已经不重要。跨进程之后,真正的契约是协议和 schema,而不是对方的语言。
Java 还有一个容易被忽略的优势:成熟的运行时。JIT、GC、线程模型、profiling、observability、成熟框架和庞大的企业生态,使它仍然适合长期运行的大型业务服务。AI 给 Java 带来的更像是"新增一种基础设施依赖",而不是要求它让位。
真正需要警惕的是另一种情况:为了使用几个 Python 独有的模型库,强行把复杂业务逻辑也搬进 Python 服务,最后把事务边界、领域模型和基础设施拆得一团糟。语言边界应该服从系统边界,而不是服从热点。
C#
C# 和 Java 的情况有些像,但它还有两个比较明显的阵地:Windows/.NET 企业应用和 Unity。
AI 真正进入桌面软件、工业软件、内部工具和游戏之后,C# 的位置反而很自然。一个 Unity 游戏里的 NPC 系统可以把 LLM 当作服务,一个 Windows 客户端也可以调用本地模型或远程模型。没有任何理由为了"AI"两个字,把原来的 UI、设备接口、业务逻辑全部换成 Python。
.NET 这些年在 AOT、性能和跨平台方向也一直在推进,因此 C# 不应只被理解成"Windows 语言"。对已经处在 .NET 生态的团队来说,AI 更多是能力接入问题,不是语言迁移问题。
JavaScript / TypeScript
AI 应用最终还是要面对人,而 Web 仍然是最重要的交互载体之一。
JavaScript 的特殊性在于浏览器。无论后端用了多少种语言,只要最终产品是标准 Web 应用,浏览器里的交互逻辑仍然绕不开 JavaScript 体系。TypeScript 则是在 JavaScript 上增加静态类型检查和更完整的工程工具,最后仍然进入 JavaScript 生态。TypeScript 官方对自己的定义就是"JavaScript with syntax for types"。
AI 还让前端出现了一些过去不那么常见的状态管理问题。普通 CRUD 经常是一次请求对应一次响应;Agent 却可能持续几十秒甚至几分钟:
text
用户请求
↓
模型输出
↓
Tool Call
↓
工具执行中
↓
返回 Tool Result
↓
模型继续
↓
生成 Artifact
↓
等待用户确认
↓
继续执行
前端需要处理 streaming、增量 Markdown、工具状态、任务取消、重连、幂等、长任务恢复、文件和多模态输入。有些产品还要把服务端 Agent 的状态映射成 UI 中可操作的状态机。
所以 AI 并没有让前端变成"套个聊天框"。真正复杂的 Agent 产品,前端反而比传统表单式后台更难做。
官方资料:TypeScript
PHP
PHP 和模型底层基本没有关系,这一点没必要硬抬。
它没有 Python 那样的模型研究生态,也不是 Tensor Runtime、GPU Kernel 或 AI Infrastructure 的主流语言。但"PHP 不适合训练模型"和"PHP 不能做 AI 应用"是两回事。
如果模型已经是一个 HTTP 服务:
text
PHP ──HTTP──> Model API
那它和 Java、Go、C# 调模型没有本质区别。对于 WordPress、电商、CMS 和大量现有 PHP 系统,增加摘要、客服、翻译、Embedding、搜索等能力,直接调用模型服务往往比重写系统合理得多。
因此 PHP 在 AI 时代的位置很清楚:它不是模型技术栈的重要组成部分,但仍然可以是 AI 产品的业务应用层。语言的存量生态有时候比"技术上新不新"更重要。
Swift / Kotlin
端侧 AI 越来越重要之后,Swift 和 Kotlin 也不能只看成"写 App UI 的语言"。手机端和云端最大的区别是,它直接拥有摄像头、麦克风、传感器、通知、蓝牙、文件以及系统权限。模型如果只存在云端,它只是一个 API;模型进入端侧之后,就可以和这些设备能力直接组合。于是移动端架构可能变成:
text
Swift / Kotlin App
│
├── Local Model
│
├── OS Framework
│
└── Cloud Model
这里真正有价值的是端云协同:哪些任务本地完成,哪些交给云端;哪些数据不能离开设备;本地模型如何量化;模型下载和版本如何管理;端侧内存和功耗怎么控制。所以移动开发语言不会因为 AI 而失去价值,反而会因为模型进入设备而多出一层新的系统问题。
语言之间到底怎么粘起来
多语言系统真正难的地方,从来不是"能不能互相调用",而是边界设计。
同进程内通常依赖 ABI/FFI。例如 Python 调 C/C++ 扩展、Rust 调 C ABI。这种方式调用成本低,也可以做到少复制甚至共享同一块内存,但耦合很深:双方必须处理 ABI、内存布局、生命周期、异常边界和线程模型。
跨进程后一般换成 IPC、HTTP、gRPC、消息队列等。这会增加序列化和通信成本,却换来了故障隔离、独立部署和语言解耦。
所以不能简单地说"FFI 比 RPC 快,因此应该都用 FFI"。如果一个模型服务一次推理耗时 500ms,那么多几十或几百微秒的 RPC 开销可能根本不重要;反过来,如果是每秒调用几百万次的细粒度函数,跨进程就可能完全不可接受。
真正应该先看的是调用粒度:
text
细粒度、高频、共享大量内存
↓
倾向进程内 / FFI
粗粒度、独立服务、需要隔离
↓
倾向 RPC / IPC
这比先决定"全项目统一一种语言"靠谱得多。
数据移动比语言本身更容易成为瓶颈
AI 系统里还有一个经常被语言争论掩盖的问题:数据在哪里。
假设一块数据经历:
text
Python Object
↓
CPU Tensor
↓
序列化
↓
另一个进程
↓
反序列化
↓
Pinned Memory
↓
PCIe
↓
GPU VRAM
即使中间每一种语言都"很快",整个链路也可能很慢。尤其大模型推理中,数据移动经常和计算本身一样重要。CPU 有自己的 DRAM,GPU 有自己的 device memory。NVIDIA 官方 CUDA 文档明确指出,在异构系统中,数据驻留在实际访问它的处理器内存中通常性能最好。GPU Kernel 内部还要考虑 global memory、shared memory、register 等不同层级。这也是为什么高性能 AI 系统里会反复出现这些词:
text
zero-copy
memory mapping
shared memory
pinned memory
buffer reuse
batching
kernel fusion
memory pool
它们看起来不像"编程语言特性",却可能比把 Python 改成 Rust 带来的收益大得多。一个系统慢,首先应该 profile;如果 90% 时间都耗在 GPU Kernel 和数据传输上,把负责发起调用的那几百行 Python 重写成 C++,可能几乎没有意义。
模型和应用,其实已经是两个世界
把上面的语言放在一起看,会发现 AI 项目大概存在两条技术链。
第一条是模型链:
text
Python
↓
Framework
↓
C++
↓
CUDA
↓
GPU
这一条主要解决训练、推理、算子和硬件效率。
第二条是应用链:
text
TypeScript / Swift / Kotlin
↓
Java / Go / C# / PHP
↓
Agent / AI Service
↓
Model API
这一条主要解决产品、业务、并发、权限、数据和用户交互。
Rust、C++、Go 之类的语言又可能横插在两条链中间,负责 Runtime、Gateway、Sandbox 或高性能组件。
因此"AI 项目应该用什么语言"这个问题本身就太大。训练一个新模型、做一个推理引擎、写一个 Agent Runtime、做一个 AI 电商网站,虽然都带"AI",实际面对的是完全不同的问题。
AI Coding 之后,多语言会更多还是更少
有一种可能是 AI 把编程语言逐渐统一,因为开发者不再愿意学习那么多语言;另一种可能恰恰相反:AI 会让多语言项目更多。后者至少在工程上有合理性。
过去不用某门语言,很多时候不是它不合适,而是团队不会。一个 Java 团队为了一个小组件引入 Rust,需要承担学习、招聘、Code Review、CI/CD、Debug、依赖管理等一整套成本。AI Coding 可以降低其中一部分成本,尤其是语法、API 查询、样板代码、测试、Binding 和普通重构。
但 AI 解决不了语言背后的运行模型。它可以帮忙写 Rust,却不能替工程师决定某个引用的生命周期设计是否合理;可以生成 CUDA Kernel,却不代表生成的 Kernel 就有良好的 memory access pattern;可以写 Go,却不代表自动知道服务的 GC 延迟是否符合 SLO。
因此 AI 降低的是"写另一门语言"的门槛,不会消除"理解另一门语言"的必要。这反而可能让未来的技术选型更务实:不是因为团队只会 Java,所以所有组件都用 Java;也不是因为 Rust 热,就所有东西都 Rust。真正适合独立出来、收益足够大的组件,才值得换语言。
最后
AI 时代并没有出现一门可以从网页一路写到 GPU、并且每一层都占优的语言。相反,技术栈的分层越来越明显。
Python 赢在模型生态、实验效率和编排;C++守着大量 Runtime 和高性能计算;CUDA 直接面对 GPU 的并行和内存模型;Rust 在安全敏感、高性能基础设施中提供了另一种系统编程路线;Go 很适合网络服务和控制面;Java、C# 继续承载大量真实业务;JavaScript/TypeScript 负责 Web 上真正的人机交互;Swift、Kotlin 则随着端侧模型进入设备,开始面对新的端云协同问题。
真正值得关心的,已经不是"哪门语言最强",而是三个更具体的问题:
这一层的主要成本是什么?语言边界应该放在哪里?为了引入另一门语言付出的复杂度,能不能换回足够大的收益?
把这三个问题想清楚,语言通常就没那么难选了。