给VSCode写个扩展,选中代码就问AI,SSE坑不少

天天 alt-tab 切到浏览器问 AI、复制粘贴代码,烦透了。索性给自己写了个 VSCode 扩展:选中一段代码,右键"问 AI",在侧边 webview 里流式出答案。功能听着简单,真做下来发现扩展环境跟普通网页差太多------webview 是个沙箱,网络请求又得绕到 extension host 那侧,SSE 流式在中间传一道,坑比想象的多。下面是踩平的过程。

整体长这样

三层:右键命令 拿到选中代码 → extension host(Node 环境) 去请求 AI 流式接口 → 一段段 postMessagewebview 渲染。为啥不让 webview 直接 fetch?因为 webview 跨域受限、还拿不到密钥,正路是让 host 当中转。

注册命令、拿选中代码

package.json 里声明个 contributes.commands 和右键菜单,激活后:

ini 复制代码
const vscode = require('vscode');

function activate(context) {
  const cmd = vscode.commands.registerCommand('askAI.ask', () => {
    const editor = vscode.window.activeTextEditor;
    const code = editor.document.getText(editor.selection); // 选中的代码
    const panel = vscode.window.createWebviewPanel(
      'askAI', 'AI 解释', vscode.ViewColumn.Beside,
      { enableScripts: true } // 必须开,不然 webview 里跑不了 JS
    );
    panel.webview.html = getHtml();
    streamToWebview(code, panel.webview); // 见下
  });
  context.subscriptions.push(cmd);
}

核心:host 侧拉 SSE,逐段 postMessage 进 webview

webview 自己收不了 SSE,我在 host(Node)里读流,每来一段就 postMessage 推进去:

javascript 复制代码
async function streamToWebview(code, webview) {
  const res = await fetch(AGENT_API, {
    method: 'POST',
    headers: { Authorization: `Bearer ${getKey()}` }, // 密钥在 host,webview 看不到
    body: JSON.stringify({ prompt: `解释这段代码:\n${code}` }),
  });
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  while (true) {
    const { done, value } = await reader.read();
    if (done) { webview.postMessage({ type: 'done' }); break; }
    const chunk = decoder.decode(value, { stream: true });
    // SSE 每行 data: 解析出 delta,推给 webview
    for (const line of chunk.split('\n')) {
      if (line.startsWith('data: ')) {
        webview.postMessage({ type: 'delta', text: parse(line) });
      }
    }
  }
}

webview 那边 window.addEventListener('message', ...) 收着拼上去就行。

我真栽进去的几个坑

1. webview 里写死的资源路径全 404。 webview 加载本地脚本/样式不能用普通相对路径,得用 webview.asWebviewUri() 转一道,我一开始 <script src="./main.js"> 直接白屏,控制台还是 webview 那套受限的,debug 都费劲。

2. node-fetch 的流在不同 Node 版本表现不一。VSCode 内置的 Node 版本不一定带全局 fetch,我为了流式 reader 折腾了半天,最后锁了个明确的 fetch 实现才稳。

3. 取消逻辑容易漏 。用户嫌答得慢关掉 panel 了,host 那侧的 fetch 还在跑、还在 postMessage 一个已经销毁的 webview,报一堆错。得在 panel.onDidDispose 里 abort 掉请求。

4. 密钥别硬编码进扩展 。扩展是要打包分发的,key 写死等于公开。我用 VSCode 的 SecretStorage 存,首次用让用户自己填。

老实讲这扩展我只够自己用,远没到能上市场的程度------错误提示糙、长代码会超上下文我也没做截断。但"选中即问、不用切窗口"这一下,确实顺手太多了。

后端那个 AGENT_API 不是我写的,是拿一个零代码搭智能体的平台配的:塞了点我们项目的编码规范当知识库、发布成 API,所以它解释代码时还能带上我们团队的约定,比通用模型贴合。

你们有给 IDE 写过自用小扩展吗?最想让 AI 在编辑器里帮你干啥?评论区聊聊。

(后端模型走的讯飞 MaaS,现成 API,扩展 host 侧直接调,密钥锁在 SecretStorage)

相关推荐
武子康2 小时前
调查研究-203 SpaceX IPO 总览:先别急着讲故事,先把发行事实和信息边界立住
人工智能·openai·agent
IT_陈寒2 小时前
Redis内存飙升的锅,原来是我没搞懂这个过期策略
前端·人工智能·后端
东坡肘子3 小时前
SPI 加入 Apple,Swift 迈向自举 -- 肘子的 Swift 周报 #142
人工智能·swiftui·swift
小和尚同志11 小时前
AI 自动化测试探索(二):Chrome-devtools MCP
人工智能·e2e·aigc
冬奇Lab13 小时前
Workflow 系列(02):设计范式——四层架构、三种 Context 传递模式与确认门设计
人工智能·agent·工作流引擎
冬奇Lab14 小时前
每日一个开源项目(第145篇):Trellis - 把项目记忆、规范和任务上下文持久化进代码仓库
人工智能·开源·资讯
有道AI情报局14 小时前
Harness即产品
人工智能·agent
罗西的思考15 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习