什么是 AI Agent?和 ChatBot 到底有什么区别

很多人第一次听到 “AI Agent” 这个词,第一反应是:这不就是 ChatGPT 换了个名字吗?

说实话,我当初也是这么想的。直到在 NVC 练习平台的开发中,真正把 12 个专职 Agent 跑起来,才意识到这完全是两码事。

先搞清楚 ChatBot 是什么

ChatBot 的本质是问答机器。你问一句,它答一句。不管是规则引擎驱动的老式客服机器人,还是基于大语言模型的现代对话系统,核心逻辑都一样:

用户输入 → 模型处理 → 输出回答

这个过程有几个特点:

  • 单轮为主:每次对话相对独立,上下文依赖靠"记忆"拼凑
  • 被动响应:你不问,它不说
  • 无状态:聊完就忘(除非显式实现记忆)

用代码表示大概是这样:

def chat(user_input: str) -> str:
    response = llm.generate(user_input)
    return response

简单粗暴,一问一答。

Chain 是什么?比 ChatBot 多一步

Chain(链)是 LangChain 早期的核心概念。它把多个步骤串起来,形成一个固定流程:

def chain(user_input: str) -> str:
    # Step 1: 提取关键信息
    entities = extract_entities(user_input)
    # Step 2: 查询数据库
    context = query_database(entities)
    # Step 3: 生成回答
    response = llm.generate(f"{context}\n\n{user_input}")
    return response

Chain 比 ChatBot 强的地方在于:它能做多步处理,调用外部工具。但本质上还是固定流程——你写死了步骤,它按顺序执行。

如果用户的问题不在预设流程内?抱歉,它处理不了。

Agent:能自己决定下一步做什么

Agent 和前两者的根本区别在于自主决策

Agent 不需要你预先写死流程。它拿到任务后,会自己思考:我需要调用什么工具?获取什么信息?下一步该做什么?

用伪代码表达:

def agent(task: str) -> str:
    context = []
    while not is_done(task, context):
        # 思考下一步
        action = think(task, context)
        # 执行动作
        result = execute(action)
        context.append(result)
    return summarize(context)

看到那个 while 循环了吗?这就是 Agent 的核心——它能根据当前状态,反复决策、反复执行,直到任务完成。

这个循环有个专业名字:AgentLoop

Agent 的四个核心组件

一个完整的 Agent 系统,通常包含四个部分:

1. LLM 大脑

负责理解任务、推理决策。这是 Agent 的"智商"来源。

2. Tools(工具)

Agent 能调用的能力。搜索、数据库查询、文件操作、API 调用……工具越多,Agent 能做的事越多。

3. Memory(记忆)

存储历史对话、中间结果、长期知识。没有记忆的 Agent 每次都从零开始。

4. Planning(规划)

把复杂任务拆解成可执行的步骤。这是 Agent 区别于简单工具调用的关键。

画成架构图:

任务输入

LLM 大脑

规划模块

工具集

记忆系统

任务输出

注意那个双向箭头——Brain 会反复和各个组件交互,而不是线性执行。

Perceive → Think → Act:Agent 的工作循环

Agent 的工作遵循一个经典循环:感知 → 思考 → 行动

Perceive 感知

Think 思考

Act 行动

在实际代码中,这个循环看起来像这样:

public class AgentLoop {
    private final LLM llm;
    private final ToolRegistry tools;
    private final Memory memory;

    public String run(String task) {
        List<Message> context = new ArrayList<>();
        context.add(new UserMessage(task));

        while (true) {
            // Think: 让 LLM 决定下一步
            AgentResponse response = llm.chat(context, tools.getDefinitions());

            // 如果 LLM 决定完成任务,返回结果
            if (response.isFinalAnswer()) {
                return response.getContent();
            }

            // Act: 执行工具调用
            for (ToolCall call : response.getToolCalls()) {
                ToolResult result = tools.execute(call);
                context.add(new ToolMessage(result));
                memory.save(call, result);
            }
        }
    }
}

这段代码来自我在 NVC 项目中的实际实现。关键点在于:我们关闭了 Spring AI 的自动工具执行,自己控制整个循环。

为什么要这么做?因为自动执行太黑盒了。我想在循环的每一步插入自己的逻辑。

实战:NVC 项目的 12 个 Agent 架构

在 NVC 练习平台中,我们设计了 12 个专职 Agent,每个负责一个特定领域:

Agent 名称 职责
DialogueAgent 主对话管理
EmotionAgent 情绪识别与分析
IntentAgent 用户意图理解
FeedbackAgent 练习反馈生成
ScoringAgent 评分计算
HintAgent 提示生成
SummaryAgent 对话总结
ContextAgent 上下文管理
ValidationAgent 输入校验
TranslationAgent 多语言支持
AnalyticsAgent 数据分析
AdminAgent 管理操作

这 12 个 Agent 不是各干各的,而是通过一个编排中枢统一调度。

用户输入

编排中枢

DialogueAgent

EmotionAgent

IntentAgent

FeedbackAgent

ScoringAgent

输出响应

编排中枢的核心逻辑:

@Component
public class AgentOrchestrator {
    private final Map<String, Agent> agents;
    private final AgentRouter router;

    public String process(String input, SessionContext ctx) {
        // 路由到合适的 Agent
        List<String> agentSequence = router.route(input, ctx);

        String result = input;
        for (String agentName : agentSequence) {
            Agent agent = agents.get(agentName);
            result = agent.process(result, ctx);
        }
        return result;
    }
}

为什么关闭自动工具执行?

Spring AI 提供了很方便的自动工具执行功能——LLM 说要调用什么工具,框架自动帮你调用。

听起来很美好,但实际用起来问题不少:

  1. 调试困难:工具调用在框架内部发生,你想看中间状态很麻烦
  2. 控制力弱:想在工具调用前后加逻辑?对不起,框架没给你这个口子
  3. 错误处理粗糙:工具调用失败了,框架默认直接抛异常,你很难做优雅降级

所以我们选择了手动控制:

// 关闭自动执行
spring.ai.chat.client.tool-auto-execution=false

// 自己控制循环
while (true) {
    AgentResponse response = llm.chat(messages, toolDefs);

    if (response.hasToolCalls()) {
        for (ToolCall call : response.getToolCalls()) {
            // 在这里插入 Hook
            hookChain.beforeToolCall(call);
            ToolResult result = toolRegistry.execute(call);
            hookChain.afterToolCall(call, result);
        }
    }
}

7 层 Hook 链:在循环中插入业务逻辑

手动控制循环最大的好处是:你可以在任何位置插入 Hook。

我们在 AgentLoop 中设计了 7 层 Hook:

public class AgentHookChain {
    private final List<AgentHook> hooks = new ArrayList<>();

    // 1. 任务开始前
    public void beforeTask(String task, SessionContext ctx) {
        hooks.forEach(h -> h.onTaskStart(task, ctx));
    }

    // 2. LLM 调用前
    public void beforeLLMCall(List<Message> messages) {
        hooks.forEach(h -> h.onBeforeLLM(messages));
    }

    // 3. LLM 返回后
    public void afterLLMCall(AgentResponse response) {
        hooks.forEach(h -> h.onAfterLLM(response));
    }

    // 4. 工具调用前
    public void beforeToolCall(ToolCall call) {
        hooks.forEach(h -> h.onBeforeTool(call));
    }

    // 5. 工具调用后
    public void afterToolCall(ToolCall call, ToolResult result) {
        hooks.forEach(h -> h.onAfterTool(call, result));
    }

    // 6. 决策点(是否继续循环)
    public boolean shouldContinue(AgentState state) {
        return hooks.stream().allMatch(h -> h.onDecision(state));
    }

    // 7. 任务结束后
    public void afterTask(String result, SessionContext ctx) {
        hooks.forEach(h -> h.onTaskEnd(result, ctx));
    }
}

每个 Hook 都是一个扩展点。比如:

  • beforeLLMCall 中注入系统提示词
  • afterToolCall 中记录审计日志
  • shouldContinue 中实现最大轮次限制
  • afterTask 中触发后续处理

总结一下三者的区别

特性 ChatBot Chain Agent
交互模式 单轮问答 固定流程 自主决策
工具调用 预设顺序 动态决定
状态管理 无状态 有限状态 完整记忆
灵活性
复杂度

一句话概括:ChatBot 是问答机器,Chain 是固定流水线,Agent 是能自己想办法的智能体。

写在最后

理解 Agent 和 ChatBot 的区别,不是为了追概念,而是为了在合适的场景选择合适的方案。

简单的问答场景,用 ChatBot 就够了。流程固定的业务,Chain 更省心。只有当任务复杂、需要多步决策、涉及多种工具时,Agent 的价值才真正体现出来。

在 NVC 项目中,12 个 Agent 协同工作的架构让我们能够灵活应对各种练习场景,但也带来了更高的调试和维护成本。这是个权衡——没有银弹,只有适合。


更多推荐