开源了一个 Java 多智能体 LLM 框架 Baton:一个依赖,把 Agent 循环、工具调用、记忆、编排全配齐
我把做 LLM 应用最常踩的坑------多厂商接入、会话记忆、工具调用、多智能体编排------做成了一套开箱即用的 Java 框架,已发布 Maven Central。核心模块零 Spring 依赖,JDK 17 开箱即用。
前言
用 Java 做 LLM 应用开发,你会发现一个尴尬的现状:Python 生态里 LangChain、LlamaIndex 卷得飞起,Java 这边却基本只有 Spring AI 一条路------绑定 Spring 全家桶,想在自己已有的工程里嵌一个 Agent 循环,或者不用 Spring,选择就很有限。
所以我写了 Baton (指挥棒/接力棒):单智能体的 ReAct 循环是"接力",多智能体的工作流编排是"指挥"。它不是 Spring AI 的替代品,而是一套核心纯 Java、按需组合的积木------你可以只拿一个对话循环嵌进任何工程,也可以一个依赖拉起带 HTTP/SSE/WebSocket/gRPC 的完整服务。
已经发布 Maven Central,欢迎体验:
xml
xml
<dependency>
<groupId>io.github.lookfukc</groupId>
<artifactId>baton-all</artifactId>
<version>1.0.0</version>
</dependency>
GitHub:github.com/lookfukc/ba...
一、它能干什么
| 能力 | 说明 |
|---|---|
| 多厂商接入 | 一套 API 适配 OpenAI / Anthropic / Gemini 三种协议,DeepSeek、GLM 等 OpenAI 兼容厂商开箱即用,带 per-model 定价与成本核算 |
| ReAct Agent 循环 | 有状态/无状态双模式,流式输出、迭代熔断、dangling tool-call 自动修复 |
| 工具调用 | 工具注册表 + 内置工具(安全计算器/时钟/SSRF 防护的 HTTP 抓取)+ 完整 MCP 客户端(stdio/HTTP) |
| 会话记忆 | 文件 / SQLite / PostgreSQL / Redis 四后端,TTL 过期、摘要压缩、快照回滚、AES-256-GCM 加密 |
| 长期记忆 | pgvector 向量+关键词混合召回、LLM 事实抽取 |
| 多智能体编排 | 顺序 / Router / Supervisor / 人工 Checkpoint,运行状态落盘、断点续跑 |
| 可观测性 | Micrometer 指标、trace、事件总线、HMAC 签名 webhook |
| 中间件链 | 重试 / 限流 / 主备切换 / 响应缓存,流式与非流式全覆盖 |
二、3 分钟跑起第一个 Agent
注册厂商 → 组装 → 跑循环,就这么点代码:
java
less
// 1. 注册厂商(密钥永远走环境变量)
Registry registry = new Registry();
registry.register(ProviderConfig.builder()
.id("deepseek").protocol("openai")
.baseURL("https://api.deepseek.com/v1")
.apiKeyEnv("DEEPSEEK_API_KEY")
.defaultModel("deepseek-chat")
.addModel(ModelConfig.builder().id("deepseek-chat")
.capabilities(ModelCapabilities.builder()
.streaming(true).toolCalls(true).contextWindow(64_000).build())
.inputPricePerMtok(0.28).outputPricePerMtok(1.10)
.build())
.build());
registry.mustGet("deepseek").loadApiKeyFromEnv();
// 2. 组装 + 中间件(日志→重试→流式重试)
LLM llm = Adapters.newLLM(registry.mustGet("deepseek"));
LLM wrapped = Pipeline.streamRetry(
Pipeline.of(llm, Pipeline.logging(null), Pipeline.retry(3)), 3);
// 3. Agent 循环
Loop loop = new Loop(wrapped, new ToolRegistry(),
PersistentMemory.open("./sessions", null),
Loop.Config.builder()
.model("deepseek-chat")
.systemPrompt("你是一个简洁的助手")
.maxIterations(16) // 熔断,防失控
.tokenBudget(32_000) // 预算内自动截断历史
.onEvent(e -> { // 流式回调
if (e.type() == LoopEvent.Type.DELTA_TEXT) System.out.print(e.text());
})
.build());
Loop.RunOutcome out = loop.run("user-42", "帮我查下明天天气并总结");
System.out.printf("tokens: in=%d out=%d%n",
out.usage().inputTokens(), out.usage().outputTokens());
自定义工具也只要几行:
java
less
tools.register(Tool.of("weather", "查询城市天气",
Json.parse("""
{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}"""),
args -> ToolResult.of(Json.parse(args).get("city").asText() + ":晴,23°C")));
三、两个我特别想聊的设计
1. 有状态 / 无状态,一个 API 讲清楚
框架最常被问的问题:历史由谁保管? Baton 两种都给,内部循环逻辑完全一致:
- 有状态 :
loop.run(sessionId, input)------只传会话 ID,记忆、截断、工具配对全由框架管。适合服务端聊天应用。 - 无状态 :
loop.runWithHistory(history, input)------框架零存储,跑完把本轮新增消息newMessages()还给你自己存库。适合 Serverless、已有用户表、数据合规严格的场景,水平扩展天然不需要共享存储。
2. 多智能体编排,带人工审批点
java
php
Orchestrator orch = new Orchestrator(FileRunStore.open("./runs"));
orch.registerAgent("writer", writerLoop);
orch.registerAgent("reviewer", reviewerLoop);
orch.registerWorkflow(new Workflow("review", List.of(
new AgentStep("", "writer", "$input"),
new CheckpointStep("approve", "审核草稿"), // 人工审批点
new AgentStep("", "reviewer", "$prev"))));
try {
orch.run("review", "写一首关于秋天的诗");
} catch (Orchestrator.CheckpointException cp) {
// 暂停在审批点;人工批复后跨进程、跨重启续跑
orch.resume(cp.state.id, "通过,发表它");
}
Router 步骤(分类器选路由)、Supervisor 步骤(监督者循环委派 worker)也都内置了。
四、模块化:要什么拿什么
核心链路(core→agent→orchestrator)零 Spring 依赖 ,不想挑模块就 baton-all 一个依赖全家桶:
| 引入 | 用途 |
|---|---|
baton-agent |
只跑对话循环(自动带 core/tools) |
baton-provider |
连真实 LLM(OpenAI/Anthropic/Gemini 协议) |
baton-memory |
会话记忆(四后端可选) |
baton-orchestrator |
多智能体 |
baton-ltm |
pgvector 长期记忆 |
baton-server |
直接起 HTTP/SSE/WS/gRPC 服务 |
五、质量怎么保证
- 349 个测试用例,覆盖协议适配流式语义、Agent 并发、记忆原子组截断、编排断点续跑、SSRF/限流/重试回归
- GitHub Actions CI 里跑真实 Redis / PostgreSQL+pgvector 服务容器,外部存储联调用例全量激活,不是摆设
- 开发过程抓出并修复过若干有意思的 bug:JDK 线程中断污染 BlockingQueue 导致流式事件静默丢失、Lettuce 单连接上 MULTI..EXEC 被并发读穿透、pgvector 占位符风格不兼容 PgJDBC 等------每个都有对应回归用例钉死
总结
如果你在用 Java 做 LLM 应用,想要一套不绑框架、按需组合、API 朴素直白的 Agent 工具箱,可以试试 Baton:
- GitHub:github.com/lookfukc/ba... (中英双语文档,点个 ⭐ 是对开源人最大的鼓励)
- Maven Central:
io.github.lookfukc:baton-all:1.0.0 - 许可:MIT,随便用
欢迎 issue / PR 交流。