市面上的 Agent Harness 框架都是 Python/TS,JVM 开发者去哪了?

在这里插入图片描述

TL;DR(30 秒速览)

  • 调研了市面上 20+ 主流 Agent Harness 框架,Python 和 TypeScript 各占半壁江山,Rust 是少数派,JVM 生态几乎没有
  • LLM 调用本质是 HTTP 请求,Agent 框架 90% 时间在等 I/O,JVM 处理 HTTP 是专业的
  • Kotlin 凭借协程并发、sealed 类型穷举、代码简洁、LLM 生成质量高、Java 互操作五大优势,是 JVM 生态做 Agent 框架的最优解
  • 基于此我构建了 EasyAI——一个全栈 Kotlin Agent Harness 框架,开源地址:github.com/haibingzhao/easyai

打开 GitHub 搜 “Agent Harness Framework”,结果会让你产生一种错觉——这个世界只有两种语言:Python 和 TypeScript。

事实也确实如此。我花了一周时间调研了市面上几乎所有主流的 Agent Harness 框架,结论如下:

阵营 代表框架 特点
TypeScript Vercel AI SDK、Mastra、pi、openclaw、opencode、deepseek-harness 前端友好,生态增长最快
Python LangChain、CrewAI、AutoGen、LlamaIndex、hermes-agent、nanobot 生态最繁荣,快速上手首选
Rust rig、swiftide 性能极致,生态早期
JVM ……? 几乎没有

这就引出了一个灵魂拷问:JVM 上有全世界最大规模的企业级开发者群体,为啥没有对标的 Agent Harness 框架?


一个被忽视的事实:LLM 调用本质上就是一个 HTTP 请求

核心观点: Agent 框架 90% 时间在等 I/O,不需要极致 CPU 性能,需要的是优秀的并发模型、类型安全和成熟的后端生态。

在讨论语言选型之前,我们先回归本质。

不管框架包装得多花哨,Agent 的核心循环其实很简单:

发送 Prompt → 调用 LLM API(HTTP POST)→ 解析响应 → 提取工具调用 → 执行工具 → 把结果塞回 Prompt → 重复

LLM 调用就是一个 HTTP 请求,工具执行就是本地函数调用。整个 Agent 循环 90% 的时间在等 I/O(等 LLM 返回响应),10% 的时间在做本地计算(解析 JSON、估算 token、调度 DAG)。

这意味着什么?意味着 Agent 框架不需要极致的 CPU 性能(Rust 的优势场景),而是需要:

  1. 优秀的 I/O 并发模型 —— 同时等 14 个 LLM API 响应
  2. 结构化并发 —— Agent 取消时,所有后台任务干净退出
  3. 类型安全 —— 15+ 种事件类型、消息类型,重构时编译器帮你兜底
  4. 成熟的后端生态 —— 数据库、认证、可观测性、部署
    在这里插入图片描述

带着这四个需求,我重新审视了三个语言阵营。


Python:生态最繁荣,快速上手的首选

Python 的 Agent 生态确实最繁荣——LangChain 几乎成了"Agent 框架"的代名词,CrewAI 在多 Agent 编排上也有很好的抽象,快速搭建一个 Demo 或原型,Python 是最高效的选择。

但如果要从 Demo 走向生产级系统,有几个维度需要留意:

并发模型的边界。 Agent 框架主要是 I/O 密集(等 LLM 响应),asyncio 处理得很好。但当涉及上下文压缩、token 估算、DAG 拓扑排序等 CPU 密集任务时,GIL 会限制真正的并行执行。这不是说 Python 做不了——可以通过 multiprocessing 或 C 扩展绕过,只是多了一层工程复杂度。

类型安全的取舍。 Python 的 typing 是可选注解,这在快速迭代时是优势(灵活、不用和编译器较劲),但在大型项目中,重构 15 种事件类型的层级时,缺少编译器的穷举检查,需要更完善的测试覆盖来兜底。

部署与分发。 Python 的依赖管理这些年进步很大(uv、pyproject.toml),但如果要打包成桌面应用让非技术用户"一次下载零配置"使用,仍然需要额外的工程投入。


TypeScript:前端友好,生态增长最快

TS 阵营的增长势头很猛——Vercel AI SDK、Mastra 等框架对前端开发者非常友好,语言栈统一,async/await 处理 I/O 并发也很自然。对于前端集成、轻量 Agent、或者以 UI 为核心的 AI 应用,TypeScript 是很好的选择。

不过当 Agent 系统复杂度上升时,有几个维度值得关注:

CPU 密集任务与事件循环。 DAG 拓扑排序、token 估算、JSON Schema 校验——这些在 Agent 运行时频繁执行的操作,在 Node.js 单线程模型下需要谨慎处理。Worker Threads 可以分担,但跨线程通信有一定的工程成本。JVM 的线程池模型在这方面更直接——CPU 密集任务天然跑在独立线程上。

内存空间。 V8 堆内存默认约 1.5GB,对于大多数场景足够。但当 14 个 Agent 并行执行、每个持有大量消息历史时,可能需要调优。JVM 的 -Xmx 可以灵活配置到更高,GC 策略(G1/ZGC)在长时间运行的服务场景下经验更丰富。

后端生态的厚度。 这不是说 Node.js 生态不好——Express/Fastify/NestJS 都很优秀。但如果你需要企业级的事务管理、安全框架、数据库 ORM、可观测性一体化方案,Spring Boot 的"全家桶"确实更省心。


Rust:性能极致,适合特定场景

rig 和 swiftide 证明了 Rust 在 Agent 领域的可行性,对于追求极致性能、低资源占用的场景(比如嵌入式 Agent 或边缘计算),Rust 是不二之选。

不过 Agent 框架也是一个需要频繁迭代的项目——Prompt 工程要调、新工具要加、编排模式要实验。Rust 的编译周期和借用检查器在这种快速探索场景下会需要更多耐心。另外,大多数 LLM 厂商的官方 SDK 优先覆盖 Python/TypeScript/Java,Rust 有时需要用社区 SDK 或直接封装 HTTP。


那 JVM 开发者呢?

核心观点: Spring AI、MCP Java SDK、Exposed R2DBC 等基础设施已就绪,缺的只是把它们组装成一个完整框架的人。

这才是让我最困惑的地方。JVM 上有:

  • Spring AI —— 提供了优秀的模型抽象层(多 Provider 统一接口)
  • MCP Java SDK —— Model Context Protocol 的官方 Java 实现
  • Exposed R2DBC —— 全异步数据库框架
  • Jackson、Netty、Micrometer —— 序列化、网络、可观测性的工业级方案

这些基础设施都已经就绪,但就是没有人把它们组装成一个完整的 Agent Harness 框架。

这让我想到一个现实:JVM 开发者如果想用 Agent,往往需要切换到另一门语言。但很多企业的核心系统就跑在 JVM 上——让 Agent 框架融入现有技术栈,而不是引入一套新的语言生态,可能是更务实的选择。


为什么是 Kotlin,而不是 Java?

在这里插入图片描述
JVM 生态不等于 Java 生态。2026 年的今天,如果你要在 JVM 上写一个新项目,Kotlin 几乎是比 Java 更好的选择——尤其是在 Agent 框架这种场景下。

五大优势一句话总结

  1. 协程 —— 挂起不阻塞,10 个 Agent 并行只占几个线程
  2. Sealed 类型 —— 15+ 种事件类型漏写一个就编译报错
  3. 代码量少 —— 比 Java 少 30-50%,和 Python 差不多
  4. LLM 友好 —— 静态类型 + 空安全 = LLM 生成代码质量高
  5. Java 互操作 —— 白嫖整个 JVM 生态,零适配成本

理由 1:协程天然适配 I/O 密集的 Agent 循环

Agent 循环 90% 的时间在等 LLM 响应。Kotlin 协程的设计哲学就是"挂起不阻塞":

// 10 个 Agent 并行调用 LLM,只占几个线程
coroutineScope {
    agents.map { agent ->
        async { agent.callLLM(prompt) }  // 挂起等待,不阻塞线程
    }.awaitAll()
}

对比一下:Python 的 asyncio 是运行时库层面的异步,Kotlin 的 suspend fun 是编译器级别的——零运行时开销,且和 JVM 多线程无缝配合。Node.js 的 async/await 在单线程上工作得很好,但遇到 CPU 密集任务时会阻塞事件循环,Kotlin 则天然跑在 JVM 线程池上,不受此限制。

更重要的是结构化并发——Agent 取消时,所有子协程(正在执行的工具调用、正在等待的 LLM 响应)自动取消,不会泄漏后台任务:

// Agent 取消 → 所有子协程自动取消 → 资源干净释放
coroutineScope {
    launch { executeTool1() }
    launch { executeTool2() }
    // scope 取消时,tool1 和 tool2 的协程都被取消
}

理由 2:Sealed 类型 + Data Class = Agent 状态管理的天花板

Agent 框架有大量的类型层级。以 EasyAI 的事件系统为例:

sealed interface AgentEvent {
    data class MessageStartEvent(val messageId: String, val turnId: Int) : AgentEvent
    data class MessageUpdateEvent(val messageId: String, val delta: String) : AgentEvent
    data class ToolExecutionStartEvent(val toolName: String) : AgentEvent
    data class PermissionRequestEvent(val toolCallId: String) : AgentEvent
    data class CompactionStartEvent(val turnId: Int, val reason: String) : AgentEvent
    // ... 15+ 种事件类型
}

消费端用 when 处理:

when (event) {
    is MessageStartEvent -> { /* ... */ }
    is MessageUpdateEvent -> { /* ... */ }
    is ToolExecutionStartEvent -> { /* ... */ }
    // 漏掉任何一个 → 编译错误
}

TypeScript 的 switch + 联合类型也能做到类似效果,但需要额外的 never 类型断言技巧。Python 由于 typing 是可选的,这类穷举检查主要依赖测试覆盖。Kotlin 的优势在于这是语言原生支持的——不需要任何额外技巧。

Data class 的 copy() 也是 Agent 状态管理的神器:

// 不可变状态,变更 = 创建新实例
val newState = state.copy(turnId = state.turnId + 1, status = AgentStatus.RUNNING)

没有 builder 模式,没有 mutable state,没有并发修改异常。

理由 3:代码量真的少

同样的功能,Kotlin 的代码量通常比 Java 少 30-50%,和 Python 差不多但类型安全性高出一个量级。以工具定义为例:

// Kotlin:一个工具定义,约 15 行
class ReadFileTool : ToolDefinition {
    override val name = "read_file"
    override val description = "Read a file from the filesystem"
    
    override suspend fun doExecute(
        agentContext: AgentContext,
        toolCallId: String,
        args: Map<String, Any?>,
        scope: CoroutineScope,
        onUpdate: suspend (ToolUpdate) -> Unit
    ): ToolResult {
        val path = args["path"] as String
        val content = withContext(Dispatchers.IO) { Files.readString(Path.of(path)) }
        return ToolResult(content = listOf(TextContent(content)))
    }
}

如果用 Java 写同样的功能,需要更多的样板代码(getter/setter、接口实现的冗长签名)。Python 写起来代码量差不多,但类型注解需要自觉维护。Kotlin 在简洁性和类型安全之间找到了一个不错的平衡点。

理由 4:一个意外优势——LLM 生成 Kotlin 代码的质量特别高

这可能比较反常识,毕竟 Kotlin 语料相比Python和TypeScript少很多,但在 EasyAI 的实践中 LLM生成Kotlin代码质量的确很高。

为什么?深入分析后,我发现这不是巧合,而是 Kotlin 的语言特性天然契合 LLM 的预测机制:

静态类型 = 更强的上下文约束。 LLM 本质上是概率预测模型,约束越多,幻觉越少。当 LLM 看到 fun process(user: User): Result<Data> 时,它被强制限制了输入输出的结构——类型签名本身就是高密度的 Prompt。Python 的动态类型让 LLM 经常需要"猜测"变量类型,虽然 Pydantic/Dataclass 改善了这一点,但原生语法层面的约束力仍弱于 Kotlin。

空安全消灭了 LLM 最常见的 Bug。 LLM 生成代码最常见的错误之一就是空指针异常。Kotlin 在类型系统层面区分 StringString?,如果 LLM 生成了对可空类型的直接调用,编译器会直接报错。这迫使 LLM 在生成阶段就必须处理 null 检查(?.?:),大幅提高了生成代码的鲁棒性。对比来看:TypeScript 有 strictNullChecks,但很多项目并未开启或配置宽松;Python 则完全依赖运行时检查。LLM 在这两种语言中更容易生成"看起来对但一跑就崩"的空指针代码。

样板代码少 = Token 效率高。 LLM 的上下文窗口和注意力是有限的。Kotlin 表达同样的业务逻辑,代码量通常只有 Java 的 1/3 到 1/2。更少的 Token 意味着更少的"废话"干扰,LLM 可以把注意力集中在业务逻辑上。对比来看:Python 虽然语法简洁,但构建大型应用时往往需要引入大量框架装饰器和配置代码,结构容易分散;TypeScript 简洁度介于两者之间,但类型定义有时比较冗长。Kotlin 的 data class、协程语法、扩展函数等特性让它在表达完整业务逻辑时既简洁又不牺牲类型信息。

训练数据质量 > 数量。 这是一个反直觉的点。Python 的训练语料最多,但包含大量初学者脚本、过时教程和非标准写法。TypeScript 的生态极其碎片化(React/Vue/Angular/Node/Deno/Bun),API 变动频繁,LLM 经常混淆不同框架的版本或生成已废弃的写法。相比之下,Kotlin 的语料主要集中在 Spring Boot 现代实践、JetBrains 官方文档和高质量的开源库中,社区对惯用写法(Idiomatic)的要求普遍更高。高质量、风格统一的训练数据让 LLM 更容易收敛到"最佳实践"。

在 SWE-bench 和 HumanEval 等基准测试中,LLM 生成 Kotlin 代码的一次性成功率通常优于 Python,与 TypeScript 互有胜负但在大型项目中往往略占优势。当然,随着LLM推理模型的进步,语言之间的差距正在缩小,但对于生产级代码的生成质量,Kotlin 目前的结构性优势依然明显。

理由 5:Java 互操作 = 白嫖整个 JVM 生态

Kotlin 100% 兼容 Java。MCP Java SDK、Jackson、Netty、Spring AI——所有 Java 库直接可用,零适配成本。但 Kotlin 的语法比 Java 更简洁,空安全(String? vs String)在编译时消灭了大量 NPE。


最终成果:EasyAI

EasyAI 核心特性一览

特性 技术方案
DAG Swarm 编排 Kahn 算法分层拓扑排序,同层并行
AI 对抗辩论 多轮裁判制,Judge 自主收敛
Leader-Member 团队 Channel 事件驱动,Leader 动态分配
AI 创造 AI 自然语言 → Agent 配置,validate-fix 循环
增量上下文压缩 100+ 轮对话不丢上下文
影子 Git 快照 每次工具执行自动存档,文件级回滚
纵深防御权限 Shell 命令三级安全分类
桌面零配置 内置 JRE + H2,一次下载即用

技术栈:Kotlin 2.3 / Spring Boot 4.1 / React 18 / TypeScript / Vite 6 / Electron 33

开源地址:https://github.com/haibingzhao/easyai

欢迎 Star、Issue 和 PR,especially from JVM developers who finally have a proper Agent Harness framework.

下一篇,我们聊聊为什么放弃 Spring AI 的 Agent 循环,选择手写 ReAct。


写在最后

先说结论:Python、TypeScript、Rust 的 Agent 框架都非常优秀,它们在各自的场景下是更好的选择。如果你在做快速原型、前端集成、或者追求极致性能,它们可能是比 Kotlin 更合适的工具。

EasyAI 选择 Kotlin,更多是因为 JVM 生态已经有大量成熟的基础设施(Spring AI、MCP Java SDK、Exposed R2DBC……),加上 Kotlin 协程的天然并发优势、强类型系统对 LLM 生成代码的友好度,以及 Spring 全家桶的一站式体验。这不是一个"谁更好"的问题,而是一个"谁更适合我们的场景"的问题。

如果你也是一个 Kotlin/Java 开发者,想要一个生产级的 Agent 框架,希望它能融入现有技术栈而不是引入一套新的语言生态——EasyAI 可能值得看一看。

毕竟,LLM 调用只是一个 HTTP 请求,而 JVM 处理 HTTP 请求,是专业的。

更多推荐