AI 开发基础第5篇Skills 与 MCP - Agent 的能力扩展适合读者已读完第4篇Reasoning想了解Agent能力模块化和标准化预计阅读时间30分钟前言Agent的技能包问题第3篇我们给Agent加了工具get_weather、search_poi。工具少的时候还好但如果Agent有20个工具你的代码会变成什么样# 20个工具的噩梦tools[tool_1,tool_2,...,tool_20]tool_map{tool_1:func_1,tool_2:func_2,...,tool_20:func_20}更麻烦的是不同项目要用不同的工具组合工具的API变了要改Agent代码团队里其他人写了新工具你想复用但格式不兼容Skills和MCP就是为了解决这个问题。一、Skills可复用的能力单元1.1 什么是SkillSkill 一组相关工具 使用说明 配置不是单个工具而是一个能力包。比如Skill包含的工具说明天气Skillget_weather get_forecast get_weather_alert天气相关的一组能力地图Skillsearch_poi get_route get_geocode地图相关的一组能力文档Skillread_doc write_doc search_doc文档操作的一组能力1.2 Skill的标准结构weather-skill/ ├── SKILL.md # 技能说明Agent读取这个来了解技能 ├── tools/ │ ├── get_weather.py │ ├── get_forecast.py │ └── weather_alert.py └── config.json # 配置API Key、默认参数等SKILL.md 是核心。它告诉Agent这个Skill能做什么、怎么用# 天气技能 ## 描述 获取天气信息支持实时天气、天气预报、天气预警。 ## 工具列表 1. get_weather(city, date) - 获取实时天气 2. get_forecast(city, days) - 获取未来N天预报 3. weather_alert(city) - 获取天气预警 ## 使用场景 - 用户问天气时自动触发 - 行程规划时查询目的地天气 ## 注意事项 - forecast API免费版只支持7天 - 每分钟调用限制10次1.3 在Agent中加载Skillimportjsonimportimportlib.utilfrompathlibimportPathclassSkillLoader:技能加载器def__init__(self,skill_dirs:list[str]):self.tools[]self.tool_map{}forskill_dirinskill_dirs:self._load_skill(skill_dir)def_load_skill(self,skill_dir:str):加载一个Skill目录下的所有工具skill_pathPath(skill_dir)skill_mdskill_path/SKILL.mdconfig_pathskill_path/config.jsonifnotskill_md.exists():print(f⚠️ 跳过{skill_dir}没有SKILL.md)return# 读取配置config{}ifconfig_path.exists():configjson.loads(config_path.read_text())# 读取工具定义tools_dirskill_path/toolsiftools_dir.exists():fortool_fileinsorted(tools_dir.glob(*.py)):self._load_tool(tool_file,config)def_load_tool(self,tool_file:Path,config:dict):加载单个工具文件specimportlib.util.spec_from_file_location(tool_file.stem,tool_file)moduleimportlib.util.module_from_spec(spec)spec.loader.exec_module(module)# 从模块中提取工具信息ifhasattr(module,TOOL_DEF):self.tools.append(module.TOOL_DEF)ifhasattr(module,tool_func):self.tool_map[module.TOOL_DEF[function][name]]module.tool_funcprint(f ✅ 加载工具:{module.TOOL_DEF[function][name]})# 使用loaderSkillLoader([skills/weather,skills/map])agentrun_agent(messages,loader.tools,loader.tool_map)好处工具按Skill分组管理清晰新增Skill只需复制目录不改Agent代码不同项目可以组合不同的Skill二、MCP连接模型与外部世界的标准协议2.1 为什么需要MCP问题每个大模型厂商的Function Calling格式不一样。# OpenAI的格式{type:function,function:{name:...,parameters:{...}}}# Anthropic Claude的格式{name:...,input_schema:{...}}# DeepSeek的格式兼容OpenAI但有些差异# Google Gemini的格式又是另一种如果你写了一个工具想同时给GPT-4、Claude、DeepSeek用你得适配4种格式。**MCPModel Context Protocol**就是为了解决这个巴别塔问题。2.2 MCP是什么MCP是Anthropic在2024年底提出的开放标准协议类似USB接口USB统一了硬件接口→ 一个U盘插任何电脑都能用MCP统一了模型和工具的接口→ 一个工具接任何模型都能用核心概念概念说明MCP Server工具提供方如天气API、数据库、文件系统MCP Client模型/Agent如Claude Desktop、你的Agent代码MCP Protocol通信协议JSON-RPC over stdio/SSE2.3 MCP的工作原理┌──────────┐ MCP Protocol ┌──────────────┐ │ Agent │ ◄──────────────────► │ MCP Server │ │ (Client) │ JSON-RPC 2.0 │ (天气服务) │ └──────────┘ └──────────────┘ │ │ 同时连接多个Server ▼ ┌──────────────┐ │ MCP Server │ │ (文件系统) │ └──────────────┘通信流程1. Client → Server: 你有哪些工具tools/list 2. Server → Client: 我有 get_weather、get_forecast 3. Client → Server: 调用 get_weather(city北京)tools/call 4. Server → Client: 结果晴 18-30°C2.4 写一个MCP Server用Python FastMCP官方库# weather_mcp_server.pyfrommcp.server.fastmcpimportFastMCPimporthttpx mcpFastMCP(天气服务)mcp.tool()asyncdefget_weather(city:str,date:str今天)-str:获取城市天气信息 Args: city: 城市名称 date: 日期默认今天 # 真实项目中这里调外部APIweather_db{北京:{今天:晴 18-30°C,明天:多云 15-28°C},上海:{今天:阴 22-28°C,明天:小雨 20-25°C},}resultweather_db.get(city,{}).get(date,f{city}{date}暂无数据)returnf{city}{date}的天气{result}mcp.tool()asyncdefget_weather_alert(city:str)-str:获取天气预警信息 Args: city: 城市名称 # 模拟预警查询returnf{city}当前无天气预警if__name____main__:mcp.run(transportstdio)运行pipinstallmcp python weather_mcp_server.py就这么简单。任何支持MCP的Client都可以调用这两个工具不管是Claude Desktop、Cursor、还是你自己的Agent。2.5 在Agent中使用MCP ClientfrommcpimportClientSession,StdioServerParametersfrommcp.client.stdioimportstdio_clientasyncdefcreate_mcp_tool_map(server_script:str):从MCP Server获取工具列表server_paramsStdioServerParameters(commandpython,args[server_script],)asyncwithstdio_client(server_params)as(read,write):asyncwithClientSession(read,write)assession:awaitsession.initialize()# 获取工具列表tools_resultawaitsession.list_tools()tools[]tool_map{}fortoolintools_result.tools:# 转换为OpenAI格式tools.append({type:function,function:{name:tool.name,description:tool.description,parameters:tool.inputSchema,}})tool_map[tool.name]toolreturntools,session,tool_map# 调用工具时asyncdefcall_mcp_tool(session,tool_name:str,args:dict)-str:通过MCP调用工具resultawaitsession.call_tool(tool_name,argumentsargs)returnresult.content[0].text2.6 MCP vs 直接Function Calling对比项直接Function CallingMCP格式适配每个模型格式不同需适配统一协议一次开发处处用工具发现手动注册自动发现tools/list工具管理工具代码和Agent代码耦合独立进程解耦生态共享工具不能跨项目复用MCP Server可以被任何Client使用性能直接调用延迟低进程间通信略有延迟部署简单需要启动Server进程什么时候用MCP工具需要被多个Agent/模型复用 → MCP团队协作工具由不同人开发 → MCP简单个人项目一两个工具 → 直接Function Calling就够三、真实项目Skills MCP 的组合使用3.1 智能行程规划助手 v2第一版第3篇工具直接写在Agent代码里第二版用Skills组织 MCP标准化smart-trip-planner/ ├── agent/ │ ├── main.py # Agent主程序 │ └── skill_loader.py # Skill加载器 ├── skills/ │ ├── weather/ │ │ ├── SKILL.md │ │ ├── config.json │ │ ├── weather_server.py # MCP Server │ │ └── tools/ │ ├── map/ │ │ ├── SKILL.md │ │ ├── config.json │ │ └── map_server.py # MCP Server封装高德API │ ├── restaurant/ │ │ ├── SKILL.md │ │ └── restaurant_server.py │ └── calendar/ │ ├── SKILL.md │ └── calendar_server.py └── configs/ └── production.json # 生产环境配置好处新增能力加一个skill目录就行不改Agent代码团队协作张三负责天气Skill李四负责地图Skill互不干扰复用天气Skill可以直接给另一个项目用测试每个Skill独立测试3.2 动态加载SkillimportasynciofrompathlibimportPathclassSmartAgent:支持动态加载Skill的Agentdef__init__(self):self.tools[]self.sessions{}asyncdefload_skill(self,skill_dir:str):加载一个Skill通过MCP连接skill_pathPath(skill_dir)server_scriptskill_path/server.pyifnotserver_script.exists():print(f⚠️{skill_dir}没有server.py跳过)returntools,session,tool_mapawaitcreate_mcp_tool_map(str(server_script))self.tools.extend(tools)self.sessions.update(tool_map)print(f✅ 加载Skill:{skill_path.name}{len(tools)}个工具)asyncdefrun(self,user_input:str):运行Agentifnotself.tools:print(⚠️ 没有加载任何Skill)return# 使用加载的所有工具运行Agent Loopmessages[{role:system,content:你是一个智能助手。},{role:user,content:user_input},]# ... Agent Loop同第3篇# 使用asyncdefmain():agentSmartAgent()awaitagent.load_skill(skills/weather)awaitagent.load_skill(skills/map)awaitagent.load_skill(skills/restaurant)awaitagent.run(北京明天天气怎么样帮我找附近的火锅店)asyncio.run(main())四、MCP生态现状4.1 主流工具对MCP的支持工具/平台MCP支持情况Claude Desktop原生支持官方推荐Cursor支持用于代码编辑Windsurf支持LangChain通过langchain-mcp-adapters支持OpenClaw原生支持自建Agent通过mcp Python SDK支持4.2 热门MCP ServerServer功能filesystem文件读写githubGitHub操作Issue、PR、代码postgres/sqlite数据库查询brave-search网络搜索slackSlack消息操作puppeteer浏览器自动化这些Server都是开源的直接pip install或npx就能用。五、本章总结你学到了什么Skills把相关工具打包成一个能力单元方便管理和复用MCP统一的工具调用协议一次开发处处用类似USB接口MCP Server用FastMCP几行代码就能写一个任何MCP Client都能调用Skills MCP结合Skill作为组织单位MCP作为通信协议两者互补动态加载Agent运行时按需加载Skill灵活组合关键公式Skill 工具组 说明文档 配置 MCP 统一的Client-Server通信协议 Skills MCP 模块化 标准化下一篇预告第6篇Memory - 让 Agent 拥有记忆你会学到短期记忆、长期记忆、RAG、对话管理参考资料MCP官方规范https://modelcontextprotocol.io/MCP Python SDKhttps://github.com/modelcontextprotocol/python-sdkAnthropic MCP公告https://www.anthropic.com/news/model-context-protocolFastMCP文档https://github.com/jlowin/fastmcp上一篇第4篇 Reasoning 与 Planning下一篇第6篇 Memory