1. 引言
随着大语言模型(LLM)能力的持续增强,围绕 AI 的插件生态与技能(Skills)体系正成为开发者提升效率、扩展模型能力边界的重要抓手。无论是为 IDE 编写智能编码助手插件,还是为 Agent 框架定制可复用的 Skills,都涉及从设计、开发到跨平台迁移的完整链路。
本文将从 AI 插件与 Skills 的基本概念出发,梳理两者的异同,并结合实际案例讲解开发流程、调试技巧以及在不同平台间的迁移策略,帮助读者快速上手并规避常见坑点。
2. 核心概念:AI 插件与 Skills
2.1 什么是 AI 插件
AI 插件是指嵌入到宿主应用(如 IDE、浏览器、聊天客户端)中的扩展模块,通过调用大模型能力或本地逻辑,为用户提供智能化的交互体验。典型形态包括:
- IDE 插件:代码补全、智能重构、错误解释、单元测试生成等。
- 浏览器插件:网页摘要、翻译、表单自动填充等。
- 聊天机器人插件:接入外部工具、数据库查询、API 调用等。
2.2 什么是 Skills
Skills(技能)是面向 Agent 或 LLM 应用的可复用能力单元,通常以结构化描述(如自然语言指令、JSON Schema、示例)定义模型在特定场景下的行为方式。Skills 的核心价值在于:
- 可复用:同一技能可在多个 Agent 或应用间共享。
- 可组合:多个技能可串联成复杂工作流。
- 可迁移:以标准格式描述,便于跨平台移植。
2.3 两者的关系与区别
| 维度 | AI 插件 | Skills |
|---|---|---|
| 载体 | 宿主应用(IDE/浏览器等) | Agent / LLM 应用 |
| 核心 | 代码与 UI 集成 | 指令与行为定义 |
| 扩展方式 | 插件 API + 模型调用 | Prompt / 工具调用 / 工作流 |
| 典型场景 | 代码补全、对话增强 | 任务编排、领域专家 |
两者并非互斥:插件内部可以调用 Skills,Skills 也可以通过插件暴露给用户。
3. AI 插件开发实战
3.1 技术选型
以 IDE 插件为例,常见技术栈包括:
- VS Code:TypeScript + VS Code Extension API。
- JetBrains:Kotlin/Java + IntelliJ Platform SDK。
- 通用方案:通过 LSP(Language Server Protocol)解耦语言服务。
3.2 最小可运行示例(VS Code)
下面是一个调用大模型实现「选中代码解释」的最小插件示例:
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
const disposable = vscode.commands.registerCommand('ai-assistant.explain', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showWarningMessage('请先打开一个编辑器');
return;
}
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (!selectedText) {
vscode.window.showWarningMessage('请先选中代码');
return;
}
// 调用大模型接口(此处以 OpenAI 兼容接口为例)
const explanation = await callLLM(`请解释以下代码:\n${selectedText}`);
vscode.window.showInformationMessage(explanation);
});
context.subscriptions.push(disposable);
}
async function callLLM(prompt: string): Promise<string> {
// 实际项目中请将 API Key 放入配置或环境变量
const response = await fetch('https://api.example.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.LLM_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }]
})
});
const data = await response.json();
return data.choices[0].message.content;
}
export function deactivate() {}
3.3 测试策略
插件逻辑建议分层测试:纯逻辑(如 Prompt 组装、结果解析)用单元测试覆盖,涉及 VS Code API 的部分用集成测试验证。
// test/suite/extension.test.ts
import * as assert from 'assert';
import * as vscode from 'vscode';
import { buildPrompt } from '../../src/prompt';
suite('Extension Test Suite', () => {
test('buildPrompt 应包含选中代码', () => {
const code = 'const a = 1;';
const prompt = buildPrompt(code);
assert.ok(prompt.includes(code));
});
test('命令 ai-assistant.explain 应已注册', async () => {
const commands = await vscode.commands.getCommands(true);
assert.ok(commands.includes('ai-assistant.explain'));
});
});
// .vscode/launch.json(测试调试配置)
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
],
"outFiles": ["${workspaceFolder}/out/test/**/*.js"]
}
]
}
3.4 维护与可观测性
插件上线后需要持续观测调用质量与稳定性,建议在 callLLM 中埋点:
async function callLLM(prompt: string): Promise<string> {
const start = Date.now();
try {
const response = await fetch('https://api.example.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.LLM_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }]
})
});
const data = await response.json();
const latency = Date.now() - start;
console.log(`[llm] prompt_len=${prompt.length} latency=${latency}ms status=${response.status}`);
return data.choices[0].message.content;
} catch (err) {
console.error(`[llm] call failed: ${err}`);
throw err;
}
}
3.5 调试与发布要点
- 本地调试:使用 VS Code 的
F5启动 Extension Development Host。 - 日志输出:通过
OutputChannel输出调试信息,避免阻塞 UI 线程。 - 异步处理:模型调用耗时较长,务必使用异步方式并考虑超时与取消。
- 发布:通过
vsce打包并发布到 Marketplace,注意配置publisher与repository。
4. Skills 开发实战
4.1 Skills 的典型结构
一个标准化的 Skill 通常包含以下部分:
name: code-reviewer
description: 对代码变更进行审查,发现潜在问题并给出改进建议。
version: 1.0.0
author: example
inputs:
- name: diff
description: Git diff 内容
required: true
type: string
prompt: |
你是一位资深代码审查专家。请根据以下 diff 内容,指出潜在问题并给出改进建议:
{{ diff }}
4.2 在 Agent 中注册与调用
以 Python 为例,演示如何在自定义 Agent 中加载并调用 Skill:
import yaml
from pathlib import Path
class Skill:
def __init__(self, skill_dir: Path):
with open(skill_dir / "skill.yaml", "r", encoding="utf-8") as f:
self.meta = yaml.safe_load(f)
self.prompt_template = self.meta["prompt"]
def render(self, **kwargs) -> str:
return self.prompt_template.format(**kwargs)
# 使用示例
skill = Skill(Path("./skills/code-reviewer"))
prompt = skill.render(diff="@@ -1,3 +1,4 @@\n-print('hello')\n+print('hello world')")
print(prompt)
4.3 设计高质量 Skills 的原则
- 单一职责:一个 Skill 只做一件事,便于复用与测试。
- 输入明确:清晰定义输入参数的类型、必填性与默认值。
- 示例驱动:在描述中附带输入输出示例,帮助模型理解预期行为。
- 错误处理:在 Prompt 中说明模型遇到无法处理的情况时应如何回应。
5. 跨平台迁移策略
5.1 迁移的挑战
- API 差异:不同平台的插件 API 与权限模型不同。
- 模型差异:不同模型对 Prompt 的敏感度不同,同一 Skill 效果可能差异明显。
- 数据格式:配置、存储、日志格式各异。
5.2 插件迁移:从 VS Code 到 JetBrains
迁移时建议采用「核心逻辑与平台解耦」的分层架构:
┌─────────────────────────────┐
│ 平台适配层 │
│ (VS Code / JetBrains / ...)│
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ 核心逻辑层 │
│ (LLM 调用 / 代码分析 / ...)│
└──────────────┬──────────────┘
│
┌──────────────▼──────────────┐
│ 通用模型层 │
│ (Prompt 模板 / Skills) │
└─────────────────────────────┘
核心逻辑层与平台无关,仅通过接口与适配层交互,从而最大化复用。
5.3 Skills 迁移:标准化是关键
Skills 的迁移相对轻量,关键在于采用平台无关的标准化格式:
- 使用 YAML/JSON 描述元数据与 Prompt。
- 将平台相关配置(如 API Key、模型名称)外置为环境变量。
- 提供统一的加载与渲染接口。
下面是一个跨平台加载 Skills 的示例:
import os
import yaml
from typing import Dict, Any
def load_skill(skill_path: str) -> Dict[str, Any]:
"""加载 Skill 元数据,并注入环境变量。"""
with open(skill_path, "r", encoding="utf-8") as f:
meta = yaml.safe_load(f)
# 将环境变量注入到 Prompt 中
for key, value in os.environ.items():
meta["prompt"] = meta["prompt"].replace("{{ " + key + " }}", value)
return meta
# 示例:加载并渲染
skill = load_skill("./skills/code-reviewer/skill.yaml")
print(skill["prompt"])
5.4 迁移案例:从 VS Code 到 JetBrains 的完整落地
下面以一个「代码解释助手」插件为例,展示从 VS Code 迁移到 JetBrains 的完整落地过程。
第一步:抽取平台无关的核心逻辑
将 Prompt 组装与 LLM 调用抽成独立模块,与平台 API 完全解耦:
// core/llm.ts —— 平台无关的核心逻辑
export interface ExplainRequest {
code: string;
language: string;
model?: string;
}
export interface ExplainResult {
explanation: string;
latencyMs: number;
promptTokens: number;
}
export async function explainCode(req: ExplainRequest): Promise<ExplainResult> {
const start = Date.now();
const prompt = buildExplainPrompt(req.code, req.language);
const response = await fetch(process.env.LLM_ENDPOINT!, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.LLM_API_KEY}`
},
body: JSON.stringify({
model: req.model ?? process.env.LLM_MODEL ?? 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }]
})
});
const data = await response.json();
return {
explanation: data.choices[0].message.content,
latencyMs: Date.now() - start,
promptTokens: data.usage?.prompt_tokens ?? 0
};
}
function buildExplainPrompt(code: string, language: string): string {
return `请用中文解释以下 ${language} 代码的功能与关键逻辑:\n\`\`\`${language}\n${code}\n\`\`\``;
}
第二步:VS Code 适配层
// vscode-adapter/extension.ts —— VS Code 适配层
import * as vscode from 'vscode';
import { explainCode } from '../core/llm';
export function activate(context: vscode.ExtensionContext) {
const disposable = vscode.commands.registerCommand('ai-assistant.explain', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const selection = editor.selection;
const code = editor.document.getText(selection);
if (!code) {
vscode.window.showWarningMessage('请先选中代码');
return;
}
const language = editor.document.languageId;
const result = await explainCode({ code, language });
vscode.window.showInformationMessage(result.explanation);
});
context.subscriptions.push(disposable);
}
第三步:JetBrains 适配层(Kotlin)
// jetbrains-adapter/src/ExplainAction.kt —— JetBrains 适配层
package com.example.aiassistant
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.ui.Messages
import kotlinx.coroutines.*
class ExplainAction : AnAction() {
override fun actionPerformed(e: AnActionEvent) {
val editor: Editor? = e.getData(CommonDataKeys.EDITOR)
val project = e.project ?: return
val selection = editor?.selectionModel?.selectedText ?: run {
Messages.showWarningDialog(project, "请先选中代码", "AI Assistant")
return
}
val language = editor.document.getLanguage(editor.caretModel.offset).displayName
CoroutineScope(Dispatchers.IO).launch {
val result = explainCode(ExplainRequest(selection, language))
withContext(Dispatchers.UIThread) {
Messages.showInfoMessage(project, result.explanation, "AI 代码解释")
}
}
}
}
第四步:注册 JetBrains 插件
<!-- jetbrains-adapter/src/main/resources/META-INF/plugin.xml -->
<idea-plugin>
<id>com.example.ai-assistant</id>
<name>AI Assistant</name>
<version>1.0.0</version>
<depends>com.intellij.modules.platform</depends>
<actions>
<action id="com.example.aiassistant.ExplainAction"
class="com.example.aiassistant.ExplainAction"
text="AI 解释选中代码"
description="调用大模型解释选中的代码">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
</action>
</actions>
</idea-plugin>
第五步:迁移验证
# 在 JetBrains 插件工程中运行
./gradlew runIde # 启动沙箱 IDE 验证
./gradlew test # 运行单元测试
./gradlew buildPlugin # 打包插件
通过以上五步,核心逻辑零改动,仅新增适配层即可完成跨平台迁移。
5.5 迁移验证清单
- 核心逻辑是否与平台解耦?
- 所有 API Key 与敏感信息是否已外置?
- Prompt 是否在目标模型上完成效果验证?
- 错误处理与日志是否适配目标平台?
- 是否补充了目标平台的自动化测试?
- 是否在目标平台完成端到端冒烟测试?
5.6 迁移流程图
下面是插件与 Skills 从开发到跨平台迁移的整体流程:
6. 常见问题与最佳实践
6.1 常见坑点
- 硬编码模型名:不同环境模型版本不同,建议通过配置注入。
- 忽略上下文长度:长文本输入易超出模型上下文窗口,需做截断或分块。
- 同步阻塞:在 UI 线程中同步调用模型会导致界面卡死。
- Prompt 过拟合:针对单一模型调优的 Prompt 在迁移后效果可能大幅下降。
6.2 最佳实践
- 配置驱动:模型、Key、超参数全部走配置。
- 可观测性:记录每次调用的输入输出、耗时与 Token 消耗。
- 渐进式迁移:先迁移核心场景,验证通过后再扩展。
- 版本管理:Skills 与插件代码一并纳入 Git 管理,便于回溯。
7. 术语表
7.1 核心概念
| 术语 | 英文 | 说明 |
|---|---|---|
| 大语言模型 | LLM (Large Language Model) | 基于海量文本训练、具备自然语言理解与生成能力的模型。 |
| 智能体 | Agent | 能感知环境、自主决策并调用工具完成任务的 AI 程序。 |
| 技能 | Skills | 面向 Agent 的可复用能力单元,以结构化描述定义模型行为。 |
| 插件 | Plugin / Extension | 嵌入宿主应用、扩展其功能的模块。 |
| 提示词 | Prompt | 输入给模型的指令文本,用于引导输出。 |
| 提示词工程 | Prompt Engineering | 设计、优化 Prompt 以提升模型输出质量的方法。 |
7.2 开发与集成
| 术语 | 英文 | 说明 |
|---|---|---|
| 工具调用 | Tool Calling / Function Calling | 模型在对话中请求调用外部函数或 API 的机制。 |
| 语言服务器协议 | LSP (Language Server Protocol) | 编辑器与语言服务之间的标准化通信协议。 |
| 扩展开发宿主 | Extension Development Host | VS Code 中用于调试插件的独立进程。 |
| 平台适配层 | Platform Adapter Layer | 隔离平台 API 差异、对接核心逻辑的中间层。 |
| 核心逻辑层 | Core Logic Layer | 与平台无关的业务逻辑,如 LLM 调用、代码分析。 |
7.3 模型与性能
| 术语 | 英文 | 说明 |
|---|---|---|
| 上下文窗口 | Context Window | 模型单次可处理的输入 Token 上限。 |
| 令牌 | Token | 模型处理文本的最小单位,中文通常一字对应多 Token。 |
| 可观测性 | Observability | 通过日志、指标、追踪等手段掌握系统运行状态的能力。 |
| 过拟合 | Overfitting | 模型或 Prompt 过度适配训练/调优数据,泛化能力下降。 |
| 延迟 | Latency | 从发起请求到收到响应的时间间隔。 |
8. 全流程落地案例:从零构建「代码审查助手」
下面以一个真实可落地的「代码审查助手」为例,串联插件开发、Skills 设计、测试维护与跨平台迁移的完整链路。
8.1 需求与架构设计
业务场景:团队在 GitLab MR(Merge Request)中人工审查代码效率低,希望构建一个自动审查助手,在提交 MR 时自动分析 diff 并给出改进建议。
整体架构:
技术选型:
- 审查服务:Python FastAPI,接收 GitLab Webhook。
- Skills 管理:YAML 定义审查规则,支持热更新。
- LLM 调用:OpenAI 兼容接口,模型名走环境变量。
- IDE 插件:VS Code 插件,支持本地触发审查。
8.2 定义审查 Skill
# skills/code-reviewer/skill.yaml
name: code-reviewer
description: 对代码变更进行审查,发现潜在问题并给出改进建议。
version: 1.0.0
author: example
inputs:
- name: diff
description: Git diff 内容
required: true
type: string
- name: language
description: 代码语言
required: false
type: string
default: python
prompt: |
你是一位资深代码审查专家。请根据以下 diff 内容,从以下维度给出审查意见:
1. 潜在 Bug 与逻辑错误
2. 安全风险(注入、越权、敏感信息泄露)
3. 性能问题
4. 代码规范与可维护性
请按「严重程度 + 问题描述 + 修改建议」的格式输出。
语言:{{ language }}
Diff 内容:
{{ diff }}
8.3 实现审查服务
# server/main.py —— 审查服务
import os
import yaml
from pathlib import Path
from fastapi import FastAPI, Request
from openai import OpenAI
app = FastAPI()
client = OpenAI(
base_url=os.getenv("LLM_ENDPOINT", "https://api.example.com/v1"),
api_key=os.getenv("LLM_API_KEY"),
)
def load_skill(skill_path: str) -> dict:
"""加载 Skill 并注入环境变量。"""
with open(skill_path, "r", encoding="utf-8") as f:
meta = yaml.safe_load(f)
for key, value in os.environ.items():
meta["prompt"] = meta["prompt"].replace("{{ " + key + " }}", value)
return meta
def render_prompt(skill: dict, **kwargs) -> str:
"""渲染 Prompt 模板。"""
prompt = skill["prompt"]
for key, value in kwargs.items():
prompt = prompt.replace("{{ " + key + " }}", str(value))
return prompt
@app.post("/webhook/gitlab")
async def handle_gitlab_webhook(request: Request):
"""接收 GitLab MR 事件,触发代码审查。"""
payload = await request.json()
if payload.get("object_kind") != "merge_request":
return {"status": "ignored"}
# 提取 MR 的 diff(此处简化,实际应调用 GitLab API 获取)
diff = payload.get("changes", {}).get("diff", "")
# 加载 Skill 并渲染 Prompt
skill = load_skill("./skills/code-reviewer/skill.yaml")
prompt = render_prompt(skill, diff=diff, language="python")
# 调用 LLM
response = client.chat.completions.create(
model=os.getenv("LLM_MODEL", "gpt-4o-mini"),
messages=[{"role": "user", "content": prompt}],
)
review_result = response.choices[0].message.content
# 将审查结果回写到 GitLab MR 评论(此处省略 GitLab API 调用)
print(f"审查完成:{review_result}")
return {"status": "ok", "review": review_result}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
8.4 在 VS Code 插件中复用同一 Skill
// vscode-plugin/src/extension.ts —— 复用同一 Skill 的插件端
import * as vscode from 'vscode';
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import * as path from 'path';
export function activate(context: vscode.ExtensionContext) {
const disposable = vscode.commands.registerCommand('ai-assistant.review', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const code = editor.document.getText();
const language = editor.document.languageId;
// 加载与服务器端相同的 Skill 文件
const skillPath = path.join(context.extensionPath, 'skills', 'code-reviewer', 'skill.yaml');
const skill = yaml.load(fs.readFileSync(skillPath, 'utf-8')) as any;
// 渲染 Prompt
let prompt = skill.prompt;
prompt = prompt.replace('{{ language }}', language);
prompt = prompt.replace('{{ diff }}', code);
// 调用 LLM
const response = await fetch(process.env.LLM_ENDPOINT!, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.LLM_API_KEY}`
},
body: JSON.stringify({
model: process.env.LLM_MODEL ?? 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }]
})
});
const data = await response.json();
// 在侧边栏展示审查结果
const panel = vscode.window.createWebviewPanel(
'reviewResult', '代码审查结果', vscode.ViewColumn.Beside
);
panel.webview.html = `<pre>${data.choices[0].message.content}</pre>`;
});
context.subscriptions.push(disposable);
}
8.5 测试与部署
# server/test_review.py —— 审查服务单元测试
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))
from main import load_skill, render_prompt
def test_load_skill():
skill = load_skill("./skills/code-reviewer/skill.yaml")
assert skill["name"] == "code-reviewer"
assert "{{ diff }}" in skill["prompt"]
def test_render_prompt():
skill = load_skill("./skills/code-reviewer/skill.yaml")
prompt = render_prompt(skill, diff="@@ -1,3 +1,4 @@", language="python")
assert "python" in prompt
assert "@@ -1,3 +1,4 @@" in prompt
assert "{{ diff }}" not in prompt
# 部署脚本
pip install -r requirements.txt
export LLM_ENDPOINT="https://api.example.com/v1"
export LLM_API_KEY="sk-xxx"
export LLM_MODEL="gpt-4o-mini"
uvicorn main:app --host 0.0.0.0 --port 8000
8.6 全流程效果
通过以上实现,团队获得了两端复用的完整链路:
- 服务端:GitLab Webhook 自动触发审查,MR 提交即获得 AI 审查意见。
- IDE 端:开发者本地选中代码即可触发审查,无需等待 CI。
- Skill 复用:同一份
code-reviewerSkill 在服务端与插件端共享,保证 Prompt 一致。 - 可观测性:在
callLLM中埋点,记录延迟、Token 消耗与失败率。
7. 总结与展望
AI 插件与 Skills 是构建智能应用的两大支柱:插件负责与用户和宿主环境交互,Skills 负责沉淀可复用的模型能力。开发时注重分层解耦、配置驱动与标准化描述,迁移时以「核心逻辑平台无关」为原则,即可大幅降低维护成本。
未来,随着 Agent 生态的成熟,Skills 的标准化与互操作性将成为关键议题。尽早建立规范的开发与迁移流程,将帮助团队在 AI 应用浪潮中保持敏捷。
441



被折叠的 条评论
为什么被折叠?



