通义千问1.5-1.8B-Chat-GPTQ-Int4在VSCode中的插件开发指南

1. 开篇:为什么要在VSCode里集成AI模型?

如果你是个开发者,可能经常在写代码、写文档、调试程序的时候,希望有个智能助手在旁边帮忙。比如写代码时想要自动补全注释,写文档时需要润色文字,或者调试时想要智能分析错误日志。

把通义千问这样的AI模型集成到VSCode里,就能让这些想法变成现实。你不需要每次都去打开网页或者调用其他工具,直接在熟悉的开发环境里就能获得AI辅助。今天我就带你一步步实现这个功能,用最直接的方式把通义千问1.5-1.8B-Chat-GPTQ-Int4模型装进VSCode。

这个教程特别适合已经有一定全栈开发经验的程序员,不需要你之前做过VSCode插件开发,只要会JavaScript/TypeScript基础就能跟着做下来。我们会从最简单的插件结构开始,逐步添加AI功能,最后做出一个真正可用的智能编程助手。

2. 环境准备与项目搭建

2.1 安装必备工具

首先确保你的电脑上已经装好了这些基础工具:

  • Node.js (版本16.x或以上)
  • VSCode (最新稳定版)
  • Git (用于版本控制)

打开终端,用这个命令安装Yeoman和VSCode插件生成器:

npm install -g yo generator-code

2.2 创建新插件项目

在你想存放项目的目录下,运行以下命令:

yo code

这时候会出现交互式命令行界面,按顺序选择这些选项:

  1. New Extension (TypeScript) - 选择TypeScript版本
  2. 输入你的插件名称,比如 qianwen-helper
  3. 输入一个唯一的标识符,比如 qianwen-helper
  4. 输入简单的描述,比如 "通义千问AI编程助手"
  5. 是否初始化Git仓库,选择Yes
  6. 包管理器选择npm

等待几分钟,基础项目就生成好了。用VSCode打开这个新创建的项目文件夹,你会看到这样的目录结构:

qianwen-helper/
├── src/
│   └── extension.ts    # 插件主入口文件
├── package.json        # 插件配置和依赖
├── tsconfig.json       # TypeScript配置
└── README.md

2.3 安装通义千问相关依赖

在项目根目录下,运行这些命令来安装需要的依赖包:

npm install @alibaba-cloud/qianwen
npm install --save-dev @types/vscode

第一个包是阿里云官方的通义千问SDK,第二个是VSCode的TypeScript类型定义,这样我们写代码时能有更好的智能提示。

3. 插件基础架构搭建

3.1 理解VSCode插件的基本结构

打开 src/extension.ts 文件,你会看到默认生成的代码。这是每个VSCode插件的起点,主要包含两个部分:

  1. activate 函数 - 插件激活时执行
  2. deactivate 函数 - 插件关闭时执行

我们先来修改这个文件,建立一个简单但完整的基础架构:

import * as vscode from 'vscode';
import { QianWen } from '@alibaba-cloud/qianwen';

let qianwenClient: QianWen | null = null;

export function activate(context: vscode.ExtensionContext) {
    console.log('通义千问插件已激活');
    
    // 初始化通义千问客户端
    const config = vscode.workspace.getConfiguration('qianwen');
    const apiKey = config.get<string>('apiKey');
    
    if (apiKey) {
        qianwenClient = new QianWen({
            apiKey: apiKey
        });
    }
    
    // 注册命令
    const disposable = vscode.commands.registerCommand('qianwen-helper.askAI', async () => {
        if (!qianwenClient) {
            vscode.window.showErrorMessage('请先设置通义千问API密钥');
            return;
        }
        
        // 这里以后会添加AI调用逻辑
        vscode.window.showInformationMessage('AI功能准备就绪');
    });
    
    context.subscriptions.push(disposable);
}

export function deactivate() {
    if (qianwenClient) {
        // 清理资源
        qianwenClient = null;
    }
}

3.2 配置插件功能

现在打开 package.json 文件,这是VSCode插件的配置文件。我们需要修改几个关键部分:

首先在 contributes 部分添加命令定义:

"contributes": {
    "commands": [
        {
            "command": "qianwen-helper.askAI",
            "title": "向通义千问提问",
            "category": "AI助手"
        }
    ],
    "configuration": {
        "title": "通义千问配置",
        "properties": {
            "qianwen.apiKey": {
                "type": "string",
                "default": "",
                "description": "通义千问API密钥"
            }
        }
    }
}

然后在 activationEvents 部分确保插件能正确激活:

"activationEvents": [
    "onCommand:qianwen-helper.askAI"
]

这样我们就建立了一个最基础的插件框架,接下来就可以开始添加真正的AI功能了。

4. 集成通义千问模型

4.1 实现基本的AI对话功能

现在我们来添加核心的AI功能。修改 extension.ts 文件中的命令处理逻辑:

const disposable = vscode.commands.registerCommand('qianwen-helper.askAI', async () => {
    if (!qianwenClient) {
        vscode.window.showErrorMessage('请先设置通义千问API密钥');
        return;
    }
    
    // 获取用户当前选中的文本
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        vscode.window.showWarningMessage('请先打开一个文件并选中一些文本');
        return;
    }
    
    const selection = editor.selection;
    const selectedText = editor.document.getText(selection);
    
    if (!selectedText.trim()) {
        vscode.window.showWarningMessage('请先选中一些文本作为问题');
        return;
    }
    
    // 显示进度提示
    vscode.window.withProgress({
        location: vscode.ProgressLocation.Notification,
        title: "通义千问思考中...",
        cancellable: false
    }, async (progress) => {
        try {
            // 调用通义千问API
            const response = await qianwenClient!.chat({
                model: "qwen-1.8b-chat",
                messages: [
                    {
                        role: "user",
                        content: selectedText
                    }
                ]
            });
            
            // 显示AI回复
            const aiResponse = response.output.choices[0].message.content;
            vscode.window.showInformationMessage(aiResponse);
            
        } catch (error) {
            vscode.window.showErrorMessage(`调用AI失败: ${error.message}`);
        }
    });
});

4.2 添加设置界面

为了让用户方便地配置API密钥,我们添加一个设置界面。在 package.json 中添加配置项:

"contributes": {
    "configuration": {
        "title": "通义千问配置",
        "properties": {
            "qianwen.apiKey": {
                "type": "string",
                "default": "",
                "description": "通义千问API密钥",
                "scope": "application"
            },
            "qianwen.model": {
                "type": "string",
                "default": "qwen-1.8b-chat",
                "description": "使用的模型版本",
                "scope": "application"
            }
        }
    }
}

然后在插件激活时读取这些配置:

const config = vscode.workspace.getConfiguration('qianwen');
const apiKey = config.get<string>('apiKey');
const modelName = config.get<string>('model') || 'qwen-1.8b-chat';

if (apiKey) {
    qianwenClient = new QianWen({
        apiKey: apiKey
    });
}

用户现在可以在VSCode的设置界面(Ctrl+,)中搜索"通义千问"来配置这些参数了。

5. 设计用户界面

5.1 创建Webview面板

简单的消息提示不够用,我们来创建一个完整的聊天界面。首先在 src 目录下创建 webview 文件夹,然后添加 aiPanel.ts

import * as vscode from 'vscode';
import { QianWen } from '@alibaba-cloud/qianwen';

export class AIPanel {
    public static currentPanel: AIPanel | undefined;
    private readonly _panel: vscode.WebviewPanel;
    private readonly _extensionUri: vscode.Uri;
    private _disposables: vscode.Disposable[] = [];
    private _qianwenClient: QianWen;

    private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri, qianwenClient: QianWen) {
        this._panel = panel;
        this._extensionUri = extensionUri;
        this._qianwenClient = qianwenClient;
        
        this._update();
        this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
    }

    public static createOrShow(extensionUri: vscode.Uri, qianwenClient: QianWen) {
        const column = vscode.window.activeTextEditor?.viewColumn;
        
        if (AIPanel.currentPanel) {
            AIPanel.currentPanel._panel.reveal(column);
            return;
        }
        
        const panel = vscode.window.createWebviewPanel(
            'qianwenChat',
            '通义千问助手',
            column || vscode.ViewColumn.One,
            {
                enableScripts: true,
                localResourceRoots: [extensionUri]
            }
        );
        
        AIPanel.currentPanel = new AIPanel(panel, extensionUri, qianwenClient);
    }

    private async _update() {
        const webview = this._panel.webview;
        this._panel.webview.html = this._getHtmlForWebview(webview);
    }

    private _getHtmlForWebview(webview: vscode.Webview): string {
        return `
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>通义千问助手</title>
            <style>
                body { padding: 10px; font-family: var(--vscode-font-family); }
                .chat-container { max-width: 100%; margin: 0 auto; }
                .message { margin: 10px 0; padding: 10px; border-radius: 5px; }
                .user { background: var(--vscode-input-background); text-align: right; }
                .ai { background: var(--vscode-badge-background); }
                input, button { 
                    padding: 8px; 
                    margin: 5px 0; 
                    border: 1px solid var(--vscode-input-border);
                    background: var(--vscode-input-background);
                    color: var(--vscode-input-foreground);
                }
                button { cursor: pointer; }
            </style>
        </head>
        <body>
            <div class="chat-container">
                <div id="chatMessages"></div>
                <div>
                    <input type="text" id="userInput" placeholder="输入你的问题..." />
                    <button onclick="sendMessage()">发送</button>
                </div>
            </div>
            
            <script>
                function sendMessage() {
                    const input = document.getElementById('userInput');
                    const message = input.value.trim();
                    if (message) {
                        addMessage('user', message);
                        input.value = '';
                        
                        // 发送消息到插件主进程
                        vscode.postMessage({
                            type: 'askAI',
                            content: message
                        });
                    }
                }
                
                function addMessage(role, content) {
                    const container = document.getElementById('chatMessages');
                    const messageDiv = document.createElement('div');
                    messageDiv.className = 'message ' + role;
                    messageDiv.textContent = content;
                    container.appendChild(messageDiv);
                    container.scrollTop = container.scrollHeight;
                }
                
                // 处理来自插件主进程的消息
                window.addEventListener('message', event => {
                    const message = event.data;
                    if (message.type === 'aiResponse') {
                        addMessage('ai', message.content);
                    }
                });
            </script>
        </body>
        </html>`;
    }

    public dispose() {
        AIPanel.currentPanel = undefined;
        this._panel.dispose();
        while (this._disposables.length) {
            const x = this._disposables.pop();
            if (x) {
                x.dispose();
            }
        }
    }
}

5.2 连接Webview与AI功能

现在修改主扩展文件来使用这个Webview面板:

import { AIPanel } from './webview/aiPanel';

// 在activate函数中添加
const showAIPanelCommand = vscode.commands.registerCommand('qianwen-helper.showPanel', () => {
    if (!qianwenClient) {
        vscode.window.showErrorMessage('请先设置通义千问API密钥');
        return;
    }
    AIPanel.createOrShow(context.extensionUri, qianwenClient);
});

context.subscriptions.push(showAIPanelCommand);

同时更新 package.json 添加新命令:

"commands": [
    {
        "command": "qianwen-helper.showPanel",
        "title": "打开通义千问聊天面板",
        "category": "AI助手"
    }
]

6. 性能优化与实用技巧

6.1 减少API调用次数

频繁调用API不仅慢,还可能产生额外费用。我们可以添加简单的缓存机制:

class ResponseCache {
    private cache = new Map<string, string>();
    private maxSize = 100;

    get(key: string): string | null {
        return this.cache.get(key) || null;
    }

    set(key: string, value: string) {
        if (this.cache.size >= this.maxSize) {
            const firstKey = this.cache.keys().next().value;
            this.cache.delete(firstKey);
        }
        this.cache.set(key, value);
    }
}

const responseCache = new ResponseCache();

// 在调用API前先检查缓存
const cacheKey = selectedText.trim().toLowerCase();
const cachedResponse = responseCache.get(cacheKey);

if (cachedResponse) {
    vscode.window.showInformationMessage(cachedResponse);
    return;
}

// 没有缓存时才调用API
const response = await qianwenClient!.chat({
    model: modelName,
    messages: [{ role: "user", content: selectedText }]
});

const aiResponse = response.output.choices[0].message.content;
responseCache.set(cacheKey, aiResponse);
vscode.window.showInformationMessage(aiResponse);

6.2 添加上下文感知

让AI理解代码上下文能提供更准确的回答。我们可以自动包含一些上下文信息:

async function getEnhancedPrompt(selectedText: string, editor: vscode.TextEditor): Promise<string> {
    const document = editor.document;
    const languageId = document.languageId; // 如: javascript, python等
    const fileName = document.fileName.split('/').pop() || '';
    
    // 获取当前函数或类的上下文
    const fullText = document.getText();
    const selectionStart = document.offsetAt(editor.selection.start);
    
    return `作为编程助手,请用${languageId}语言回答以下问题。
文件: ${fileName}
问题: ${selectedText}

请提供专业且准确的回答。`;
}

// 使用增强后的提示词
const enhancedPrompt = await getEnhancedPrompt(selectedText, editor);
const response = await qianwenClient!.chat({
    model: modelName,
    messages: [{ role: "user", content: enhancedPrompt }]
});

7. 调试与测试插件

7.1 使用调试模式

按下F5键,VSCode会打开一个新的"扩展开发主机"窗口,在这个窗口里你的插件是激活状态。你可以在这里测试插件的所有功能。

7.2 添加日志输出

为了更好地调试,添加一些日志输出:

const outputChannel = vscode.window.createOutputChannel('通义千问插件');
context.subscriptions.push(outputChannel);

// 在关键位置添加日志
outputChannel.appendLine('插件初始化完成');
outputChannel.appendLine(`使用模型: ${modelName}`);

// 在API调用时
outputChannel.appendLine(`发送请求: ${selectedText}`);
outputChannel.appendLine(`收到响应: ${aiResponse}`);

7.3 处理错误情况

完善错误处理机制:

try {
    const response = await qianwenClient!.chat({
        model: modelName,
        messages: [{ role: "user", content: enhancedPrompt }]
    });
    
    if (response.output.choices && response.output.choices.length > 0) {
        const aiResponse = response.output.choices[0].message.content;
        responseCache.set(cacheKey, aiResponse);
        vscode.window.showInformationMessage(aiResponse);
    } else {
        throw new Error('API返回空响应');
    }
} catch (error) {
    outputChannel.appendLine(`错误详情: ${error.message}`);
    vscode.window.showErrorMessage(`AI请求失败: ${error.message}`);
}

8. 打包与发布

8.1 本地打包插件

安装打包工具:

npm install -g vsce

然后运行打包命令:

vsce package

这会生成一个 .vsix 文件,你可以直接在VSCode中安装这个文件来使用你的插件。

8.2 发布到市场

如果你想把插件发布到VSCode扩展市场,需要:

  1. 创建Azure DevOps账号
  2. 获取Personal Access Token
  3. 运行 vsce publish 命令

不过对于个人使用来说,本地打包安装已经足够了。

9. 实际使用体验

做完这个插件后,我在自己的日常开发中试用了几天,感觉确实挺方便的。最实用的场景是写代码注释和调试错误信息——选中一段代码,让AI生成注释;或者把错误日志扔给AI,让它帮忙分析可能的原因。

响应速度方面,通义千问1.8B模型确实比较轻快,基本上2-3秒内就能返回结果,不会打断编码节奏。准确度对于日常编程问题也够用了,特别是代码相关的问题回答得都挺靠谱。

有个小建议是,刚开始用的时候最好先从小范围的简单问题开始,慢慢熟悉AI的能力边界。比如先让它生成简单的函数注释,再逐步尝试更复杂的代码优化建议。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐