CLI + MCP + Skill:2026年AI Agent开发的三大范式
1. 引言:从单点工具到智能体协作
2026年的AI Agent开发已经不再是简单的提示词工程,而是演变为一套围绕执行环境、上下文协议、能力封装的系统工程。开发者不再只关心模型能“说什么”,更关心Agent能“做什么”。在这一背景下,CLI(命令行接口)、MCP(模型上下文协议)、Skill(技能封装)构成了当前AI Agent开发的三大核心范式,分别解决了执行、连接与复用三个层面的问题。
本文将从原理出发,结合可运行的代码实战,逐一拆解这三大范式,并给出一个将它们整合在一起的完整示例。
2. 范式一:CLI——Agent的执行底座
2.1 为什么CLI是Agent的天然接口
CLI是计算机最古老也最稳定的交互界面。对于AI Agent而言,CLI具备三个不可替代的优势:
- 确定性:命令的输入输出是结构化、可解析的,模型不需要理解图形界面。
- 可组合性:命令可以通过管道、脚本自由组合,形成复杂工作流。
- 低开销:相比GUI自动化,CLI的执行速度快、资源占用少,适合Agent高频调用。
在2026年的实践中,Agent调用CLI不再是通过Shell字符串拼接,而是通过结构化的命令定义与参数校验,让模型在受限的“动作空间”内安全地操作系统。
2.2 实战:构建一个可被Agent调用的CLI工具
下面我们使用Python的argparse和subprocess构建一个文件统计工具,它将被后续的Agent通过MCP调用。
# file_stats.py
import argparse
import os
import json
def count_lines(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
return sum(1 for _ in f)
def count_words(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
return len(f.read().split())
def main():
parser = argparse.ArgumentParser(description='统计文件的行数和词数')
parser.add_argument('filepath', type=str, help='目标文件路径')
parser.add_argument('--format', choices=['text', 'json'], default='text',
help='输出格式,默认为text')
args = parser.parse_args()
if not os.path.exists(args.filepath):
print(json.dumps({"error": "文件不存在"}), file=sys.stderr)
sys.exit(1)
result = {
"filepath": args.filepath,
"lines": count_lines(args.filepath),
"words": count_words(args.filepath)
}
if args.format == 'json':
print(json.dumps(result, ensure_ascii=False))
else:
print(f"文件: {result['filepath']}")
print(f"行数: {result['lines']}")
print(f"词数: {result['words']}")
if name == 'main':
main()
这个CLI工具的关键设计在于:支持JSON输出。Agent解析JSON远比解析人类可读文本可靠,这是CLI作为Agent执行底座的核心约定。
2.3 CLI范式的进阶:结构化命令注册
为了让Agent更安全地使用CLI,2026年的主流做法是引入命令白名单和参数Schema校验。下面是一个简单的命令注册表实现:
# command_registry.py
from dataclasses import dataclass, field
from typing import Callable, Dict, List
@dataclass
class CommandSpec:
name: str
description: str
parameters: Dict[str, str] # 参数名 -> 类型描述
handler: Callable
allowed: bool = True
class CommandRegistry:
def init(self):
self._commands: Dict[str, CommandSpec] = {}
def register(self, spec: CommandSpec):
self._commands[spec.name] = spec
def get_spec(self, name: str) -> CommandSpec | None:
return self._commands.get(name)
def list_commands(self) -> List[Dict]:
return [
{"name": c.name, "description": c.description, "parameters": c.parameters}
for c in self._commands.values() if c.allowed
]
注册上面的文件统计命令
registry = CommandRegistry()
registry.register(CommandSpec(
name="file_stats",
description="统计文件的行数和词数",
parameters={"filepath": "string", "format": "string"},
handler=main
))
通过这样的注册表,Agent的决策层可以只看到“允许执行”的命令集合,从机制上降低了误操作风险。
3. 范式二:MCP——Agent的上下文连接器
3.1 MCP解决了什么问题
MCP(Model Context Protocol)由Anthropic于2024年底提出,旨在统一AI应用与外部数据源、工具之间的连接方式。在2026年,MCP已经成为事实上的行业标准,其核心价值在于:
- 标准化:一套协议连接数据库、文件系统、API、浏览器等所有工具。
- 双向性:既允许模型调用工具(tool use),也允许外部系统向模型推送上下文(resource)。
- 安全性:通过权限声明和范围限定,控制模型能访问什么、能做什么。
3.2 MCP协议的核心概念
一个典型的MCP架构包含三个角色:
- MCP Host:运行Agent的进程,如Claude Desktop、自研Agent框架。
- MCP Client:Host内部与Server建立连接的组件。
- MCP Server:暴露工具、资源和提示词的独立服务,可以是本地进程,也可以是远程服务。
协议基于JSON-RPC 2.0,核心方法包括tools/list、tools/call、resources/list、resources/read等。
3.3 实战:用Python实现一个MCP Server
下面我们使用官方mcp Python SDK,把上一节的file_stats工具封装成MCP Server。
# mcp_file_server.py
import asyncio
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationOptions
import mcp.server.stdio
import mcp.types as types
import subprocess
import json
import os
server = Server("file-stats-server")
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
return [
types.Tool(
name="file_stats",
description="统计文件的行数和词数",
inputSchema={
"type": "object",
"properties": {
"filepath": {"type": "string", "description": "目标文件路径"},
"format": {"type": "string", "enum": ["text", "json"], "default": "json"}
},
"required": ["filepath"]
}
)
]
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name != "file_stats":
raise ValueError(f"未知工具: {name}")
filepath = arguments.get("filepath")
if not os.path.exists(filepath):
return [types.TextContent(type="text", text=json.dumps({"error": "文件不存在"}))]
调用上一节实现的CLI
result = subprocess.run(
["python", "file_stats.py", filepath, "--format", "json"],
capture_output=True, text=True, check=True
)
return [types.TextContent(type="text", text=result.stdout)]
async def main():
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream, write_stream,
InitializationOptions(
server_name="file-stats-server",
server_version="0.1.0"
)
)
if name == "main":
asyncio.run(main())
启动这个Server后,任何支持MCP的Host(如Claude Desktop、自研Agent)都可以通过配置一行地址来发现并调用file_stats工具,无需关心底层是Python还是Node.js。
3.4 MCP的三种传输方式
| 传输方式 | 适用场景 | 特点 |
|---|---|---|
| stdio | 本地子进程 | 零配置、安全隔离,适合单机Agent |
| SSE(Server-Sent Events) | 远程服务 | 单向推送,实现简单,适合只读场景 |
| Streamable HTTP | 远程服务 | 双向流式,支持工具调用和资源订阅,2025年后成为主流 |
4. 范式三:Skill——Agent的能力封装单元
4.1 从Prompt到Skill的演进
在早期Agent开发中,开发者把指令、示例和约束全部塞进System Prompt。这种方式在任务复杂后迅速失控:Prompt越来越长、互相冲突、难以维护。Skill范式将“完成某一类任务所需的一切”封装为一个独立单元,包括:
- 指令文本:告诉模型如何完成任务的步骤和规则。
- 示例:少样本示例,帮助模型理解输出格式。
- 依赖工具:该Skill需要调用的CLI或MCP工具列表。
- 资源引用:需要读取的参考文档、数据文件。
- 校验规则:输出必须满足的结构化约束。
4.2 Skill的目录结构
一个标准的Skill通常以目录形式存在,包含元数据文件和资源文件:
my_skill/
├── SKILL.md # 技能说明,含指令、示例、约束
├── requirements.txt # 依赖的Python包
├── scripts/ # 辅助脚本
│ └── validate.py # 输出校验脚本
└── assets/ # 参考文档、模板
└── template.md
4.3 实战:编写一个代码审查Skill
下面是一个用于代码审查的SKILL.md示例,它组合了CLI工具和MCP资源:
---
name: code-reviewer
description: 对指定代码文件进行静态审查,输出结构化问题清单
version: 1.0.0
tools:
- file_stats
- git_diff
resources:
- style_guide.md
---
代码审查技能
任务目标
审查指定代码文件,找出潜在bug、风格问题和安全隐患。
执行步骤
使用 file_stats 工具获取文件行数和词数,评估规模。
使用 git_diff 工具获取该文件的最近变更。
读取 style_guide.md 资源,了解项目编码规范。
逐行审查代码,按严重程度分类问题。
输出格式
必须输出JSON数组,每个元素包含:
severity: critical | warning | info
line: 行号
message: 问题描述
suggestion: 修改建议
示例
[
{"severity": "critical", "line": 42, "message": "SQL注入风险", "suggestion": "使用参数化查询"}
]
注意,这里的SKILL.md使用了YAML front-matter声明元数据,正文使用Markdown。在实际的Agent框架中,Skill会被解析为结构化的“子提示词”,在需要时动态注入主对话上下文,而不是常驻在System Prompt中。
4.4 Skill的动态加载机制
Skill的核心优势在于按需加载。Agent框架维护一个Skill索引,当用户请求涉及某类任务时,才把对应的SKILL.md注入上下文。下面是一个简化的Skill管理器:
# skill_manager.py
import os
import yaml
from pathlib import Path
class SkillManager:
def init(self, skills_dir: str):
self.skills_dir = Path(skills_dir)
self._index = self._build_index()
def _build_index(self):
index = {}
for skill_dir in self.skills_dir.iterdir():
skill_file = skill_dir / "SKILL.md"
if skill_file.exists():
with open(skill_file, 'r', encoding='utf-8') as f:
content = f.read()
# 解析front-matter
parts = content.split('---')
if len(parts) >= 3:
meta = yaml.safe_load(parts[1])
index[meta['name']] = {
"path": skill_dir,
"description": meta['description'],
"tools": meta.get('tools', []),
"content": '---'.join(parts[2:])
}
return index
def search(self, query: str) -> list[str]:
"""根据查询词匹配Skill名称和描述"""
results = []
for name, info in self._index.items():
if query in name or query in info['description']:
results.append(name)
return results
def load(self, name: str) -> str | None:
"""返回SKILL.md的正文内容"""
info = self._index.get(name)
return info['content'] if info else None
这个管理器实现了两个关键能力:语义搜索(根据用户请求找到相关Skill)和延迟加载(只在需要时读取完整内容)。
5. 三范式整合:一个完整的Agent实战
5.1 架构总览
下面我们把CLI、MCP、Skill三者整合到一个真实的Agent中。这个Agent的任务是:分析一个代码仓库的健康状况,并生成结构化报告。
flowchart TD
A[用户请求] --> B[Agent核心]
B -- 加载Skill --> C[Skill: repo-health]
B -- 调用MCP工具 --> D[MCP Server]
D -- 执行CLI --> E[git命令/文件统计]
E -- 返回JSON --> D
D -- 返回结构化结果 --> B
B -- 生成报告 --> F[Markdown报告]
5.2 实现Agent核心
下面是一个简化但可运行的Agent核心,它使用MCP客户端连接Server,并根据Skill的指令编排工具调用:
# agent_core.py
import asyncio
import json
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from skill_manager import SkillManager
class RepoHealthAgent:
def init(self, skills_dir: str, mcp_server_cmd: list[str]):
self.skills = SkillManager(skills_dir)
self.mcp_server_cmd = mcp_server_cmd
async def run(self, repo_path: str) -> str:
# 1. 加载Skill
skill_content = self.skills.load("repo-health")
if not skill_content:
return "错误:未找到repo-health技能"
# 2. 连接MCP Server
server_params = StdioServerParameters(
command=self.mcp_server_cmd[0],
args=self.mcp_server_cmd[1:]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# 3. 列出可用工具
tools = await session.list_tools()
print(f"发现 {len(tools.tools)} 个工具")
# 4. 调用git_diff工具获取仓库变更
result = await session.call_tool(
"git_diff",
{"repo_path": repo_path, "since": "1 week"}
)
diff_text = result.content[0].text
# 5. 调用file_stats工具统计代码规模
stats = await session.call_tool(
"file_stats",
{"filepath": f"{repo_path}/main.py", "format": "json"}
)
stats_data = json.loads(stats.content[0].text)
# 6. 根据Skill指令生成报告
report = self._generate_report(skill_content, diff_text, stats_data)
return report
def _generate_report(self, skill: str, diff: str, stats: dict) -> str:
实际项目中这里会调用LLM,结合skill指令和工具结果生成报告
这里简化为模板拼接
return f"""
仓库健康报告
代码规模
行数: {stats['lines']}
词数: {stats['words']}
最近变更
{diff[:500]}
审查结论
(此处由LLM根据repo-health技能指令生成)
"""
async def main():
agent = RepoHealthAgent(
skills_dir="./skills",
mcp_server_cmd=["python", "mcp_repo_server.py"]
)
report = await agent.run("./my_project")
print(report)
if name == "main":
asyncio.run(main())
5.3 完整运行流程
这个整合示例展示了三大范式的协作方式:
- Skill层:
repo-health技能定义了任务步骤、工具依赖和输出格式,是Agent的“大脑指令”。 - MCP层:Agent通过MCP协议发现并调用
git_diff、file_stats等工具,是Agent的“神经连接”。 - CLI层:MCP Server内部通过subprocess执行真实的git命令和Python脚本,是Agent的“手脚”。
6. 三大范式的选型建议
| 维度 | CLI | MCP | Skill |
|---|---|---|---|
| 核心定位 | 执行动作 | 连接工具与数据 | 封装任务知识 |
| 解决的问题 | Agent如何操作系统 | Agent如何发现和调用工具 | Agent如何知道该做什么 |
| 粒度 | 单个命令 | 一组工具/资源 | 一类完整任务 |
| 复用单位 | 命令脚本 | Server服务 | Skill目录 |
| 典型场景 | 文件操作、进程管理 | 数据库查询、API调用 | 代码审查、报告生成 |
在实际项目中,三者并非互斥,而是层层递进:CLI是最底层的执行单元,MCP是连接CLI与Agent的桥梁,Skill则是把CLI和MCP组合成完整工作流的“配方”。
7. 总结与展望
2026年的AI Agent开发已经形成了一套清晰的分层范式:CLI提供确定性的执行能力,MCP提供标准化的连接能力,Skill提供可复用的知识封装能力。三者结合,让Agent从“能聊天”进化到“能干活”,从“单次对话”进化到“持续协作”。
对于开发者而言,掌握这三层范式的核心不在于记住某个框架的API,而在于理解每一层解决的本质问题:执行要确定、连接要标准、知识要复用。沿着这个思路,无论底层模型如何迭代,Agent工程的骨架都不会过时。
未来,随着MCP生态的进一步成熟和Skill市场的出现,Agent开发将越来越像“搭积木”:开发者从市场挑选合适的Skill,通过MCP连接企业内部的CLI工具,快速组装出满足业务需求的智能体。这将是AI工程化的重要里程碑。
更多推荐



所有评论(0)