纯 JS + Node,一个下午手搓了能读懂公司代码的 AI 助手,老板以为我转行了

前端人的 AI 入门不必学 Python------用你最熟的 JS,配合 LangChain + DeepSeek + 本地 Embedding,把团队四个项目的私有文档喂进去,搭一个「只懂我们代码」的 AI 助手。


一、起因:天天画页面,迟早被替代?

今年年初,Cursor 能写组件了,GitHub Copilot 能自动补全了,公司领导在会上来了一句:"咱们的 GitLab MR 能不能用 AI 自动审查?"

会后我坐在工位上想了两件事:

  1. 页面画得再好,迟早被 AI 吃掉增量市场。
  2. 但 AI 落地的最后一公里------渲染 UI、打字机效果、流式传输、接到 DevOps 管道------全是我们前端的活。

于是我决定:不卷下一个前端框架了,用我最熟的 JavaScript,给团队搭一个能读懂我们四个项目私有文档的 AI 助手


二、先看效果(比你想象的简单)

一个下午,npm install + 几段代码,跑出来的效果:

📚 本地知识库模式:

👨‍💻 问:E1 和 E2 两套 API 有什么区别?

🤖 答(📚 本地文档 · 4 个片段):

维度 E1 (legacy) E2 (new)
前缀 /api/e1 /api/e2
成功标识 status: 0 code: 200
Ajax 工厂 Ajax() createE2Ajax()

------这是我项目 AGENTS.md 里的真实约定,ChatGPT 永远答不出。

🌐 联网搜索模式(本地没有的自动切):

👨‍💻 问:今天深圳天气怎么样?

🤖 答(🌐 联网搜索 · 4 条结果): 深圳今天多云转晴,气温 28-34°C......

------这一步接入了博查 AI 搜索引擎,本地没命中的自动兜底联网。

一整页代码就跑了,不依赖任何外部数据库、向量服务、Python 环境。


三、架构极简:能用一个文件的,绝不多开一个端口

bash 复制代码
提问 → 
  │
  ├─ 识别是本地问题?(含 pdk/core/equipment/workflow 关键词?)
  │   ├─ 是 → RAG 检索本地 docs/*.md → LLM 判断片段相关?
  │   │       ├─ 相关 → 用本地文档回答
  │   │       └─ 不相关 → 联网搜索
  │   └─ 否 → 联网搜索
  │
  └─ 流式输出 + 打字机光标 + Markdown 渲染

四个技术栈全在一个 server.js(~270 行)里跑:

技术 作用
模型 DeepSeek(via LangChain) 理解问题、生成回答
向量化 transformers.js + BGE-small-zh 本地把文档转向量,不调 API 不花钱
RAG MemoryVectorStore 内存向量库,检索最相关文档片段
联网 博查 Web Search API 本地没有的自动联网搜索
交付 Node 原生 http + 流式 chunked 打字机效果 + Markdown 渲染

没有 Chroma/Pinecone,没有 Docker,没有 Python 虚拟环境。


四、核心代码拆解(只讲干货)

4.1 本地 Embedding:0 元、0 API、纯 JS

整个系统最硬核也最爽的一环------我用的不是 OpenAI Embedding API,而是一个叫 @huggingface/transformers 的 npm 包,在本地 Node 进程里直接跑 BGE-small-zh 模型

js 复制代码
import { pipeline } from '@huggingface/transformers';

const pipe = await pipeline('feature-extraction', 'Xenova/bge-small-zh-v1.5', { dtype: 'fp32' });
const vec = await pipe('E1和E2两套API的区别', { pooling: 'mean', normalize: true });
// vec.data = Float32Array[384] ← 这段文字变成了 384 维向量

然后包裹成 LangChain 的 Embeddings 接口:

js 复制代码
class LocalEmbeddings {
  async embedQuery(text) { return Array.from((await this.pipe(text)).data); }
  async embedDocuments(texts) { return Promise.all(texts.map(t => this.embedQuery(t))); }
}

第一次下载模型 ~100MB,之后秒开。按 1 万次调用算,OpenAI Embedding 大概要几十块钱------而这套方案:零。

⚠️ 踩坑:huggingface.co 在国内被墙。用 hf-mirror.com 镜像解决:

js 复制代码
import { env } from '@huggingface/transformers';
env.remoteHost = 'https://hf-mirror.com';

4.2 RAG 完整流程(读文档 → 切块 → 向量化 → 检索 → 喂 LLM)

js 复制代码
// 1. 读 docs/ 目录下所有 .md 文件
const files = readdirSync('./docs').filter(f => extname(f) === '.md');
const raw = files.map(f => readFileSync(join('./docs', f), 'utf-8')).join('\n\n');

// 2. 切块(500字符一块,80字符重叠)
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 80 });
const docs = await splitter.splitDocuments([new Document({ pageContent: raw })]);

// 3. 向量化 + 存入内存库
const store = await MemoryVectorStore.fromDocuments(docs, new LocalEmbeddings());

// 4. 提问时检索最相关的 4 个块
const hits = await store.similaritySearchWithScore(question, 4);

// 5. 喂给 DeepSeek
const context = hits.map(([doc]) => doc.pageContent).join('\n\n');
const answer = await model.invoke([
  { role: 'system', content: `仅用以下文档回答:\n\n${context}` },
  { role: 'user', content: question }
]);

这五步一跑通,你的 AI 助手就能用你们的私有文档回答问题了。 知识库里目前放的是我们团队 pdk/core/equipment/workflow 四个项目的 AGENTS.md,加起来大约 30KB 的文档。


4.3 双路检索:本地优先,LLM 判断兜底,不靠谱的才联网

最开始我省事用向量相似度阈值------topScore > 0.5 就算命中。结果「今天国际原油价格」这种跟代码八竿子打不着的问题,BGE-small 竟然给了个 0.4 的相似度......

换成 LLM 自己判断:

js 复制代码
const checkChunks = hits.map(([doc]) => doc.pageContent.slice(0, 250)).join('\n---\n');
const check = await model.invoke([
  { role: 'system', content: '严格判断:这些片段能切实回答用户问题吗?不确定就答"不能"。只回能或不能。' },
  { role: 'user', content: `问题: ${q}\n\n片段:\n${checkChunks}` }
]);

if (check.content.includes('能')) {
  /* 走本地文档 */
} else {
  /* 走博查联网搜索 */
}

比向量阈值靠谱十倍。LLM 自己知道「国际原油」和 AGENTS.md 里的代码规范不沾边。


4.4 流式输出 + 打字机光标 + Markdown 渲染

三个细节让体验从"能用"变成"舒服":

js 复制代码
// 后端:DeepSeek stream
const stream = await model.stream(messages);
res.writeHead(200, { 'Transfer-Encoding': 'chunked' });
res.write(`SOURCE:${source}|${count}\n`);
for await (const chunk of stream) {
  if (chunk.content) res.write(chunk.content);
}
res.end();

// 前端:ReadableStream 逐字追加
const reader = res.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  raw += decoder.decode(value, { stream: true });
  body.textContent = raw; // 字一个字蹦出来
}
body.innerHTML = marked.parse(raw); // 完成后渲染 Markdown

配上 CSS 闪烁光标:

css 复制代码
@keyframes blink { 0%,100% { opacity: 1 } 50% { opacity: 0 } }
.streaming::after { content: "|"; animation: blink .8s infinite; color: #7ee787; }

字一个一个蹦,末尾绿色光标一闪一闪------这就是前端给 AI 加的"人味儿"。


五、踩过的坑(你的时间就是在这省的)

现象 解决办法
huggingface 被墙 transformers.js 下模型超时 env.remoteHost = 'https://hf-mirror.com'
Node v25 undici 不吃 HTTP_PROXY 代理设了但 fetch 仍直连 用镜像代替代理,或 setGlobalDispatcher
向量阈值不可靠 不相关问题给高分 改用 LLM 判断相关性
DeepSeek key 带引号 .env 里 KEY='sk-...' → 认证失败 不要引号:KEY=sk-...
模板字符串嵌套 HTML 内的 JS 嵌套 ${} 报错 外层用拼接代替模板

六、为什么是前端,不是 Python?

因为 AI 落地的最后一公里全是前端的活:

  • 打字机效果、Markdown 渲染 → 前端
  • 流式数据传输(SSE / chunked transfer)→ 前端
  • 把 AI 接进 GitLab CI、飞书 Bot、DevOps → 前端

Python 能调 API、写 RAG、跑模型------但把 AI 变得「丝滑可用」的,是前端。

我的建议:别再去死磕下一个前端轮子了。你已经是 JS 高手,LangChain 有完整的 JS SDK,DeepSeek 有 OpenAI 兼容接口------你只需要一个周末。


七、下一步

这套东西现在跑在我们内部演示里,下一步计划:

  • 接 GitLab API,每个 MR 自动拉 diff → RAG 检索项目规范 → AI 出审查报告
  • 扩散到飞书 Bot,团队成员 @ 一下就能问
  • 把 Swagger JSON 也喂进去,「这个接口返回什么字段?」秒答

源码

需要的自己去ai生成看看

目录结构:

bash 复制代码
ai-share-demo/
├── server.js          # 主程序(~270 行,含全部功能)
├── step1-hello.js     # Demo 1: 5 行 JS 调 DeepSeek
├── step2-structured.js # Demo 2: Zod 结构化 JSON 输出
├── step3-rag.js       # Demo 3: RAG 独立命令行版
├── docs/              # 知识库文档(放 .md 即涨知识)
│   ├── PDK.md
│   ├── Core.md
│   ├── Equipment.md
│   └── Workflow.md
├── package.json
└── .env.example

一键启动:npm run web,浏览器打开 localhost:3456


如果这篇文章让你觉得「我好像也能做」,那就是我写它的全部意义。前端没有天花板,JavaScript 能做的事比你想的多。

------写于一个用公司真实文档跑通 AI 助手的下午

相关推荐
梨子同志1 小时前
JavaScript
前端
Delicate2 小时前
前端路由扫盲篇:Hash 模式和 History 模式到底怎么选?
前端
妙码生花2 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十四):眨眼小人登录页制作
前端·javascript·ai编程
妙码生花2 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十三):前端路由初始化
前端·javascript·ai编程
PBitW2 小时前
GPT训练我的第四天,被打惨了!!!😭😭😭
前端·javascript·面试
梨子同志2 小时前
CSS
前端
一tiao咸鱼3 小时前
Ai 相关 7月1日学习
前端·agent
DarkLONGLOVE3 小时前
快速上手 Pinia!Vue3 极简状态管理使用教程
javascript·vue.js
mackbob3 小时前
.eslintrc.js详细配置说明
javascript