1. 项目概述:为AI智能体打造可插拔的“技能库”
最近在折腾AI智能体(Agent)的开发,特别是想让Claude、Cursor这类大模型助手能更深入地介入我的编码工作流。我发现,虽然它们能写代码,但要让它们真正理解代码库、执行静态分析、甚至进行结构化的代码重构,光靠对话是远远不够的。我需要给它们装上“手”和“眼睛”,让它们能直接调用我日常开发中那些强大的命令行工具。
这就是umutbasal/ai这个项目吸引我的地方。它本质上是一个为AI智能体设计的“技能库”(Skills Collection),基于Model Context Protocol(MCP)构建。你可以把它想象成一个为Claude Desktop、Cursor等AI应用准备的“瑞士军刀”扩展包。目前,它主要集成了两个极其实用的工具技能:Semgrep(用于静态分析和安全扫描)和Comby(用于结构化的代码搜索与重写)。这个项目的核心思路不是重新造轮子,而是将成熟的开发者工具封装成AI能直接理解和调用的标准化接口,从而极大地扩展了AI在代码审查、重构和自动化任务中的能力边界。
对于任何正在探索AI编程助手深度集成的开发者、希望构建更强大AI智能体的工程师,或者单纯想自动化一些繁琐代码审查和重构流程的团队来说,这个项目都是一个非常值得研究和实践的起点。它展示了如何将人类开发者的专业工具链,无缝地转化为AI的“肌肉记忆”。
2. 核心设计思路:MCP协议与技能标准化
2.1 为什么是MCP?
在深入技能细节之前,必须先理解其底层协议——Model Context Protocol。MCP是Anthropic提出的一种开放协议,旨在标准化AI应用(如Claude Desktop)与外部工具、数据源之间的通信方式。你可以把它类比为计算机的“USB协议”或者“驱动程序框架”。
在没有MCP之前,如果你想为某个AI助手添加自定义功能,往往需要针对其特定的插件API进行开发,过程封闭且不通用。MCP的出现解决了这个问题。它定义了一套标准的接口,任何遵循MCP协议实现的“服务器”(Server,即提供能力的后端,如本项目的技能库),都可以被任何支持MCP的“客户端”(Client,如Claude Desktop)发现和调用。这意味着,我为Claude写的工具,理论上也能被其他支持MCP的AI应用使用,实现了“一次编写,处处运行”。
注意:MCP协议本身仍在快速发展中,但其核心思想——通过标准化的JSON-RPC over stdio/SSE进行工具(Tools)、资源(Resources)和提示(Prompts)的注册与调用——已经为AI智能体生态的互操作性奠定了坚实基础。选择基于MCP构建技能库,是项目具备前瞻性和扩展性的关键。
2.2 技能(Skill)的设计哲学
本项目中的“技能”,本质上是一个个遵循MCP规范的微服务。每个技能都封装了一个独立工具的核心功能,并通过清晰的接口暴露给AI。这种设计有以下几个显著优点:
- 解耦与专注:每个技能只负责一件事,并且把它做好。Semgrep技能专注于模式匹配和漏洞发现,Comby技能专注于语法感知的代码转换。这使得每个技能的开发、测试和维护都变得相对独立和简单。
- AI友好型接口:技能暴露给AI的并非原始的命令行参数,而是经过抽象和语义化的“工具”。例如,AI不需要知道如何拼接复杂的
semgrep scan命令,它只需要调用run_semgrep_scan这个工具,并传入target_path和rules等自然语言描述的参数即可。这大大降低了AI调用工具的认知门槛。 - 可组合性:未来,复杂的任务可以通过组合多个简单的技能来完成。例如,可以先使用Semgrep技能发现一个常见的代码异味(如未处理的空指针),然后自动调用Comby技能,应用一个预定义的重写模板来修复它。
3. 核心技能深度解析与实操
3.1 Semgrep技能:将静态分析变为AI的直觉
Semgrep是一个基于抽象语法树(AST)的静态代码分析工具。它允许你编写类似于代码片段的“规则”来查找代码中的特定模式,无论是安全漏洞、代码异味还是风格违规。
3.1.1 技能核心功能拆解
本项目封装的Semgrep技能,预计会提供至少以下几个核心MCP工具:
list_semgrep_rules:列出可用的或预定义的Semgrep规则集。这对于AI了解当前有哪些“检查项”可用至关重要。run_semgrep_scan:执行扫描。这是核心工具,参数可能包括:target_paths:要扫描的目录或文件列表。rule_ids或rule_content:指定使用哪些规则,或者直接提供一段规则YAML内容。severity:过滤特定严重级别(ERROR, WARNING, INFO)的结果。
explain_semgrep_finding:对某个扫描结果进行解释。当AI发现一个潜在问题时,它可以调用此工具来获取关于该规则原理、风险以及修复建议的更详细说明,从而生成对开发者更友好的反馈。
3.1.2 实操:如何与AI协作进行代码审计
假设我正在Claude Desktop中审查一个Python的Flask项目。我可以直接对AI说:“请用Semgrep检查当前项目目录下是否存在常见的Web安全漏洞,比如SQL注入或路径遍历。”
AI(集成了本技能后)的内部工作流程会是这样的:
- 调用
list_semgrep_rules,发现有一组预置的python.flask.security规则。 - 调用
run_semgrep_scan,参数为target_paths: [“.”],rule_ids: [“python.flask.security.injection.sqlalchemy-sql-injection”]。 - 收到JSON格式的扫描结果,其中包含发现问题的文件、行号、代码片段和规则说明。
- AI解析结果,并可能对高风险项调用
explain_semgrep_finding获取详细信息。 - AI最终以清晰的列表形式向我汇报:“在
app/views.py第42行,发现一个潜在的SQL注入风险。你的查询字符串直接拼接了用户输入。建议使用参数化查询。这里是详细的解释和修复示例...”
3.1.3 注意事项与配置心得
- 规则库管理:技能预置的规则库需要精心挑选和维护。建议从Semgrep官方规则库中挑选高质量、误报低的规则,并可以根据团队内部规范编写自定义规则。技能应支持从本地文件或远程URL加载规则集。
- 性能考量:扫描大型代码库可能耗时。技能实现时应考虑支持异步或进度报告,避免阻塞AI主线程。可以设置默认的扫描超时时间。
- 输出格式化:原始Semgrep输出是给机器看的。技能的一个关键价值是将输出“翻译”成对AI和最终用户都友好的结构化数据,包括问题的分类、优先级排序和修复建议的初步生成。
3.2 Comby技能:赋予AI重构代码的“巧手”
如果说Semgrep是AI的“代码扫描仪”,那么Comby就是它的“手术刀”。Comby是一个用于结构化的代码搜索和重写的工具。它不同于简单的文本替换,因为它理解代码的语法结构。
3.2.1 技能核心功能拆解
Comby技能可能暴露的工具包括:
comby_search:在代码中搜索符合特定语法结构的模式。例如,搜索所有try块中没有对应finally的语句。comby_rewrite:执行重写。这是核心工具,参数包括:match_template:匹配模板,描述要找到的代码模式。rewrite_template:重写模板,描述要替换成的代码模式。target_paths:目标文件或目录。language:指定编程语言(如.py,.js),以便Comby使用正确的语法解析器。
3.2.2 实操:自动化代码风格统一
想象一个场景:团队决定将所有的Python字符串格式化从旧的%操作符统一迁移到str.format()方法。手动操作繁琐且易错。
我可以对AI说:“帮我把项目里所有用%进行字符串格式化的地方,都改成等价的.format()方法。”
AI调用Comby技能的过程:
- 调用
comby_rewrite。 - 参数
match_template设置为:“:%[1]” :[1]。这是一个Comby模板,:[1]是匹配任意表达式的hole。 - 参数
rewrite_template设置为:“{}”.format(:[1])。 - 指定目标路径和语言为Python。
- Comby会进行语法感知的替换。例如,它能把
“Hello, %s” % name精准地替换为“Hello, {}”.format(name),而不会错误地匹配到取模运算符%。
3.2.3 高级用法与避坑指南
- 模板编写的学习曲线:Comby模板虽然强大,但需要学习。技能可以集成一些常用模板作为示例,或者提供
validate_template工具来帮助AI检查模板的有效性。 - 安全第一:自动重写代码风险极高。技能必须实现“预览模式”(dry-run)。
comby_rewrite工具应默认返回差异预览,并在执行实际写入前需要明确的用户确认。更好的设计是,技能只提供“生成重写建议”的工具,由AI将建议呈现给用户,用户批准后再由AI或用户手动执行。 - 处理边缘情况:复杂的重构(如重命名函数签名)可能涉及多个文件的联动更改。单一的Comby替换可能不够。这时,技能可以设计为执行一系列有序的重写步骤,或者与AI的推理能力结合,由AI规划多步重构策略。
4. 项目架构与本地开发部署实践
4.1 项目结构剖析
根据提供的测试脚本,我们可以推断出项目的标准结构:
umutbasal-ai/ ├── skills/ # 所有技能实现 │ ├── semgrep/ # Semgrep技能包 │ │ ├── index.ts # 主入口,注册MCP工具 │ │ ├── semgrep-runner.ts # 封装Semgrep命令执行逻辑 │ │ └── schemas.ts # 工具输入输出参数的TypeScript类型定义 │ ├── comby/ # Comby技能包(结构类似) │ └── ... # 未来其他技能 ├── tests/ # 测试目录 │ ├── semgrep/ │ │ └── index.test.ts # Semgrep技能单元测试 │ ├── comby/ │ │ └── index.test.ts # Comby技能单元测试 │ └── ... ├── package.json ├── tsconfig.json └── README.md每个技能包都是一个独立的Node.js模块,导出符合MCP服务器规范的createServer函数。使用TypeScript确保接口类型的严谨性。
4.2 环境准备与技能运行
4.2.1 前置依赖安装
技能本身依赖于Semgrep和Comby的本地命令行工具。因此,在运行技能服务器前,必须在开发机器上全局安装它们。
# 安装Semgrep (macOS/Linux示例) brew install semgrep # 或使用Python pip pip install semgrep # 安装Comby # 从GitHub Release页面下载最新二进制文件,或使用脚本安装 bash <(curl -sL get.comby.dev)安装后,请在终端验证命令是否可用:
semgrep --version comby -version4.2.2 技能服务器的启动与连接
本项目使用Bun作为JavaScript运行时。首先克隆项目并安装依赖:
git clone https://github.com/umutbasal/ai.git cd ai bun install要测试单个技能,可以运行其测试文件。但真正的使用场景是将技能服务器与AI客户端连接。这通常需要在AI客户端的配置文件中进行设置。
以Claude Desktop为例,你需要找到其MCP配置文件(通常在~/Library/Application Support/Claude/claude_desktop_config.json或类似位置),并添加一个指向本地技能服务器的配置项:
{ "mcpServers": { "semgrep-skill": { "command": "bun", "args": ["run", "/ABSOLUTE/PATH/TO/umutbasal-ai/skills/semgrep/index.ts"], "env": { "SEMGREP_RULES": "p/ci" // 可选环境变量,指定默认规则集 } }, "comby-skill": { "command": "bun", "args": ["run", "/ABSOLUTE/PATH/TO/umutbasal-ai/skills/comby/index.ts"] } } }配置完成后,重启Claude Desktop,AI就应该能识别并调用这些新技能了。
4.3 测试策略:确保技能稳定可靠
项目使用bun test进行测试,这是一个快速且现代化的测试运行器。测试代码是技能可靠性的基石。
4.3.1 测试内容要点
对于每个技能,测试应覆盖:
- 工具注册:确保MCP工具被正确声明,输入输出Schema无误。
- 核心逻辑:模拟调用工具函数,验证其能正确调用底层CLI(如
semgrep、comby)并处理成功、失败等不同情况。 - 错误处理:测试当CLI工具未安装、目标路径不存在、模板语法错误时,技能是否能给出清晰、友好的错误信息,而不是崩溃。
- 输出解析:验证技能能否将CLI的原始输出(可能是多行文本、JSON等)正确解析为MCP协议要求的结构化数据。
4.3.2 模拟(Mock)的使用
在测试中,不应该真正执行耗时的Semgrep扫描或修改实际文件的Comby操作。应该使用模拟(Mock)来替代对child_process.spawn或fs模块的调用。
// 伪代码示例:模拟Semgrep运行 import { mock } from 'bun:test'; import { runScan } from '../semgrep-runner'; mock.module('child_process', () => ({ spawn: () => ({ stdout: JSON.stringify({ results: [...] }), // 模拟成功输出 stderr: '', on: (event, callback) => { if (event === 'close') callback(0); // 模拟进程成功退出 } }) })); const result = await runScan('.', ['rule-id']); expect(result).toHaveLength(1); // 断言解析后的结果5. 扩展与进阶:打造你自己的AI技能
umutbasal/ai项目提供了一个优秀的范本。其更大的价值在于,它为你封装自己的工具技能铺平了道路。
5.1 如何开发一个新技能
- 选择工具:找一个你日常高频使用、且希望AI能代劳的命令行工具(如
jq处理JSON、ffmpeg处理媒体、pandoc转换文档)。 - 定义接口:思考AI如何与这个工具交互。需要哪些参数?输出应该是什么结构?设计出对AI最友好的工具函数签名。
- 实现包装器:在
skills/目录下创建新文件夹。使用child_process或更友好的包装库来安全地调用命令行工具。务必做好错误处理和超时控制。 - 注册MCP工具:在技能的
index.ts中,使用MCP SDK(如@modelcontextprotocol/sdk)创建服务器,并注册你实现的工具函数。 - 编写测试:为你的技能编写全面的单元测试。
- 集成测试:在Claude Desktop或Cursor中配置你的新技能服务器,进行端到端测试。
5.2 技能设计的黄金法则
- 单一职责:一个技能只做好一件事。
- 无状态性:技能服务器应该是无状态的,每次调用相互独立。状态(如会话、缓存)应由客户端或外部存储管理。
- 安全沙箱:特别是对于执行代码或文件操作的技能,要考虑在沙箱环境(如Docker容器)中运行,限制其权限。
- 丰富的上下文:在工具描述和错误信息中提供尽可能多的上下文,帮助AI理解何时以及如何使用该工具。
5.3 常见问题与排查实录
Q1: 在Claude Desktop中配置了技能,但AI说找不到工具?A1: 首先,检查Claude Desktop的日志文件(通常可在其设置中找到日志路径)。查看MCP服务器启动是否有错误。最常见的原因是:
- 路径错误:
command或args中的路径不正确。务必使用绝对路径。 - 依赖缺失:技能服务器本身的Node.js依赖未安装。确保在技能目录下运行过
bun install。 - 端口/进程冲突:确保没有其他进程占用了MCP通信所需的stdio通道。重启Claude Desktop有时能解决。
Q2: Semgrep扫描速度很慢,影响了AI响应速度怎么办?A2: 有几种优化策略:
- 限制扫描范围:在技能中默认添加排除目录(如
node_modules,.git,dist)。 - 使用缓存:Semgrep支持
--cache选项。可以在技能启动时启用它。 - 异步处理:对于大型扫描,可以将技能设计为异步模式。工具调用立即返回一个任务ID,然后通过另一个工具或资源来查询扫描进度和结果。
Q3: Comby重写时,AI给出的修改建议不是我想要的,甚至可能出错?A3: 这是自动化重构的固有风险。务必遵循以下流程:
- 始终预览:任何重写操作,必须先通过
dry-run模式生成diff预览。 - 人工确认:AI应该将预览结果清晰地展示给用户,并明确请求确认:“我计划进行以下更改,您确认吗?”
- 小步快跑:复杂的重构分解为多个简单、安全的步骤依次执行和确认。
- 版本控制:确保所有操作前,代码已提交到Git。这样一旦出错,可以轻松回退。
Q4: 我想贡献新的技能或改进现有技能,流程是怎样的?A4: 标准的开源贡献流程:
- Fork本仓库到你自己的GitHub账户。
- 克隆你的fork到本地,创建新的特性分支。
- 进行开发,并确保通过所有测试(
bun test)。 - 提交清晰的commit信息,推送到你的fork。
- 在原始仓库创建Pull Request,详细描述你的变更内容和原因。
深入使用和扩展这个项目后,我最大的体会是,AI智能体的能力边界不再仅仅由模型本身决定,而是由我们为其装备的“工具链”所定义。umutbasal/ai项目像是一套标准的“工具接口规范”,将强大的开发者工具从复杂的命令行中解放出来,变成了AI可以轻松调用的函数。这不仅仅是自动化,更是创造了一种新的人机协作范式:人类负责提出高阶意图和做最终决策,AI负责理解意图、规划步骤并精确地调用工具执行。从简单的代码检查到复杂的自动化重构,这个项目的思路为AI编程助手的未来打开了充满想象力的空间。如果你也对此感兴趣,不妨从运行这两个技能开始,感受一下AI拥有“专业工具”后带来的效率提升。