August 21, 2026 in 人工智能4 minutes
详细介绍MCP、SKILL、Hook、Plugin的基础知识
模型上下文协议
场景:你问 AI “帮我分析一下当前项目的 README 并总结待办事项”。 MCP 作用:AI 通过 MCP Server 调用
filesystem工具,以只读权限读取本地的README.md文件内容,将其作为 Context 传回给模型,模型再生成总结。整个过程遵循 MCP 的tools/callJSON-RPC 规范。
原子化能力单元
场景:用户说 “把这张图片翻译成英文并生成一段 Twitter 文案”。 Skill 作用:Agent 识别出两个 Skill:
ImageOCRTranslation和SocialCopywriting。先触发前者提取并翻译文字,将结果作为输入传递给后者,最终输出符合推特风格的文案。
生命周期拦截点
on_start, on_end, on_error, before_request, after_response。场景:企业级 AI 助手需要合规审计。 Hook 作用:注册一个
after_llm_responseHook。每当 AI 生成回复后,该 Hook 自动触发,将问答记录异步发送到审计日志系统,并对敏感词进行脱敏处理。用户无感知,主对话流程不受影响。
模块化扩展包
plugin.json, manifest.yaml,声明版本、依赖、权限、入口点。IPlugin, activate(), deactivate())。目标:让 AI 能查询本机 SQLite 数据库
# server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-db-server")
@mcp.tool()
def query_sqlite(sql: str) -> str:
"""Execute a read-only SQL query on the local analytics database.
Args:
sql: A SELECT statement. INSERT/UPDATE/DELETE are not allowed.
"""
import sqlite3
conn = sqlite3.connect("analytics.db")
# 安全检查:只允许 SELECT
if not sql.strip().upper().startswith("SELECT"):
return "Error: Only SELECT queries are permitted."
cursor = conn.execute(sql)
rows = cursor.fetchall()
conn.close()
return str(rows)
if __name__ == "__main__":
mcp.run(transport="stdio")@mcp.tool() 装饰器,函数名即工具名,docstring 即 LLM 看到的描述。目标:让 Agent 能把 Markdown 转成 PDF
# skills/md_to_pdf.yaml
name: markdown_to_pdf
description: >
Converts Markdown text to a downloadable PDF file.
Use when the user wants to export notes, reports, or documents as PDF.
Do NOT use for HTML or Word conversion.
parameters:
markdown_content:
type: string
required: true
description: Raw Markdown text to convert
filename:
type: string
required: false
default: "export.pdf"
description: Output PDF filename
return_type: file# skills/md_to_pdf.py
import markdown
from weasyprint import HTML
def execute(markdown_content: str, filename: str = "export.pdf") -> str:
html = markdown.markdown(markdown_content)
HTML(string=html).write_pdf(filename)
return f"/tmp/{filename}"description 写给 LLM 看,决定它何时被选中。parameters 一一对应。目标:在每次 AI 回复后自动记录 Token 消耗
# hooks/token_logger.py
from agent_framework import hook
@hook("after_llm_response")
async def log_token_usage(response, context):
"""
此函数在每次 LLM 返回响应后自动触发。
签名 (response, context) 由框架规定,不可更改。
"""
usage = response.usage # {prompt_tokens, completion_tokens}
cost = usage.prompt_tokens * 0.0001 + usage.completion_tokens * 0.0002
await context.logger.info(
f"Token usage: {usage}, estimated cost: ${cost:.4f}"
)
# Hook 不返回值,仅做副作用操作# main.py 中注册
from hooks.token_logger import log_token_usage
app.register_hook("after_llm_response", log_token_usage)目标:为 Obsidian 添加一个“AI 摘要笔记”插件
ai-summarizer/
├── manifest.json ← 插件身份证
├── main.ts ← 入口逻辑
└── styles.css ← 可选 UI 样式
// manifest.json
{
"id": "ai-summarizer",
"name": "AI Note Summarizer",
"version": "1.0.0",
"minAppVersion": "1.5.0",
"description": "Summarize current note using OpenAI API",
"author": "YourName",
"isDesktopOnly": false
}// main.ts
import { Plugin, Notice } from 'obsidian';
export default class AISummarizerPlugin extends Plugin {
async onload() {
// 注册命令 → 用户可通过 Ctrl+P 触发
this.addCommand({
id: 'summarize-current-note',
name: 'Summarize this note with AI',
callback: async () => {
const content = await this.app.workspace.getActiveFile()?.vault.read();
const summary = await callOpenAI(content);
new Notice(`Summary: ${summary.slice(0, 100)}...`);
},
});
}
onunload() {
// 清理资源
}
}onload() / onunload() 是插件的入口契约。| 你在创作什么 | 交付物形态 | 谁来调用它 | 创作时最关心什么 |
|---|---|---|---|
| MCP Tool | 一个带装饰器的 Python/TS 函数 | AI Client 通过协议自动发现并调用 | 参数类型注解 + 清晰的 docstring |
| Skill | YAML 元数据 + 执行函数 | Agent 编排器根据意图匹配选择 | description 写得让 LLM 能准确理解用途 |
| Hook | 一个固定签名的回调函数 | 宿主系统在特定事件点自动触发 | 签名是否正确、副作用是否安全 |
| Plugin | manifest + 入口模块的完整包 | 宿主应用加载后由用户或系统触发 | 接口契约 + 权限声明 + 版本兼容 |