人工智能(十二)- Java AI Agent / 智能体 开发入门指南

0 阅读12分钟

人工智能(十一)- 什么是 Skills

一、先搞懂:AI Agent 到底是什么?

1.1 一句话定义

Java AI Agent = 大模型的“脑子” + Java 工程的“手和脚”。

普通的 ChatGPT 聊天窗口,本质是“你问一句,它答一句”,它没有手脚、不能真正帮你做事。而 Agent(智能体)不一样,它在一个目标驱动下,可以:

  1. 理解用户意图:你说“帮我查一下北京明天要不要带伞”,它知道这是“查天气”。
  2. 规划下一步动作:它会想“我需要先调天气 API,再根据降水概率给建议”。
  3. 调用外部工具 / 系统:真的去调 HTTP 接口、查数据库、发消息。
  4. 利用上下文记忆持续工作:记得你上一句说的是“北京”,这一句“那后天呢?”也能接上。
  5. 必要时结合知识库检索(RAG):遇到公司内部制度、产品文档这种模型不知道的东西,它会先查资料再回答。
  6. 最终返回一个“助手”,而不是“聊天机器人”

1.2 用一个生活类比

把 Agent 想象成公司里的 “新来的实习生助理”

能力对应 Agent 的组件
听懂你在说啥大模型(LLM)
会查资料(翻手册、翻 wiki)RAG(知识库检索)
会用公司的各种系统(OA、CRM、工单)Tools(工具调用)
记得你昨天交代过啥Memory(记忆)
做事有流程、不乱来Workflow(编排)
干活有留痕、能追溯可观测性 + 审计

二、Java 生态目前主流的技术选型

在 Java 里做 Agent,当前比较常见的两个框架:

框架特点适合场景
Spring AI跟 Spring Boot 深度绑定,配置中心、依赖注入、AOP、Actuator 都能复用企业级后端系统集成
LangChain4j轻量直接,API 更像 Python 的 LangChain,Tool Calling / Memory / RAG 一把梭快速做原型、独立 Agent 服务

还有一个新东西值得关注:

  • MCP(Model Context Protocol):Anthropic 提出的“工具接入标准协议”。未来工具越接越多时,用 MCP 做标准化接入,能避免每个工具都写一遍对接代码。

🧭 选型建议

  • 想快速跑起来看效果 → LangChain4j
  • 要接入现有 Spring Boot 项目 → Spring AI
  • 工具很多、要长期维护 → 在上面两个之外再引入 MCP

三、Java Agent 开发的 8 个步骤

下面是一条比较实用的推进顺序。建议严格按顺序来,别一上来就搞多 Agent 协作——那是第 9 步以后的事。

1. 定义目标  →  2. 选框架  →  3. 接大模型  →  4. 定义工具
        ↓
5. 加记忆  →  6. 接 RAG  →  7. 编排流程  →  8. 可观测 + 安全

第 1 步:先定义 Agent 的目标(最重要!)

很多人一上来就写代码,结果做到一半发现“我到底要做个啥?”

先用一句话回答三个问题:

  1. 谁用?(客服、员工、运维、开发者…)
  2. 解决什么问题?(退款查询、报销咨询、故障排查…)
  3. 边界在哪?(不处理投诉、不做支付、不回答 xx…)

常见的 Agent 类型:

  • 智能客服:回答产品问题、查订单、开工单
  • 工单助手:自动分类工单、补全字段、推荐处理人
  • 旅行助手:查天气、订酒店、规划路线
  • 知识库问答:读内部文档回答问题
  • 运维排障:读监控、查日志、给修复建议

⚠️ 小白最容易踩的坑:想做一个“什么都能干”的 Agent。不要。目标越聚焦,效果越好。


第 2 步:选择基础框架

假设我们要做一个 “天气小助手 Agent”,用 LangChain4j 起步。

先在 Maven 里引依赖:

<dependencies>
    <!-- LangChain4j 核心 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.35.0</version>
    </dependency>

    <!-- OpenAI 兼容接口(国内模型大多兼容这个协议) -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>0.35.0</version>
    </dependency>
</dependencies>

💡 国内大多数模型平台(DeepSeek、通义千问、豆包、Kimi 等)都提供“OpenAI 兼容模式”,换一个 baseUrlapiKey 就能用。


第 3 步:接入大模型(Agent 的脑子)

最基础的调用长这样:

import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;

public class HelloAgent {

    public static void main(String[] args) {
        // 1. 构建一个模型客户端(相当于“找到脑子”)
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("https://api.deepseek.com/v1")   // 也可以换成其他兼容平台
                .apiKey(System.getenv("LLM_API_KEY"))
                .modelName("deepseek-chat")
                .temperature(0.3)                         // 温度越低越稳重
                .timeout(java.time.Duration.ofSeconds(30))
                .build();

        // 2. 让模型说句话
        String answer = model.generate("用一句话解释什么是 AI Agent");
        System.out.println(answer);
    }
}

跑通这一步,你已经拥有一个“会聊天的 Java 程序”了。但它还不是 Agent——它没有工具、没有记忆。


第 4 步:定义工具(Tools)—— Agent 和聊天机器人的分水岭

没有工具的 Agent 只是一个会聊天的玩具。

工具是什么? 就是 Agent 可以调用的“外部能力”,本质上是一个 Java 方法。在 LangChain4j 里,你只要给方法加两个注解,模型就能自动决定“要不要调”“怎么调”。

4.1 定义两个工具:查天气 + 查订单

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.P;

public class MyTools {

    @Tool("查询指定城市未来一天的天气,返回文字描述")
    public String getWeather(@P("城市中文名,例如:北京") String city) {
        // 真实场景:调用高德/和风天气 API
        // 这里先 mock
        return city + "明天多云转晴,20~28℃,降水概率 20%";
    }

    @Tool("根据订单号查询订单状态")
    public String getOrderStatus(@P("订单号,例如:O20260101001") String orderId) {
        // 真实场景:调 DB 或内部 HTTP API
        return "订单 " + orderId + " 状态:已发货,预计明天送达";
    }
}

4.2 把工具交给 Agent 使用

import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;

// 定义 Agent 的对外接口(就是一个普通 Java 接口)
interface WeatherAgent {

    @SystemMessage("你是一个贴心的生活助手,必要时请调用工具获取真实数据,不要编造。")
    String chat(String userMessage);
}

public class AgentDemo {
    public static void main(String[] args) {
        ChatLanguageModel model = /* 同第 3 步 */;

        WeatherAgent agent = AiServices.builder(WeatherAgent.class)
                .chatLanguageModel(model)
                .tools(new MyTools())        // 把工具塞进去
                .build();

        System.out.println(agent.chat("帮我查一下北京明天的天气,顺便看看订单 O20260101001 到哪了"));
    }
}

背后发生了什么?(重要,小白一定要理解)

  1. 模型看到用户问题,自己决定:这里要调 getWeather("北京")getOrderStatus("O20260101001")
  2. LangChain4j 真的执行这两个 Java 方法,把结果喂回模型。
  3. 模型再把结果组织成自然语言返回给用户。

这就是所谓的 Function Calling / Tool Calling,是现代 Agent 的核心机制。

🎯 口诀:能让程序去做的事,都写成 Tool;让模型只负责“想”,别让它“算”“查”“执行”。


第 5 步:加入 Memory(记忆)

没有记忆的 Agent,每轮对话都是“初次见面”。加上记忆才像个助手。

常见的三种记忆策略:

类型做法适用
窗口记忆只保留最近 N 轮对话绝大多数对话场景
持久化记忆存到 Redis / DB,按 userId 隔离多会话、多用户
用户画像记忆抽取长期偏好(如“不吃辣”)单独存个性化强的场景

5.1 窗口记忆(入门用这个)

import dev.langchain4j.memory.chat.MessageWindowChatMemory;

WeatherAgent agent = AiServices.builder(WeatherAgent.class)
        .chatLanguageModel(model)
        .tools(new MyTools())
        .chatMemory(MessageWindowChatMemory.withMaxMessages(20))  // 只记最近 20 条
        .build();

5.2 持久化记忆(多用户场景)

import dev.langchain4j.memory.chat.ChatMemoryProvider;

// 改成按 userId 维护各自的记忆
AiServices.builder(WeatherAgent.class)
        .chatLanguageModel(model)
        .tools(new MyTools())
        .chatMemoryProvider(userId ->
                MessageWindowChatMemory.builder()
                        .id(userId)
                        .maxMessages(30)
                        .chatMemoryStore(new RedisChatMemoryStore(/*…*/))  // 自己实现存 Redis
                        .build())
        .build();

⚠️ 小白坑点:Memory 不是越长越好!每一条消息都会变成 token 扔给模型,太长 = 又贵又慢,还容易“跑题”。


第 6 步:接入 RAG(检索增强生成)

什么时候需要 RAG?

当你要让 Agent 回答“模型自己不可能知道”的事,比如:

  • 公司内部 HR 制度
  • 自研产品的 API 文档
  • 最新的销售手册、FAQ
  • 项目的设计文档

RAG 的核心逻辑(一句话):

把你的资料切片 → 转成向量 → 用户提问时,先去向量库找最相关的几段 → 连同问题一起喂给模型。

6.1 RAG 的最小流程图

[你的 PDF / MD / Wiki]
        ↓ 切块(chunk)
        ↓ 向量化(embedding)
   [向量数据库]
        ↑
用户问题 → 向量化 → 相似度检索 → Top-K 片段 + 问题 → 大模型 → 答案

6.2 LangChain4j 里的简化写法

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;

// 1. 加载文档
Document doc = FileSystemDocumentLoader.loadDocument("docs/handbook.md");

// 2. 切块 + 向量化 + 存入向量库(入门先用内存版)
EmbeddingModel embeddingModel = /* 省略:通常用 OpenAI embedding 或本地 bge-m3 */;
InMemoryEmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor.ingest(doc, store);

// 3. 构造一个 “带资料检索能力” 的 Agent
WeatherAgent agent = AiServices.builder(WeatherAgent.class)
        .chatLanguageModel(model)
        .contentRetriever(EmbeddingStoreContentRetriever.builder()
                .embeddingStore(store)
                .embeddingModel(embeddingModel)
                .maxResults(3)              // 取最相关的 3 段
                .minScore(0.6)              // 相似度低于 0.6 就不要了
                .build())
        .build();

📌 小白误区

  • RAG 不是万能的,资料质量决定一切。垃圾进,垃圾出。
  • 切块大小很关键:一般 300~800 字一块,按语义(段落、标题)切,别按字数硬切。
  • 生产环境建议用 Milvus / Qdrant / PGVector,内存版只适合 demo。

第 7 步:加入工作流与约束(Workflow / Orchestration)

一个真实的 Agent,很少是“来一句答一句”,而是一条流水线

用户输入
   ↓
意图识别(是闲聊?查资料?办业务?)
   ↓
分支:
  ├─ 闲聊       → 直接 LLM 回复
  ├─ 知识问答   → 走 RAG
  └─ 办业务     → Tool 调用(可能多步)
   ↓
结果整理 + 异常兜底
   ↓
返回

7.1 用代码表达这个流程(伪代码 + Java)

public class RouterAgent {

    public String handle(String userInput, String userId) {
        // 1. 意图识别(也可以用模型做,也可以用正则 + 关键词)
        Intent intent = intentClassifier.classify(userInput);

        // 2. 分发
        switch (intent) {
            case CHITCHAT:
                return chatAgent.chat(userInput);

            case KNOWLEDGE_QA:
                return ragAgent.ask(userInput);

            case BUSINESS:
                try {
                    return toolAgent.chat(userInput);
                } catch (ToolException e) {
                    // 3. 异常兜底:降级到“告诉用户我没查到,要不要转人工”
                    return "抱歉我暂时没查到结果,是否转人工?";
                }

            default:
                return "这个问题我暂时不擅长回答~";
        }
    }
}

7.2 更复杂的场景:多步规划(ReAct / Plan-and-Execute)

对于“帮我订明天去上海的机票并发消息给同事”这种任务,Agent 要能自己拆步骤

  1. 查机票
  2. 选一个合适的
  3. 下单
  4. 发消息

LangChain4j 的 AiServices + Tools 默认就支持 多轮 Tool Calling,模型会自己循环调用工具直到完成。但当步骤多、需要人工介入时,建议显式编排,不要完全放养模型——那样不可控。

💡 经验法则

  • 简单任务(1~3 步)→ 让模型自己 Tool Calling
  • 复杂任务(多分支、多系统)→ 自己写 Workflow,把模型当“判断器”用

第 8 步:可观测性与安全(上线前必须)

原型跑通 ≠ 可以上线。生产环境最容易爆雷的几件事:

8.1 必须监控的指标

指标为什么重要
Token 消耗直接等于钱,要能按用户 / 接口 / 场景拆分
响应时延(P95/P99)模型调用慢是常态,要能定位瓶颈
工具调用成功率一个工具挂了可能拖垮整个 Agent
重试次数 / 超时率网络、限流、模型故障都会触发
命中率(RAG)检索结果没命中,模型会乱编

Spring Boot 项目直接用 Micrometer + Prometheus + Grafana 就能搞定。

8.2 必须做的安全措施

// 示例:工具调用前的权限校验
@Tool("删除指定订单(危险操作)")
public String deleteOrder(@P("订单号") String orderId) {
    // 1. 校验当前用户权限
    if (!SecurityContext.current().hasRole("ADMIN")) {
        throw new SecurityException("无权限执行该操作");
    }
    // 2. 敏感操作要二次确认(可以通过 workflow 控制)
    // 3. 写审计日志
    auditLog.record("deleteOrder", orderId, SecurityContext.current().getUserId());

    return orderService.delete(orderId);
}

安全红线清单:

  • ✅ 工具调用前做权限校验,不要相信模型的判断
  • ✅ 敏感操作(删除、支付、外发消息)二次确认
  • ✅ 对模型输入做 Prompt 注入防护(过滤“忘记之前的指令…”这类攻击)
  • ✅ 对模型输出做脱敏(手机号、身份证、密钥)
  • ✅ 所有工具调用写审计日志,可追溯
  • ✅ 限流:防止用户恶意刷 token

四、一个最小可运行的完整例子

把前面的步骤串起来,做一个**“带记忆 + 会调工具 + 会查资料”的天气助手**:

public class MiniAgentApp {

    public static void main(String[] args) {
        // 1. 模型
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("https://api.deepseek.com/v1")
                .apiKey(System.getenv("LLM_API_KEY"))
                .modelName("deepseek-chat")
                .temperature(0.3)
                .build();

        // 2. 向量库 + RAG
        EmbeddingModel embeddingModel = /* … */;
        InMemoryEmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
        EmbeddingStoreIngestor.ingest(
                FileSystemDocumentLoader.loadDocument("docs/travel-tips.md"),
                store);

        // 3. 组装 Agent
        WeatherAgent agent = AiServices.builder(WeatherAgent.class)
                .chatLanguageModel(model)
                .tools(new MyTools())
                .chatMemory(MessageWindowChatMemory.withMaxMessages(20))
                .contentRetriever(EmbeddingStoreContentRetriever.builder()
                        .embeddingStore(store)
                        .embeddingModel(embeddingModel)
                        .maxResults(3)
                        .build())
                .build();

        // 4. 跑起来
        System.out.println(agent.chat("北京明天天气怎么样?要带伞吗?"));
        System.out.println(agent.chat("那出差需要准备啥?"));   // 会命中 travel-tips.md
    }
}

短短几十行,你就拥有了一个真实可用的 Java Agent。


五、小白最容易踩的 10 个坑(血泪总结)

  1. 目标不聚焦:想做“全能助手”,最后啥都做不好。
  2. 上来就搞多 Agent:单 Agent 都没跑通就想 Multi-Agent,纯属自找麻烦。
  3. Memory 无限增长:token 爆炸 + 回答跑偏。务必加窗口或摘要。
  4. Tool 描述写得敷衍:模型靠 @Tool 的描述决定要不要调,描述越清楚调用越准。
  5. 把所有逻辑塞给模型:该用 if-else 写死的判断,不要交给模型“猜”。
  6. RAG 切块乱切:按固定字数硬切,上下文断裂,检索全是残片。
  7. 没有超时和重试:一次模型接口卡住,整个请求挂住。
  8. 不监控 token:等月底账单来了才发现烧了好几万。
  9. 不做权限校验:模型被 Prompt 注入后直接删库,责任你背。
  10. 不做评估(Eval):没有评估集,迭代全凭感觉,改着改着越改越差。

六、进阶方向(下一步学什么)

当你跑通上面所有步骤后,可以继续探索:

  • Function Calling vs MCP:标准化工具协议,解决工具爆炸问题。
  • Agent 评估(Eval):搭建一个“考题库”自动打分。
  • 多 Agent 协作:比如一个 Planner Agent + 多个 Worker Agent。
  • 流式输出(SSE / WebFlux):让回答像打字一样实时出来。
  • 工作流引擎:LangGraph / Spring AI 的 Advisor 机制 / 自研 DAG。
  • Agent + 微服务治理:熔断、限流、灰度,让 Agent 成为真正的生产级服务。

七、总结

做一个 Java AI Agent,本质上是把大模型这个“新同事”融入到你现有的 Java 工程体系里。记住这条主线:

目标 → 框架 → 模型 → 工具 → 记忆 → 知识 → 编排 → 可观测 + 安全

一步一步来,不要跳步。跑通第一个最小可用版本,比追求“架构先进”重要 100 倍。

祝你早日把那个“只会聊天的玩具”,变成一个真正帮你干活的数字同事。🚀


如果这篇文章对你有帮助,欢迎收藏、转发;有问题也欢迎在评论区交流。