跳到主要内容

HippoBuddy:从"框架驱动"到"能力驱动"

AI 时代的 Agent 框架:从"框架驱动"到"能力驱动"


缘起

以安装量、Pull Requests 数量和 Stack Overflow 讨论热度来看,当前市场上 AI Agent 框架绝大多数以 Python 为主(LangChain、CrewAI、AutoGPT 等),背后原因有历史的惯性,也有生态的路径依赖:

  • LLM SDK 优先支持 Python — OpenAI、Anthropic、HuggingFace 的 SDK 首发都是 Python
  • 学术界的传承 — 深度学习/CV/NLP 的研究几乎全用 Python,研究者进入工业界自然延续
  • Jupyter 文化 — Agent 开发本质是实验驱动,Python 的 REPL + Jupyter 迭代极快

HippoBuddy 选择了 Java 21。这不是技术上的逆流而行,而是一次有意识的架构判断:Agent 的核心复杂度不在"调用 LLM",而在"构建可靠的自动化系统"——这正是 Java 生态积累数十年的强项。


核心洞察:框架在 AI 时代的角色变化

框架的黄金时代

在 AI 爆发之前,框架的价值无可争议:

你想做一个 Web 项目 →
需要 HTTP、路由、MVC、ORM、事务管理、DI…
自己写?半年没了
→ 用 Spring Boot,一天搞定 ✅

框架的本质是**"将大量重复的基建封装好,让你专注于业务"**。

AI 时代的转折

但 Agent 开发的"基建"发生了根本变化:

你想做一个 Agent →
需要 LLM 调用、Tool Calling 循环、消息管理、Prompt 模板…
自己写?—— 让 AI 帮你写

"帮我写一个 Tool Calling 循环,
LLM 返回 function_call 时解析参数并执行本地工具"
→ 30 秒生成,5 分钟调通 ✅

旧世界:

框架价值 = 节省的工作量 - 学习成本 - 约束成本
≈ 巨大,因为手写太难

AI 时代:

框架价值 = 节省的工作量 - 学习成本 - 约束成本
≈ 变小,因为 AI 能帮你手写大部分基建

框架解决的是"旧问题",不是"新问题"

框架擅长的旧问题Agent 场景的实际需求
Spring事务管理、ORM、AOPAgent 不需要数据库事务
LangChainChain、Agent、Memory 抽象Prompt 改一下比改框架配置快 10 倍
HibernateORM 映射Agent 状态是对话消息,不是关系型数据
MyBatisSQL 映射同上

Agent 真正需要的东西,框架反而帮不上忙:

真实需求解决方案需要框架吗?
调 LLM APIOkHttp + Jackson 发 HTTP❌ 10 行代码搞定
解析 Tool CallJSON 反序列化❌ Jackson 一行注解
执行本地工具接口 + 实现❌ 7 行接口定义
管理对话历史List<Message>❌ ArrayList 就够了
SSE 流式响应OkHttp SSE❌ 一个库依赖搞定

Agent 的核心复杂度不在基础设施,而在 prompt 设计和工具编排——这两样框架帮不了你,甚至会限制你。


HippoBuddy 的架构选择

不用框架,用"模式"

HippoBuddy 的 Java 后端没有使用任何重量级框架——没有 Spring、没有 LangChain4j、没有 Guice。取而代之的是一套轻量的、手写的架构模式:

1. 手动 DI,而非自动注入

// CoreModule.java — 按层级手动组装依赖
ServiceLocator.registerSingleton(ToolRegistry.class, toolRegistry);
ServiceLocator.registerSingleton(LlmClient.class, llmClient);
ServiceLocator.registerSingleton(ConcurrentToolExecutor.class, concurrentToolExecutor);

没有 @Autowired、没有 @Bean、没有组件扫描。每个服务的生命周期和依赖关系都显式声明,可追踪、可调试。

2. 接口约定,而非框架注解

// ToolExecutor.java — 7 行接口定义一切
public interface ToolExecutor {
String getName();
String getDescription();
String getParametersSchema(); // JSON Schema 字符串
String execute(JsonNode arguments) throws ToolExecutionException;
}

每个工具就是一个接口实现,没有装饰器、没有基类继承链、不需要理解框架的"正确用法"。

3. 直接使用 JSON Schema,而非框架抽象

// ReadFileTool.java — Java 21 文本块直写 Schema
@Override
public String getParametersSchema() {
return """
{
"type": "object",
"properties": {
"path": { "type": "string", "description": "文件路径" },
"offset": { "type": "integer", "description": "起始行号" },
"limit": { "type": "integer", "description": "读取行数" }
},
"required": ["path"]
}
""";
}

LLM 理解的格式就是 JSON Schema,中间不需要任何框架做"二次翻译"。

为什么不选专属 AI 框架

Java 生态也有专门的 AI 框架——Spring AI 和 LangChain4j。没有选择它们,同样基于对 AI 时代框架角色的判断:

1. AI 编码时代,快速变动的框架反而是负担

如今项目的代码大量由 AI 生成,但 Spring AI、LangChain4j 仍在快速迭代期,API 变动频繁。AI 模型对这些"年轻框架"的知识覆盖有限且容易过时——你问它"Spring AI 怎么调 tool calling",它给出的代码很可能基于旧版本 API,跑起来全是 NoSuchMethodError,最终还得翻官网文档校准。与其让 AI 去学一个它学不准的框架,不如让它直接生成最稳定、最底层的 HTTP + JSON 代码——OpenAI API 规范已经一年没变了,这部分知识 AI 掌握得远比对框架准确。

2. 框架封装的能力,AI 生成更快、更可控

Spring AI 的 ToolCallback、LangChain4j 的 ToolSpecification,本质都是对"调 LLM API → 解析 JSON → 调本地方法"这一流程的封装。但让 AI 直接写这个循环,5 分钟就能得到一段无依赖、可单步调试的代码。框架帮你省的那点工作量,在 AI 编码能力面前可以忽略不计,而换来的是对每一行代码的完全掌控。

3. 复杂功能终究要自己写,框架反而变成天花板

一旦你的 Agent 需要框架没有预设的功能——比如工具级别的缓存、文件锁、并发控制策略、自定义安全拦截链——框架的抽象就会成为障碍。你要么 hack 框架的内部 API(升级兼容噩梦),要么绕开框架自己再套一层(那不如一开始就不用)。Agent 领域的"复杂功能"正在被快速定义,绑定一个框架相当于默认接受了它对"什么算复杂"的假设。

这些选择带来的自由度

因为去掉了框架的约束,HippoBuddy 可以自由地实现很多 Python Agent 框架里难以做到的事情:

能力实现方式框架下的难度
文件缓存ReadFileTool 内置 LRU 缓存,避免重复读盘LangChain 的 Tool 是 stateless 的,得自己套一层
安全拦截链BlockerChain 在工具执行前做权限/安全检查AgentExecutor 没有这个 hook 点
事件监控EventBus 发布工具执行事件,用于监控和统计需要继承框架的 callback 机制
并发工具调用虚拟线程 + ConcurrentToolExecutor,同步写法跑并发asyncio 会传染整个调用链
文件锁requiresFileLock() 控制工具间文件互斥Python Agent 基本没人做
精细错误处理LlmApiException / LlmConnectionException / LlmTimeoutException 分层异常通常一个 APIError 全兜了

JSON Schema 定义工具

每个工具通过 getParametersSchema() 返回 JSON Schema 字符串定义参数结构,ToolRegistry 统一注册,Jackson 统一序列化,构建 tools 参数列表并传给 LLM 进行 function calling。

工具执行流程:

LLM 返回 tool_call (JSON)
→ ToolRegistry.execute(name, arguments)
→ BlockerChain 安全检查
→ ToolExecutor.execute(JsonNode)
→ 返回结果字符串
→ 结果追加到消息列表
→ 继续下一轮 LLM 调用

与 Python Agent 的对比

Python Agent 的常见问题

# Python + LangChain 的典型痛苦
from langchain.agents import AgentExecutor

# 想自定义工具执行逻辑?
# → 得继承 BaseTool,实现 _run + _arun
# → 想改 agent prompt?得重写整个 agent 类
# → 想并发执行?AgentExecutor 不支持
# → 想加中间件?没有 hook 点

HippoBuddy 的对应解法

// 实现接口,仅此而已
public class CustomTool implements ToolExecutor {
@Override
public String execute(JsonNode arguments) {
// 完全自由——想加缓存、加锁、加日志、加监控都可以
// 不需要遵循任何框架的"正确姿势"
}
}

对比总结

维度Python Agent (LangChain)HippoBuddy (Java)
上手速度快,pip install 即用慢一点,但有 AI 辅助编码
灵活度框架约束多,定制困难无约束,完全自由
类型安全运行时才能发现类型错误编译期捕获大部分错误
并发模型asyncio 传染,心智负担重虚拟线程,同步写法
桌面端需额外套 Electron/PyQt原生集成 Electron
企业集成需额外桥接 Java 技术栈天然融入 Java 生态
生产部署环境管理复杂(pip env)Maven shade 单 JAR 搞定
框架版本升级LangChain 破坏性变更频繁无框架,永远不需要升级

对 AI 时代软件工程的思考

框架的定位正在变化

以前:框架 = 你能做出来的上限
现在:框架 = 你能做出来的下限(而且可能是瓶颈)

什么时候该用框架?

框架依然有价值,但要重新评估:

场景建议理由
团队有成熟技术栈沿用现有框架降低团队切换成本
核心业务无关使用框架日志、配置、监控等,没必要自己写
Agent 核心逻辑自己写这是你的核心差异化,框架帮不了你
实验性项目框架快速验证验证可行后再考虑去框架化

为什么"自己写"在 AI 时代可行了?

因为在传统开发中,写一个 Tool Calling 循环你需要:

  1. 理解 HTTP 请求和 SSE 流式响应
  2. 掌握 JSON 序列化/反序列化
  3. 设计状态管理(消息列表)
  4. 处理错误和重试
  5. 设计工具注册和发现机制

这每一项都需要查阅大量文档和代码示例。

而在 AI 时代,你只需要对 LLM 说:

"帮我写一个 Java 方法,接收 LLM 的 chat completion 响应, 解析其中的 tool_calls,根据 tool name 找到对应的执行器, 传入参数执行,把结果包装成 tool message 返回。"

30 秒后,你就有了一份可运行的代码。 剩下的就是根据你的具体需求做调整——而这正是框架最限制你的地方。


结语

HippoBuddy 的架构选择背后的核心哲学是:

AI 时代,最好的"框架"就是没有框架。

不是因为框架不好,而是因为框架解决的是"已知问题", 而 Agent 领域还在快速演化,每天都有"未知问题"出现。

用灵活的架构 + AI 的编码能力,比绑定任何一个框架都更能应对变化。

这也解释了 HippoBuddy 技术栈选择背后的逻辑:

问题回答
为什么用 Java?类型安全 + 虚拟线程 + 企业级生态,Agent 是系统不是脚本
为什么不用 Spring?Agent 不需要 ORM/事务/AOP,手写 DI 更可控
为什么不用 LangChain4j?Tool Calling 的核心就是一个循环,自己写比学框架快
为什么用 Electron?桌面端是最好的 Agent 交互形态,Electron 是 Java 后端最自然的搭档
为什么能自己写?因为 AI 让手写基建的成本从"数月"降到了"数分钟"

这就是 HippoBuddy 的架构哲学:不追随框架潮流,而是用最适合的方式构建真正可用的 AI Agent。