CLI、MCP、Skill:构建 AI Agent 的三层基础设施,你真的分清楚了吗?

CLI、MCP、Skill:构建 AI Agent 的三层基础设施,你真的分清楚了吗?

很多人在学 LangGraph、Claude Code 的时候,会同时接触到 CLI、MCP、Skill 这三个概念,但很少有文章把它们放在一起对比讲清楚。本文试图做这件事:它们分别解决什么问题、在 Agent 体系里扮演什么角色、应该怎么组合使用。


先说结论

三者不是同一层次的东西,不存在谁替代谁的关系:

objectivec 复制代码
CLI   → 解决"怎么运行 Agent"的问题(执行层)
MCP   → 解决"Agent 怎么连接外部世界"的问题(协议层)
Skill → 解决"Agent 怎么复用能力"的问题(能力层)

就像盖房子:CLI 是施工队(执行),MCP 是水电管道(连接),Skill 是预制模块(能力)。三者各司其职,缺一不可。


一、CLI:最被低估的执行层

是什么

CLI(Command Line Interface,命令行界面)是通过文字命令操作程序的方式。对于 Agent 开发来说,CLI 是最直接的触发和调试手段。

bash 复制代码
# 最简单的形式
python risk_agent.py --biz_hour "2026-06-11 08:00:00"

# Claude Code:把 Claude 变成命令行工具
claude "分析这段 SQL 有什么性能问题"
claude --model claude-sonnet-4-6 "帮我写单元测试"

# 结合 shell 脚本实现自动化调度
#!/bin/bash
for hour in 01 02 03 04 05 06; do
    python agent.py --hour "2026-06-11 ${hour}:00:00"
    echo "完成 ${hour} 时的处理"
done

为什么重要

很多人觉得 CLI 是"老技术",在 AI 时代显得过时。但恰恰相反,Agent 系统落地生产后,CLI 是最稳定的调度方式。

原因有三:

可脚本化:任何 CLI 命令都能写进 shell 脚本,配合 crontab 实现定时调度,不依赖额外的调度平台。

可管道化 :CLI 命令可以用管道组合,python extract.py | python transform.py | python load.py,每一步都可以独立测试。

可观测 :命令行的标准输出天然就是日志,配合 tee 命令可以同时输出到终端和文件,运维成本极低。

和 Agent 的关系

CLI 是 Agent 的"入口"。一个生产级的 Agent 系统,最终都需要一个清晰的 CLI 接口:

ini 复制代码
# agent_cli.py
import argparse
import asyncio

def main():
    parser = argparse.ArgumentParser(description="风控 Agent")
    parser.add_argument("--biz_hour",  required=True, help="处理时间")
    parser.add_argument("--dry_run",   action="store_true", help="试跑不写库")
    parser.add_argument("--debug",     action="store_true", help="调试模式")
    args = parser.parse_args()

    asyncio.run(run_agent(
        biz_hour=args.biz_hour,
        dry_run=args.dry_run,
        debug=args.debug
    ))

if __name__ == "__main__":
    main()

这个接口让 Agent 可以被任何调度系统调用------无论是 crontab、Airflow、华为云的任务调度服务,还是 CI/CD 流水线。


二、MCP:连接外部世界的协议标准

是什么

MCP(Model Context Protocol,模型上下文协议)是 Anthropic 提出的开放标准,定义了 AI 模型和外部工具之间的通信规范。

在 MCP 出现之前,每个 Agent 系统都要自己实现工具调用的适配层:调用数据库要写一套、调用文件系统要写一套、调用 API 要写一套,每换一个 LLM 还要重写一遍。MCP 解决的就是这个重复造轮子的问题。

arduino 复制代码
没有 MCP:
Agent ──自定义适配──→ 数据库
Agent ──自定义适配──→ 文件系统
Agent ──自定义适配──→ 外部 API
(换一个 LLM,三套适配全要重写)

有了 MCP:
Agent ──MCP 协议──→ MCP Server(数据库)
Agent ──MCP 协议──→ MCP Server(文件系统)
Agent ──MCP 协议──→ MCP Server(外部 API)
(换 LLM 只需支持 MCP 协议,工具层完全不用改)

架构设计

MCP 是典型的客户端-服务端架构:

arduino 复制代码
MCP Host(宿主)
  └── MCP Client(协议客户端)
        └── MCP Server(工具提供方)
              ├── Tools(可调用的工具函数)
              ├── Resources(可读取的数据资源)
              └── Prompts(可复用的提示词模板)

一个 MCP Server 本质上是一个进程,通过标准输入输出(stdio)或 HTTP SSE 和客户端通信。Claude Desktop、Claude Code、LangGraph 都是 MCP 的宿主。

实战:给风控 Agent 写一个 DWS MCP Server

python 复制代码
# dws_mcp_server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import psycopg2
import json

app = Server("dws-risk-control")

DWS_CONFIG = {
    "host":     "your-dws-host.huaweicloudapps.com",
    "port":     8000,
    "database": "rc_dws",
    "user":     "dws_risk_control_prod",
    "password": "your_password",
}

@app.list_tools()
async def list_tools():
    return [
        types.Tool(
            name="query_risk_features",
            description="查询指定时间段的风控特征数据",
            inputSchema={
                "type": "object",
                "properties": {
                    "biz_hour": {
                        "type": "string",
                        "description": "业务时间,格式:2026-06-11 08:00:00"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "返回行数限制,默认100"
                    }
                },
                "required": ["biz_hour"]
            }
        ),
        types.Tool(
            name="get_risk_score",
            description="查询指定uid的实时风险分",
            inputSchema={
                "type": "object",
                "properties": {
                    "uid": {"type": "string", "description": "用户ID"}
                },
                "required": ["uid"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    conn = psycopg2.connect(**DWS_CONFIG)
    cursor = conn.cursor()

    if name == "query_risk_features":
        biz_hour = arguments["biz_hour"]
        limit    = arguments.get("limit", 100)
        cursor.execute("""
            SELECT uid, risk_value, risk_level, gang_id
            FROM rc_dws.validate_ads_risk_gang_daily_hourly
            WHERE biz_hour = %s
            LIMIT %s
        """, (biz_hour, limit))
        rows = cursor.fetchall()
        result = [{"uid": r[0], "risk_value": r[1],
                   "risk_level": r[2], "gang_id": r[3]} for r in rows]
        return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False))]

    elif name == "get_risk_score":
        uid = arguments["uid"]
        cursor.execute("""
            SELECT risk_value, risk_level, gang_id, biz_hour
            FROM rc_dws.validate_ads_risk_gang_daily_hourly
            WHERE uid = %s
            ORDER BY biz_hour DESC
            LIMIT 1
        """, (uid,))
        row = cursor.fetchone()
        if row:
            result = {"uid": uid, "risk_value": row[0],
                      "risk_level": row[1], "gang_id": row[2], "biz_hour": str(row[3])}
        else:
            result = {"uid": uid, "message": "未找到风险记录"}
        return [types.TextContent(type="text", text=json.dumps(result, ensure_ascii=False))]

    conn.close()

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await app.run(read_stream, write_stream, app.create_initialization_options())

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

配置到 Claude Desktop 或 Claude Code 后,你就可以直接用自然语言查风控数据库了:

yaml 复制代码
你:查一下 2026-06-11 08:00 这个小时有多少高风险用户
Claude:(调用 query_risk_features MCP 工具)共识别 1247 个高风险用户,
        其中团伙用户 386 个,分布在 42 个团伙中...

MCP 的核心价值

MCP 的价值不只是"让 Agent 能调工具",更重要的是标准化

工具开发者只需要实现一次 MCP Server,就能被所有支持 MCP 的 AI 工具调用(Claude、Cursor、Windsurf......)。AI 工具开发者只需要实现一次 MCP Client,就能调用所有 MCP Server。这是一个双向解耦的设计,和 USB 接口的思路如出一辙。


三、Skill:Agent 的能力复用单元

是什么

Skill(技能)是对 Agent 某项能力的封装,让这段能力可以被复用、被组合、被测试。Skill 没有统一的技术规范,更多是一种架构设计理念。

在 LangGraph 体系里,Skill 有三种主要形态:

提示词 Skill:把复杂的提示词逻辑封装成函数。

python 复制代码
def risk_analysis_skill(data: dict, context: str = "") -> str:
    """风险分析技能:标准化的风险评估提示词"""
    return f"""
    你是专业的风控分析师。请分析以下数据,按格式输出:

    分析维度:
    1. 行为异常:是否存在异常的时间、频率、金额模式
    2. 设备风险:设备指纹是否异常,是否多账号共用
    3. 关联风险:是否与已知风险账号有关联
    4. 综合评级:高危 / 中危 / 低危

    输出格式:JSON,包含 risk_level、risk_reasons、confidence 三个字段。

    {'参考背景:' + context if context else ''}
    待分析数据:{data}
    """

工具 Skill:把可调用的工具封装成标准接口。

python 复制代码
from langchain_core.tools import tool

@tool
def gang_detection_skill(uids: list, biz_hour: str) -> dict:
    """
    团伙识别技能:对给定uid列表进行团伙关联分析。

    适用场景:已有高风险uid列表,需要识别团伙关系时调用。
    算法:Union-Find 联通分量。
    返回:团伙列表,每个团伙包含成员uid和平均风险分。
    """
    edges = query_edges_from_dws(uids, biz_hour)
    gangs = union_find(uids, edges)
    return {
        "gang_count":  len(gangs),
        "gang_list":   gangs,
        "total_uids":  sum(len(g["members"]) for g in gangs)
    }

子图 Skill:把完整的处理流程封装成可复用的 LangGraph 子图。

scss 复制代码
def build_report_generation_skill():
    """报告生成技能:独立子图,接收风险数据,输出结构化报告"""
    builder = StateGraph(ReportState)

    builder.add_node("summarize",   summarize_risk_data)
    builder.add_node("visualize",   generate_charts)
    builder.add_node("format",      format_report)
    builder.add_node("distribute",  send_to_notion)

    builder.set_entry_point("summarize")
    builder.add_edge("summarize", "visualize")
    builder.add_edge("visualize", "format")
    builder.add_edge("format",    "distribute")
    builder.add_edge("distribute", END)

    return builder.compile()

# 作为节点嵌入主图
report_skill = build_report_generation_skill()
main_builder.add_node("generate_report", report_skill)

Skill 的设计原则

好的 Skill 应该遵循以下原则:

单一职责:一个 Skill 只做一件事,团伙识别 Skill 不应该同时包含特征生成逻辑。

有清晰的接口说明:工具 Skill 的 docstring 是 LLM 决定是否调用这个工具的唯一依据,写得越清楚,LLM 的决策越准确。

幂等设计:同样的输入多次调用,结果一致。Agent 在重试时会重新调用 Skill,幂等设计避免副作用。

可单独测试:Skill 是纯函数或接近纯函数,可以脱离 Agent 框架独立测试。

python 复制代码
# Skill 的单元测试非常简单
def test_gang_detection_skill():
    uids = ["uid_001", "uid_002", "uid_003"]
    result = gang_detection_skill(uids, "2026-06-11 08:00:00")
    assert "gang_count" in result
    assert result["total_uids"] <= len(uids)

四、三者的本质区别

回到开头的定义,用一张表格总结:

维度 CLI MCP Skill
解决的问题 怎么运行 怎么连接 怎么复用
所在层次 执行层 协议层 能力层
标准化程度 无统一标准 有开放协议规范 无统一标准
主要使用者 开发者/运维 工具开发者 Agent 架构师
典型形态 shell 命令、argparse MCP Server/Client Tool、子图、Prompt模板
替换成本 高(需双端适配)

五、三者如何协同工作

以一个完整的风控 Agent 系统为例,三者是这样配合的:

objectivec 复制代码
【CLI 层】定时调度脚本
python risk_agent.py --biz_hour "2026-06-11 08:00:00"
    │
    ▼
【Agent 核心】LangGraph 图执行引擎
    │
    ├── 特征生成节点 ──── 调用 Skill(特征工程 Skill)
    │                          │
    │                          └── 通过 MCP 查询 DWS 数据库
    │
    ├── 预测节点 ────────  调用 Skill(XGBoost 预测 Skill)
    │
    ├── 团伙识别节点 ─────  调用 Skill(团伙识别子图 Skill)
    │                          │
    │                          └── 通过 MCP 查询关联边数据
    │
    └── 结果写回节点 ─────  通过 MCP 写回 DWS
                            通过 MCP 发送 Notion 报告

CLI 负责触发和参数传递,是外部系统和 Agent 的边界。

MCP 负责 Agent 和外部数据源的通信,Agent 不需要关心数据库连接细节,只需要调用 MCP 工具。

Skill 负责 Agent 内部的能力复用,把经过验证的处理逻辑封装成稳定的模块,新的 Agent 可以直接引用。


六、常见误区

误区一:MCP 就是 Function Calling

不完全对。Function Calling 是 LLM 层面的能力,让模型可以输出结构化的工具调用请求。MCP 是协议层面的标准,定义了工具的发现、调用、返回的完整规范。两者是不同层次的东西,MCP 的工具调用底层可以用 Function Calling 实现,但 MCP 还包括资源管理、提示词模板等 Function Calling 没有的概念。

误区二:Skill 只是 Tool

Skill 是比 Tool 更广泛的概念。Tool 是 Skill 的一种形态(工具 Skill),但 Skill 还包括提示词模板 Skill 和子图 Skill。一个团伙识别的完整流程(建图、联通分量、评分),用一个 Tool 表达太复杂,封装成子图 Skill 才是正确的做法。

误区三:这三个用一个就够了

实际上它们解决的是不同层次的问题,缺任何一个都会有明显的短板。没有 CLI,Agent 很难在生产环境调度;没有 MCP,Agent 和外部系统的连接会变成一堆自定义适配代码;没有 Skill,随着业务增长 Agent 代码会变成一团乱麻。


七、总结

CLI、MCP、Skill 三者构成了 Agent 系统的基础设施:

CLI 是基础,让 Agent 能够被外部系统可靠地触发和调度,是 Agent 走向生产环境的必要条件。MCP 是管道,解决了 Agent 和外部世界的连接标准化问题,是 AI 生态互联互通的基石。Skill 是积木,让 Agent 的能力可以被沉淀、复用和组合,是 Agent 系统保持可维护性的关键。

三者之间没有高低之分,只有职责的不同。真正生产级的 Agent 系统,一定是三者协同工作的结果。


参考资料

相关推荐
70asunflower1 小时前
【Day1-2】部署&运行 Gemma4 大模型 - Datawhale AI学习
人工智能·学习·datawhale·amdev
wuhanzhanhui1 小时前
智能座舱技术新高地!2026武汉国际智能显示及智能座舱展览会
人工智能·物联网
学Linux的语莫1 小时前
OpenCV 视频处理入门教程
人工智能·opencv·音视频
王小王-1231 小时前
基于机器学习的二手汽车交易价格分析与可视化
人工智能·机器学习·二手车价格预测·汽车销量分析·二手车分析·新能源汽车系统·汽车销量分析可视化系统
Luminbox紫创测控1 小时前
AM1.5G光谱在LED太阳模拟器中的工程实现:光谱匹配与均匀性优化(A+级指标)
人工智能·测试工具·5g·安全性测试
“码”力全开1 小时前
解耦安防黑盒:基于 Docker 容器化与 GB28181/RTSP 双协议架构的 AI 边缘计算视频平台(全源码交付)
人工智能·docker·架构
析稿AI写作1 小时前
AI视频创作实战:用飙算工具箱实现图转视频与文字成片,个人开发者的多模态效率方案
人工智能·音视频
赛博三把手1 小时前
「2026 最新推荐」AI 大模型 API 中转站 | 国内直连 ChatGPT/Claude/Gemini 稳定优质的 API 接口服务
人工智能·github·ai编程
AI服务老曹2 小时前
解耦安防黑盒:基于 Docker 的国标 GB28181 与 RTSP 统一接入 AI 视频管理平台架构设计(附源码交付与边缘计算实践)
人工智能·docker·音视频