Java 手写 AI Agent:ZenoAgent 实战笔记
💡 项目初衷
市面上已有 LangChain 和 AutoGen 等成熟框架,但作为 Java 开发者,通过亲手实现一个简单的 Agent 系统 —— ZenoAgent,能更深入理解其核心运作机制。本项目重点探索了手写 ReAct 循环、分布式环境下的 Human-in-the-loop、流式思考模拟以及错误处理机制。
🏗️ 核心架构概览
ZenoAgent 采用经典的 DDD(领域驱动设计)分层架构,确保高内聚低耦合。
- 后端:Java 17, Spring Boot 3, LangChain4j (LLM 交互核心), Redisson (分布式协调)
- 数据存储:PostgreSQL + pgvector (向量数据库), Redis (缓存与消息队列)
- 前端:Vue 3, TypeScript, Tailwind CSS, SSE (Server-Sent Events)

🔥 硬核亮点解析
1. 上下文构造与思维链控制 (Context Construction & CoT)
ZenoAgent 的 ThinkingEngine 采用了 Hybrid Context Assembly(混合上下文组装)策略,充分利用 LLM 的 Native Messages 结构。
- System Message: 定义角色、工具使用规范和输出格式(JSON Schema)。
- History Messages (Native): 直接插入 List,保留 User/Assistant 的原生角色信息。
- Current Context (Text): 将'当前目标'、'可用工具'、'最近的 Action 执行结果'拼接到最新的一条 UserMessage 中。
// ThinkingEngine.java 核心重构
List<ChatMessage> messages = new ArrayList<>();
// 1. System Prompt (规则与约束)
messages.add(new SystemMessage(sysPrompt));
// 2. Native History (利用 KV Cache)
messages.addAll(context.getMessages());
// 3. Current Context (动态任务背景)
String currentStepPrompt = """
## 当前目标 %s
## 可用工具 %s
## 最近执行结果 %s
""".formatted(goal, tools, actionHistory);
messages.add(new UserMessage(currentStepPrompt));
强制输出 <thinking> 标签:在 System Prompt 中明确要求 LLM 先输出 XML 格式的思考过程,再输出 JSON 格式的动作指令。引入强制的截断标记 以确保 的纯净。






