2025年到2026年AI Agent 无疑是技术圈最热门的话题之一。Claude Code、OpenCode、Cursor 等工具让AI 编程助手成为日常而 Agent 的概念也从学术论文走进了工程实践——能自主思考、调用工具、完成复杂任务的智能体正在重塑我们对软件能力的认知。但有趣的是目前 Agent 的开源生态几乎被 Python 垄断。LangChain、CrewAI、AutoGPT……这些框架的底层都是 Python。如果你是一个 Java 开发者想深入理解 Agent 的原理或者想在 Java 项目中落地 Agent 能力会发现参考资料少得可怜。这就是我动手写agent-demo的初衷。我想知道在 Java 生态里能不能也构建出一个具备思考-工具-记忆-技能完整能力的 Agent 系统如果能架构长什么样有哪些坑和 Python 生态有什么本质不同这篇文章是我从零搭建 Java Agent 的完整记录。不只是一个 Demo 展示更是整个思考过程和技术决策的复盘。希望给同样在 Java 领域探索 Agent 的开发者一些参考。 项目总览agent-demo 是什么agent-demo是一个基于 Spring AI Alibaba 的智能 Agent 演示项目。它不是一个玩具而是一个具备完整 Agent 能力栈的工程化实现多模型路由通义千问 智谱 GLM、工具调用天气查询、文件操作、数学运算、多轮对话记忆、以及核心的Agent Skill 系统基于 Anthropic 发布的 Agent Skills 开放标准。技术栈如下后端框架Spring Boot 3.4.6 Spring AI Alibaba 1.1.2.0 Java 17AI 模型通义千问 qwen-plus复杂任务 智谱 GLM-5.1简单问答工具集成和风天气 API 文件系统操作 数学运算Skill 系统3 个 Skillweather / calculator / xiaohongshu遵循三层加载架构项目提供了 5 个 REST API 接口以及一个交互式 CLI 客户端agent-cli.sh支持三种对话模式无记忆对话、带记忆对话、智能路由对话。同时允许手动切换模型或恢复自动路由。架构上项目遵循一个清晰的层次HTTP 层Controller→ 编排层AgentService→ 模型层QWEN / GLM→ 工具层Tool→ Skill 系统。这个分层的核心思想是每个组件只做一件事通过组合实现复杂能力。Skill 三层加载架构Tier 1 · 元数据层常驻内存name / description / keywords / tools~100 tokens/skill语义/关键词命中 ↓Tier 2 · 指令层按需加载SKILL.md 正文 → 注入 System Prompt~1k-5k tokens执行中需要 ↓Tier 3 · 资源层预留scripts/ 脚本 references/ 参考文档— 按需加载控制 Token 开销 — 第一阶段Hello Agent一切从 Spring Initializr 开始。项目使用 Maven 构建核心依赖只有三个spring-boot-starter-web提供 REST 能力spring-ai-alibaba-starter-dashscope接入通义千问lombok减少样板代码。第一个 Agent 程序简单得令人惊讶Beanpublic ChatClient qwenChatClient(ChatClient.Builder builder) {return builder.defaultSystem(“你是一个helpful的助手”).build();}这个ChatClient是 Spring AI 的核心抽象。它封装了模型调用、参数传递、结果解析的全流程提供了一套 Fluent API让开发者可以用链式调用构建 Prompt。不需要手动拼接 HTTP 请求不需要处理 JSON 序列化一行代码就能发出对话请求。但如果你以为这只是调个 API那就太小看 Agent 了。真正的 Agent 需要三个核心能力调用工具Tool Calling、记住上下文Memory、以及按需激活知识Skill。接下来的每一阶段都是在这三个维度上逐步扩展。️ 第二阶段让 Agent 有手有脚模型再聪明如果只能聊天那就只是一个高级聊天机器人。Agent 的本质区别在于它能调用工具改变外部世界。Spring AI 的Tool注解让这件事情变得异常简单。你只需要在一个 Spring Bean 的方法上加上Tool注解框架就会自动生成对应的 JSON Schema在模型需要时通过 Function Calling 协议完成调用。我在 AgentService 中注册了 8 个工具覆盖了三个典型场景️ 天气查询getWeather(city)— 对接和风天气 API两步调用城市名→城市ID→实时天气 文件操作listDirectory / readFile / writeFile / createDirectory— 完整的文件系统访问能力➕ 数学计算add(a, b)— 整数加法虽简单但完整演示了工具调用链路最让我印象深刻的是 Function Calling 的思考-行动-观察循环。当用户问上海今天天气怎么样时模型会① 理解意图 → ② 决定调用getWeather(上海)→ ③ 等待工具返回原始数据 → ④ 将结构化数据转化为自然语言回复。整个过程模型自主完成开发者只需要注册工具并提供实现。这个阶段让我意识到工具的粒度决定了 Agent 的能力边界。每个工具的定义参数、返回值、描述都在告诉模型它能做什么、不能做什么。设计好工具层就是设计好 Agent 的世界模型。Tool Calling 执行流程① 用户提问 → 模型理解意图② 模型返回 Function Call 请求③ Spring AI 调用 Tool 方法④ 模型用工具结果生成回复 第三阶段给 Agent 装上记忆没有记忆的 Agent 是金鱼——每次对话都是全新的开始。你告诉它你叫张三下一轮它就忘了。这在真实场景中是不可接受的。Spring AI 提供了ChatMemory抽象配合MessageChatMemoryAdvisor可以用极少的代码实现多轮对话记忆Beanpublic ChatMemory chatMemory() {return new MessageWindowChatMemory(“agent-demo”,new InMemoryChatMemoryRepository(),20 // 保留最近 20 条消息);}这里有两个关键设计。第一是窗口大小限制为 20 条消息防止上下文无限膨胀。第二是sessionId 隔离不同会话的记忆完全独立互不干扰。在测试中同一 sessionId 的三轮对话连贯无误不同 sessionId 的切换则完全隔离。但记忆系统和路由系统有一个微妙的问题当用户回复模型的追问时比如模型先问你在哪个城市用户再说上海这个上海本身没有上下文含义需要结合上一轮对话才能理解。为此我在 ModelRouter 中加入了一个追问检测逻辑——如果上一轮模型回复中包含疑问句相关关键词即使当前消息很短也强制走千问避免路由到无工具的 GLM 导致对话断裂。这个细节让我深刻体会到Agent 系统的难点不在单个功能实现而在组合时的边界情况。记忆 路由 工具三个系统各自独立工作时都没问题一旦组合起来到处都是连接处的细节。 第四阶段双模型路由架构项目最有趣的设计决策是双模型路由。为什么要搞两个模型答案很简单成本和能力的平衡。通义千问qwen-plus能力强、支持工具调用但需要按 Token 付费。智谱 GLMGLM-5.1有免费额度能力足以处理日常闲聊但不支持工具调用或者说项目初期没有对接它的 Tool Calling 接口。于是我设计了一个ModelRouter包含 5 条路由规则规则 0最高优先级命中 Skill → 千问规则 1AI 追问上一轮含疑问词→ 千问规则 2消息长度 50 字符 → 千问规则 3含复杂关键词分析/对比/代码等→ 千问默认简单闲聊 → GLM免费路由的执行顺序是先判断是否命中 Skill需千问执行工具再判断是否 AI 追问需保持千问上下文再判断消息复杂度和长度最后兜底走 GLM。同时保留了手动覆盖的能力——用户可以通过POST /api/model强制指定任意模型。这个设计在实践中运行良好。日常的你好今天心情不错等简单对话全部走 GLM零成本天气查询、文件操作、技术分析等复杂请求自动路由到千问保证能力完整。据我的粗略统计约 60% 的日常对话由 GLM 处理API 成本降低了 50% 以上。ModelRouter 路由决策树用户消息规则0 命中Skill?规则1 AI追问?规则2 长度50?规则3 复杂词?默认 → GLM→ QWEN— 任一规则命中则走千问全不命中走 GLM — 第五阶段Agent Skill 系统最核心的设计如果说工具是 Agent 的手记忆是脑那么 Skill 就是 Agent 的专业知识库。这个设计灵感来源于 Anthropic 在 2025 年 12 月发布的Agent Skills 开放标准并被 Claude Code 和 OpenCode 广泛采用。Skill 的核心思想非常简洁通过结构化 Prompt 注入让模型在特定任务上表现得更专业。它不是代码而是指令——告诉模型在特定场景下应该怎么做。我参照 Agent Skills 开放标准和 OpenCode 的源码分析设计了三个核心原则原则一三层加载架构Tier 1元数据常驻→ Tier 2指令按需加载→ Tier 3资源预留。核心在于按需加载——不把所有 Skill 的正文塞进上下文只在匹配到才注入。原则二description 是最重要的字段它是匹配的唯一依据。OpenCode 由 AI 自主判断本项目提供了两种匹配器关键词匹配零 Token 成本和 AI 语义匹配更高准确率。原则三Skill 驱动工具挂载Skill 声明自己需要哪些工具激活时自动挂载。这样模型不会在不需要的上下文中看到不必要的工具定义减少误导。在标准的namedescription基础上我扩展了两个字段keywords关键词匹配用和tools声明需要哪些 Tool 方法。name: weatherdescription: 查询城市天气、温度、天气预报相关问题。当用户询问天气时激活。keywords: [天气, 温度, 气温, 下雨, 晴天]tools: [getWeather]你是一个专业的天气助手。当用户询问天气时如果用户没有指定城市先询问城市调用 getWeather 工具获取天气数据将原始数据解析为友好的自然语言描述回复格式「{城市}今天{天气}气温{温度}°C」SkillLoader 实现了两阶段加载启动时只扫描 FrontmatterTier 1匹配到 Skill 后才通过loadContent()读取正文Tier 2结果缓存到ConcurrentHashMap。这种方式确保无论有多少个 Skill只有被激活的那个才消耗 Token。两种匹配器各有优劣。KeywordSkillMatcher简单粗暴——检查用户消息是否包含 keywords 中的词零 Token 消耗但覆盖不全。例如用户说今天适合出门吗关键词天气没出现就不会匹配。AiSkillMatcher则将所有 Skill 的 description 发给 GLM-4.7-Flash让模型语义判断准确率高但每次匹配要消耗少量 Token。两种模式可通过配置切换。目前项目注册了三个 Skillweather天气查询、calculator数学计算、xiaohongshu小红书文案生成。每个 Skill 对应一个 SKILL.md 文件放在resources/skills/目录下。新加一个 Skill 只需要新建目录 写 SKILL.md无需改代码——这是架构设计最让人满意的地方。Skill 匹配注入流程用户输入消息SkillMatcherKeyword / AI 语义无 Skill 命中基础 Prompt 即可命中 SkillloadContent() 注入 Prompt挂载 Tool 踩坑与思考那些在文档中找不到的答案整个开发过程中遇到了不少问题有些是 Spring AI 文档没覆盖到的有些是 Java 生态做 Agent 特有的。记录下来给后来者参考。1. 为什么 GLM 用 OkHttp 直调而不是 Spring AI StarterSpring AI Alibaba 官方只提供了 DashScope通义千问的 Starter没有智谱 GLM 的官方集成。虽然可以使用spring-ai-starter-model-zhipuai社区版但版本兼容性存在风险。考虑到 GLM 只处理简单的纯对话不需要工具调用直接通过 OkHttp 调用其 OpenAI 兼容接口反而更可控依赖更少、代码更透明、出问题时更容易排查。2. Skill 触发方式为什么没走AI 自主调用在 OpenCode 中Skill 由 AI 自主调用 SkillTool 触发。这需要模型支持工具调用并且在系统 Prompt 中告诉模型你有 Skill 可用。但本项目使用 Spring AI 的 ChatClient它虽然支持 Tool但要让模型理解还有一个叫 Skill 的特殊工具需要额外设计而且会额外消耗 Token。权衡之下我选择了在 Java 端通过 SkillMatcher 做匹配再注入 Prompt——实现简单、逻辑透明、不增加 Token 消耗。这是适配 Java 生态的务实选择。3. 三层加载解决了什么问题最开始我打算把所有 Skill 的完整内容拼到一个超大 System Prompt 里看起来简单粗暴。但算了一笔账假如有 10 个 Skill每个平均 2000 字约 500 Tokens全部注入就是 5000 Tokens 的常驻开销。而实际每次对话只用到 1~2 个 Skill90% 的 Token 被浪费了。三层加载的核心价值就是按需加载不为不用的能力付费。这个原则在 Agent 系统中极其重要——上下文窗口是有限的每一寸都很珍贵。4. 记忆系统的边界在哪里当前使用内存存储重启即丢失。生产环境需要接入 Redis 或数据库做持久化。另一个问题是当路由规则把对话从 GLM 切换到 QWEN或反之时记忆内容是否能连贯目前在 route-chat 接口中两种模型共享同一个 ChatMemory 实例所以连续性没问题。但这也意味着 GLM 能看到千问之前的对话历史——目前没有区分模型之间的记忆隔离这是一个待改进点。 为什么值得动手写一个 Agent写到这里我想聊聊一个更根本的问题作为开发者我们为什么要花时间去写一个 Agent直接用 ChatGPT、Claude 或者各种 AI 编程助手不好吗我的答案是因为用和造之间有一条巨大的认知鸿沟。用 AI 聊天、用 AI 写代码你学到的是这个模型能做什么。但当你自己动手搭建一个 Agent 系统你要回答的是模型怎么知道该调用什么工具、“工具返回的数据怎么变成人话”、“多轮对话的历史存在哪里、怎么取”、“不同任务该用哪个模型”——这些是产品文档里不会写的东西。这个项目的整个过程让我对 Agent 有了几个核心认知Agent 是架构问题不是模型问题很多人以为 Agent 能力取决于模型大小。实际上GPT-4 不会知道自己该查天气还是该聊天——是代码让它知道的。路由、记忆、工具编排、Skill 注入这些架构设计决定了 Agent 的上限。Prompt 工程正在变成架构工程一两年前我们聊写 Prompt是指写一段话让模型理解。现在写 Prompt 意味着设计多层注入策略、按需加载、Token 预算管理——它本质上和写后端服务没有区别。从调 API到造能力是技术成长的质变调一个 LLM 的 API 十分钟就能学会。但设计和实现一个 Agent 系统需要你理解模型特性、API 协议、内存管理、成本优化、系统架构——这些能力在任何技术领域都通用。回到最初的问题Java 生态适不适合做 Agent我的结论是完全适合而且有独特优势。Spring AI 的 ChatClient Tool ChatMemory 三板斧已经覆盖了 Agent 的核心基础设施。Java 的类型安全、成熟的生态Spring、Maven、企业级运维能力是 Python 生态不具备的护城河。如果你的团队以 Java 为主完全没必要为了AI去学一整套 Python 技术栈。但 Java 生态也有它的短板Agent 相关的开源工具和文档远不如 Python 丰富很多模式需要自己从零摸索。这篇文章所记录的就是这种摸索的过程。希望它能成为 Java 开发者进入 Agent 领域的一块垫脚石。毕竟最好的学习方式从来不是读文档而是动手做一个。写在最后Agent 不是模型能力的延伸而是架构能力的体现。最好的学习方式从来不是读文档而是动手做一个。— 一个从北京回到西安、从大厂回归生活的程序员假如你从2026年开始学大模型按这个步骤走准能稳步进阶。接下来告诉你一条最快的邪修路线3个月即可成为模型大师薪资直接起飞。阶段1:大模型基础阶段2:RAG应用开发工程阶段3:大模型Agent应用架构阶段4:大模型微调与私有化部署配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】