CLI + MCP + Skill:2026年AI Agent开发的三大范式详解与实战

发布时间:2026/7/17 17:57:51
CLI + MCP + Skill:2026年AI Agent开发的三大范式详解与实战 引言AI Agent开发范式的演进2026年AI Agent的开发已从早期的单一模型调用演进为模块化、标准化和工具化的系统工程。在这一演进过程中三种核心范式脱颖而出共同构成了现代AI Agent开发的基石CLI命令行界面作为人机交互与自动化执行的基础入口。MCP模型上下文协议作为连接AI模型与外部工具/数据的标准化通信层。Skill技能作为封装可复用业务逻辑与工具调用的功能单元。本文将深入剖析这三大范式阐明其各自角色、交互关系并通过一个完整的“智能数据分析助手”Agent实战项目展示如何将它们有机结合构建强大、可维护的AI应用。范式一CLI - 统一的控制面与执行入口CLI是开发者、用户乃至其他系统与AI Agent交互的首要界面。它超越了传统命令执行成为Agent的“总控台”。核心价值标准化入口为Agent的所有功能对话、任务执行、技能调用提供一致的启动和配置方式。自动化集成易于嵌入CI/CD流水线、cron作业或其他自动化脚本。环境与配置管理集中处理环境变量、认证信息、模型选择等配置。实战构建一个Agent CLI骨架我们使用argparse(Python标准库) 或typer(更现代) 来创建CLI。以下使用typer为例# 首先安装依赖pipinstalltyper rich# agent_cli.pyimporttyperfromtypingimportOptionalimportjsonfromrich.consoleimportConsolefromrich.tableimportTablefromrichimportprintasrprint apptyper.Typer(help 智能数据分析助手 CLI)consoleConsole()# 模拟的Agent核心和技能库agent_core{status:ready}skills_registry[data_fetcher,chart_generator,report_writer]app.command()defstart(task:strtyper.Argument(...,help启动Agent执行的具体任务描述),model:strtyper.Option(gpt-4,--model,-m,help选择使用的AI模型),verbose:booltyper.Option(False,--verbose,-v,help显示详细日志)): 启动AI Agent执行一项任务。 rprint(f[bold green] 启动Agent...[/bold green])rprint(f 任务:{task})rprint(f 模型:{model})rprint(f 详细模式:{verbose})# 此处会触发后续的MCP调用和Skill执行# 例如process_task_via_mcp(task, model)rprint([bold green]✅ 任务已接收并进入处理队列。[/bold green])app.command()deflist_skills():列出当前Agent已注册的所有技能。tableTable(title️ 已注册技能)table.add_column(技能名称,stylecyan)table.add_column(描述,stylemagenta)table.add_column(状态,stylegreen)# 模拟从技能库获取信息forskillinskills_registry:table.add_row(skill,f执行与{skill}相关的操作,✅ 可用)console.print(table)app.command()defstatus():查看Agent核心状态。rprint(json.dumps(agent_core,indent2))if__name____main__:app()使用这个CLI# 查看帮助python agent_cli.py--help# 启动一个任务python agent_cli.py start分析本月销售数据并生成趋势图--modelclaude-3-5-sonnet# 列出技能python agent_cli.py list-skills# 查看状态python agent_cli.py statusCLI范式要点CLI不包含核心业务逻辑它只是一个调度器和配置器其命令最终会转化为对MCP层的调用。范式二MCP - 模型上下文的标准化协议MCP (Model Context Protocol) 是一种开放协议用于在AI模型如ChatGPT、Claude与工具Tools、数据源Data Sources之间建立标准化、声明式的连接。它解决了模型如何安全、可控地访问外部能力的问题。核心概念Server服务器提供工具或数据访问能力的后端服务。一个Agent可以连接多个MCP Server。Tools工具Server暴露的可调用函数模型可以决定在何时、传入何种参数来调用它们。Resources资源Server提供的可读数据源如数据库表、文件列表。Prompts提示词可复用的提示词模板。实战为Agent实现一个MCP Server数据获取工具假设我们有一个“数据获取”MCP Server它向AI模型暴露一个query_sales_data工具。# mcp_data_server.pyimportasynciofrommcpimportClientSession,StdioServerParametersfrommcp.serverimportServerfrommcp.server.modelsimportToolimportpandasaspdfromdatetimeimportdatetime,timedeltaimportjson# 创建MCP Server实例serverServer(sales-data-server)# 1. 声明Server提供的工具server.list_tools()asyncdefhandle_list_tools()-list[Tool]:return[Tool(namequery_sales_data,description查询指定日期范围内的销售数据。,inputSchema{type:object,properties:{start_date:{type:string,description:开始日期 (YYYY-MM-DD)},end_date:{type:string,description:结束日期 (YYYY-MM-DD)},product_category:{type:string,description:产品类别可选,default:all}},required:[start_date,end_date]})]# 2. 实现工具的执行逻辑server.call_tool()asyncdefhandle_call_tool(name:str,arguments:dict)-dict:ifnamequery_sales_data:returnawaitexecute_query_sales_data(**arguments)raiseValueError(f未知工具:{name})asyncdefexecute_query_sales_data(start_date:str,end_date:str,product_category:strall)-dict:模拟查询销售数据。# 在实际应用中这里会连接数据库# 此处返回模拟数据datespd.date_range(start_date,end_date)data[]fordateindates:forcategoryin[电子产品,家居用品,图书]:ifproduct_category!allandcategory!product_category:continuerevenue1000(hash(f{date}{category})%500)# 模拟收入data.append({date:date.strftime(%Y-%m-%d),category:category,revenue:revenue})dfpd.DataFrame(data)summarydf.groupby(category)[revenue].sum().to_dict()return{status:success,message:f查询到{len(df)}条记录。,data_preview:df.head().to_dict(records),# 预览前5条summary:summary,metadata:{query_params:{start_date:start_date,end_date:end_date,product_category:product_category}}}# 3. 运行Server通常通过stdio与模型客户端通信asyncdefmain():asyncwithserver.run_stdio_server()as(read_stream,write_stream):# 这里Server会持续运行等待模型客户端的指令awaitasyncio.Future()# 永久运行if__name____main__:asyncio.run(main())MCP范式要点MCP Server是能力的提供者它通过标准协议告诉模型“我能做什么”list_tools并在模型请求时“执行具体操作”call_tool。Agent的核心或模型作为MCP Client会动态发现并调用这些工具。范式三Skill - 模块化与可复用的功能单元Skill是对一个或多个相关工具调用、决策逻辑和提示词工程的高层封装。它代表Agent能完成的一个完整“任务”或“能力”。核心特征声明式定义描述Skill的输入、输出、所需工具和前置条件。可组合性简单的Skill可以组合成复杂的Skill例如“获取数据” “生成图表” “生成数据报告”。独立可测试每个Skill都可以在脱离主Agent的情况下进行单元测试。实战定义并实现一个“生成销售图表”Skill# skills/chart_generator_skill.pyfromtypingimportTypedDict,Optionalimportplotly.graph_objectsasgoimportplotly.ioaspioimportjsonimportosclassChartInput(TypedDict):生成图表Skill的输入参数。data:list# 数据列表通常来自query_sales_data工具的结果chart_type:str# 图表类型如 line, bar, pietitle:stroutput_format:str# html, png, jsonclassChartOutput(TypedDict):生成图表Skill的输出结果。status:strchart_path:Optional[str]# 生成的图表文件路径chart_html:Optional[str]# 如果是HTML格式直接返回内容error_message:Optional[str]classChartGeneratorSkill:技能根据数据生成可视化图表。namegenerate_sales_chartdescription将销售数据转换为可视化图表。required_tools[query_sales_data]# 此技能依赖的工具classmethoddefexecute(cls,input_params:ChartInput,context:dict)-ChartOutput: 执行技能。 :param input_params: 技能输入参数。 :param context: 执行上下文包含可用的工具调用函数等。 :return: 技能执行结果。 try:datainput_params[data]chart_typeinput_params[chart_type]titleinput_params[title]# 1. 数据转换 (根据实际数据结构调整)# 假设data是 query_sales_data 返回的 data_preview 格式df_datapd.DataFrame(data)ifdf_data.empty:return{status:error,error_message:输入数据为空。}# 2. 根据图表类型创建Plotly图形figNoneifchart_typeline:figgo.Figure()forcategoryindf_data[category].unique():cat_datadf_data[df_data[category]category]fig.add_trace(go.Scatter(xcat_data[date],ycat_data[revenue],modelinesmarkers,namecategory))fig.update_layout(titletitle,xaxis_title日期,yaxis_title销售额)elifchart_typebar:# 按类别聚合summarydf_data.groupby(category)[revenue].sum().reset_index()figgo.Figure([go.Bar(xsummary[category],ysummary[revenue])])fig.update_layout(titletitle,xaxis_title产品类别,yaxis_title总销售额)else:return{status:error,error_message:f不支持的图表类型:{chart_type}}# 3. 输出处理output_formatinput_params.get(output_format,html)output_diroutput/chartsos.makedirs(output_dir,exist_okTrue)timestampdatetime.now().strftime(%Y%m%d_%H%M%S)filenamefsales_chart_{timestamp}ifoutput_formathtml:html_pathos.path.join(output_dir,f{filename}.html)fig.write_html(html_path)withopen(html_path,r,encodingutf-8)asf:html_contentf.read()return{status:success,chart_path:html_path,chart_html:html_content}elifoutput_formatpng:img_pathos.path.join(output_dir,f{filename}.png)fig.write_image(img_path)return{status:success,chart_path:img_path}else:return{status:error,error_message:f不支持的输出格式:{output_format}}exceptExceptionase:return{status:error,error_message:f生成图表时出错:{str(e)}}# 技能的使用示例if__name____main__:# 模拟从MCP工具调用获取的数据mock_data[{date:2026-07-01,category:电子产品,revenue:1200},{date:2026-07-01,category:家居用品,revenue:800},{date:2026-07-02,category:电子产品,revenue:1500},{date:2026-07-02,category:家居用品,revenue:950},]skill_input:ChartInput{data:mock_data,chart_type:line,title:近两日销售趋势,output_format:html}skillChartGeneratorSkill()resultskill.execute(skill_input,context{})print(json.dumps(result,indent2,ensure_asciiFalse))Skill范式要点Skill是业务的封装。它知道完成一个特定任务需要调用哪些工具通过MCP如何处理这些工具的返回结果以及如何将结果转化为最终输出。Skill使Agent的能力变得可插拔、可管理。综合实战构建“智能数据分析助手”Agent现在我们将三大范式串联起来构建一个完整的Agent。项目结构smart_data_agent/ ├── agent_cli.py # CLI入口 (范式一) ├── mcp_servers/ # MCP Server集合 (范式二) │ ├── data_server.py # 数据查询Server │ └── chart_server.py # 图表生成Server (可独立也可作为Skill内部调用) ├── skills/ # Skill集合 (范式三) │ ├── chart_generator_skill.py │ └── report_skill.py # (可扩展)组合数据获取和图表生成的报告Skill ├── agent_core.py # Agent核心协调CLI、MCP Client和Skill └── requirements.txtAgent核心协调逻辑 (agent_core.py简化版)# agent_core.pyimportasynciofromtypingimportList,Dict,AnyfrommcpimportClientSession,StdioServerParametersimportimportlibimportsysimportosclassSmartDataAgent:def__init__(self):self.mcp_clients:Dict[str,ClientSession]{}self.skills_registry:Dict[str,Any]{}self.load_skills()defload_skills(self):动态加载skills目录下的所有技能。skills_dirskillsforfilenameinos.listdir(skills_dir):iffilename.endswith(_skill.py):module_namefskills.{filename[:-3]}specimportlib.util.spec_from_file_location(module_name,os.path.join(skills_dir,filename))moduleimportlib.util.module_from_spec(spec)sys.modules[module_name]module spec.loader.exec_module(module)# 假设每个skill模块都有一个SkillClass类forattr_nameindir(module):attrgetattr(module,attr_name)ifhasattr(attr,name)andhasattr(attr,execute):self.skills_registry[attr.name]attrprint(f✅ 已加载技能:{attr.name})asyncdefconnect_to_mcp_server(self,server_command:List[str]):连接到一个MCP Server。paramsStdioServerParameters(commandserver_command[0],argsserver_command[1:])sessionClientSession(params)awaitsession.__aenter__()# 简化连接# 初始化会话获取Server提供的工具列表awaitsession.initialize()toolsawaitsession.list_tools()server_nameserver_command[0]self.mcp_clients[server_name]sessionprint(f 已连接MCP Server:{server_name}, 可用工具:{[t.namefortintools.tools]})returnsessionasyncdefexecute_skill(self,skill_name:str,skill_input:Dict,context:Dict)-Dict:执行一个指定的技能。ifskill_namenotinself.skills_registry:return{status:error,message:f技能 {skill_name} 未找到。}skill_classself.skills_registry[skill_name]# 技能执行可能需要调用MCP工具这里需要将MCP client传递给技能上下文context[mcp_clients]self.mcp_clients resultskill_class.execute(skill_input,context)returnresultasyncdefprocess_task(self,task_description:st