AI Agent详解:RAG与MCP的区别与联合实现智能体

一、什么是AI Agent?

AI Agent(智能体)是一个能够感知环境、做出决策并执行行动的自主系统。在AI领域,Agent通常指能够:

  • 感知:理解用户输入和环境状态
  • 推理:分析问题并制定解决方案
  • 行动:调用工具和服务执行任务
  • 学习:从交互中改进性能

AI Agent的核心组件

  1. LLM(大语言模型):提供推理和决策能力
  2. 工具集(Tools):可执行的操作集合
  3. 记忆系统(Memory):存储对话历史和知识
  4. 规划器(Planner):制定执行计划
  5. 执行器(Executor):执行具体操作

二、RAG与MCP的区别

1. RAG(检索增强生成)

核心功能

  • 从知识库中检索相关信息
  • 将检索到的信息作为上下文增强生成
  • 主要用于知识问答和信息检索

特点

  • ✅ 静态知识库查询
  • ✅ 基于文档的问答
  • ✅ 可追溯的信息来源
  • ❌ 无法执行操作
  • ❌ 无法调用外部服务

适用场景

  • 文档问答系统
  • 知识库查询
  • 内容生成(基于已有文档)

2. MCP(模型上下文协议)

核心功能

  • 提供标准化的工具调用接口
  • 连接外部系统和数据源
  • 执行具体的操作和任务

特点

  • ✅ 动态工具调用
  • ✅ 外部系统集成
  • ✅ 实时数据获取
  • ✅ 可执行操作
  • ❌ 不提供知识检索

适用场景

  • 数据库操作
  • API调用
  • 文件系统操作
  • 业务系统集成

3. 对比总结

特性 RAG MCP
知识检索
工具调用
静态知识
动态操作
信息生成
系统集成

三、为什么需要联合使用?

RAG和MCP各有优势,联合使用可以构建更强大的AI Agent:

  1. 知识 + 行动:RAG提供知识,MCP执行操作
  2. 静态 + 动态:RAG处理历史知识,MCP处理实时数据
  3. 查询 + 执行:RAG回答"是什么",MCP执行"做什么"

四、联合实现AI Agent

1. 架构设计

用户输入
    ↓
Agent控制器
    ↓
┌─────────────────┐
│  规划器(Planner) │  ← 使用LLM分析任务
└─────────────────┘
    ↓
┌─────────────────┐
│  工具选择器      │
└─────────────────┘
    ↓
    ├──→ RAG工具(知识检索)
    │       ↓
    │    向量数据库
    │
    └──→ MCP工具(操作执行)
            ↓
        外部系统
    ↓
结果整合
    ↓
用户输出

2. 添加依赖

<dependencies>
    <!-- Spring AI Core -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-core</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- Spring AI OpenAI -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- Spring AI MCP -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-mcp</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- Spring AI Vector Store -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-pgvector-store</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

3. 定义工具接口

package com.example.agent.tools;

import org.springframework.ai.chat.model.ToolCall;

public interface AgentTool {
    /**
     * 工具名称
     */
    String getName();
    
    /**
     * 工具描述
     */
    String getDescription();
    
    /**
     * 执行工具
     */
    String execute(ToolCall toolCall);
}

4. 实现RAG工具

package com.example.agent.tools;

import org.springframework.ai.chat.model.ToolCall;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

@Component
public class RAGTool implements AgentTool {
    
    @Autowired
    private VectorStore vectorStore;
    
    @Override
    public String getName() {
        return "rag_search";
    }
    
    @Override
    public String getDescription() {
        return "从知识库中检索相关信息。输入:查询问题。输出:相关文档内容。";
    }
    
    @Override
    public String execute(ToolCall toolCall) {
        String query = toolCall.getArguments().get("query").toString();
        int topK = Integer.parseInt(toolCall.getArguments().getOrDefault("top_k", "5").toString());
        
        // 检索相关文档
        List<Document> docs = vectorStore.similaritySearch(query, topK);
        
        if (docs.isEmpty()) {
            return "未找到相关信息";
        }
        
        // 格式化返回结果
        return docs.stream()
            .map(doc -> String.format(
                "来源:%s\n内容:%s",
                doc.getMetadata().get("source"),
                doc.getContent()
            ))
            .collect(Collectors.joining("\n\n---\n\n"));
    }
}

5. 实现MCP工具

package com.example.agent.tools;

import org.springframework.ai.chat.model.ToolCall;
import org.springframework.ai.mcp.McpClient;
import org.springframework.ai.mcp.McpRequest;
import org.springframework.ai.mcp.McpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DatabaseMcpTool implements AgentTool {
    
    @Autowired
    private McpClient mcpClient;
    
    @Override
    public String getName() {
        return "database_query";
    }
    
    @Override
    public String getDescription() {
        return "查询数据库信息。输入:SQL查询语句或自然语言查询。输出:查询结果。";
    }
    
    @Override
    public String execute(ToolCall toolCall) {
        String query = toolCall.getArguments().get("query").toString();
        
        McpRequest request = McpRequest.builder()
            .tool("query_database")
            .parameter("query", query)
            .build();
        
        McpResponse response = mcpClient.send(request);
        return response.getContent();
    }
}

6. 实现Agent核心服务

package com.example.agent.service;

import com.example.agent.tools.AgentTool;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ToolCall;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class AgentService {
    
    @Autowired
    private ChatClient chatClient;
    
    @Autowired
    private List<AgentTool> tools;
    
    /**
     * Agent主处理流程
     */
    public AgentResponse process(AgentRequest request) {
        String userInput = request.getInput();
        List<String> conversationHistory = request.getHistory();
        
        // 1. 构建系统提示
        String systemPrompt = buildSystemPrompt();
        
        // 2. 构建对话历史
        List<Object> messages = new ArrayList<>();
        messages.add(new SystemMessage(systemPrompt));
        
        // 添加历史对话
        for (int i = 0; i < conversationHistory.size(); i += 2) {
            if (i + 1 < conversationHistory.size()) {
                messages.add(new UserMessage(conversationHistory.get(i)));
                messages.add(new AssistantMessage(conversationHistory.get(i + 1)));
            }
        }
        
        // 添加当前用户输入
        messages.add(new UserMessage(userInput));
        
        // 3. 调用LLM(支持工具调用)
        Prompt prompt = new Prompt(messages);
        AssistantMessage response = chatClient.call(prompt).getResult().getOutput();
        
        // 4. 处理工具调用
        List<ToolCall> toolCalls = response.getToolCalls();
        if (toolCalls != null && !toolCalls.isEmpty()) {
            return handleToolCalls(toolCalls, userInput, conversationHistory);
        }
        
        // 5. 返回最终结果
        return AgentResponse.builder()
            .output(response.getContent())
            .toolsUsed(Collections.emptyList())
            .build();
    }
    
    /**
     * 构建系统提示
     */
    private String buildSystemPrompt() {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一个智能助手,可以使用以下工具:\n\n");
        
        for (AgentTool tool : tools) {
            prompt.append(String.format(
                "- %s: %s\n",
                tool.getName(),
                tool.getDescription()
            ));
        }
        
        prompt.append("\n根据用户的问题,选择合适的工具来获取信息或执行操作。");
        prompt.append("如果需要查询知识库,使用rag_search工具。");
        prompt.append("如果需要查询数据库,使用database_query工具。");
        prompt.append("可以组合使用多个工具来完成任务。");
        
        return prompt.toString();
    }
    
    /**
     * 处理工具调用
     */
    private AgentResponse handleToolCalls(List<ToolCall> toolCalls, 
                                         String userInput,
                                         List<String> history) {
        List<String> toolsUsed = new ArrayList<>();
        List<String> toolResults = new ArrayList<>();
        
        // 执行所有工具调用
        for (ToolCall toolCall : toolCalls) {
            String toolName = toolCall.getName();
            AgentTool tool = findTool(toolName);
            
            if (tool != null) {
                toolsUsed.add(toolName);
                String result = tool.execute(toolCall);
                toolResults.add(String.format("%s的结果:%s", toolName, result));
            }
        }
        
        // 将工具结果整合到提示中,再次调用LLM生成最终回答
        String combinedResults = String.join("\n\n", toolResults);
        String finalPrompt = String.format(
            "用户问题:%s\n\n工具执行结果:\n%s\n\n请基于工具执行结果回答用户问题。",
            userInput,
            combinedResults
        );
        
        Prompt prompt = new Prompt(new UserMessage(finalPrompt));
        AssistantMessage finalResponse = chatClient.call(prompt).getResult().getOutput();
        
        return AgentResponse.builder()
            .output(finalResponse.getContent())
            .toolsUsed(toolsUsed)
            .intermediateResults(toolResults)
            .build();
    }
    
    private AgentTool findTool(String name) {
        return tools.stream()
            .filter(tool -> tool.getName().equals(name))
            .findFirst()
            .orElse(null);
    }
}

7. 创建控制器

package com.example.agent.controller;

import com.example.agent.service.AgentService;
import com.example.agent.model.AgentRequest;
import com.example.agent.model.AgentResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/api/agent")
public class AgentController {
    
    @Autowired
    private AgentService agentService;
    
    @PostMapping("/chat")
    public AgentResponse chat(@RequestBody AgentRequest request) {
        return agentService.process(request);
    }
}

8. 数据模型

package com.example.agent.model;

import lombok.Builder;
import lombok.Data;

import java.util.List;

@Data
@Builder
public class AgentRequest {
    private String input;
    private List<String> history;
}

@Data
@Builder
public class AgentResponse {
    private String output;
    private List<String> toolsUsed;
    private List<String> intermediateResults;
}

五、智能体实现示例

示例场景:智能客服助手

输入

{
  "input": "用户ID为123的用户最近有什么订单?订单总金额是多少?",
  "history": []
}

处理流程

  1. 规划阶段

    • LLM分析:需要查询用户订单信息
    • 决定使用工具:database_query
  2. 执行阶段

    • 调用database_query工具
    • 执行SQL:SELECT * FROM orders WHERE user_id = 123 ORDER BY create_time DESC
    • 获取订单数据
  3. 整合阶段

    • LLM基于查询结果生成回答
    • 格式化输出

输出

{
  "output": "用户ID为123的用户最近有以下订单:\n1. 订单号:ORD-2024-001,金额:¥1,299.00,状态:已完成\n2. 订单号:ORD-2024-002,金额:¥599.00,状态:待发货\n订单总金额:¥1,898.00",
  "toolsUsed": ["database_query"],
  "intermediateResults": [
    "database_query的结果:订单列表数据..."
  ]
}

更复杂的示例:知识查询 + 数据操作

输入

{
  "input": "根据公司政策文档,新用户的优惠额度是多少?然后帮我查询用户ID为456的账户余额。",
  "history": []
}

处理流程

  1. 规划阶段

    • 需要查询政策文档(使用RAG)
    • 需要查询用户账户(使用MCP)
  2. 执行阶段

    • 调用rag_search工具:查询"新用户优惠额度"
    • 调用database_query工具:查询用户账户余额
  3. 整合阶段

    • LLM整合两个工具的结果
    • 生成完整回答

输出

{
  "output": "根据公司政策文档,新用户的优惠额度是¥100。\n\n用户ID为456的账户当前余额为¥1,250.00。",
  "toolsUsed": ["rag_search", "database_query"],
  "intermediateResults": [
    "rag_search的结果:政策文档相关内容...",
    "database_query的结果:账户余额数据..."
  ]
}

六、Agent工作流程总结

输入:用户问题
    ↓
1. 任务分析(LLM)
    ↓
2. 工具选择(LLM + 工具描述)
    ↓
3. 工具执行
    ├─→ RAG工具:检索知识库
    └─→ MCP工具:调用外部系统
    ↓
4. 结果整合(LLM)
    ↓
输出:最终回答 + 使用的工具 + 中间结果

七、最佳实践

1. 工具设计

  • 单一职责:每个工具只做一件事
  • 清晰描述:工具描述要准确,帮助LLM正确选择
  • 错误处理:工具执行要有完善的错误处理

2. 提示工程

  • 明确指令:清楚说明何时使用哪个工具
  • 格式规范:统一工具输入输出格式
  • 上下文管理:合理管理对话历史

3. 性能优化

  • 并行执行:多个独立工具可以并行执行
  • 缓存机制:对频繁查询的结果进行缓存
  • 超时控制:设置工具执行超时时间

八、总结

通过联合使用RAG和MCP,我们可以构建强大的AI Agent:

  • RAG:提供知识检索能力,回答"是什么"
  • MCP:提供工具调用能力,执行"做什么"
  • Agent:整合两者,实现智能决策和执行

这种架构使得AI系统既能理解知识,又能执行操作,真正实现了智能体的自主能力。

参考资料

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐