ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零实现VS Code AI面试模拟插件:粘贴JD即可模拟面试

从零实现VS Code AI面试模拟插件:粘贴JD即可模拟面试 很多人都有过这样的场景刷到一家心仪公司的招聘 JD看完岗位要求后心里没底不知道对方会问什么也不知道自己离岗位要求还差多远。市面上的刷题平台题目很多但大多是通用题库和具体公司、具体岗位的职责匹配度并不高。如果能直接把招聘 JD 粘贴到我们每天应用的 IDE 里让 AI 基于岗位要求生成一套面试题并模拟面试官提问、追问、点评整个过程就能在几分钟内完成。这个思路听起来很“科幻”但落地并不复杂。本质上就是把“招聘 JD 文本解析”和“大模型对话生成”组合成一个 IDE 插件。本文会从需求拆解、核心模块、完整代码、运行验证和常见排查几个方面带你从零实现一个名为 AI Interview Coach 的 VS Code 扩展。它让你在编辑器里选中一段 JD两分钟左右就能开始一场贴合该岗位的模拟面试。这篇文章适合两类人一类是准备面试、想做针对性练习的开发者另一类是对 IDE 插件开发和大模型应用集成感兴趣的工程师。读完你会掌握 VS Code 扩展的基本骨架、JD 文本结构化解析的思路、 OpenAI 兼容接口的调用方式以及如何在 Webview 中实现一个交互式面试面板。1. 背景为什么要做一个“粘贴 JD 就能面试”的 IDE 工具1.1 从招聘 JD 到模拟面试的需求拆解招聘 JD 信息密度很高通常包含岗位名称、公司名称、工作地点、职责描述、任职要求、加分项、薪资范围等。这些信息对候选人来说是了解岗位的入口对 AI 面试模拟工具来说则是生成面试题的“输入特征”。举个例子一份 Java 后端 JD 里频繁出现 Spring Boot、MySQL、Redis、Kafka、分布式事务等关键词那么面试题就应该围绕这些技术点展开。而如果一份 JD 强调“负责系统架构设计”“主导过大型项目重构”题目就应该偏向系统设计、技术选型和代码质量把控。过去我们准备面试需要自己阅读 JD、拆解技术栈、查阅高频面经、再整理答案整个过程可能要花几个小时。而 IDE 里的智能工具可以做三件事自动解析 JD 中的职位、公司、技术栈、职责等关键字段。把解析结果转换为结构化的面试题生成提示词。通过大模型生成一套有层次、有追问、有评分的面试题并通过 Webview 面板在 IDE 内呈现。这不是替候选人作弊而是帮助候选人在真实面试前进行“模拟练习”。就像运动员训练前会先研究对手录像一样这套工具的本质是把准备过程自动化。1.2 IDE 作为面试模拟工具载体的优势很多人会问为什么非要做成 IDE 插件而不是做一个网页应用这里有几个很实际的原因。第一开发者每天最常待的环境就是 IDE。把面试模拟入口放到编辑器右键菜单里使用路径非常短。你正在看一段代码突然想了解一下某家公司后端岗位会考什么选中 JD 文本右键启动马上就能进入面试状态。第二IDE 插件可以读取本地上下文。比如你可以选中当前项目中的某个类文件内容结合 JD 一起发给 AI让它生成更具针对性的代码审查或系统设计问题。这种“基于真实代码的面试模拟”是网页工具很难做到的。第三Webview 面板可以在 VS Code 内提供一个完整的富交互界面不需要额外打开浏览器窗口。题目的展示、答案的输入、评分的反馈都能在一个界面内完成。1.3 涉及的核心技术栈实现这个工具涉及以下关键技术点VS Code 扩展开发package.json 中的 contributes 配置命令注册右键菜单配置项。TypeScriptVS Code 扩展官方推荐的开发语言。文本解析使用正则表达式和简单规则从 JD 中提取结构化字段。大模型 API以 OpenAI 兼容接口为例实现 chat/completions 调用。Webview 前端使用 HTML/CSS/JavaScript 构建交互式面试面板。环境变量与配置管理API Key 通过环境变量或 VS Code 配置项加载避免硬编码。整体流程可以概括为用户选中 JD 文本 → 插件解析 JD → 拼接 Prompt → 请求大模型 → 渲染面试题 → 用户作答 → 大模型点评。2. 环境准备与项目结构2.1 开发环境说明开始写代码之前先明确环境要求。由于 VS Code 扩展运行在 Node.js 环境中你的电脑需要准备Node.js 18 或更高版本建议使用 20 LTS。Visual Studio Code 1.85 或更高版本。TypeScript 5.x。一个支持 OpenAI 兼容接口的大模型 API或者本地部署的模型服务。版本需要根据你的实际环境调整本文示例以常见的 VS Code 扩展开发环境为例重点演示整体设计思路。如果本地 Node 版本较低建议先升级。2.2 初始化项目打开终端创建一个项目目录mkdir ai-interview-coach cd ai-interview-coach npm init -y安装 TypeScript 和 VS Code 扩展类型声明npm install --save-dev typescript types/vscode types/node创建tsconfig.json文件{ compilerOptions: { module: Node16, target: ES2022, outDir: dist, rootDir: src, strict: true, esModuleInterop: true, skipLibCheck: true }, include: [src], exclude: [node_modules, .vscode-test] }这里把编译输出目录设置为dist源码放在src目录。VS Code 扩展的主入口文件是dist/extension.js。2.3 项目目录结构我建议按照下面的结构组织代码职责比较清晰ai-interview-coach/ ├── package.json ├── tsconfig.json ├── src/ │ ├── extension.ts # 插件激活入口注册命令 │ ├── jdParser.ts # JD 文本解析为结构化数据 │ ├── llmClient.ts # 大模型 API 客户端 │ ├── promptBuilder.ts # 提示词构建器 │ ├── interviewPanel.ts # Webview 面试面板 │ └── types.ts # 公共类型定义 ├── media/ │ └── interview.css # Webview 样式可选 └── .vscode/ └── launch.json # VS Code 调试配置extension.ts是插件入口负责注册命令和生命周期jdParser.ts负责把 JD 原始文本变成结构化对象llmClient.ts是所有大模型调用的统一出口promptBuilder.ts负责构造提示词interviewPanel.ts负责创建和渲染 Webview 面板。3. 核心模块设计3.1 JD 解析模块从文本到结构化字段JD 解析是整个流程的第一步也是最容易被忽略的一步。很多人会直接把整段 JD 文本拼到提示词里发给大模型这样当然也能工作但解析成结构化数据后有几个好处可以单独对技术栈做统计比如 JD 中出现多少种框架。可以筛选无用信息避免 JD 中大量公司介绍、福利描述干扰题目生成。可以在 UI 上展示解析结果让用户确认 AI 理解的岗位画像是否准确。解析器的核心思路非常简单先用正则匹配公司、职位、地点等常见字段再通过一组关键词从句子中划分“岗位职责”和“任职要求”最后从文本中匹配出技术关键字列表。// 文件路径src/jdParser.ts export interface ParsedJD { companyName: string; position: string; locations: string[]; skills: string[]; responsibilities: string[]; requirements: string[]; seniority: string; rawText: string; } export function parseJD(rawText: string): ParsedJD { const parsed: ParsedJD { companyName: , position: , locations: [], skills: [], responsibilities: [], requirements: [], seniority: , rawText, }; const companyMatch rawText.match(/(?:公司|company)[:\s]*([^\n])/i); if (companyMatch) { parsed.companyName companyMatch[1].trim(); } const positionMatch rawText.match(/(?:职位|岗位|position)[:\s]*([^\n])/i); if (positionMatch) { parsed.position positionMatch[1].trim(); } const locationMatch rawText.match(/(?:工作地点|办公地点|地点)[:\s]*([^\n])/i); if (locationMatch) { parsed.locations locationMatch[1].split(/[,、]/).map(s s.trim()).filter(Boolean); } const techKeywords [ Java, Python, Spring, MySQL, Redis, Kubernetes, Docker, React, Vue, TypeScript, Node.js, Go, Kafka, Flink, Hadoop, Spark, Nginx, RabbitMQ ]; for (const keyword of techKeywords) { if (rawText.includes(keyword)) { parsed.skills.push(keyword); } } const sentenceArray rawText.match(/[^。\n][。\n]?/g) ?? []; for (const sentence of sentenceArray) { const s sentence.trim(); if (!s || s.length 200) { continue; } if (/负责|参与|主导|设计|开发|优化|维护|保证|推动|配合|支持/.test(s)) { parsed.responsibilities.push(s); } if (/熟悉|掌握|精通|了解|具备|要求|优先|学历|经验|能力/.test(s)) { parsed.requirements.push(s); } } const seniorityMatch rawText.match(/(\d[-~至]\d年|\d年以上|应届|实习|初级|中级|高级|专家|架构师)/); if (seniorityMatch) { parsed.seniority seniorityMatch[1]; } return parsed; }这个实现只用了正则和关键词判断没有引入复杂的 NLP 依赖足以覆盖大多数中文招聘 JD。如果遇到英文 JD可以把关键词列表扩展为英文形式规则完全相同。3.2 大模型调用模块统一 OpenAI 兼容接口大模型客户端的核心设计是“面向接口编程”。不同厂商的模型服务差异很大但多数兼容 OpenAI 的/v1/chat/completions接口格式。我们只需要实现一个chatCompletion函数接收模型名称、消息列表和参数返回生成的文本内容。// 文件路径src/llmClient.ts export interface ChatMessage { role: system | user | assistant; content: string; } export interface ChatCompletionOptions { baseUrl: string; apiKey: string; model: string; messages: ChatMessage[]; temperature?: number; maxTokens?: number; } export async function chatCompletion(options: ChatCompletionOptions): Promisestring { const url options.baseUrl.replace(/\/$/, ) /chat/completions; const body JSON.stringify({ model: options.model, messages: options.messages, temperature: options.temperature ?? 0.7, max_tokens: options.maxTokens ?? 2048, stream: false, }); const controller new AbortController(); const timeout setTimeout(() controller.abort(), 60000); try { const response await fetch(url, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${options.apiKey}, }, body, signal: controller.signal, }); if (!response.ok) { const text await response.text(); throw new Error(LLM request failed: ${response.status} ${text}); } const data (await response.json()) as any; const content data?.choices?.[0]?.message?.content ?? ; return content.trim(); } finally { clearTimeout(timeout); } }这个函数有几个值得注意的点使用controller和timeout做 60 秒超时控制避免模型响应过慢阻塞插件。通过response.ok判断 HTTP 状态码失败时把响应体文本带出方便排查。把baseUrl处理成可配置项用户既可以使用云服务也可以配置到本地模型服务。3.3 提示词构建让大模型扮演面试官提示词直接决定面试题的质量。为了让生成结果符合“模拟面试”场景系统提示词需要包含角色设定、出题规则、输出格式约束三个部分。// 文件路径src/promptBuilder.ts import { ChatMessage, ParsedJD } from ./types; export function buildInterviewPrompt(parsed: ParsedJD): ChatMessage[] { const systemPrompt 你是一名经验丰富的技术面试官现在代表招聘方对候选人进行模拟面试。 要求 1. 根据 JD 信息设计 5 道面试题2 道基础题、2 道进阶题、1 道系统设计题。 2. 每道题先询问候选人不要一次性展示所有题目。 3. 候选人回答后给出专业点评和 0-10 分的打分。 4. 如果候选人回答模糊可以追问一次。 5. 语气专业、客观、有耐心不要评价候选人的人格。; const userContent 以下是该职位的 JD 解析结果 岗位名称${parsed.position || 未知} 公司名称${parsed.companyName || 未知} 工作地点${parsed.locations.join(, ) || 未知} 级别要求${parsed.seniority || 未知} 技术栈${parsed.skills.join(, ) || 未知} 岗位职责 ${parsed.responsibilities.map((item, index) ${index 1}. ${item}).join(\n) || 无} 任职要求 ${parsed.requirements.map((item, index) ${index 1}. ${item}).join(\n) || 无} 请先用一段话欢迎候选人并介绍面试流程然后开始出第一道题。; return [ { role: system, content: systemPrompt }, { role: user, content: userContent }, ]; }你可能注意到这里没有让 AI 一次性生成全部题目而是要求先出第一道题。这是模拟真实面试体验的关键。如果所有题目一次性展示用户就没有“临场作答”的感觉。后续用户提交答案后插件会再把答案追加到消息列表里继续请求模型生成点评和下一题。4. 完整实战在 VS Code 里实现 AI 面试模拟插件4.1 编写 package.json 插件配置VS Code 扩展的package.json不只是 npm 包描述更是插件注册表。命令、菜单、配置项都定义在这里。{ name: ai-interview-coach, displayName: AI Interview Coach, description: Paste a job posting, start a mock interview in your IDE, version: 0.1.0, publisher: your-name, engines: { vscode: ^1.85.0 }, categories: [Other], main: ./dist/extension.js, contributes: { commands: [ { command: aiInterviewCoach.start, title: AI Interview: Start Mock Interview } ], menus: { editor/context: [ { command: aiInterviewCoach.start, group: ai-interview } ] }, configuration: { title: AI Interview Coach, properties: { aiInterviewCoach.baseUrl: { type: string, default: https://api.openai.com/v1, description: OpenAI 兼容接口的 Base URL }, aiInterviewCoach.apiKeyEnv: { type: string, default: OPENAI_API_KEY, description: 存放 API Key 的环境变量名 }, aiInterviewCoach.model: { type: string, default: gpt-4o-mini, description: 使用的模型名称 } } } }, scripts: { vscode:prepublish: npm run compile, compile: tsc -p ./, watch: tsc -watch -p ./ }, devDependencies: { types/node: ^20.0.0, types/vscode: ^1.85.0, typescript: ^5.3.0 } }这里重点解释三个配置项aiInterviewCoach.baseUrl大模型 API 地址。默认使用 OpenAI 兼容地址如果你使用国内的模型服务或本地服务改成对应地址即可。aiInterviewCoach.apiKeyEnvAPI Key 所在的环境变量名称。插件在运行时通过process.env[apiKeyEnv]读取不会把密钥硬编码到代码或配置文件中。aiInterviewCoach.model模型名称按实际可用模型填写。editor/context菜单配置的作用是当用户在编辑器中选中文本后点击右键就会看到 “AI Interview: Start Mock Interview” 菜单项。4.2 编写插件入口 extension.ts插件入口负责注册命令。核心逻辑是获取当前编辑器中的文本解析 JD读取配置调用大模型创建 Webview 面板。// 文件路径src/extension.ts import * as vscode from vscode; import { parseJD } from ./jdParser; import { chatCompletion } from ./llmClient; import { buildInterviewPrompt } from ./promptBuilder; import { InterviewPanel } from ./interviewPanel; export function activate(context: vscode.ExtensionContext) { console.log(AI Interview Coach is activated); const startCommand vscode.commands.registerCommand(aiInterviewCoach.start, async () { const editor vscode.window.activeTextEditor; if (!editor) { vscode.window.showWarningMessage(请先打开一个包含招聘 JD 的文本文件); return; } const selection editor.selection; let jdText editor.document.getText(selection.isEmpty ? undefined : selection); if (!jdText || jdText.trim().length 30) { jdText editor.document.getText(); } if (jdText.trim().length 30) { vscode.window.showWarningMessage(JD 内容太短请先在编辑器中粘贴完整招聘信息); return; } const parsedJD parseJD(jdText); const config vscode.workspace.getConfiguration(aiInterviewCoach); const baseUrl config.getstring(baseUrl) ?? https://api.openai.com/v1; const apiKeyEnv config.getstring(apiKeyEnv) ?? OPENAI_API_KEY; const model config.getstring(model) ?? gpt-4o-mini; const apiKey process.env[apiKeyEnv]; if (!apiKey) { const action await vscode.window.showWarningMessage( 未找到环境变量 ${apiKeyEnv}是否前往设置页配置, 去配置, 取消 ); if (action 去配置) { await vscode.commands.executeCommand(workbench.action.openSettings, aiInterviewCoach); } return; } const panel InterviewPanel.create(context.extensionUri); panel.showLoading(parsedJD); vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: AI 面试官正在准备面试题..., }, async () { try { const messages buildInterviewPrompt(parsedJD); const content await chatCompletion({ baseUrl, apiKey, model, messages, temperature: 0.7, }); panel.renderInitialMessage(content); } catch (error: any) { vscode.window.showErrorMessage(生成面试题失败${error.message}); } } ); }); context.subscriptions.push(startCommand); } export function deactivate() {}代码中的关键点是先通过getSelection()判断用户是否选中文本如果选区为空就使用整个文档内容。然后因为vscode.window.withProgress中的回调无法直接写return所以把面板创建放到进度条外面避免界面卡住。4.3 实现 JD 解析模块JD 解析模块的代码在 3.1 节已经展示过。这里补充一个类型定义文件types.ts统一管理模块之间的依赖类型// 文件路径src/types.ts export interface ParsedJD { companyName: string; position: string; locations: string[]; skills: string[]; responsibilities: string[]; requirements: string[]; seniority: string; rawText: string; } export interface ChatMessage { role: system | user | assistant; content: string; }在jdParser.ts中从types.ts引入ParsedJD类型保持类型一致。4.4 实现大模型调用服务大模型调用服务的核心代码在 3.2 节已经说明。实际使用时需要注意两点如果你的 Node.js 环境不支持全局fetch可以通过npm install axios引入 axios把请求改写为axios.post(url, body, { headers })的形式。如果 API 响应内容很长建议后续升级为流式输出避免用户等待过久。4.5 实现 Webview 面试面板Webview 是 VS Code 中承载 HTML 页面的容器。我们把面试题、输入框、按钮都放在这里让用户不需要离开 IDE 就能完成整个模拟面试流程。// 文件路径src/interviewPanel.ts import * as vscode from vscode; import { ParsedJD } from ./types; export class InterviewPanel { public static currentPanel: InterviewPanel | undefined; private readonly panel: vscode.WebviewPanel; private constructor(panel: vscode.WebviewPanel) { this.panel panel; this.panel.onDidDispose(() { InterviewPanel.currentPanel undefined; }); } public static create(extensionUri: vscode.Uri): InterviewPanel { if (InterviewPanel.currentPanel) { InterviewPanel.currentPanel.panel.reveal(vscode.ViewColumn.One); } else { const panel vscode.window.createWebviewPanel( aiInterviewCoach, AI Mock Interview, vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true } ); InterviewPanel.currentPanel new InterviewPanel(panel); } return InterviewPanel.currentPanel; } public showLoading(jd: ParsedJD) { this.panel.webview.html this.getHtml( h2AI 模拟面试/h2 p岗位${jd.position || 未知}/p p公司${jd.companyName || 未知}/p p技术栈${jd.skills.join(, ) || 未知}/p pAI 面试官正在准备题目请稍候.../p ); } public renderInitialMessage(content: string) { this.panel.webview.postMessage({ type: appendMessage, content }); } private getHtml(bodyHtml: string): string { return !DOCTYPE html html langzh-CN head meta charsetUTF-8 style body { font-family: -apple-system, Microsoft YaHei, sans-serif; padding: 16px; line-height: 1.6; } .message { background: #f6f8fa; border-radius: 8px; padding: 12px 16px; margin-bottom: 12px; white-space: pre-wrap; } .user-message { background: #e3f2fd; } .answer-box { width: 100%; min-height: 120px; border: 1px solid #ccc; border-radius: 6px; padding: 8px; box-sizing: border-box; } button { background: #1565c0; color: #fff; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; margin-top: 8px; } /style /head body div idapp${bodyHtml}/div script (function() { const vscode acquireVsCodeApi(); const app document.getElementById(app); window.addEventListener(message, (event) { const message event.data; if (message.type appendMessage) { const div document.createElement(div); div.className message; div.textContent message.content; app.appendChild(div); app.appendChild(createAnswerUI()); } }); function createAnswerUI() { const wrap document.createElement(div); wrap.innerHTML textarea classanswer-box placeholder输入你的回答.../textareabrbutton提交回答/button; const button wrap.querySelector(button); button.addEventListener(click, () { const answer wrap.querySelector(textarea).value; if (!answer.trim()) return; vscode.postMessage({ type: submitAnswer, answer: answer }); }); return wrap; } })(); /script /body /html; } }这里用acquireVsCodeApi()获取插件与 Webview 之间的通信对象。用户在文本框中输入回答后点击提交前端会通过postMessage把答案发给插件主进程。为了完整演示还需要在extension.ts中添加监听webview.postMessage的逻辑把答案拼接到大模型对话中继续生成点评。考虑到篇幅我这里给出在extension.ts中补充通信监听的思路panel.panel.webview.onDidReceiveMessage( async (message) { if (message.type submitAnswer) { // 把 message.answer 追加到消息列表再次调用 chatCompletion } }, undefined, context.subscriptions );完整实现需要把对话历史保存在InterviewPanel实例或插件上下文中这里不再展开。你可以根据实际需求决定是否支持多轮追问。4.6 运行与验证完成代码后在.vscode目录下创建launch.json{ version: 0.2.0, configurations: [ { name: Run Extension, type: extensionHost, request: launch, args: [--extensionDevelopmentPath${workspaceFolder}], outFiles: [${workspaceFolder}/dist/**/*.js], preLaunchTask: npm: compile } ] }然后在 VS Code 中按F5会打开一个新的“扩展开发宿主”窗口。在新窗口里新建一个文件粘贴一段招聘 JD选中文本后点击右键选择 “AI Interview: Start Mock Interview”。运行前记得设置环境变量export OPENAI_API_KEY你的密钥如果你使用的是 macOS换行前的环境变量写法如下OPENAI_API_KEY你的密钥 code .在未设置密钥的情况下插件会弹出警告并引导你去设置页配置aiInterviewCoach相关项。预期效果编辑器命令执行后通知栏出现“AI 面试官正在准备面试题...”随后 Webview 面板打开显示岗位信息摘要和 AI 生成的第一道面试题。5. 常见问题与排查思路在插件开发和使用过程中可能会遇到各种问题。下面整理最常见的几类。问题现象常见原因解决思路右键菜单找不到命令插件未成功激活或命令 ID 不匹配检查package.json中contributes.commands的 command 字段与extension.ts中注册的名字是否一致点击命令无反应编译输出未更新运行npm run compile确认dist/extension.js已重新生成提示未找到环境变量API Key 所在环境变量名错误检查配置项aiInterviewCoach.apiKeyEnv确认环境变量是否已导出大模型接口返回 401/403API Key 无效或没有调用权限验证密钥是否有效确认模型名称是否有访问权限大模型接口返回 404Base URL 拼写错误检查aiInterviewCoach.baseUrl是否包含/v1路径不同服务要求不同Webview 面板空白CSP 策略或脚本加载失败按下CtrlShiftI打开开发者工具查看 console 报错信息生成速度很慢模型响应延迟或网络问题先确认接口连通性再考虑升级为流式输出或选用速度更快的模型插件在 IDE 中加载很慢插件市场网络问题导致安装/更新失败可以尝试离线安装 VSIX 包或更换插件市场镜像源不要依赖不稳定的网络环境JD 解析结果不准确正则/关键词覆盖不全在parseJD中补充更多行业词汇或把 JD 原文加入提示词让大模型二次提炼排查时第一件事是看“输出面板”。在 VS Code 中点击菜单“视图 → 输出”选择 “AI Interview Coach” 通道可以看到插件日志。如果没有任何日志说明插件没有激活。此外由于不同大模型服务的接口格式存在差异如果调用了 OpenAI 之外的服务建议先用 curl 验证接口是否正常curl -X POST https://api.example.com/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer YOUR_KEY \ -d {model:your-model,messages:[{role:user,content:Hello}]}接口正常后再回到插件中测试能快速隔离问题范围。6. 最佳实践与工程建议6.1 提示词工程把面试质量提上去提示词质量直接决定 AI 面试官的表现。建议你在实际项目中持续迭代系统提示词。一个可用的迭代方向是加入“难度分层”和“追问逻辑”。例如第一题要求候选人简单介绍自己。第二题考察 JD 中排第一位的核心技术栈。第三题追问一个真实项目中的极端场景。第四题系统设计题让候选人画出高可用架构。第五题开放题考察业务理解和沟通能力。同时提示词中要明确限制输出格式。如果 AI 一次性输出了所有题目和答案面试体验就会打折扣。你可以在系统提示词里写“每次只输出一道题和必要的开场白等待候选人回答后再继续。”6.2 API 密钥安全这是所有接入大模型应用的硬门槛。千万不要把 API Key 硬编码到项目代码中更不要提交到 Git 仓库。推荐的密钥管理方案是在开发阶段通过环境变量注入。在 VS Code 配置中只存储环境变量名不存储密钥。在 CI/CD 或打包时使用 Secret 管理工具注入密钥。提醒用户妥善保管密钥定期轮换。本文示例已经采用这种设计apiKeyEnv配置项存的是环境变量名插件运行时从process.env读取。这样做既安全又可以在不同机器上切换不同密钥。6.3 流式输出与用户体验对于内容生成类功能流式输出stream是提升体验的关键。目前chatCompletion使用的是非流式请求模型需要完整生成内容后才一次性返回。当面试题较长时用户会一直看到加载动画。改进方案是使用stream: true参数并通过 HTTP 的text/event-stream逐段解析响应。VS Code 的 Webview 可以实时把消息追加到页面中用户能看到 AI 逐字“打字”输出体验接近真实对话。流式输出的实现代码会稍复杂推荐使用成熟的事件流解析库或者直接使用支持流式响应的 AI SDK。6.4 架构扩展从 VS Code 扩展到多 IDE文中示例只实现了 VS Code 扩展。如果你想照顾更多用户可以按照下面的思路扩展JetBrains ID
返回列表