
IntelliJ IDEA插件开发集成Nanbeige 4.1-3B实现智能代码补全作为一名和代码打了十几年交道的开发者我深知在IDE里写代码时那种“下一行该写什么”的短暂停顿有多频繁。传统的代码补全基于静态分析虽然准确但缺乏对开发者意图的“理解”。最近我尝试将本地部署的Nanbeige 4.1-3B大模型集成到IntelliJ IDEA中做了一个实验性的智能代码助手插件。效果出乎意料它不仅能根据上下文给出更“聪明”的补全建议甚至能把自然语言注释直接变成代码。今天我就把这个从零到一的实践过程分享给你看看如何给你的IDE装上“大脑”。1. 为什么要在IDE里集成大模型在开始动手之前你可能会有疑问现有的代码补全工具比如IDEA自带的已经很好用了为什么还要折腾大模型简单来说这是两种不同的思路。传统的补全工具就像一个记忆力超群的图书管理员它能快速告诉你这个类有哪些方法、这个方法需要什么参数这些都是基于已有的、确定的代码库。而集成大模型更像是请了一位经验丰富的编程搭档坐在你旁边。它不仅能“回忆”还能“推理”和“创造”。举个例子当你写下// 读取配置文件并解析为Map这样一行注释时传统的工具无能为力。但大模型能理解你的意图并生成一段符合当前项目风格的、包含异常处理的Properties读取代码。再比如你写了一个复杂的循环大模型可能会在旁边提示“这段逻辑可以用Stream API重构更简洁。” 它补全的不仅仅是符号更是思路和解决方案。对于Java开发者而言将类似Nanbeige 4.1-3B这样的轻量级模型部署在本地通过插件与IDEA集成既能享受AI辅助编程的高效又能保证代码的私密性不用担心敏感业务逻辑上传到云端。接下来我们就一步步实现它。2. 准备工作模型部署与插件工程创建这个项目主要分为两大部分一是让大模型跑起来并提供API服务二是开发IDEA插件去调用这个服务。我们先搞定模型服务端。2.1 本地部署Nanbeige 4.1-3B API服务Nanbeige 4.1-3B是一个对中文和代码都支持不错的轻量级模型非常适合在本地机器上运行。部署方式有很多这里我选择用流行的text-generation-webuiOobabooga来快速搭建一个API服务。首先你需要准备好Python环境建议3.10以上和足够的显存8G以上跑量化版比较流畅。然后克隆项目并安装依赖git clone https://github.com/oobabooga/text-generation-webui cd text-generation-webui pip install -r requirements.txt接下来下载Nanbeige 4.1-3B的模型文件。你可以在ModelScope或Hugging Face上找到它。我使用的是Nanbeige/Nanbeige-4.1-3B-Base这个基础版本。将下载的模型文件放在text-generation-webui/models目录下。启动WebUI服务并启用API模式python server.py --model Nanbeige-4.1-3B-Base --api --listen--api参数会开启一个兼容OpenAI格式的API端点默认在http://localhost:5000/v1--listen允许本地网络访问。看到服务成功启动的日志后你可以先用curl测试一下curl http://localhost:5000/v1/completions \ -H Content-Type: application/json \ -d { model: Nanbeige-4.1-3B-Base, prompt: // 用Java写一个Hello World, max_tokens: 100 }如果返回了一段Java代码恭喜你模型服务已经就绪了。我们的插件后续就会向http://localhost:5000/v1/completions这个地址发送请求。2.2 创建IntelliJ IDEA插件项目打开IntelliJ IDEA社区版即可选择New Project。在左侧找到IntelliJ Platform Plugin这是开发IDEA插件的官方模板。输入项目名称比如SmartCodeAssist选择JDK 17或以上版本点击创建。项目创建好后你会看到一个标准的插件工程结构。核心配置文件是src/main/resources/META-INF/plugin.xml这里定义了插件的基本信息、依赖和扩展点。我们稍后会修改它。为了让插件能进行网络通信我们需要在build.gradle.kts文件的dependencies块中添加一个HTTP客户端库比如OkHttpdependencies { implementation(com.squareup.okhttp3:okhttp:4.12.0) }同步一下Gradle项目准备工作就完成了。现在我们有了一个能对话的本地大模型和一个空的插件骨架。接下来就是把它们连接起来。3. 核心功能实现让插件“聪明”起来我们的插件计划实现三个核心功能智能代码补全、注释生成代码、代码检查与重构建议。我们一个一个来构建。3.1 构建与大模型通信的服务层首先创建一个类来处理所有与本地模型API的交互。这个类负责构造请求、发送HTTP调用、解析响应。在src/main/kotlin目录下如果你用Java就放在java目录新建一个com.yourcompany.service包然后创建AICodeService.kt文件package com.yourcompany.service import com.intellij.openapi.diagnostic.Logger import okhttp3.* import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONObject import java.io.IOException import java.util.concurrent.TimeUnit class AICodeService { private val client OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) // 模型生成可能需要时间 .build() private val logger Logger.getInstance(AICodeService::class.java) private val apiUrl http://localhost:5000/v1/completions // 你的模型服务地址 private val jsonMediaType application/json; charsetutf-8.toMediaType() /** * 向大模型发送代码相关的提示获取补全或建议 * param prompt 构造好的提示词包含代码上下文和任务描述 * return 模型返回的文本内容失败时返回null */ fun getCodeSuggestion(prompt: String): String? { val requestBody JSONObject().apply { put(model, Nanbeige-4.1-3B-Base) put(prompt, prompt) put(max_tokens, 256) // 根据需求调整 put(temperature, 0.2) // 低温度让输出更确定、更贴近代码风格 put(stop, listOf(\n\n, )) // 设置停止词避免生成过多无关内容 }.toString() val request Request.Builder() .url(apiUrl) .post(requestBody.toRequestBody(jsonMediaType)) .build() return try { client.newCall(request).execute().use { response - if (!response.isSuccessful) { logger.warn(API请求失败: ${response.code} - ${response.message}) return null } val responseBody response.body?.string() val jsonResponse JSONObject(responseBody) // 解析OpenAI兼容格式的响应 jsonResponse.getJSONArray(choices) .getJSONObject(0) .getString(text) .trim() } } catch (e: IOException) { logger.error(网络通信异常, e) null } catch (e: Exception) { logger.error(解析响应异常, e) null } } }这个服务类是整个插件的“发动机”。它使用OkHttp以同步方式调用我们本地部署的API。这里设置了较长的超时时间因为模型推理可能需要几十秒。temperature参数调低是为了让生成的代码更稳定、更少“天马行空”。3.2 实现上下文感知的智能补全IDEA的代码补全功能是通过实现CompletionContributor类来扩展的。我们需要创建一个贡献者在用户输入时不仅提供传统的基于索引的补全项还能提供来自AI的智能建议。在src/main/kotlin下创建com.yourcompany.completion包新建AICodeCompletionContributor.ktpackage com.yourcompany.completion import com.intellij.codeInsight.completion.* import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.editor.Editor import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiFile import com.yourcompany.service.AICodeService import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.Task class AICodeCompletionContributor : CompletionContributor() { private val aiService AICodeService() init { // 扩展Java文件的代码补全 extend(CompletionType.BASIC, PlatformPatterns.psiElement().inFile(PlatformPatterns.psiFile().withLanguage(com.intellij.lang.java.JavaLanguage.INSTANCE)), object : CompletionProviderCompletionParameters() { override fun addCompletions( parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet ) { // 1. 首先仍然添加IDEA原有的基础补全这行代码保证了传统补全不丢失 // 这里我们主要添加AI补全所以先不干扰原有流程 // 2. 在后台线程中获取AI建议避免阻塞UI val editor parameters.editor val file parameters.originalFile val offset parameters.offset ProgressManager.getInstance().run(object : Task.Backgroundable(parameters.editor.project, 获取AI代码建议, true) { override fun run(indicator: ProgressIndicator) { indicator.isIndeterminate true // 构建提示词获取当前文件内容、光标前的一段代码作为上下文 val document editor.document val fileText document.text // 取光标前200个字符作为上下文避免提示词过长 val contextStart maxOf(0, offset - 200) val codeContext fileText.substring(contextStart, offset) val prompt 你是一个资深的Java开发助手。请根据以下代码上下文推测开发者接下来最可能想输入的一行或几行代码。 只返回代码片段不要有任何解释。 上下文代码 $codeContext 建议的后续代码 .trimIndent() val suggestion aiService.getCodeSuggestion(prompt) // 3. 回到UI线程将AI建议添加到补全结果中 ApplicationManager.getApplication().invokeLater { suggestion?.let { // 对建议进行简单清理如去除多余的空行、引号 val cleanSuggestion it.trim().removeSurrounding(\, \) if (cleanSuggestion.isNotBlank()) { // 创建一个特殊的LookupElement可以加个图标或前缀区分 val aiLookupItem LookupElementBuilder.create(cleanSuggestion) .withIcon(com.intellij.icons.AllIcons.Actions.SmartBulb) // 使用灯泡图标 .withTypeText(AI建议, true) // 在右侧显示类型提示 .withInsertHandler { context, _ - // 当用户选择此项时执行插入操作 context.document.replaceString(context.selectionStart, context.selectionEnd, cleanSuggestion) } result.addElement(aiLookupItem) } } } } }) } }) } }这段代码做了几件事首先它只在Java文件中触发。当用户输入时它在后台异步地获取光标前的一段代码构造一个清晰的提示词发送给大模型。拿到模型的代码建议后再回到UI线程将这个建议作为一个特殊的补全项带有一个灯泡图标和“AI建议”标签添加到补全列表中。这样用户在按CtrlSpace时就能在传统补全项下面看到AI给出的“智能”选项了。3.3 实现“注释生成代码”的快捷操作这个功能更主动一些用户选中一行自然语言注释然后通过一个快捷键或右键菜单让AI将其转换为代码。我们先创建一个动作Action。在src/main/kotlin下创建com.yourcompany.actions包新建GenerateCodeFromCommentAction.ktpackage com.yourcompany.actions import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.Task import com.intellij.openapi.ui.Messages import com.yourcompany.service.AICodeService class GenerateCodeFromCommentAction : AnAction(根据注释生成代码) { private val logger Logger.getInstance(GenerateCodeFromCommentAction::class.java) private val aiService AICodeService() override fun actionPerformed(e: AnActionEvent) { val project e.project ?: return val editor e.getData(CommonDataKeys.EDITOR) ?: return val document editor.document val selectionModel editor.selectionModel val selectedText selectionModel.selectedText if (selectedText.isNullOrBlank() || !selectedText.trim().startsWith(//)) { Messages.showInfoMessage(project, 请选中一行以//开头的注释文本。, 提示) return } val comment selectedText.trim().removePrefix(//).trim() ProgressManager.getInstance().run(object : Task.Backgroundable(project, 正在生成代码..., true) { private var generatedCode: String? null override fun run(indicator: ProgressIndicator) { indicator.isIndeterminate true indicator.text 正在请求AI模型... // 构建更详细的提示词可以加入当前类名或方法名来提升相关性 val fileName e.getData(CommonDataKeys.PSI_FILE)?.name ?: 当前类 val prompt 你是一个Java编程专家。请将以下自然语言需求转化为简洁、规范、可运行的Java代码片段。 需求描述$comment 请只返回代码不要有任何额外的解释、注释或Markdown标记。假设代码将插入到文件 $fileName 中。 生成的Java代码 .trimIndent() generatedCode aiService.getCodeSuggestion(prompt) } override fun onSuccess() { val code generatedCode if (code.isNullOrBlank()) { Messages.showErrorDialog(project, 生成代码失败请检查模型服务或网络。, 错误) return } // 在UI线程中执行文档修改 WriteCommandAction.runWriteCommandAction(project) { // 用生成的代码替换选中的注释 document.replaceString(selectionModel.selectionStart, selectionModel.selectionEnd, code) Messages.showInfoMessage(project, 代码已生成并替换注释。, 完成) } } override fun onThrowable(error: Throwable) { logger.error(生成代码过程中出错, error) Messages.showErrorDialog(project, 生成过程中发生错误${error.message}, 错误) } }) } // 可选控制该动作何时显示仅当选中了注释文本时 override fun update(e: AnActionEvent) { val editor e.getData(CommonDataKeys.EDITOR) val selectedText editor?.selectionModel?.selectedText e.presentation.isEnabledAndVisible editor ! null selectedText ! null selectedText.trim().startsWith(//) } }然后我们需要在plugin.xml中注册这个动作并为其绑定一个快捷键比如Alt Gactions action idSmartCodeAssist.GenerateFromComment classcom.yourcompany.actions.GenerateCodeFromCommentAction text根据注释生成代码 description将选中的自然语言注释转换为Java代码 add-to-group group-idEditorPopupMenu anchorfirst/ !-- 添加到编辑器右键菜单 -- keyboard-shortcut keymap$default first-keystrokealt G/ /action /actions现在当你在Java文件中写下一行// 读取用户列表并从数据库查询详细信息这样的注释选中它按下AltG或者从右键菜单选择插件就会在后台请求模型并将生成的类似ListUser users userRepository.findAllById(userIds);的代码替换掉原来的注释。这个过程是异步的不会卡住IDE。4. 进阶功能与优化思路实现了基础功能后我们可以思考如何让它更好用、更智能。这里分享几个我实践过的进阶方向。4.1 代码异味检测与重构建议除了生成代码大模型在理解代码逻辑后也能给出改进建议。我们可以创建一个代码检查工具Inspection在后台分析当前方法或类并给出建议。思路是定期或在用户显式触发时将当前聚焦的代码片段发送给模型提示词可以设计为“分析以下Java代码指出可能存在的代码异味如过长方法、重复代码、复杂条件判断等并给出具体的重构建议。只返回问题和建议不要代码。”然后我们可以利用IDEA的Annotator或Highlighting机制将模型返回的建议以“弱警告”或信息提示的形式展示在代码的侧边栏或下方就像IDE自带的代码分析一样。4.2 提升提示词Prompt质量模型输出的质量极大程度上取决于输入提示词的质量。针对代码补全场景我们可以优化提示词工程提供更多上下文不仅包括光标前的代码还可以包含当前方法的签名、类的成员变量、甚至同一文件中导入的类帮助模型更好地理解“语境”。指定代码风格在提示词中明确要求“遵循阿里巴巴Java开发规范”或“使用Guava风格的工具类”让生成的代码更符合项目规范。分步骤思考Chain-of-Thought对于复杂任务可以要求模型“先解释思路再输出代码”虽然我们只取代码部分但这个过程能提高最终代码的准确性。4.3 性能与用户体验优化本地模型推理毕竟需要时间为了不让开发者感到明显的卡顿优化至关重要缓存机制对相似的代码上下文和提示词缓存模型的返回结果。短时间内重复的补全请求可以直接使用缓存。延迟触发与防抖不要每次按键都请求AI补全。可以设置一个延迟比如停止输入500ms后或者仅在输入特定触发字符如.、空格后才去获取AI建议。后台低优先级任务将模型调用放在低优先级的后台线程中绝不能阻塞UI线程。就像我们上面用Task.Backgroundable做的那样。提供取消选项如果生成时间过长应该在界面上提供一个取消按钮。5. 总结把Nanbeige 4.1-3B这样的本地大模型集成到IntelliJ IDEA里做一个私密的智能编程助手这件事的可行性比想象中要高。整个过程走下来技术难点并不在于模型本身或插件开发框架而在于如何设计好“人机交互”的流程以及如何用高质量的提示词让模型发挥出最佳水平。我自己的使用感受是对于模板化的代码、基于注释的代码生成、以及一些简单的逻辑建议这个插件的帮助非常直接能省去不少查阅文档和重复敲击的时间。当然它还不是万能的复杂的业务逻辑和算法实现仍然需要开发者自己把握。但作为一个“副驾驶”它已经能提供不少有价值的参考和灵感。如果你也想尝试可以从最基础的“注释生成代码”功能开始感受一下AI辅助编程的潜力。随着模型能力的持续进化以及我们对提示词和交互方式的不断打磨这类工具很可能在未来成为每个开发者的标配。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。