Spring AI 学习篇(十四)| 实战:开发一个智能办公Agent
- 一、本章核心学习目标
- 二、前置知识准备
- 三、为什么选择智能办公Agent作为实战项目?
- 四、智能办公Agent整体架构设计
- 五、工具集设计与实现
-
- [1. 邮件工具MCP服务器](#1. 邮件工具MCP服务器)
- [2. 文档工具MCP服务器](#2. 文档工具MCP服务器)
- [3. 数据库工具MCP服务器](#3. 数据库工具MCP服务器)
- [4. RAG知识库工具MCP服务器](#4. RAG知识库工具MCP服务器)
- 六、Agent定制化与系统提示词设计
- 七、个性化记忆系统优化
-
- [1. 用户偏好记忆](#1. 用户偏好记忆)
- [2. 上下文管理](#2. 上下文管理)
- 八、完整Agent服务实现
-
- [1. Agent服务层](#1. Agent服务层)
- [2. Agent控制器](#2. Agent控制器)
- 九、测试与效果演示
- 十、企业级优化
-
- [1. 安全控制增强](#1. 安全控制增强)
- [2. 可观测性](#2. 可观测性)
- [3. 性能优化](#3. 性能优化)
- 十一、常见坑与解决方案
-
- [1. ❌ Agent过度依赖工具](#1. ❌ Agent过度依赖工具)
- [2. ❌ Agent忘记用户的要求](#2. ❌ Agent忘记用户的要求)
- [3. ❌ 工具调用参数错误](#3. ❌ 工具调用参数错误)
- [4. ❌ 复杂任务规划失败](#4. ❌ 复杂任务规划失败)
- 十二、本章总结与下章预告
- 十三、课后练习
一、本章核心学习目标
学完本章,你将能够:
- 独立完成企业级Agent的需求分析与架构设计
- 构建智能办公场景的完整工具集(邮件、日历、文档、数据库)
- 设计专业的Agent系统提示词,精准控制Agent的行为
- 实现多任务上下文管理与用户个性化记忆
- 完成一个可直接上线的智能办公Agent完整代码
- 掌握Agent的测试方法与效果优化技巧
- 拥有一个可以放到简历上的完整AI Agent项目经验
二、前置知识准备
- 已经完成前13篇的学习,熟练掌握ReAct Agent框架
- 精通Spring AI工具调用与MCP协议
- 了解Agent记忆系统的实现原理
- 熟悉Spring Boot Web开发与数据库操作
三、为什么选择智能办公Agent作为实战项目?
智能办公是AI Agent落地最成熟的场景之一,需求非常旺盛。大量企业都有重复性的办公工作可通过AI Agent自动化,直接产生商业价值。
我们要实现的智能办公Agent核心能力
我们将开发一个个人智能办公助手,具备以下6大核心能力:
- 邮件管理:自动收发、分类、回复邮件,撰写邮件草稿
- 文档处理:生成、编辑、总结各类办公文档(周报、会议纪要、报告)
- 日程管理:安排会议、提醒待办事项、查询日程
- 数据查询:查询数据库、生成统计报表、分析数据
- 知识库问答:基于企业知识库回答内部问题
- 任务自动化:自动完成多步骤复杂办公任务
预告式提及:本章完成后,你将拥有一个可以直接在工作中使用的智能办公助手。下一章我们将学习如何为这个Agent添加可观测性,监控它的运行状态和性能。
四、智能办公Agent整体架构设计
我们采用分层架构设计,确保系统的可扩展性和可维护性:
┌─────────────────────────────────────────────────────────┐
│ 接入层 │
│ Web界面 企业微信集成 钉钉集成 Slack集成 │
├─────────────────────────────────────────────────────────┤
│ Agent核心层 │
│ ReAct Agent引擎 任务规划器 记忆系统 工具调度器 │
├─────────────────────────────────────────────────────────┤
│ 工具层 │
│ 邮件工具 日历工具 文档工具 数据库工具 RAG工具 │
├─────────────────────────────────────────────────────────┤
│ 基础设施层 │
│ 大模型服务 向量数据库 关系型数据库 文件存储 │
└─────────────────────────────────────────────────────────┘
核心设计原则
- 模块化:每个工具独立封装,方便添加和修改
- 可配置:所有敏感信息和配置都通过配置文件管理
- 安全可控:所有危险操作都需要用户确认,有完整的审计日志
- 可扩展:方便后续添加新的工具和能力
- 个性化:能够记住用户的偏好和习惯,提供个性化服务
五、工具集设计与实现
工具集是智能办公Agent的核心(以下代码展示核心概念和设计思路,具体 API 以官方文档为准):
1. 邮件工具MCP服务器
实现邮件的收发、分类和回复功能:
java
import org.springframework.ai.mcp.server.annotation.McpServer;
import org.springframework.ai.mcp.server.annotation.McpTool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import jakarta.mail.*;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
@Component
@McpServer(name = "email-mcp-server", description = "提供邮件管理功能的MCP服务器")
public class EmailMcpServer {
private final EmailConfig emailConfig;
public EmailMcpServer(EmailConfig emailConfig) {
this.emailConfig = emailConfig;
}
@McpTool(description = "发送邮件")
public String sendEmail(
@ToolParam("收件人邮箱地址") String to,
@ToolParam("邮件主题") String subject,
@ToolParam("邮件内容") String content,
@ToolParam("抄送人邮箱地址,多个用逗号分隔") String cc) {
try {
Properties props = new Properties();
props.put("mail.smtp.host", emailConfig.getSmtpHost());
props.put("mail.smtp.port", emailConfig.getSmtpPort());
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(emailConfig.getUsername(), emailConfig.getPassword());
}
});
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(emailConfig.getUsername()));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
if (cc != null && !cc.isEmpty()) {
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
}
message.setSubject(subject);
message.setText(content);
Transport.send(message);
return "邮件发送成功";
} catch (Exception e) {
return "邮件发送失败:" + e.getMessage();
}
}
@McpTool(description = "读取最新的邮件")
public String readLatestEmails(
@ToolParam("读取的邮件数量,默认10封") int count) {
// 实现读取邮件的逻辑
return "已读取最新" + count + "封邮件";
}
}
2. 文档工具MCP服务器
实现文档的生成、编辑和总结功能:
java
@Component
@McpServer(name = "document-mcp-server", description = "提供文档处理功能的MCP服务器")
public class DocumentMcpServer {
private final ChatClient chatClient;
public DocumentMcpServer(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@McpTool(description = "生成周报")
public String generateWeeklyReport(
@ToolParam("本周完成的工作") String completedWork,
@ToolParam("下周计划的工作") String plannedWork,
@ToolParam("遇到的问题和风险") String problems) {
String prompt = """
请根据以下信息生成一份专业的项目周报:
本周完成工作:{completedWork}
下周计划工作:{plannedWork}
遇到的问题和风险:{problems}
要求:
1. 结构清晰,分为本周总结、下周计划、问题与风险三个部分
2. 语言简洁专业,符合企业规范
3. 突出重点工作和成果
""".replace("{completedWork}", completedWork)
.replace("{plannedWork}", plannedWork)
.replace("{problems}", problems);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
@McpTool(description = "总结文档内容")
public String summarizeDocument(
@ToolParam("文档内容") String content,
@ToolParam("总结的长度,可选:short/medium/long") String length) {
String prompt = """
请总结以下文档内容,长度要求:{length}
文档内容:{content}
""".replace("{length}", length).replace("{content}", content);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
}
3. 数据库工具MCP服务器
实现安全的数据库查询功能:
java
@Component
@McpServer(name = "database-mcp-server", description = "提供数据库查询功能的MCP服务器")
public class DatabaseMcpServer {
private final JdbcTemplate jdbcTemplate;
public DatabaseMcpServer(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@McpTool(description = "执行SQL查询,只能执行SELECT语句")
public String executeQuery(
@ToolParam("SQL查询语句,只能是SELECT语句") String sql) {
// 安全检查:只允许执行SELECT语句
if (!sql.trim().toLowerCase().startsWith("select")) {
return "错误:只允许执行SELECT查询语句";
}
try {
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
if (result.isEmpty()) {
return "查询结果为空";
}
return result.toString();
} catch (Exception e) {
return "查询失败:" + e.getMessage();
}
}
@McpTool(description = "获取数据库表结构")
public String getTableSchema(
@ToolParam("表名") String tableName) {
try {
Map<String, Object> result = jdbcTemplate.queryForMap(
"DESCRIBE " + tableName);
return result.toString();
} catch (Exception e) {
return "获取表结构失败:" + e.getMessage();
}
}
}
4. RAG知识库工具MCP服务器
集成我们之前实现的RAG系统:
java
@Component
@McpServer(name = "knowledge-base-mcp-server", description = "提供企业知识库查询功能的MCP服务器")
public class KnowledgeBaseMcpServer {
private final RagService ragService;
public KnowledgeBaseMcpServer(RagService ragService) {
this.ragService = ragService;
}
@McpTool(description = "查询企业知识库")
public String queryKnowledgeBase(
@ToolParam("查询问题") String query,
@ToolParam("知识库ID") Long kbId) {
return ragService.chat(kbId, query).getAnswer();
}
}
六、Agent定制化与系统提示词设计
系统提示词是Agent的灵魂,一个好的系统提示词可以让Agent的表现提升一个档次。
智能办公Agent专业系统提示词
java
@Bean
public Agent officeAgent(ChatClient.Builder chatClientBuilder,
List<McpClient> mcpClients,
ChatMemory chatMemory) {
return ReActAgent.builder()
.chatClient(chatClientBuilder.build())
.tools(mcpClients)
.maxIterations(15)
.chatMemory(chatMemory)
.systemPrompt("""
# 智能办公助手系统提示词
## 身份定位
你是一个专业、高效、可靠的个人智能办公助手,拥有5年以上的企业办公经验。
你的目标是帮助用户自动化处理各种办公任务,提高工作效率。
## 核心能力
你可以使用以下工具来完成任务:
1. 邮件工具:发送、读取和管理邮件
2. 文档工具:生成、编辑和总结各类办公文档
3. 数据库工具:查询业务数据和生成报表
4. 知识库工具:查询企业内部知识库
5. 文件系统工具:读取和写入本地文件
## 行为准则
1. **用户至上**:始终以用户的需求为中心,提供最优质的服务
2. **专业严谨**:所有回答和输出都要专业、准确、符合企业规范
3. **安全第一**:对于删除文件、发送邮件等危险操作,必须先向用户确认
4. **透明沟通**:清晰地告诉用户你正在做什么,以及为什么这么做
5. **主动学习**:记住用户的偏好和习惯,提供个性化的服务
6. **诚实可信**:如果你不知道答案或者无法完成任务,如实告诉用户,不要编造内容
## 任务处理流程
当用户提出一个任务时,请按照以下步骤处理:
1. **理解需求**:仔细分析用户的需求,明确任务目标
2. **制定计划**:将复杂任务分解为多个清晰的步骤
3. **执行计划**:调用合适的工具逐步执行计划
4. **检查结果**:检查每个步骤的执行结果是否正确
5. **总结反馈**:任务完成后,给用户一个简洁清晰的总结
## 输出格式
- 使用简洁明了的语言,避免使用技术术语
- 重要信息使用加粗标记
- 列表内容使用有序列表或无序列表
- 代码和数据使用代码块包裹
## 注意事项
- 不要讨论政治、宗教、色情等敏感话题
- 不要泄露企业的机密信息
- 不要执行任何可能危害系统安全的操作
- 如果用户的要求违反公司规定,礼貌地拒绝
现在,你已经准备好开始工作了。请以专业、友好的态度回应用户的每一个请求。
""")
.build();
}
七、个性化记忆系统优化
我们将短期记忆和长期记忆结合起来,为用户提供个性化的服务。
1. 用户偏好记忆
让Agent记住用户的常用设置和偏好:
java
@Component
public class UserPreferenceService {
private final LongTermMemory longTermMemory;
public UserPreferenceService(LongTermMemory longTermMemory) {
this.longTermMemory = longTermMemory;
}
// 保存用户偏好
public void savePreference(String userId, String key, String value) {
longTermMemory.saveMemory(userId, key + "=" + value, "preference");
}
// 获取用户偏好
public String getPreference(String userId, String key) {
List<Document> memories = longTermMemory.retrieveMemory(userId, key);
if (memories.isEmpty()) {
return null;
}
return memories.get(0).getContent().split("=")[1];
}
}
2. 上下文管理
实现多任务上下文切换,让Agent能够同时处理多个任务:
java
@Component
public class ContextManager {
private final Map<String, String> currentTaskContext = new ConcurrentHashMap<>();
// 设置当前任务上下文
public void setCurrentTask(String userId, String task) {
currentTaskContext.put(userId, task);
}
// 获取当前任务上下文
public String getCurrentTask(String userId) {
return currentTaskContext.get(userId);
}
// 清除当前任务上下文
public void clearCurrentTask(String userId) {
currentTaskContext.remove(userId);
}
}
八、完整Agent服务实现
1. Agent服务层
java
@Service
public class OfficeAgentService {
private final Agent officeAgent;
private final UserPreferenceService preferenceService;
private final ContextManager contextManager;
private final AuditLogService auditLogService;
public OfficeAgentService(Agent officeAgent,
UserPreferenceService preferenceService,
ContextManager contextManager,
AuditLogService auditLogService) {
this.officeAgent = officeAgent;
this.preferenceService = preferenceService;
this.contextManager = contextManager;
this.auditLogService = auditLogService;
}
public AgentResponse chat(String userId, String message) {
// 记录审计日志
auditLogService.log(userId, "user_message", message);
// 获取用户偏好
String emailSignature = preferenceService.getPreference(userId, "email_signature");
String reportFormat = preferenceService.getPreference(userId, "report_format");
// 构建增强的用户消息
String enhancedMessage = message;
if (emailSignature != null) {
enhancedMessage += "\n\n用户邮件签名:" + emailSignature;
}
if (reportFormat != null) {
enhancedMessage += "\n\n用户偏好的报告格式:" + reportFormat;
}
// 调用Agent
AgentResponse response = officeAgent.call(enhancedMessage);
// 记录审计日志
auditLogService.log(userId, "agent_response", response.getContent());
// 更新上下文
contextManager.setCurrentTask(userId, message);
return response;
}
// 危险操作确认
public String confirmAction(String userId, String actionId, boolean confirmed) {
if (confirmed) {
// 执行确认的操作
auditLogService.log(userId, "action_confirmed", actionId);
return "操作已确认,正在执行...";
} else {
// 取消操作
auditLogService.log(userId, "action_cancelled", actionId);
return "操作已取消";
}
}
}
2. Agent控制器
java
@RestController
@RequestMapping("/office-agent")
public class OfficeAgentController {
private final OfficeAgentService agentService;
public OfficeAgentController(OfficeAgentService agentService) {
this.agentService = agentService;
}
@PostMapping("/chat")
public Result<AgentResponseVO> chat(@RequestParam String userId,
@RequestParam String message) {
AgentResponse response = agentService.chat(userId, message);
AgentResponseVO vo = new AgentResponseVO();
vo.setContent(response.getContent());
vo.setSteps(response.getSteps().stream()
.map(step -> new StepVO(step.getThought(), step.getAction(), step.getObservation()))
.toList());
return Result.success(vo);
}
@PostMapping("/confirm")
public Result<String> confirmAction(@RequestParam String userId,
@RequestParam String actionId,
@RequestParam boolean confirmed) {
String result = agentService.confirmAction(userId, actionId, confirmed);
return Result.success(result);
}
}
九、测试与效果演示
现在我们来测试这个智能办公Agent的能力。
测试用例1:生成并发送周报
用户输入:帮我写一份本周的项目周报,然后发送给team@example.com,抄送给manager@example.com。本周我完成了用户管理模块的开发和测试,下周计划开发订单管理模块,遇到的问题是数据库性能有点慢。
Agent执行过程:
- 思考:我需要先生成周报内容,然后发送邮件。首先调用文档工具生成周报。
- 行动:调用
generateWeeklyReport工具,传入完成的工作、计划的工作和遇到的问题。 - 观察:周报生成成功。
- 思考:现在我需要发送邮件。但发送邮件是危险操作,我需要先向用户确认。
- 行动:向用户发送确认请求:"我已经生成了周报内容,是否确认发送给team@example.com并抄送给manager@example.com?"
- 观察:用户确认发送。
- 行动:调用
sendEmail工具发送邮件。 - 观察:邮件发送成功。
- 思考:所有步骤都已完成,任务结束。
最终回答:已为你生成并发送了本周的项目周报。邮件已发送至team@example.com,抄送给manager@example.com。
测试用例2:查询数据并生成报表
用户输入:帮我查询上个月的销售数据,然后生成一个销售报表。
Agent执行过程:
- 思考:我需要先查询销售数据表的结构,然后编写SQL查询数据,最后生成报表。
- 行动:调用
getTableSchema工具获取sales表的结构。 - 观察:获取到表结构。
- 思考:现在我可以编写SQL查询上个月的销售数据。
- 行动:调用
executeQuery工具执行SQL查询。 - 观察:获取到销售数据。
- 思考:现在我需要根据这些数据生成销售报表。
- 行动:调用文档工具生成销售报表。
- 观察:报表生成成功。
- 思考:任务完成。
最终回答:已为你查询到上个月的销售数据并生成了销售报表。报表显示上个月总销售额为120万元,同比增长15%。
十、企业级优化
1. 安全控制增强
- 操作分级:将操作分为普通操作、敏感操作和危险操作,不同级别需要不同的确认机制
- 权限控制:根据用户的角色限制可以调用的工具和可以访问的数据
- 内容审核:对所有输入和输出进行内容审核,防止敏感信息泄露
- 沙箱执行:在沙箱环境中执行所有外部操作,隔离风险
2. 可观测性
- 步骤追踪:记录Agent的每一步思考、行动和观察
- 性能监控:监控Agent的响应时间、工具调用次数和成功率
- 错误告警:当Agent失败次数超过阈值时,发送告警通知
- 用户反馈:收集用户对Agent回答的反馈,持续优化
3. 性能优化
- 工具调用缓存:缓存相同参数的工具调用结果
- 并行执行:对于独立的子任务,并行调用多个工具
- 模型缓存:缓存大模型的响应结果
- 异步处理:对于耗时较长的任务,异步执行并通知用户结果
十一、常见坑与解决方案
1. ❌ Agent过度依赖工具
问题 :Agent遇到任何问题都调用工具,即使可以直接回答
解决方案:在系统提示词中明确告诉Agent"如果可以直接回答的问题,不要调用工具"
2. ❌ Agent忘记用户的要求
问题 :Agent在执行过程中忘记了用户的部分要求
解决方案:
- 在系统提示词中强调"严格按照用户的要求执行任务"
- 在每个步骤开始前,回顾用户的原始需求
- 定期向用户确认任务进展和要求
3. ❌ 工具调用参数错误
问题 :Agent调用工具时参数格式不正确
解决方案:
- 为工具添加详细的参数描述和示例
- 在工具内部添加严格的参数验证
- 当参数错误时,返回清晰的错误信息,让Agent可以调整参数重试
4. ❌ 复杂任务规划失败
问题 :对于非常复杂的任务,Agent无法制定正确的执行计划
解决方案:
- 将复杂任务分解为多个简单任务,由用户逐个确认
- 使用更强大的推理模型(如DeepSeek-R1-14B)
- 提供任务分解的示例,引导Agent正确分解任务
十二、本章总结与下章预告
本章总结
- 智能办公是AI Agent落地最成熟的场景,能够直接产生商业价值
- 我们设计并实现了一个具备邮件管理、文档处理、数据查询等6大核心能力的智能办公Agent
- 使用MCP协议实现了标准化的工具集,确保可复用和可扩展
- 设计了专业的系统提示词,精准控制Agent的行为
- 实现了个性化记忆系统和上下文管理,提供个性化服务
- 添加了安全控制、可观测性和性能优化,确保系统可以在生产环境运行
预告式提及:我们现在已经完成了一个功能完善的智能办公Agent。但要将它部署到生产环境,我们还需要解决可观测性、安全合规和性能优化等问题。下一章我们将学习Spring AI应用的可观测性,如何监控和调试AI应用。
下章预告
下一章我们将学习Spring AI应用的可观测性。你将学会:
- 日志配置与链路追踪
- 模型调用监控:耗时、token消耗、成功率
- 向量数据库监控与性能调优
- 用户行为分析与反馈收集
- 告警机制与故障排查
十三、课后练习
- 为智能办公Agent添加日历管理工具,支持安排会议和提醒待办事项
- 实现会议纪要生成功能,让Agent能够根据会议录音生成会议纪要
- 添加用户偏好设置功能,让用户可以自定义邮件签名、报告格式等
- 实现操作确认机制,对于发送邮件、删除文件等危险操作,要求用户确认
- 部署你的智能办公Agent,让你的同事也能使用它来提高工作效率