最近在做一个项目时,我需要让AI智能体能够直接与本地数据库进行交互。经过一番研究,发现Model Context Protocol(MCP)是个非常优雅的解决方案。今天就跟大家分享一下如何构建一个完全本地化的MCP客户端,让AI智能体能够智能地操作SQLite数据库。
什么是MCP?为什么选择它? MCP(Model Context Protocol)是一个标准化协议,专门用于AI应用程序与外部工具和数据源的连接。想象一下,如果AI智能体是一个万能助手,那么MCP就是它的”工具箱接口”,让它能够标准化地使用各种外部工具。
技术栈选择 经过多次尝试,我选择了这样的技术栈:
LlamaIndex :构建MCP智能体的核心框架
Ollama :本地运行Deepseek-R1模型
LightningAI :开发和托管环境
SQLite :作为演示的数据存储
整体工作流程
整个系统的运行逻辑其实很简单:
用户提交查询
智能体连接MCP服务器,发现可用工具
根据查询内容,智能体选择合适的工具
获取上下文信息并返回智能响应
代码实现详解 构建SQLite MCP服务器 首先,我们需要一个简单的MCP服务器作为演示。这个服务器提供两个核心功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import sqlite3import jsonfrom typing import Any , Dict , List import asyncioclass SQLiteMCPServer : def __init__ (self, db_path: str = "demo.db" ): self .db_path = db_path self .init_database() def init_database (self ): """初始化数据库表""" conn = sqlite3.connect(self .db_path) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS players ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, sport TEXT NOT NULL, achievements TEXT ) ''' ) conn.commit() conn.close() def add_data (self, name: str , sport: str , achievements: str = "" ) -> Dict [str , Any ]: """添加数据到数据库""" try : conn = sqlite3.connect(self .db_path) cursor = conn.cursor() cursor.execute( "INSERT INTO players (name, sport, achievements) VALUES (?, ?, ?)" , (name, sport, achievements) ) conn.commit() row_id = cursor.lastrowid conn.close() return {"success" : True , "id" : row_id, "message" : f"成功添加 {name} " } except Exception as e: return {"success" : False , "error" : str (e)} def get_data (self, sport: str = None ) -> Dict [str , Any ]: """从数据库获取数据""" try : conn = sqlite3.connect(self .db_path) cursor = conn.cursor() if sport: cursor.execute("SELECT * FROM players WHERE sport = ?" , (sport,)) else : cursor.execute("SELECT * FROM players" ) rows = cursor.fetchall() columns = [description[0 ] for description in cursor.description] data = [] for row in rows: data.append(dict (zip (columns, row))) conn.close() return {"success" : True , "data" : data, "count" : len (data)} except Exception as e: return {"success" : False , "error" : str (e)} mcp_server = SQLiteMCPServer()
设置本地大语言模型 使用Ollama在本地运行Deepseek-R1模型:
1 2 3 4 5 6 7 8 9 10 11 12 from llama_index.llms.ollama import Ollamadef setup_local_llm (): """配置本地LLM""" llm = Ollama( model="deepseek-r1:latest" , base_url="http://localhost:11434" , temperature=0.1 , request_timeout=120.0 ) return llm local_llm = setup_local_llm()
定义智能体系统提示词 这一步很关键,好的提示词能让智能体更好地理解任务:
1 2 3 4 5 6 7 8 9 10 11 12 SYSTEM_PROMPT = """ 你是一个智能数据库助手。你拥有以下能力: 1. 向数据库添加运动员信息 2. 从数据库查询运动员数据 重要规则: - 在回答用户问题之前,先使用相应的工具获取或操作数据 - 如果用户想要添加数据,使用 add_data 工具 - 如果用户想要查看数据,使用 get_data 工具 - 始终以友好、专业的语调回应 - 将结果以清晰、易读的格式呈现给用户 请根据用户的请求,选择合适的工具并提供有用的响应。 """
创建MCP工具包装器 将MCP服务器的功能包装成LlamaIndex可以使用的工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from llama_index.core.tools import FunctionToolfrom typing import Optional def create_mcp_tools (server: SQLiteMCPServer ) -> List [FunctionTool]: """创建MCP工具列表""" def add_player_data (name: str , sport: str , achievements: str = "" ) -> str : """ 添加运动员数据到数据库 Args: name (str): 运动员姓名 sport (str): 运动项目 achievements (str): 主要成就,可选 Returns: str: 操作结果 """ result = server.add_data(name, sport, achievements) if result["success" ]: return f"✅ {result['message' ]} " else : return f"❌ 添加失败: {result['error' ]} " def get_player_data (sport: Optional [str ] = None ) -> str : """ 从数据库获取运动员数据 Args: sport (str, optional): 运动项目筛选,不提供则获取所有数据 Returns: str: 查询结果 """ result = server.get_data(sport) if result["success" ]: if result["count" ] == 0 : return "📭 数据库中暂无符合条件的运动员数据" data_str = f"📊 找到 {result['count' ]} 条记录:nn" for player in result["data" ]: data_str += f"🏆 {player['name' ]} n" data_str += f" 项目: {player['sport' ]} n" if player['achievements' ]: data_str += f" 成就: {player['achievements' ]} n" data_str += "n" return data_str else : return f"❌ 查询失败: {result['error' ]} " tools = [ FunctionTool.from_defaults( fn=add_player_data, name="add_data" , description="向数据库添加运动员信息" ), FunctionTool.from_defaults( fn=get_player_data, name="get_data" , description="从数据库查询运动员信息" ) ] return tools
构建MCP智能体 现在我们把所有组件整合起来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 from llama_index.core.agent import FunctionCallingAgentfrom llama_index.core.memory import ChatMemoryBufferclass MCPAgent : def __init__ (self, llm, tools, system_prompt: str ): self .llm = llm self .tools = tools self .memory = ChatMemoryBuffer.from_defaults(token_limit=4000 ) self .agent = FunctionCallingAgent.from_tools( tools=tools, llm=llm, system_prompt=system_prompt, memory=self .memory, verbose=True ) def chat (self, message: str ) -> str : """与智能体对话""" try : response = self .agent.chat(message) return str (response) except Exception as e: return f"抱歉,处理您的请求时出现错误:{str (e)} " def reset_memory (self ): """重置对话记忆""" self .memory.reset() def create_mcp_agent (mcp_server: SQLiteMCPServer ) -> MCPAgent: """创建MCP智能体""" llm = setup_local_llm() tools = create_mcp_tools(mcp_server) agent = MCPAgent( llm=llm, tools=tools, system_prompt=SYSTEM_PROMPT ) return agent
完整的运行示例 让我们把所有代码整合起来,创建一个完整的演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 def main (): """主函数:演示MCP客户端的完整功能""" print ("🚀 正在初始化本地MCP客户端..." ) mcp_server = SQLiteMCPServer() print ("✅ SQLite MCP服务器已启动" ) agent = create_mcp_agent(mcp_server) print ("✅ MCP智能体已就绪" ) print ("n" + "=" *50 ) print ("🤖 MCP智能体已启动!您可以尝试以下操作:" ) print ("- 添加运动员信息:'添加拉斐尔·纳达尔,网球运动员,22个大满贯冠军'" ) print ("- 查看所有数据:'显示所有运动员信息'" ) print ("- 输入 'quit' 退出" ) print ("=" *50 ) while True : try : user_input = input ("n👤 您: " ).strip() if user_input.lower() in ['quit' , 'exit' , '退出' ]: print ("👋 再见!" ) break if not user_input: continue print ("🤖 智能体思考中..." ) response = agent.chat(user_input) print (f"🤖 智能体: {response} " ) except KeyboardInterrupt: print ("n👋 程序已退出" ) break except Exception as e: print (f"❌ 发生错误: {str (e)} " ) if __name__ == "__main__" : main()
运行效果展示 当你运行这个程序时,你会看到类似这样的交互:
1 2 3 4 5 6 7 👤 您: 添加拉斐尔·纳达尔,网球运动员,22个大满贯冠军 🤖 智能体: ✅ 成功添加 拉斐尔·纳达尔 👤 您: 显示所有运动员信息 🤖 智能体: 📊 找到 1 条记录: 🏆 拉斐尔·纳达尔 项目: 网球 成就: 22个大满贯冠军
实际应用场景 这个MCP客户端的应用场景非常广泛:
数据管理助手 :让AI帮助管理各种结构化数据
智能客服系统 :结合知识库进行智能问答
业务流程自动化 :让AI执行复杂的数据操作任务
开发工具集成 :在开发环境中提供智能化的数据操作
扩展可能性 基于这个基础架构,你可以轻松扩展更多功能:
总结 通过这个完全本地化的MCP客户端,我们实现了AI智能体与数据库的无缝对话。整个系统不依赖任何外部API,保证了数据的安全性和隐私性。最重要的是,这种架构非常灵活,你可以根据自己的需求轻松修改和扩展。无论是简单的数据管理,还是复杂的业务流程自动化,都能够很好地适应。如果你也在探索AI智能体的实际应用,不妨试试这个方案。相信它会给你带来不少启发!