提到AI智能体(Agent),很多人会联想到「自主任务执行」「ReAct范式」「工具调用」等抽象概念,甚至觉得这是只有大厂才能落地的复杂系统。事实上,智能体的定义非常具体——我们可以从一个真实落地的MBTI智能体项目出发,结合完整源码逐层拆解。本文所有代码示例均来自笔者的群面模拟系统,核心模块为MBTI智能体对话功能,对应代码路径、文件名、逻辑均与工程实现完全一致。


一、先和「裸调大模型API」划清界限

要理解智能体,首先要明确它和普通大模型API调用的本质差异:

裸调LLM的本质:无状态的工具调用

如果我们直接调用通义千问、DeepSeek的API,流程是:

用户输入 → 拼接Prompt → 调用LLM API → 返回结果 → 结束

整个过程是无状态的:每次调用都不会保留任何历史,不知道「自己是谁」,也不会主动做任何决策,完全依赖外部传入的Prompt决定输出内容。哪怕你给Prompt加上「你是INTJ型的领导者」,下次调用如果不重新传这段Prompt,模型就会立刻「失忆」。

智能体的本质:封装LLM的「自主实体」

参考OpenAI对智能体的定义:能够感知环境、自主决策、执行动作以完成目标的实体。对应到代码层面,智能体就是一个「封装了LLM调用能力,具备身份、记忆、决策逻辑的业务对象」——和你平时写的Service、Controller没有本质区别,只是核心能力从「处理业务逻辑」变成了「调用LLM生成符合自身属性的输出」。


二、智能体的四大核心特征(逐一定义+代码对应)

我们完全基于backend/src/main/java/com/interview/agent/Agent.java拆解,每一个特征都有明确的代码实现:


特征1:具身身份(Embodied Identity)

定义

每个智能体都有唯一的身份标识固定的属性集合(如人格、角色、名称),不是匿名的大模型调用入口。

代码对应
// Agent.java 第9-16行,核心接口定义
public interface Agent {
    String getAgentId();          // 唯一身份ID
    AgentProfile getProfile();    // 身份档案(名称、MBTI、角色等)
    // ...其他方法
}

在你的项目中:

  • 身份ID:由AgentFactory(智能体工厂)创建时生成,格式为${mbti}_${role}_${uuid},确保全局唯一
  • 身份档案:AgentProfile包含中文姓名、MBTI类型(如INTJ)、群面角色(如LEADER)、默认角色等属性,由工厂类根据MbtiType枚举(共16种MBTI类型)初始化
  • 前端展示:用户选择MBTI和角色后,智能体的回复会携带mbtiroleType字段(见AgentChatController.java),明确告知用户「对话对象是谁」

对比裸调API:裸调LLM没有固定身份,每次调用都相当于「匿名用户」,而我的智能体从创建之初就明确了「我是INTJ型的推进型领导者张三」,所有回复都符合这个身份设定。


特征2:状态与记忆(State & Memory)

定义

智能体内部维护状态变量记忆存储,能够记录对话历史、行为记录、情绪变化等信息,不需要外部每次传入完整上下文。

代码对应
// Agent.java 第16行,状态查询方法
AgentState getState();

// Agent.java 第25-31行,发言上下文(包含记忆相关字段)
record SpeakContext(
    Phase currentPhase,
    int elapsedTime,
    int silenceDuration,    // 自身沉默时长(状态变量)
    List<Event> recentEvents, // 最近对话事件(记忆)
    Map<String, AgentState> agentStates
) {}

// AbstractAgent(抽象基类)中维护的对话历史
protected final List<Event> conversationHistory = new ArrayList<>();

在你的项目中:

  • 对话记忆:AbstractAgent维护conversationHistory列表,每次对话后自动将用户消息和智能体回复加入列表,限制最多存储20条(避免上下文过长导致LLM超时)
  • 状态变量:每个智能体记录lastSpeakTime(最后发言时间)、当前情绪值、发言次数等状态,calculateSpeakScore计算时会读取lastSpeakTime计算沉默时长得分
  • 会话隔离:通过sessionId映射智能体实例(见AgentChatController.java第23行sessionAgents缓存),不同用户的对话对应不同的智能体实例,记忆完全隔离

对比裸调API:裸调LLM没有自身状态,必须每次手动传入所有历史对话;而我的智能体自己维护记忆,哪怕用户关闭页面再打开,只要sessionId不变,智能体依然记得之前的对话内容。


特征3:自主决策逻辑(Autonomous Decision-Making)

定义

智能体可以基于自身状态和上下文自主做出行为决策,而非被动响应用户输入。即使是单轮对话的智能体,也会根据用户输入选择不同的回复策略;多智能体场景下则会主动竞争发言权。

代码对应
// Agent.java 第13行,发言评分(决策核心方法)
double calculateSpeakScore(SpeakContext context);

// AbstractAgent中定义的决策参数
protected static final double SPEAK_THRESHOLD = 0.65; // 发言阈值
protected static final double ROLE_WEIGHT = 0.2;       // 角色权重
protected static final double SILENCE_WEIGHT = 0.3;     // 沉默时长权重

在你的项目中:

  • 单智能体场景(MBTI对话):虽然是一问一答,但智能体也会自主决策——比如用户问「你是谁」,智能体会根据自身AgentProfile返回身份说明;用户问专业问题,智能体根据MBTI类型调整回复风格(INTJ更严谨,ENFP更发散)
  • 多智能体场景(群面模拟):AgentEngine(智能体引擎)会调用所有智能体的calculateSpeakScore方法,分数高于SPEAK_THRESHOLD的智能体获得发言权,完全自主决策,不需要用户触发

对比裸调API:裸调LLM永远被动响应,你发一句它回一句,永远不会主动开口;而我的群面智能体会自己计算「我要不要说话」,分数够了就会主动发言。


特征4:场景化适配能力(Context-Aware Adaptation)

定义

智能体可以根据当前场景(讨论阶段、话题、历史对话)调整自身行为,生成符合身份的回复,而不是千篇一律的输出。

代码对应
// Agent.java 第14行,回复生成方法(带完整上下文)
String generateResponse(AgentContext context);

// AgentContext 包含完整场景信息(Agent.java 第33-39行)
record AgentContext(
    Phase currentPhase,             // 当前讨论阶段(破冰/辩论/总结)
    String currentSpeakerId,        // 当前发言者
    List<Event> conversationHistory,// 对话历史
    String questionContent,         // 讨论问题
    Map<String, AgentState> allAgentStates // 所有智能体状态
) {}

在你的项目中:

  • 提示词适配:LlmCandidateAgent(基于LLM的智能体实现)会根据自身的MBTI和角色拼接不同的系统提示词:INTJ的Leader提示词会要求「逻辑严谨,主导讨论方向」,ENFP的Viewpoint会要求「提出新颖观点,发散思维」
  • 阶段适配:如果当前是破冰阶段,智能体回复偏轻松;辩论阶段偏逻辑;总结阶段Leader会主动做收尾,这些逻辑都通过currentPhase参数传入generateResponse方法实现

对比裸调API:裸调LLM不管场景,给什么Prompt答什么;而我的智能体自己会根据场景调整回复,同样调通义千问API,不同智能体说出来的话完全不一样。


三、完整交互流程走读(从用户操作到返回结果)

我们以一次完整的MBTI智能体对话为例,串联所有代码模块,验证上述特征:

步骤 前端逻辑(对应文件) 后端逻辑(对应文件) 智能体特征体现
1. 初始化 AgentChatView.vue:240 调用getMbtiTypes() AgentChatController.java:25 处理/agent/mbti-types接口,返回16种MBTI类型 具身身份:提前定义所有智能体的身份属性
2. 选择身份 AgentChatView.vue:127 选MBTI,145选角色,生成唯一sessionId - 会话隔离:每个身份组合对应唯一的智能体实例
3. 发送消息 AgentChatView.vue:161 调用chatWithAgent(),携带mbti/role/message/sessionId AgentChatController.java:39 处理/agent/chat接口,根据sessionId找/创建智能体 状态与记忆:复用已有智能体实例,保留历史对话
4. 生成回复 - 构造AgentContext,调用agent.generateResponse(context) 场景化适配:根据上下文生成符合身份的回复
5. 返回结果 前端将回复加入消息列表,展示在聊天框 返回response/mbti/roleType字段 具身身份:明确告知用户对话对象的属性

四、智能体的不同形态

智能体不是只有「能自主完成复杂任务」一种形态,我的项目里已经实现了三种不同层级的智能体,核心特征完全一致:

  1. 基础型智能体:本文重点介绍的MBTI单对话智能体,具备完整四大特征,是最基础的智能体形态
  2. 协作型智能体:群面场景下的5-6个智能体,通过AgentEngine调度,竞争发言、互相影响状态,完成群面讨论任务
  3. 工具型智能体:ReAct模式的ReportManusAgent,支持工具调用(加载上下文、导出PDF、生成报告),能够自主规划步骤完成复杂任务

总结

智能体从来不是玄学,就是我代码里的Agent接口实现类:

智能体 = 唯一身份 + 自主状态记忆 + 决策逻辑 + LLM调用封装

我写的LeaderAgentSupporterAgent这些类,本质都是这个定义的具象化。对于开发者来说,不需要纠结概念层级,只要实现了上述四大特征,你写的就是一个合格的AI智能体。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐