内网安装LlamaIndexTS无法下载npm包的问题

问题描述

项目需要用到 RAG,我们选择用 LlamaIndexTS,但是外网功能开发完,在内网准备发布的时候,发现 npm install 报错。

1
2
3
return binding.readFileUtf8(path,stringToFlags(options.flag));

Error: UNKNOWN: unknown error, open 'xxx/node_modules/rc/compile.js

原因分析

从报错来看,是这个文件读不到,去对应位置查看,确实没这个文件。
这个文件是位于 node_modules 下的,那应该就是内网环境部分包资源无法下载导致的。

解决方案

从外网的项目的 package-lock.json,找到使用的 rc 版本是 1.2.8。
先手动安装 rc 这个包:

1
npm install rc@1.2.8

安装失败,然后等待 10 分钟,等内网拉取缓存,再次 install,成功。

然后继续进行项目的 npm install,发现报错变成了下载这个资源失败:

1
https://github.com/lovell/sharp-libvips/releases/download/v8.12.2/libvips-8.12.2-linux-x64.tar.br

查询了下外网的项目的 package-lock.json,发现这是 transformer.js 依赖的 sharp 这个包用到的,然后拉取 transformer.js 的源码看了下,这是一个用于图像处理的库(transformers.js/src/utils/image.js):

1
2
3
4
5
// Will be empty (or not used) if running in browser or web-worker
import sharp from 'sharp';
// 省略
// Use sharp.js to read (and possible resize) the image.
const img = sharp(await blob.arrayBuffer());

一开始以为仍然是无缓存的缘故,单独安装这个包:

1
npm install sharp@0.33.5

过了 10 分钟,还是不行。然后我去 github 看了下 libvips,发现这不是 JS 写的,那么实际 npm 安装 sharp 的时候,应该是直接拉取了当前系统对应平台的编译文件。这个地址内网是无法访问的,因此得另想他法。

既然内网无法安装这个依赖的文件,那就采用外网安装 sharp,然后拷贝到内网,再离线安装 npm 包的方案。

首先外网安装 sharp(注意平台必须和内网保持一致,内网容器是 CentOS 的,也就是 Unix,恰好我外网有 Mac 笔记本,刚好同为 Unix 平台;如果外网是 Windows 的,则需要自己开个 Unix 的 docker 容器再安装):

1
2
npm install sharp@0.33.5 --global-style --offline
npm install sharp@0.32.6 --global-style --offline

将下载的文件打个包,传到内网,然后内网开启 CentOS 的 docker 容器,同步该包到容器内部后,进入包文件夹,全局安装 sharp 包:

1
npm install sharp -g

接着我再npm install安装项目依赖,就 OK 了。

然后再将这个容器 commit 为镜像(rag 为启动容器时给容器的命名):

1
docker commit -m '安装sharp包' rag node:rag

离线安装 npm 包

1
2
3
4
5
6
# 先在有网络的环境下载包
npm pack @huggingface/transformers@3.0.2

# 这会生成一个 huggingface-transformers-3.0.2.tgz 文件
# 然后在离线环境中使用
npm install huggingface-transformers-3.0.2.tgz
1
npm install @huggingface/transformers@3.0.2 --install-strategy=shallow
1
2
# config global-style This option has been deprecated in favor of `--install-strategy=shallow`
npm install @huggingface/transformers@3.0.2 --global-style

别加--offline,这是限制离线安装的,不会去下载包,而是直接用本地的包。

如何把所依赖的其他包也打包进去?

1
2
npm pack @huggingface/transformers@3.0.2
打的包只会包含其本身的代码,所依赖的其他包并不会打包进去。如何把所依赖的其他包也打包进去,方便离线安装?

(不行)使用 npm-pack 工具

这个不行,不会打包其依赖的包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 全局安装工具
npm install -g npm-pack

# 创建 package.json
npm init -y

# 安装包
npm install @huggingface/transformers@3.0.2

# 打包所有依赖
npm-pack

# 离线安装
npm install ./huggingface-transformers-3.0.2.tgz

(可行)使用 npm-pack-all 工具

https://github.com/kleingtm/npm-pack-all

参考[这个文章]https://www.leanpro.cn/docs/leanrunner/zh-cn/shared/npm_offline()。

注意:必须全局安装你需要的包,否则其依赖的其他包文件不会位于当前目录下,会导致最终打的包缺少这些依赖包。

外网安装&修改&打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 全局安装工具
npm install -g npm-pack-all

# 安装包(注意:必须全局安装你需要的包,否则其依赖的其他包文件不会位于当前目录下,会导致最终打的包缺少这些依赖包)
npm install -g llamaindex@0.8.26

# 查询包的安装位置
npm ls -g llamaindex@0.8.26

# 进入安装目录
cd /Users/leozhou/.nvm/versions/node/v18.16.0/lib/node_modules/llamaindex

# 删除package/package.json中dependencies和bundledDependencies下的无用且会导致下载公网包的依赖:chromadb、chromadb-default-embed

# 删除无用的包(不删除的话,会执行该包下面的script/install脚本,去公网地址下载文件)
rm -rf node_modules/onnxruntime-node

# 打包
npm-pack-all

注意:如果是先 npm-pack-all 打包,再解压后修改,然后再手动打包的话,必须进入解压后的 package 的平级目录,然后再打包,否则会因为路径问题导致后面安装失败。

1
tar -cvzf llamaindex-0.8.26.tgz package

内网安装

1
npm install llamaindex-0.8.26.tgz

报错

下载 onnxruntime 失败:

1
2
sh -c node ./script/install
# 下载onnxruntime失败:https://github.com/microsoft/onnxruntime/releases/download/v1.20.1/onnxruntime-linux-x64-gpu-1.20.1.tgz

看了下,这个是 GPU 加速的,我们的 docker 环境根本用不着:
https://github.com/microsoft/onnxruntime

查看 script/install.js 脚本,发现可以设置环境变量来跳过:

1
export ONNXRUNTIME_NODE_INSTALL_CUDA=skip &&  node script/install.js

下载 chromadb-default-embed 下的 sharp 失败:

chromadb-default-embed 是 llamaindex 的 package.json 中的依赖,是向量数据库的操作库:

1
2
3
4
5
6
{
"dependencies": {
"chromadb-default-embed": "^2.13.2",
"chromadb": "1.9.2"
}
}

实际上是这个脚本报的错:

1
# LlamaIndexTS/examples/node_modules/chromadb-default-embed/node_modules/sharp/install/libvips.js

这个可以从本地缓存文件读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// LlamaIndexTS/examples/node_modules/chromadb-default-embed/node_modules/sharp/install/libvips.js
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
if (fs.existsSync(tarPathCache)) {
libvips.log(`Using cached ${tarPathCache}`);
extractTarball(tarPathCache, platformAndArch);
}

// LlamaIndexTS/examples/node_modules/chromadb-default-embed/node_modules/sharp/lib/libvips.js
const cachePath = function () {
const npmCachePath =
env.npm_config_cache /* istanbul ignore next */ ||
(env.APPDATA
? path.join(env.APPDATA, 'npm-cache')
: path.join(os.homedir(), '.npm'));
mkdirSync(npmCachePath);
const libvipsCachePath = path.join(npmCachePath, '_libvips');
mkdirSync(libvipsCachePath);
return libvipsCachePath;
};

下载的文件路径是类似这样的:
https://github.com/lovell/sharp-libvips/releases/download/v8.14.5/libvips-8.14.5-linux-x64.tar.br

然后试试设置这个参数:

1
export npm_config_cache="/path/to/the/sharp/cache/dir" && npm install

最终的命令:

1
export ONNXRUNTIME_NODE_INSTALL_CUDA=skip && export npm_config_cache="/path/to/the/sharp/cache/dir" && npm install

Takeaways

  • 读报错信息
  • 读源码
  • 明确每个库的作用,确定我们是否需要
  • 从原理上弄清楚