🤖 系列:Java工程师转AI Agent 3个月学习计划 👤 作者:宸丶一 | 28岁Java程序员,规划狂魔,正在被AI Agent按头学习 🎯 今日目标: 理解Agent核心架构、工具调用机制、错误处理策略 💬 个人格言: 代码改不改变世界我不知道,但先让我准时下班。


前言

大家好,我是宸一,一个28岁的Java程序员。

今天是第4天,学习内容是:Agent核心架构全解析

前三天我们学了:

  • Day 1:大模型API基础
  • Day 2:LangChain与工具调用
  • Day 3:记忆系统与向量数据库

今天要把这些串起来,看看一个完整的Agent到底是怎么工作的。

这次的学习方式有点不一样——我用的是"1对1问答式"学习。

什么意思?就是我问AI老师问题,它秒回我,我再追问,它再解答。不像传统学习那样"看视频→做笔记→忘了",而是"问→答→理解→追问→深入"。

下面我把今天的核心内容整理出来,全是问答中碰撞出来的干货。


一、Agent三元组:规划、工具、记忆

1.1 最简模型

Agent的本质就是三个核心模块:

flowchart LR

    User["👤 用户"]

    Agent["🤖 Agent"]

    Planning["📋 Planning"]
    Action["🔧 Action"]
    Memory["💾 Memory"]

    User --> Agent

    Agent --> Planning
    Planning --> Action
    Action --> Memory
    Memory --> Planning

    Planning --> Result["✅ 输出结果"]

    classDef main fill:#3B82F6,color:white,stroke:none
    classDef agent fill:#111827,color:white,stroke:none
    classDef result fill:#10B981,color:white,stroke:none

    class Planning,Action,Memory main
    class Agent agent
    class Result result

1.2 用后端思维理解

Agent概念Java后端对应说明
PlanningService层业务逻辑拆解任务、决定执行流程
Action调用外部API/工具类执行具体操作
Memory数据库 + 缓存存储历史和上下文

这就是我们天天干的事儿:

  1. 接收请求 → 理解用户意图
  2. 查数据库 → 获取历史上下文
  3. 执行业务逻辑 → 调用各种Service
  4. 返回结果 → 生成回答

二、系统提示词:全局变量

2.1 什么是System Prompt?

系统提示词就是Agent的"人设",一次创建,全程不变。

# 就像Java中的常量
public static final String ROLE = "再战Java工程师的28岁程序员";

# 或者Python中的配置
SYSTEM_PROMPT = """
你是一个正在学习AI Agent的Java工程师,名叫宸一。
你的特点是:用后端思维理解AI概念。
"""

2.2 为什么重要?

System Prompt决定了Agent的"性格"和"能力边界":

没有System Prompt的Agent:
  用户:你是谁?
  Agent:我是一个AI助手

有System Prompt的Agent:
  用户:你是谁?
  Agent:我是宸一,一个28岁的Java程序员,正在学习AI Agent

2.3 用后端思维理解

System Prompt = 全局配置 = CONFIG对象

// Java中我们这样写
@Configuration
public class AgentConfig {
    @Value("${agent.role}")
    private String role;  // "再战Java工程师"
    
    @Value("${agent.max_history}")
    private int maxHistory;  // 10
}

一次创建,全程使用,不会改变。


三、对话历史:滑动窗口

3.1 为什么需要滑动窗口?

大模型的上下文窗口有限,不能无限存储对话历史。

flowchart LR
    classDef problem fill:#FFEBEE,stroke:#C62828,color:#B71C1C,stroke-width:2px
    classDef solution fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20,stroke-width:2px
    classDef node fill:#FFFFFF,stroke:#90A4AE,stroke-width:1px

    subgraph Problem["❌ 问题"]
        P1["用户聊了100轮对话"]
        P2["全部塞给大模型"]
        P3["Token爆炸 💥<br/>费用爆炸 💰"]
        P1 --> P2 --> P3
        class P1,P2,P3 node
    end

    subgraph Solution["✅ 解决方案"]
        S1["100轮对话"]
        S2["滑动窗口<br/>只保留最近10轮"]
        S3["Token可控 ✅<br/>费用可控 ✅"]
        S1 --> S2 --> S3
        class S1,S2,S3 node
    end

    Problem -.->|采用| Solution

    class Problem problem
    class Solution solution

3.2 实现方式

from collections import deque

class ConversationHistory:
    def __init__(self, max_size=10):
        # 双向队列,两端都是O(1)操作
        self.history = deque(maxlen=max_size)
    
    def add(self, role, content):
        """添加新对话,自动淘汰最旧的"""
        self.history.append({
            "role": role,
            "content": content
        })
    
    def get_recent(self, n=5):
        """获取最近n轮对话"""
        return list(self.history)[-n:]

3.3 用后端思维理解

滑动窗口 = 固定大小的环形缓冲区

┌─────────────────────────────────────────────────────────┐
│  conversation_history (maxlen=10)                       │
├─────────────────────────────────────────────────────────┤
│ [0] 最旧 → 新消息插入时自动淘汰                         │
│ [1] ...                                                 │
│ ...                                                     │
│ [8] ...                                                 │
│ [9] 最新 ← 新消息插入这里                               │
└─────────────────────────────────────────────────────────┘

数据结构选择:
- 数组:O(n)删除头部,不推荐
- 链表:O(1)删除头部,但Python没有原生支持
- deque:最佳选择!两端O(1)操作

四、工具调用:四步走

4.1 完整流程

flowchart TD
    classDef start fill:#1E3A5F,stroke:#0D47A1,color:#FFFFFF,stroke-width:2px
    classDef answer fill:#2E7D32,stroke:#1B5E20,color:#FFFFFF,stroke-width:2px
    classDef step fill:#E3F2FD,stroke:#1565C0,color:#1565C0,stroke-width:2px
    classDef node fill:#FFFFFF,stroke:#90A4AE,stroke-width:1px
    classDef success fill:#C8E6C9,stroke:#388E3C,stroke-width:1px
    classDef fail fill:#FFCDD2,stroke:#D32F2F,stroke-width:1px

    Start["👤 用户输入<br/>帮我查一下明天北京天气"]
    class Start start

    subgraph Step1["第1步:工具注册表"]
        TR["📋 get_weather / search_web"]
        class TR node
    end

    subgraph Step2["第2步:语义匹配"]
        SM["🔍 意图分析"]
        SM1["查询天气 → 0.95"]
        SM2["搜索网页 → 0.32"]
        SM --> SM1
        SM --> SM2
        class SM node
        class SM1 success
        class SM2 fail
    end

    subgraph Step3["第3步:参数提取"]
        PE["📝 NLP解析"]
        PE1["city: 北京"]
        PE2["date: 明天"]
        PE --> PE1
        PE --> PE2
        class PE node
        class PE1,PE2 node
    end

    subgraph Step4["第4步:调用执行"]
        EX["⚡ get_weather(北京, 明天)"]
        RES["📊 25°C / 晴"]
        EX --> RES
        class EX node
        class RES success
    end

    Answer["💬 明天北京天气晴,25°C,适合出行~"]
    class Answer answer

    Start --> Step1 --> Step2 --> Step3 --> Step4 --> Answer

    class Step1,Step2,Step3,Step4 step

4.2 用后端思维理解

工具调用 = 策略模式 + 工厂模式

// 策略接口
public interface Tool {
    String getName();
    String getDescription();
    Object execute(Map<String, Object> params);
}

// 工具注册表(工厂)
public class ToolRegistry {
    private Map<String, Tool> tools = new HashMap<>();
    
    public void register(Tool tool) {
        tools.put(tool.getName(), tool);
    }
    
    public Tool findByName(String name) {
        return tools.get(name);
    }
}

// 具体工具
public class WeatherTool implements Tool {
    @Override
    public Object execute(Map<String, Object> params) {
        String city = (String) params.get("city");
        // 调用天气API
        return weatherApi.getWeather(city);
    }
}

4.3 两种工具选择方式

方式原理优点缺点
向量匹配语义相似度搜索灵活,能处理模糊表达需要向量数据库
大模型直接选择把工具列表塞给LLM简单,LLM本身就懂语义工具太多时prompt很长

现在主流是方式2(OpenAI的Function Calling就是这个原理):

# 把工具描述直接给大模型
prompt = f"""
你有以下工具可用:
1. get_weather - 查询指定城市的天气
2. search_web - 搜索网页信息

用户问题:{user_query}

请选择合适的工具并提取参数。
"""

五、错误处理:三板斧

5.1 完整流程

flowchart TD
    classDef start fill:#1E3A5F,stroke:#0D47A1,color:#FFFFFF,stroke-width:2px
    classDef success fill:#2E7D32,stroke:#1B5E20,color:#FFFFFF,stroke-width:2px
    classDef fail fill:#C62828,stroke:#B71C1C,color:#FFFFFF,stroke-width:2px
    classDef retry fill:#F57C00,stroke:#E65100,color:#FFFFFF,stroke-width:1px
    classDef fallback fill:#7B1FA2,stroke:#4A148C,color:#FFFFFF,stroke-width:1px
    classDef decision fill:#FFFFFF,stroke:#90A4AE,stroke-width:2px

    Start["👤 查一下东京天气"]
    class Start start

    R1["🔄 第1次调用<br/>get_weather(东京)"]
    D1{"成功?"}
    class R1 retry
    class D1 decision

    R2["🔄 第2次调用"]
    D2{"成功?"}
    class R2 retry
    class D2 decision

    R3["🔄 第3次调用"]
    D3{"成功?"}
    class R3 retry
    class D3 decision

    FB["🔀 备选方案<br/>search_web(东京天气)"]
    D4{"成功?"}
    class FB fallback
    class D4 decision

    GD["⚠️ 兜底<br/>网络异常,请稍后再试"]
    OK["✅ 返回结果"]
    class GD fail
    class OK success

    Start --> R1 --> D1
    D1 -->|是| OK
    D1 -->|否| R2 --> D2
    D2 -->|是| OK
    D2 -->|否| R3 --> D3
    D3 -->|是| OK
    D3 -->|否| FB --> D4
    D4 -->|是| OK
    D4 -->|否| GD

5.2 三板斧总结

策略术语说明
重试3次Retry with Backoff给系统恢复时间
失败换工具Fallback Strategy尝试备选方案
直接摊牌Graceful Degradation诚实告诉用户

5.3 用后端思维理解

这就是我们熟悉的异常处理:

public String getWeather(String city) {
    // 1. 重试3次
    for (int i = 0; i < 3; i++) {
        try {
            return weatherApi.getWeather(city);
        } catch (Exception e) {
            if (i == 2) break;  // 最后一次失败
            Thread.sleep(1000 * (i + 1));  // 指数退避
        }
    }
    
    // 2. 尝试备选方案
    try {
        return searchWeb(city + "天气");
    } catch (Exception e) {
        // 备选也失败了
    }
    
    // 3. 兜底
    return "抱歉,当前网络异常,请稍后再试";
}

六、今日收获

6.1 核心概念对照表

graph LR
    classDef root fill:#1E3A5F,stroke:#0D47A1,color:#FFFFFF,stroke-width:2px
    classDef branch fill:#E3F2FD,stroke:#1565C0,color:#1565C0,stroke-width:1px
    classDef leaf fill:#F5F7FA,stroke:#90A4AE,color:#37474F

    Root["Agent核心架构"]
    class Root root

    Root --> P["System Prompt<br/>全局配置/常量"]
    Root --> H["对话历史<br/>滑动窗口/deque"]
    Root --> T["工具调用<br/>策略模式+工厂模式"]
    Root --> E["错误处理<br/>try-catch+重试"]
    Root --> A["Agent三元组<br/>Controller+Service+DAO"]

    class P,H,T,E,A branch
AI概念Java后端对应本质
System Prompt全局配置/常量一次创建,全程不变
对话历史滑动窗口/deque只保留最近N轮
工具调用策略模式+工厂模式注册→匹配→执行
错误处理try-catch+重试重试→降级→兜底
Agent三元组Controller+Service+DAO规划+工具+记忆

6.2 1对1问答式学习的优势

这次学习我采用了"问答式",发现和传统学习完全不同:

flowchart LR
    classDef old fill:#FFEBEE,stroke:#C62828,color:#B71C1C,stroke-width:2px
    classDef new fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20,stroke-width:2px
    classDef node fill:#FFFFFF,stroke:#90A4AE,stroke-width:1px

    subgraph Traditional["📚 传统学习"]
        T1["看视频/文章"]
        T2["被动接收"]
        T3["有问题先记下"]
        T4["学完才能实践"]
        T5["容易走神 😴"]
        T1 --> T2 --> T3 --> T4 --> T5
        class T1,T2,T3,T4,T5 node
    end

    subgraph QA["❓ 问答式学习"]
        Q1["问问题"]
        Q2["主动探索"]
        Q3["问题秒回,即时解决"]
        Q4["边学边问边理解"]
        Q5["保持专注 🔥"]
        Q1 --> Q2 --> Q3 --> Q4 --> Q5
        class Q1,Q2,Q3,Q4,Q5 node
    end

    Traditional -.->|升级| QA

    class Traditional old
    class QA new
传统学习问答式学习
看视频/文章问问题
被动接收主动探索
有问题先记下问题秒回,即时解决
学完才能实践边学边问边理解
容易走神保持专注

举个例子:

我问:系统提示词是什么?
AI答:就是Agent的人设,类似全局变量

我追问:那对话历史呢?
AI答:滑动窗口,只保留最近10轮

我再追问:工具调用怎么知道调哪个?
AI答:语义匹配,向量相似度搜索

每个问题都是秒回,不用等,不用查资料
这种"即时反馈"让学习效率翻倍

6.3 学习感悟

AI Agent的学习曲线其实没有想象中陡峭。

flowchart LR
    classDef java fill:#FFF3E0,stroke:#F57C00,color:#E65100,stroke-width:2px
    classDef ai fill:#E3F2FD,stroke:#1565C0,color:#0D47A1,stroke-width:2px
    classDef arrow fill:#FFFFFF,stroke:#90A4AE,stroke-width:1px

    subgraph Java["☕ Java工程师已有基础"]
        J1["API调用"]
        J2["数据库"]
        J3["缓存"]
        J4["设计模式"]
        J5["异常处理"]
        class J1,J2,J3,J4,J5 java
    end

    subgraph AI["🤖 AI Agent对应概念"]
        A1["大模型接口"]
        A2["向量数据库"]
        A3["记忆系统"]
        A4["Agent架构"]
        A5["错误重试"]
        class A1,A2,A3,A4,A5 ai
    end

    J1 --> A1
    J2 --> A2
    J3 --> A3
    J4 --> A4
    J5 --> A5

    class Java java
    class AI ai

作为Java工程师,我们已经有很好的工程基础:

  • 理解API调用 → 理解大模型接口
  • 理解数据库 → 理解向量数据库
  • 理解缓存 → 理解记忆系统
  • 理解设计模式 → 理解Agent架构
  • 理解异常处理 → 理解错误重试

关键是要用熟悉的视角去理解新概念。


七、明日计划

按照学习计划,明天要:

  • 动手实现一个迷你Agent
  • 把今天学到的架构落地成代码
  • 继续用后端思维拆解AI概念

八、写在最后

学AI不难,难的是坚持。

作为一个"规划狂魔",我太了解那种"规划完就满足"的感觉了。

但这次不一样,我有AI老师陪我学,有问题随时问,有答案即时给。

如果你也是Java工程师,想转AI Agent,欢迎关注我的系列文章。

我们一起,用后端思维,拆解AI世界。


📌 系列目录

  • Day 1:环境搭建与大模型API基础
  • Day 2:LangChain核心与工具调用
  • Day 3:记忆系统与向量数据库
  • Day 4:Agent核心架构全解析(本文)
  • Day 5:动手实现迷你Agent(即将更新)

标签: #AI Agent #Java工程师 #Agent架构 #工具调用 #错误处理 #学习笔记 #Hermes Agent #1对1学习


关于作者: 宸丶一,28岁Java程序员,规划狂魔,正在用AI学AI。

💬 格言: "代码改不改变世界我不知道,但先让我准时下班。"

🎯 目标: 3个月转AI Agent,用后端思维拆解AI世界。

声明: 本文为原创学习笔记,如需转载请注明出处。