一、引言:

本文是《AI Agent 开发实战系列》的开篇,过去一年AI领域迎来了飞速发展,LLM从聊天助手进化为了可自主执行甚至可自进化的系统也就是Agent。今天我们不谈玄乎的"通用人工智能",而是回答一个非常具体的问题:当我们说"做一个 Agent"时,到底在做什么?

二、先破一个误解:Agent 不是"更聪明的聊天机器人"

很多人第一次接触 Agent,是从"我用 ChatGPT 帮我完成一道面试八股文"开始的。于是自然会觉得:Agent 就是能力更强的 Chatbot 吧?

不是。这两者有一个本质区别,用一句话概括:

Chatbot 生成"答案",Agent 完成"任务"。

举个例子感受一下差异。你说:"帮我查一下明天北京到上海的高铁,选一班上午出发的,把车次发我。"·

Chatbot 的反应:"抱歉,我无法访问实时购票系统。你可以去 12306 查询……"——它只能基于已有知识生成文本。

Agent 的反应:调用查询工具 → 拿到车次列表 → 筛选上午班次 → 把结果整理后返回。它采取了行动,并根据行动的结果决定下一步

区别的核心不在于"谁更聪明",而在于是否能与外部世界交互并自主推进。Chatbot 是一个"文本函数":输入文本,输出文本。Agent 是一个"回路":它会观察环境、做出决策、执行动作、再观察动作带来的变化,如此循环直到任务完成。

三、Agent 的核心回路:感知—规划—行动—观察

几乎所有 Agent,不管用什么框架、多复杂,骨架都是同一个循环:

        ┌──────────────────────────────────────────┐
        │                                            │
        ▼                                            │
   ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
   │  感知    │───▶    │  规划         │───▶   │  行动    │───▶    │  观察    │
   │ Perceive│             │  Plan         │              │  Act  │                   │ Observe │
   └─────────┘    └─────────┘    └─────────┘    └─────────┘
   接收目标/                   LLM 决定下           调用工具                获取结果,
   环境状态                    一步做什么            执行操作                判断是否完成
                                                     │
                                     完成? ──否──────┘
                                       │
                                       是
                                       ▼
                                    返回结果

拆开看这四步:

感知(Perceive):Agent 接收当前的状态——用户的目标、历史对话、上一步动作的结果。本质上是把这些信息组织成一段上下文,喂给 LLM。

规划(Plan):LLM 基于当前上下文,判断"接下来该做什么"。可能是"我需要调用搜索工具",也可能是"信息够了,可以给出最终答案"。这一步是 Agent 的"大脑"。

行动(Act):执行 LLM 决定的动作。通常是调用一个工具(函数)——搜索、查数据库、发请求、写文件。

观察(Observe):拿到动作的结果(搜索返回了什么、API 报了什么错),把它加入上下文。然后判断:任务完成了吗?没完成就回到"感知",带着新信息再走一轮。

关键点在于:是 LLM 在每一轮里自主决定下一步,而不是程序员写死流程。 这就是 Agent 与传统自动化脚本的分水岭。脚本的分支是人预先编排好的;Agent 的分支是模型在运行时决定的。

四、Agent 的四个能力维度

回路是骨架,让骨架"活起来"需要四种能力。你可以用它们来评估任何一个 Agent 系统的成熟度:

1. 工具使用(Tool Use) Agent 通过"工具"与世界交互。工具本质是一个函数 + 一段描述,告诉 LLM"这个工具能干什么、需要什么参数"。没有工具的 Agent 只能空想,有了工具才能查天气、发邮件、跑代码。

2. 记忆(Memory) 短期记忆是当前任务的上下文(这次对话说了什么、做了哪几步);长期记忆是跨会话沉淀的信息(用户偏好、历史结论)。记忆决定了 Agent 能不能处理长任务、能不能"记住你是谁"。这是本系列第四部分的重头戏。

3. 规划(Planning) 简单任务一步到位,复杂任务需要拆解:先做什么、后做什么、某步失败了怎么办。规划能力决定了 Agent 能处理多复杂的任务。ReAct、Plan-and-Execute 等范式(第 03 篇详谈)都是在解决"如何规划"。

4. 多步自主(Autonomy) 能不能在没有人逐步指挥的情况下,连续走完多个步骤直到目标达成。自主度越高,人干预越少,但可控性和风险也随之变化。

一个成熟的 Agent = 稳定的回路 + 这四种能力的组合。你会发现,后面所有的技术话题——MCP 是在强化"工具使用",向量库是在强化"记忆",多智能体、harness都是在强化"规划与自主",——都能挂到这个框架上。

五、落到工程:当代 Agent 的组成要素简介

要素 一句话是什么 对应能力
Harness(执行框架) 承载回路的运行时骨架,管状态、调度、错误恢复 回路载体
Prompt(提示/指令) 定义角色、约束、工具契约与输出格式的系统指令 规划
Loop(智能体循环) 感知—规划—行动—观察的迭代内核 多步自主
Tools / Function Calling Agent 与外部世界交互的函数接口 工具使用
MCP(模型上下文协议) 工具/数据源接入的标准化协议,解决 M×N 集成 工具使用
A2A(智能体协作协议) Agent 之间跨系统协作与任务委派的标准 规划/自主
Skill(技能) 可复用、可组合的能力封装(含指令+工具+流程) 工具使用/规划
Memory(记忆) 短期上下文 + 长期跨会话记忆 记忆
RAG / 检索 从外部知识库动态召回相关信息注入上下文 记忆
Context Engineering 动态管理窗口内该放什么、如何压缩 记忆/规划
Planner(规划器) 任务分解、子目标管理、反思纠错 规划
Guardrails(护栏) 输入输出校验、权限控制、风险拦截 安全
Observability(可观测) Trace/日志/指标,追踪每步执行 工程支撑

一句话:一个 Agent 项目 = Harness 跑 Loop,Loop 靠 Prompt 驱动,通过 Tools/MCP 行动,用 Memory/RAG 记忆,由 Guardrails 兜底,被 Observability 观测。 本篇聚焦最核心的 Loop,其余要素后续逐一拆解。

六、一个不依赖框架的最小 Agent

import java.util.*;

public class MiniAgent {

    // ---------- 1. 定义工具(Act 的载体)----------
    static String calculator(String expr) {
        try {
            // 仅演示:用脚本引擎算式子,生产环境需做沙箱与白名单
            Object r = new javax.script.ScriptEngineManager()
                    .getEngineByName("JavaScript").eval(expr);
            return String.valueOf(r);
        } catch (Exception e) {
            return "计算错误: " + e.getMessage();  // 错误如实返回给 LLM
        }
    }

    static String getWeather(String city) {
        var db = Map.of("北京", "晴,26°C", "上海", "多云,29°C", "广州", "雷阵雨,31°C");
        return db.getOrDefault(city, "暂无 " + city + " 的天气数据");
    }

    // 工具注册表:名字 -> 实际实现
    static String callTool(String name, Map<String, String> args) {
        return switch (name) {
            case "calculator" -> calculator(args.get("expression"));
            case "get_weather" -> getWeather(args.get("city"));
            default -> "未知工具: " + name;
        };
    }

    // 工具描述(JSON):告诉 LLM 有哪些工具可用,这是"规划"的依据
    static final String TOOLS_SCHEMA = """
        [
          {"type":"function","function":{"name":"calculator",
            "description":"计算数学表达式,如 '23*45'",
            "parameters":{"type":"object",
              "properties":{"expression":{"type":"string","description":"数学表达式"}},
              "required":["expression"]}}},
          {"type":"function","function":{"name":"get_weather",
            "description":"查询指定城市的当前天气",
            "parameters":{"type":"object",
              "properties":{"city":{"type":"string","description":"城市名,如'北京'"}},
              "required":["city"]}}}
        ]""";

    // ---------- 2. Agent 回路 ----------
    static String runAgent(String userQuery, int maxSteps) {
        // 感知:把目标放进上下文
        List<Map<String, Object>> messages = new ArrayList<>();
        messages.add(Map.of("role", "system",
                "content", "你是一个助手。需要时调用工具,信息足够后直接回答用户。"));
        messages.add(Map.of("role", "user", "content", userQuery));

        for (int step = 1; step <= maxSteps; step++) {
            System.out.println("\n--- 第 " + step + " 步 ---");

            // 规划:调用大模型,让它决定下一步(回答 or 调工具)
            LlmReply reply = chat(messages, TOOLS_SCHEMA);  // 封装 HTTP 请求

            // 分支 A:没有工具调用 -> 任务完成
            if (reply.toolCalls.isEmpty()) {
                System.out.println("[最终回答] " + reply.content);
                return reply.content;
            }

            // 分支 B:有工具调用 -> 行动 + 观察
            messages.add(reply.raw);  // 先把 LLM 的决策记入上下文
            for (ToolCall tc : reply.toolCalls) {
                System.out.println("[规划] 调用工具: " + tc.name + tc.args);

                String result = callTool(tc.name, tc.args);   // 行动
                System.out.println("[观察] 工具返回: " + result);

                // 把观察结果加入上下文,进入下一轮
                messages.add(Map.of("role", "tool",
                        "tool_call_id", tc.id, "content", result));
            }
        }
        return "达到最大步数,未能完成任务。";
    }

    // ---------- 3. 试跑 ----------
    public static void main(String[] args) {
        runAgent("北京今天天气怎么样?顺便帮我算一下 128 * 39 等于多少", 5);
    }
}

运行后你会看到类似的输出:

--- 第 1 步 ---
[规划] 调用工具: get_weather({'city': '北京'})
[观察] 工具返回: 晴,26°C
[规划] 调用工具: calculator({'expression': '128 * 39'})
[观察] 工具返回: 4992

--- 第 2 步 ---
[最终回答] 北京今天天气晴,26°C。128 × 39 = 4992。

请仔细体会这段输出里发生了什么:

  1. 我们从没写过"先查天气再算数"这样的流程,是 LLM 自己在第 1 步决定同时调用两个工具的。
  2. 第 2 步 LLM 拿到两个工具的结果后,自主判断"信息够了",于是不再调用工具,直接给出最终答案——循环自然终止。
  3. 整个 runAgent 方法就是那个"感知—规划—行动—观察"回路的忠实实现,核心不过一个 for 循环加两个分支。

这就是 Agent 的全部本质。 后面所有框架(LangGraph、CrewAI、AutoGen……)做的事情,归根结底都是在这个回路上加东西:更好的状态管理、更强的记忆、多个 Agent 协作、可观测性、错误恢复……但内核不变。理解了这个循环,你就理解了 Agent。

七、总结

这一篇我们建立了理解 Agent 的核心心智模型,回顾一下:

  • Agent 与 Chatbot 的本质区别是完成任务 vs 生成答案,关键在于能否与外部世界交互并自主推进;
  • 所有 Agent 的骨架都是感知—规划—行动—观察的回路,由 LLM 在每轮自主决策下一步;
  • 让回路活起来的四种能力是工具使用、记忆、规划、多步自主,后续所有技术都能挂到这个框架上;
  • 自主度是按场景权衡的设计选择,不是越高越好,大多数生产系统落在光谱中间;
  • 一个真正的 Agent 内核可以只有 40 行,框架做的是在此之上的工程增强。
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐