diff --git a/2024/07/15/modern-python-project-tools-config/index.html b/2024/07/15/modern-python-project-tools-config/index.html new file mode 100644 index 000000000..aa13eded9 --- /dev/null +++ b/2024/07/15/modern-python-project-tools-config/index.html @@ -0,0 +1,307 @@ + + + + + + 都 2024 年了,你还在用 pip 吗? - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+
+

都 2024 年了,你还在用 pip 吗?

+
+
Published on: +
+ +
+
+ +

编程语言 Python 随着 AI 的发展越来越受开发人员的喜爱,目前已经是最流行的编程语言,但由于 Python 是一门相对较老的语言,并且经过 Python2 到 Python3 这一漫长而复杂的迁移历程,使得一些 Python 开发人员可能还在使用一些过时的工具和库。今天我们就来带大家了解当前 Python 生态系统中最流行最实用的开发工具,让你彻底告别那些老古董

+ + +

Python 环境管理工具

Python 项目中虚拟环境的管理非常重要,虚拟环境可以帮助我们在不同项目中使用不同的 Python 版本和依赖库,避免不同项目之间的依赖冲突。Python 最早使用的是 virtualenv 工具来管理虚拟环境,到了 Python3.3 后自带了内置的创建虚拟环境模块 venv,但它们都存在一个问题,就是只能使用同一个 Python 版本创建虚拟环境。假如你在 A 项目想使用 Python3.10,而在 B 项目想使用 Python3.9,那么你就需要安装两个不同版本的 Python,然后分别使用 virtualenvvenv 来创建虚拟环境。

+

在使用了一些 Python 环境管理工具后,我比较推荐 Miniconda 这个工具,它是一个轻量级的 Conda 版本,可以帮助我们管理 Python 环境和依赖库,但我一般不使用它来管理依赖库,主要使用它来管理 Python 环境。

+

虽然 Miniconda 与其他 Python 环境管理工具(比如 pyenv)相比会重量级一些(包含了一些数据科学相关的库),而且功能也不是很纯粹(即有环境管理也有依赖管理等功能), 但是它的优势在于环境管理的功能非常出色,可以轻松地在不同操作系统上进行安装,同时适配 bash、fish、zsh 等不同的 shell 环境,而且跟 virtualenvvenv 一起使用也不会引起冲突。

+

Miniconda 使用示例

以下是 Miniconda 的一些常用命令:

+
    +
  • 创建 Python 环境: conda create -n myenv python=3.10
  • +
  • 切换 Python 环境: conda activate myenv
  • +
  • 展示所有 Python 环境: conda env list
  • +
  • 初始化 shell 环境: conda init <bash/fish/zsh>
  • +
+

Python 依赖管理工具

Python 项目中最常使用的工具应该要属 Pip 了,Pip 是 Python 的依赖管理工具,用于安装和管理 Python 依赖,虽然 Pip 功能强大,但在管理项目依赖时存在一些问题,比如新增依赖时需要手动修改 requirements.txt 文件,而且没有版本锁定功能,导致在不同环境中安装的依赖版本可能不一致。

+

其他编程语言比如 JS 则能有效地处理这种情况,使用它的依赖管理工具 npm 会产生一个 package.json 文件来管理项目依赖,然后生成一个 package-lock.json 文件来锁定依赖版本,确保在不同环境中安装相同的依赖版本。

+

为了解决这一问题,在 Python 中出现了不少依赖管理工具,Poetry 是其中一个比较流行的工具。Poetry 使用一个 pyproject.toml 文件来管理项目的所有依赖项和元数据,使项目配置更加简洁明了,它会自动处理依赖项的版本冲突,并且能够生成锁文件 poetry.lock,确保在不同环境中安装相同的依赖版本。

+

Poetry 安装

Poetry 有多种安装方式,最简单的是通过 Python 脚本进行安装,安装命令如下:

+
1
curl -sSL https://install.python-poetry.org | python3 -
+ +

安装完成后,可以通过 Miniconda 创建一个特定版本的 Python 环境,然后在这个环境中使用 Poetry,具体操作如下:

+
1
2
3
4
5
6
7
8
# 使用 conda 创建一个 Python 环境
conda create -n myenv python=3.10
# 切换到这个 Python 环境
conda activate myenv
# 构建一个 Poetry 虚拟环境
poetry env use python
# 进入该环境
poetry shell
+ +

Poetry 使用示例

在新项目中使用 Poetry 可以使用 poetry new <project_name> 来创建一个新的 Python 项目,如果是已有项目,可以在项目目录中使用 poetry init 命令来初始化项目,这两个命令都会生成一个 pyproject.toml 文件,用于管理项目的依赖项和元数据。

+

你可以使用 poetry install 来安装项目的所有依赖,如果是初次运行该命令,Poetry 会生成一个 poetry.lock 文件,用于锁定项目的依赖版本,确保在不同环境中安装相同的依赖版本。也可以使用 poetry add <package_name> 命令来单独添加一个依赖,这样 Poetry 会自动更新 pyproject.tomlpoetry.lock 文件。

+

我们通过一个简单的例子来看下 Poetry 对依赖管理的方法,假设我们在项目中安装了一个新的依赖 requests,那么可以使用如下命令:

+
1
poetry add requests
+ +

安装完成后,在 pyproject.toml 文件中只会添加 requests 这个依赖的信息:

+
1
2
[tool.poetry.dependencies]
requests = "^2.32.3"
+ +

但是在 poetry.lock 文件会中除了添加 requests 这个依赖外,还会添加 requests 这个依赖所需的其他依赖库的信息,可以使用以下命令查看依赖之间的关系:

+
1
2
3
4
5
6
$ poetry show --tree
requests 2.32.3 Python HTTP for Humans.
├── certifi >=2017.4.17
├── charset-normalizer >=2,<4
├── idna >=2.5,<4
└── urllib3 >=1.21.1,<3
+ +

可以看到 requests 是项目根目录下的依赖,而其他几个依赖是 requests 所需的依赖。

+

如果你用 Pip 来安装依赖,那么 pip install requests 后再用 pip freeze > requirements.txt 命令生成的 requirements.txt 文件会包含所有依赖的信息,使得你分不清哪些是项目的依赖,哪些是衍生的依赖。

+

Poetry 还允许你将 lock 文件导出成 requirements.txt 文件,这样你就可以使用 pip install -r requirements.txt 来安装项目的依赖,具体命令如下:

+
1
poetry export --without-hashes --format=requirements.txt --output requirements.txt
+ +

更多的 Poetry 使用方法可以参考官方文档

+

其他依赖管理工具

除了 Poetry 外,还有一些其他的 Python 依赖管理工具,比如 Pdm 就是不错的选择,它整体和 Poetry 类似,它还包含了 Python 环境管理的功能,这样就不需要和 Miniconda 配合也可直接使用,但是在流行度上比 Poetry 稍微逊色一些(截止时间 2024 年 7 月,Poetry 的 Github Star 数是 30K,而 Pdm 的 Github Star 数是 7.6K),可能是 Pdm 比 Poetry 发布时间晚的关系(Poetry 是 2018 年发布的,而 Pdm 是 2020 年发布的),后面如果 Pdm 发展的好的话,说不定会超过 Poetry。

+

另外一个值得推荐的 Python 依赖管理工具是 Uv,它是一款用 Rust 编写的极速 Python 包安装和解析工具,旨在作为 Pip 和 Pip-tools 的替代品,并逐步发展成为一个全面的 Python 项目和包管理器,下面是它和其他工具安装依赖的速度对比图:

+ + +

得益于 Rust 的高性能,在速度上 Uv 完全碾压了其他工具,但可惜的是 Uv 目前还是使用 requirements.txt 来管理依赖,这样就无法保证可以在不同环境安装相同的依赖,而且 Uv 也不能和 Poetry 一起使用,因为 Uv 是按照兼容 Pip 的思路进行开发,而 Poetry 内部已经不用 Pip 做依赖管理了。

+

尽管 Uv 无法和 Poetry 一起使用,但是我们可以在 CI/CD 中使用 Uv 来加速依赖安装,比如我们先用 Poetry 导出 requirements.txt 文件,然后在 CI/CD 中使用 Uv 来安装依赖,这样就可以大大缩短依赖安装的时间。

+

Pip 是否过时

虽然这些依赖管理工具很强大,但一些小型项目可能更多开发人员还是会选择 Pip,因为 Pip 无需额外安装其他工具,一般有 Python 环境就可以直接使用。另外一点是编程语言的原生工具也在不断发展,以 JS 为例,npm 刚开始时也不支持 lock 文件,但后面参考了一些 JS 的流行工具,在社区的共同努力下慢慢完善了这个功能,所以 Pip 也有可能在未来的某个版本中加入类似 Poetry 的功能。

+

所以在 Pip 没有发展完善之前,我们可以使用 Poetry 这样的工具来解决依赖管理的问题,同时也能简化项目配置,提高开发效率。

+

代码规范工具

另外一种常用的工具是代码规范类工具,因为 Python 的语法比较灵活,所以在团队协作中可能会出现代码风格不一致的问题,为了解决这个问题,每种编程语言都会有一些代码规范工具,这类工具包括代码格式化工具、代码检查工具等。

+

在 Python 中代码格式化工具有 BlackYAPFautopep8 等,而代码检查工具有 Flake8Pylintmypy 等,这些工具都可以通过 Pip 来安装,然后在项目中使用。

+

而最近比较流行的一个代码规范工具 Ruff,它同时集成了代码格式化和代码检查功能,可以帮助我们更好地在项目中统一代码风格。Ruff 是 Uv 开发团队开发的另外一款工具,同样是使用 Rust 语言进行编写,从而使它的性能远远高于其他同类型的工具,下面是 Ruff 和其他工具的性能对比图:

+ + +

Ruff 内部集成了 Black 和 Flake8 等工具,下面我们就来介绍下 Ruff 如何安装及使用。

+

Ruff 安装

Ruff 可以通过 Pip 或 Poetry 进行安装,在项目中使用的话,推荐使用 Poetry 安装到 dev 开发依赖中,表示这个工具只在开发环境中使用,具体命令如下:

+
1
poetry add --dev ruff
+ +

如果想让 Ruff 在本地 IDE 中使用的话,建议是进行全局安装,这样就可以在任何项目中使用 Ruff,具体命令如下:

+
1
curl -LsSf https://astral.sh/ruff/install.sh | sh
+ +

安装完成后,可以通过 IDE 的插件来使用 Ruff,比如在 VSCode 中安装 Ruff 插件,然后在 VSCode 中使用快捷键 Ctrl+Shift+P 打开命令面板,输入 user config 打开用户配置文件,然后添加 Ruff 安装后的路径:

+
1
2
3
{
"ruff.path": ["/your/ruff/path"]
}
+ +

Ruff 使用示例

Ruff 主要有 2 个命令,分别是 ruff checkruff format,前者用于代码检查,后者用于代码格式化。

+

为了保证团队的代码风格一致,我们可以在 Git 的 hook 中添加 Ruff 检查命令,这样每个人在执行 git commit 命令时就会自动执行 Ruff 命令,如果检查失败则无法提交代码。

+

首先我们需要安装 pre-commit 工具,这个工具可以让我们在 Git hook 上轻松配置命令,同样将其安装到 dev 开发依赖即可:poetry add --dev pre-commit,然后在项目根目录下添加 .pre-commit-config.yaml 文件,内容如下:

+
1
2
3
4
5
6
7
8
9
10
11
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff 版本
rev: v0.5.1
hooks:
# 执行 ruff check
- id: ruff
# 可选参数,自动修复代码
args: [--fix]
# 执行 ruff format
- id: ruff-format
+ +
    +
  • 在文件中我们添加 Ruff 工具来处理代码提交时的检查
  • +
  • 我们添加了 2 个工具,第一个工具 id 是 ruff 表示执行 ruff check 命令,第二个工具 id 是 ruff-format 表示执行 ruff format 命令
  • +
  • 第一个工具还有一个可选参数 args: [--fix],表示会自动修复检查出有误的代码,但也不是所有代码都能自动修复,有些代码还是需要手动修复的
  • +
+

最后我们在项目中执行 pre-commit install 命令,将文件内容添加到 Git hook 中:

+
1
2
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
+ +

配置完成后,我们故意写一些代码错误,然后提交代码, 检查结果如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ git commit -m 'add some feature'
ruff.....................................................................Failed
- hook id: ruff
- exit code: 1

main.py:1:8: F401 [*] `requests` imported but unused
|
1 | import requests
| ^^^^^^^^ F401
|
= help: Remove unused import: `requests`

Found 1 error.
[*] 1 fixable with the `--fix` option.

ruff-format..............................................................Passed
+ +

可以看到代码检查任务失败了,报了 imported but unused 的错误,错误编号 F401,第二个任务代码格式化检查通过。

+

如果想在代码中不检查某行代码,可以在代码行后面加上 # noqa: {error_code},比如:

+
1
import requests # noqa: F401
+ +

这样就可以在 Ruff 检查时忽略这个错误。更多的 Ruff 使用方法可以参考官方文档

+

总结

今天我们介绍了 Python 中新一代的项目工具,新工具带来的好处是开发效率的提升,因为每个新工具都是在解决旧工具的不足之处,是在旧工具的基础上进行了优化和改进。作为一个热衷提高生产力的开发人员,可以在适当时机尝试使用这些新工具,如果觉得新工具不合适,也可以退回去重新使用旧工具,关键在于尝试。

+

关注我,一起学习各种人工智能和 GenAI 新技术,欢迎交流,如果你有什么想问想说的,欢迎在评论区留言。

+
+ +
+
+
+

赞赏

+ +
+
+ + + + + + + + + +
+

Comments

+
+
+
+ +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/archives/2024/07/index.html b/archives/2024/07/index.html index cf240f623..e0a6b040a 100644 --- a/archives/2024/07/index.html +++ b/archives/2024/07/index.html @@ -129,6 +129,20 @@

2024

+ +

高级 RAG 检索策略之知识图谱

diff --git a/archives/2024/index.html b/archives/2024/index.html index a06839480..5c6a40b7c 100644 --- a/archives/2024/index.html +++ b/archives/2024/index.html @@ -129,6 +129,20 @@

2024

+ + - -
diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html index e05602865..65d95a7db 100644 --- a/archives/2024/page/2/index.html +++ b/archives/2024/page/2/index.html @@ -129,6 +129,20 @@

2024

+ + - -
@@ -279,6 +279,8 @@

+ +

diff --git a/archives/2024/page/3/index.html b/archives/2024/page/3/index.html new file mode 100644 index 000000000..776c7869a --- /dev/null +++ b/archives/2024/page/3/index.html @@ -0,0 +1,194 @@ + + + + + + Archives: 2024 - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2024

+ + + + +
+ + + + + +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/archives/index.html b/archives/index.html index ab3c16399..978cfb370 100644 --- a/archives/index.html +++ b/archives/index.html @@ -129,6 +129,20 @@

2024

+ + - -
diff --git a/archives/page/10/index.html b/archives/page/10/index.html index d483a7502..8890a6f08 100644 --- a/archives/page/10/index.html +++ b/archives/page/10/index.html @@ -129,6 +129,20 @@

2017

+ + - -
diff --git a/archives/page/11/index.html b/archives/page/11/index.html index 7615d697c..1d5a34bc2 100644 --- a/archives/page/11/index.html +++ b/archives/page/11/index.html @@ -129,6 +129,20 @@

2016

+ + - -
diff --git a/archives/page/12/index.html b/archives/page/12/index.html index c2a4b7d8c..bfa4e50ee 100644 --- a/archives/page/12/index.html +++ b/archives/page/12/index.html @@ -129,6 +129,20 @@

2015

+ + - -
diff --git a/archives/page/13/index.html b/archives/page/13/index.html index c22f2d064..29a87137f 100644 --- a/archives/page/13/index.html +++ b/archives/page/13/index.html @@ -129,6 +129,20 @@

2015

+ + - -
diff --git a/archives/page/14/index.html b/archives/page/14/index.html index 90c0c7655..425221323 100644 --- a/archives/page/14/index.html +++ b/archives/page/14/index.html @@ -129,6 +129,20 @@

2014

+ + - -
diff --git a/archives/page/15/index.html b/archives/page/15/index.html index ddd5f420f..6ace05cef 100644 --- a/archives/page/15/index.html +++ b/archives/page/15/index.html @@ -129,6 +129,20 @@

2014

+ + - -
diff --git a/archives/page/16/index.html b/archives/page/16/index.html index 5a63d8191..cdb713e18 100644 --- a/archives/page/16/index.html +++ b/archives/page/16/index.html @@ -129,6 +129,20 @@

2014

+ + - -
diff --git a/archives/page/17/index.html b/archives/page/17/index.html index 14521a311..ec422012f 100644 --- a/archives/page/17/index.html +++ b/archives/page/17/index.html @@ -129,6 +129,20 @@

2014

+ + - -
diff --git a/archives/page/18/index.html b/archives/page/18/index.html index f6fb3cdd9..e7845c701 100644 --- a/archives/page/18/index.html +++ b/archives/page/18/index.html @@ -129,6 +129,20 @@

2013

+ + - -
diff --git a/archives/page/19/index.html b/archives/page/19/index.html index a298c5c9e..5748d1d0d 100644 --- a/archives/page/19/index.html +++ b/archives/page/19/index.html @@ -129,6 +129,20 @@

2012

+ + - -
diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 27fb19f56..58d783359 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -129,6 +129,20 @@

2024

+ + - -
diff --git a/archives/page/20/index.html b/archives/page/20/index.html index 9af431c1a..e9a5943d6 100644 --- a/archives/page/20/index.html +++ b/archives/page/20/index.html @@ -129,6 +129,20 @@

2012

+ + - -
diff --git a/archives/page/21/index.html b/archives/page/21/index.html index bebeda671..a7a8d2dda 100644 --- a/archives/page/21/index.html +++ b/archives/page/21/index.html @@ -129,6 +129,20 @@

2012

+ + - -
@@ -279,6 +279,8 @@

+ + diff --git a/archives/page/22/index.html b/archives/page/22/index.html new file mode 100644 index 000000000..172516f29 --- /dev/null +++ b/archives/page/22/index.html @@ -0,0 +1,194 @@ + + + + + + Archives - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2012

+ + + + +
+ + + + + +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 43f130d81..1c7e2d589 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -127,6 +127,25 @@

+

2024

+ + + +
+ +

2023

- -
diff --git a/archives/page/4/index.html b/archives/page/4/index.html index baa963c47..b2fba0fd0 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -129,6 +129,20 @@

2023

+ + - -
diff --git a/archives/page/5/index.html b/archives/page/5/index.html index 43eafa1af..97a1aea52 100644 --- a/archives/page/5/index.html +++ b/archives/page/5/index.html @@ -129,6 +129,20 @@

2023

+ + - -
diff --git a/archives/page/6/index.html b/archives/page/6/index.html index 5b30e8c05..54cbee9ef 100644 --- a/archives/page/6/index.html +++ b/archives/page/6/index.html @@ -129,6 +129,20 @@

2023

+ + - -
diff --git a/archives/page/7/index.html b/archives/page/7/index.html index bd3cfaa5a..481e91fb6 100644 --- a/archives/page/7/index.html +++ b/archives/page/7/index.html @@ -129,6 +129,20 @@

2019

+ + - -
diff --git a/archives/page/8/index.html b/archives/page/8/index.html index ccfa5a8d3..a3fc5698d 100644 --- a/archives/page/8/index.html +++ b/archives/page/8/index.html @@ -129,6 +129,20 @@

2018

+ + - -
diff --git a/archives/page/9/index.html b/archives/page/9/index.html index 9ade06dce..e43295ced 100644 --- a/archives/page/9/index.html +++ b/archives/page/9/index.html @@ -129,6 +129,20 @@

2017

+ + - -
diff --git a/atom.xml b/atom.xml index 51ebeaf6b..03d5e783a 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2024-07-12T01:18:49.490Z + 2024-07-19T03:26:19.579Z https://zhaozhiming.github.io/ @@ -16,6 +16,35 @@ Hexo + + 都 2024 年了,你还在用 pip 吗? + + https://zhaozhiming.github.io/2024/07/15/modern-python-project-tools-config/ + 2024-07-15T02:49:25.000Z + 2024-07-19T03:26:19.579Z + +

编程语言 Python 随着 AI 的发展越来越受开发人员的喜爱,目前已经是最流行的编程语言,但由于 Python 是一门相对较老的语言,并且经过 Python2 到 Python3 这一漫长而复杂的迁移历程,使得一些 Python 开发人员可能还在使用一些过时的工具和库。今天我们就来带大家了解当前 Python 生态系统中最流行最实用的开发工具,让你彻底告别那些老古董

Python 环境管理工具

Python 项目中虚拟环境的管理非常重要,虚拟环境可以帮助我们在不同项目中使用不同的 Python 版本和依赖库,避免不同项目之间的依赖冲突。Python 最早使用的是 virtualenv 工具来管理虚拟环境,到了 Python3.3 后自带了内置的创建虚拟环境模块 venv,但它们都存在一个问题,就是只能使用同一个 Python 版本创建虚拟环境。假如你在 A 项目想使用 Python3.10,而在 B 项目想使用 Python3.9,那么你就需要安装两个不同版本的 Python,然后分别使用 virtualenvvenv 来创建虚拟环境。

在使用了一些 Python 环境管理工具后,我比较推荐 Miniconda 这个工具,它是一个轻量级的 Conda 版本,可以帮助我们管理 Python 环境和依赖库,但我一般不使用它来管理依赖库,主要使用它来管理 Python 环境。

虽然 Miniconda 与其他 Python 环境管理工具(比如 pyenv)相比会重量级一些(包含了一些数据科学相关的库),而且功能也不是很纯粹(即有环境管理也有依赖管理等功能), 但是它的优势在于环境管理的功能非常出色,可以轻松地在不同操作系统上进行安装,同时适配 bash、fish、zsh 等不同的 shell 环境,而且跟 virtualenvvenv 一起使用也不会引起冲突。

Miniconda 使用示例

以下是 Miniconda 的一些常用命令:

  • 创建 Python 环境: conda create -n myenv python=3.10
  • 切换 Python 环境: conda activate myenv
  • 展示所有 Python 环境: conda env list
  • 初始化 shell 环境: conda init <bash/fish/zsh>

Python 依赖管理工具

Python 项目中最常使用的工具应该要属 Pip 了,Pip 是 Python 的依赖管理工具,用于安装和管理 Python 依赖,虽然 Pip 功能强大,但在管理项目依赖时存在一些问题,比如新增依赖时需要手动修改 requirements.txt 文件,而且没有版本锁定功能,导致在不同环境中安装的依赖版本可能不一致。

其他编程语言比如 JS 则能有效地处理这种情况,使用它的依赖管理工具 npm 会产生一个 package.json 文件来管理项目依赖,然后生成一个 package-lock.json 文件来锁定依赖版本,确保在不同环境中安装相同的依赖版本。

为了解决这一问题,在 Python 中出现了不少依赖管理工具,Poetry 是其中一个比较流行的工具。Poetry 使用一个 pyproject.toml 文件来管理项目的所有依赖项和元数据,使项目配置更加简洁明了,它会自动处理依赖项的版本冲突,并且能够生成锁文件 poetry.lock,确保在不同环境中安装相同的依赖版本。

Poetry 安装

Poetry 有多种安装方式,最简单的是通过 Python 脚本进行安装,安装命令如下:

1
curl -sSL https://install.python-poetry.org | python3 -

安装完成后,可以通过 Miniconda 创建一个特定版本的 Python 环境,然后在这个环境中使用 Poetry,具体操作如下:

1
2
3
4
5
6
7
8
# 使用 conda 创建一个 Python 环境
conda create -n myenv python=3.10
# 切换到这个 Python 环境
conda activate myenv
# 构建一个 Poetry 虚拟环境
poetry env use python
# 进入该环境
poetry shell

Poetry 使用示例

在新项目中使用 Poetry 可以使用 poetry new <project_name> 来创建一个新的 Python 项目,如果是已有项目,可以在项目目录中使用 poetry init 命令来初始化项目,这两个命令都会生成一个 pyproject.toml 文件,用于管理项目的依赖项和元数据。

你可以使用 poetry install 来安装项目的所有依赖,如果是初次运行该命令,Poetry 会生成一个 poetry.lock 文件,用于锁定项目的依赖版本,确保在不同环境中安装相同的依赖版本。也可以使用 poetry add <package_name> 命令来单独添加一个依赖,这样 Poetry 会自动更新 pyproject.tomlpoetry.lock 文件。

我们通过一个简单的例子来看下 Poetry 对依赖管理的方法,假设我们在项目中安装了一个新的依赖 requests,那么可以使用如下命令:

1
poetry add requests

安装完成后,在 pyproject.toml 文件中只会添加 requests 这个依赖的信息:

1
2
[tool.poetry.dependencies]
requests = "^2.32.3"

但是在 poetry.lock 文件会中除了添加 requests 这个依赖外,还会添加 requests 这个依赖所需的其他依赖库的信息,可以使用以下命令查看依赖之间的关系:

1
2
3
4
5
6
$ poetry show --tree
requests 2.32.3 Python HTTP for Humans.
├── certifi >=2017.4.17
├── charset-normalizer >=2,<4
├── idna >=2.5,<4
└── urllib3 >=1.21.1,<3

可以看到 requests 是项目根目录下的依赖,而其他几个依赖是 requests 所需的依赖。

如果你用 Pip 来安装依赖,那么 pip install requests 后再用 pip freeze > requirements.txt 命令生成的 requirements.txt 文件会包含所有依赖的信息,使得你分不清哪些是项目的依赖,哪些是衍生的依赖。

Poetry 还允许你将 lock 文件导出成 requirements.txt 文件,这样你就可以使用 pip install -r requirements.txt 来安装项目的依赖,具体命令如下:

1
poetry export --without-hashes --format=requirements.txt --output requirements.txt

更多的 Poetry 使用方法可以参考官方文档

其他依赖管理工具

除了 Poetry 外,还有一些其他的 Python 依赖管理工具,比如 Pdm 就是不错的选择,它整体和 Poetry 类似,它还包含了 Python 环境管理的功能,这样就不需要和 Miniconda 配合也可直接使用,但是在流行度上比 Poetry 稍微逊色一些(截止时间 2024 年 7 月,Poetry 的 Github Star 数是 30K,而 Pdm 的 Github Star 数是 7.6K),可能是 Pdm 比 Poetry 发布时间晚的关系(Poetry 是 2018 年发布的,而 Pdm 是 2020 年发布的),后面如果 Pdm 发展的好的话,说不定会超过 Poetry。

另外一个值得推荐的 Python 依赖管理工具是 Uv,它是一款用 Rust 编写的极速 Python 包安装和解析工具,旨在作为 Pip 和 Pip-tools 的替代品,并逐步发展成为一个全面的 Python 项目和包管理器,下面是它和其他工具安装依赖的速度对比图:

得益于 Rust 的高性能,在速度上 Uv 完全碾压了其他工具,但可惜的是 Uv 目前还是使用 requirements.txt 来管理依赖,这样就无法保证可以在不同环境安装相同的依赖,而且 Uv 也不能和 Poetry 一起使用,因为 Uv 是按照兼容 Pip 的思路进行开发,而 Poetry 内部已经不用 Pip 做依赖管理了。

尽管 Uv 无法和 Poetry 一起使用,但是我们可以在 CI/CD 中使用 Uv 来加速依赖安装,比如我们先用 Poetry 导出 requirements.txt 文件,然后在 CI/CD 中使用 Uv 来安装依赖,这样就可以大大缩短依赖安装的时间。

Pip 是否过时

虽然这些依赖管理工具很强大,但一些小型项目可能更多开发人员还是会选择 Pip,因为 Pip 无需额外安装其他工具,一般有 Python 环境就可以直接使用。另外一点是编程语言的原生工具也在不断发展,以 JS 为例,npm 刚开始时也不支持 lock 文件,但后面参考了一些 JS 的流行工具,在社区的共同努力下慢慢完善了这个功能,所以 Pip 也有可能在未来的某个版本中加入类似 Poetry 的功能。

所以在 Pip 没有发展完善之前,我们可以使用 Poetry 这样的工具来解决依赖管理的问题,同时也能简化项目配置,提高开发效率。

代码规范工具

另外一种常用的工具是代码规范类工具,因为 Python 的语法比较灵活,所以在团队协作中可能会出现代码风格不一致的问题,为了解决这个问题,每种编程语言都会有一些代码规范工具,这类工具包括代码格式化工具、代码检查工具等。

在 Python 中代码格式化工具有 BlackYAPFautopep8 等,而代码检查工具有 Flake8Pylintmypy 等,这些工具都可以通过 Pip 来安装,然后在项目中使用。

而最近比较流行的一个代码规范工具 Ruff,它同时集成了代码格式化和代码检查功能,可以帮助我们更好地在项目中统一代码风格。Ruff 是 Uv 开发团队开发的另外一款工具,同样是使用 Rust 语言进行编写,从而使它的性能远远高于其他同类型的工具,下面是 Ruff 和其他工具的性能对比图:

Ruff 内部集成了 Black 和 Flake8 等工具,下面我们就来介绍下 Ruff 如何安装及使用。

Ruff 安装

Ruff 可以通过 Pip 或 Poetry 进行安装,在项目中使用的话,推荐使用 Poetry 安装到 dev 开发依赖中,表示这个工具只在开发环境中使用,具体命令如下:

1
poetry add --dev ruff

如果想让 Ruff 在本地 IDE 中使用的话,建议是进行全局安装,这样就可以在任何项目中使用 Ruff,具体命令如下:

1
curl -LsSf https://astral.sh/ruff/install.sh | sh

安装完成后,可以通过 IDE 的插件来使用 Ruff,比如在 VSCode 中安装 Ruff 插件,然后在 VSCode 中使用快捷键 Ctrl+Shift+P 打开命令面板,输入 user config 打开用户配置文件,然后添加 Ruff 安装后的路径:

1
2
3
{
"ruff.path": ["/your/ruff/path"]
}

Ruff 使用示例

Ruff 主要有 2 个命令,分别是 ruff checkruff format,前者用于代码检查,后者用于代码格式化。

为了保证团队的代码风格一致,我们可以在 Git 的 hook 中添加 Ruff 检查命令,这样每个人在执行 git commit 命令时就会自动执行 Ruff 命令,如果检查失败则无法提交代码。

首先我们需要安装 pre-commit 工具,这个工具可以让我们在 Git hook 上轻松配置命令,同样将其安装到 dev 开发依赖即可:poetry add --dev pre-commit,然后在项目根目录下添加 .pre-commit-config.yaml 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff 版本
rev: v0.5.1
hooks:
# 执行 ruff check
- id: ruff
# 可选参数,自动修复代码
args: [--fix]
# 执行 ruff format
- id: ruff-format
  • 在文件中我们添加 Ruff 工具来处理代码提交时的检查
  • 我们添加了 2 个工具,第一个工具 id 是 ruff 表示执行 ruff check 命令,第二个工具 id 是 ruff-format 表示执行 ruff format 命令
  • 第一个工具还有一个可选参数 args: [--fix],表示会自动修复检查出有误的代码,但也不是所有代码都能自动修复,有些代码还是需要手动修复的

最后我们在项目中执行 pre-commit install 命令,将文件内容添加到 Git hook 中:

1
2
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit

配置完成后,我们故意写一些代码错误,然后提交代码, 检查结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ git commit -m 'add some feature'
ruff.....................................................................Failed
- hook id: ruff
- exit code: 1

main.py:1:8: F401 [*] `requests` imported but unused
|
1 | import requests
| ^^^^^^^^ F401
|
= help: Remove unused import: `requests`

Found 1 error.
[*] 1 fixable with the `--fix` option.

ruff-format..............................................................Passed

可以看到代码检查任务失败了,报了 imported but unused 的错误,错误编号 F401,第二个任务代码格式化检查通过。

如果想在代码中不检查某行代码,可以在代码行后面加上 # noqa: {error_code},比如:

1
import requests # noqa: F401

这样就可以在 Ruff 检查时忽略这个错误。更多的 Ruff 使用方法可以参考官方文档

总结

今天我们介绍了 Python 中新一代的项目工具,新工具带来的好处是开发效率的提升,因为每个新工具都是在解决旧工具的不足之处,是在旧工具的基础上进行了优化和改进。作为一个热衷提高生产力的开发人员,可以在适当时机尝试使用这些新工具,如果觉得新工具不合适,也可以退回去重新使用旧工具,关键在于尝试。

关注我,一起学习各种人工智能和 GenAI 新技术,欢迎交流,如果你有什么想问想说的,欢迎在评论区留言。

]]>
+ + + 介绍新一代 Python 项目常用工具,以及如何在项目中使用 + + + + + + + + + + + + + + + + +
+ 高级 RAG 检索策略之知识图谱 @@ -511,31 +540,4 @@ - - 使用 LlamaIndex 结合 Eleasticsearch 进行 RAG 检索增强生成 - - https://zhaozhiming.github.io/2024/01/13/llamaindex-eleasticsearch-rga-practice/ - 2024-01-13T07:12:46.000Z - 2024-01-18T03:59:05.315Z - -

检索增强生成(Retrieval-Augmented Generation,RAG)是一种结合了检索(Retrieval)和生成(Generation)的技术,它有效地解决了大语言模型(LLM)的一些问题,比如幻觉、知识限制等。随着 RAG 技术的发展,RAG 涉及到的向量技术受到了大家的关注,向量数据库也慢慢被大家所了解,一些老牌的数据库厂商也纷纷表示支持向量检索,比如 Elasticsearch 也在最近的版本增加了向量检索的支持。本文将介绍 Elasticsearch 和 RAG 中相关的 Embedding 模型的部署,以及在 LLM 框架 LLamaIndex 中如何使用 Elasticsearch 进行文档索引入库和检索。

RAG 介绍

在使用 LLM 时我们经常会遇到这样一些情况,比如当我们的问题超出 LLM 的知识范围时,它要么解释说这个问题超出它的知识范围(这是 LLM 的知识限制),要么它会很自信地瞎编一些答案(这是我们所说的 LLM 幻觉)。

为了应对 LLM 的这些问题,RAG(检索增强生成)技术应运而生,RAG 的主要原理是将文档向量化后进行存储,在提出问题时将问题进行向量检索,检索出相关的文档,然后再将文档作为问题的上下文,一起发送给 LLM,让 LLM 来生成问题的答案,有了相关文档的支持,LLM 在内容的生成上就会参考这些文档,这样就可以有效地解决 LLM 的幻觉问题。同时,RAG 可以让 LLM 更快地了解到最新的信息,通常要让 LLM 了解到更新的信息,需要对 LLM 进行重新训练,训练方式不管是预训练还是微调,成本都是比较高的,而 RAG 只需要将最新的文档加入到数据库中即可,这样 LLM 就可以通过向量检索的方式来获取最新的信息。

关键字检索和语义检索

RAG 的相关技术包括向量检索,也称为语义检索,它不同于传统的关键字检索,关键字检索依赖于在文档中查找与查询中使用的确切词汇匹配的单词或短语,它通常只关注字面上的匹配,而不考虑查询的上下文或语义含义,而语义检索旨在理解查询的意图和上下文含义,不仅仅是文字匹配,它通过分析词语的语义关系(如同义词、词义消歧)来提高检索的相关性。

举一个简单的例子,比如我们输入苹果 2024 新品发布,关键字检索可能返回关于苹果公司 2024 年的任何新闻发布,但也可能包括与水果苹果相关的新品种发布的信息,语义检索则会查找出关于苹果公司最新电子产品发布的新闻,而忽略与水果苹果相关的内容。

Elasitcsearch(以下简称 ES) 虽然一开始只是全文搜索引擎,也就是关键字检索,但是随着向量检索技术的发展,ES 也开始支持向量检索,这让 ES 成为了一个既可以做关键字检索,又可以做语义检索的数据库。下面我们就来介绍 ES 数据库的部署。

Elasticsearch 部署

部署 ES 最简单的方式是通过 Docker,首先需要安装 Docker,可以参考 Docker 的官方安装文档

Docker 安装完成后开始安装 ES,我们需要使用 ES 的最新版本,因为最新的版本包括了向量检索的功能,目前最新的版本是8.11.3,安装启动命令如下:

1
docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:8.11.3

使用docker run命令启动 ES 服务,-d参数表示以后台方式运行,--name参数表示容器的名称,-p参数表示端口映射,-e参数表示环境变量,elasticsearch:8.11.3表示使用elasticsearch相关版本的镜像。如果你是单机部署的话,可以不需要映射9300端口,这个端口主要用于 ES 集群内部节点之间的通信。

修改 ES 用户密码

ES 默认的配置会开启安全认证,这意味着在访问 ES 时需要通过用户名和密码认证,因此我们需要先获取到 ES 的用户名和密码,ES 的默认用户是elastic,如果不清楚该用户的密码,可以通过以下命令来重置用户密码:

1
2
3
4
5
6
7
8
9
10
11
12
# 进入 ES 容器
$ docker exec -it es bash
# 重置密码
$ bin/elasticsearch-reset-password -u elastic -i
This tool will reset the password of the [elastic] user.
You will be prompted to enter the password.
Please confirm that you would like to continue [y/N]y


Enter password for [elastic]:
Re-enter password for [elastic]:
Password for the [elastic] user successfully reset.

在 ES 容器中我们通过elasticsearch-reset-password命令来重置elastic用户的密码,重置完成后,我们可以通过在浏览器中输入https://localhost:9200来访问 ES(注意 url 地址是 https,不是 http,后面会讲如何关闭 https),首次访问时会提示你输入用户名和密码:

输入用户名和密码后,我们就可以看到 ES 相关的 JSON 信息。

关闭 ES SSL 认证

ES 为了加强系统的安全性,会默认开启 SSL 认证,在访问 ES 时需要使用 HTTPS 协议,但如果我们只是本地使用的话不太需要这种级别的安全认证,因此我们可以关闭 ES 的 SSL 认证,关闭 SSL 认证的需要修改 ES 的配置文件elascitsearch.yml。修改该文件我们先要将 ES 默认的配置文件拷贝到本地磁盘,然后修改配置文件,最后在 ES 容器启动时挂载修改后的配置文件。

首先我们将刚才启动的 ES 容器中的配置目录拷贝到本地磁盘,然后原来的 ES 容器就可以关闭了,命令如下:

1
2
3
4
# 拷贝配置文件
docker cp es:/usr/share/elasticsearch/config ./config
# 关闭 ES 容器
docker rm -f es

config文件夹包含了elascitsearch.yml和其他配置文件,然后我们修改elascitsearch.yml文件来关闭 SSL 认证,修改内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
- enabled: true
+ enabled: false
keystore.path: certs/http.p12

# Enable encryption and mutual authentication between cluster nodes
xpack.security.transport.ssl:
- enabled: true
+ enabled: false
verification_mode: certificate
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12

修改完成后,我们需要重新运行一个新的 ES 容器,并将修改后的配置文件挂载到容器中,命令如下:

1
docker run -d --name es -p 9200:9200 -p 9300:9300 -v "$PWD/config":/usr/share/elasticsearch/config -e "discovery.type=single-node" elasticsearch:8.11.3

等容器启动后,我们就可以通过http://localhost:9200来访问 ES 了。这里要注意的是因为重新部署了 ES 容器,所以刚才修改的用户密码也会失效,需要重新重置用户密码。

ES 监控工具

想要查看 ES 中的数据,如果是使用命令行工具的话可能不太方便,因此我们需要一个 GUI 工具,这里推荐elasticvue,一个基于浏览器的 ES GUI 工具,安装也非常简单,同样是使用 docker 来进行安装:

1
docker run -p 9080:8080 --name elasticvue -d cars10/elasticvue

然后我们在浏览器中输入http://localhost:9080来访问 elasticvue,进到首页后点击ADD ELASTICSEARCH CLUSTER按钮,可以看到如下界面:

根据上图上半部分的Configure提示,需要修改 ES 的配置文件elascitsearch.yml以接入 elasticvue,修改内容可以参考图中的Configure部分,修改完后重启 ES 容器即可。

1
docker restart es

然后在 elasticvue 中添加 ES 集群,输入 ES 的地址http://localhost:9200,选择Basic auth输入用户名和密码,这样就可以连上我们的 ES 服务了。

Embedding 模型部署

向量检索的核心是向量,而向量是由 Embedding 模型生成的,我们可以使用一些线上的 Embedding 模型,比如 OpenAI 的 Embedding 模型,也可以自己部署 Embedding 模型。这里我们选择部署自己的 Embedding 模型,我们使用 BAAI/bge-base-en-v1.5 模型,这是一个英文 Embedding 模型,可以用于英文的向量生成。

我们使用 FastChat 来部署 Embedding 模型,FastChat 是一个模型训练、部署、评估的开发平台,不仅支持 LLM 模型,还支持 Embedding 模型,下面来介绍如何使用 FastChat 部署 Embedding 模型。

首先我们要安装 FastChat,然后通过 FastChat 来部署一个兼容 OpenAI API 的 Embedding API 服务,安装命令如下:

1
pip3 install "fschat[model_worker,api]"

安装完成后,先使用 FastChat 的命令行工具来启动 controller 服务,命令如下:

1
2
3
4
5
6
$ python3 -m fastchat.serve.controller --host 0.0.0.0
2024-01-14 18:29:43 | INFO | controller | args: Namespace(dispatch_method='shortest_queue', host='0.0.0.0', port=21001, ssl=False)
2024-01-14 18:29:43 | ERROR | stderr | INFO: Started server process [1154]
2024-01-14 18:29:43 | ERROR | stderr | INFO: Waiting for application startup.
2024-01-14 18:29:43 | ERROR | stderr | INFO: Application startup complete.
2024-01-14 18:29:43 | ERROR | stderr | INFO: Uvicorn running on http://0.0.0.0:21001 (Press CTRL+C to quit)

然后重新打开一个终端,使用 FastChat 的命令行工具来启动 worker 服务,命令如下:

1
2
3
4
5
6
7
$ python3 -m fastchat.serve.model_worker --model-path BAAI/bge-base-en-v1.5 --host 0.0.0.0
2024-01-14 18:32:39 | INFO | model_worker | Loading the model ['bge-base-en-v1.5'] on worker 339a9e30 ...
2024-01-14 18:32:40 | INFO | model_worker | Register to controller
2024-01-14 18:32:40 | ERROR | stderr | INFO: Started server process [1229]
2024-01-14 18:32:40 | ERROR | stderr | INFO: Waiting for application startup.
2024-01-14 18:32:40 | ERROR | stderr | INFO: Application startup complete.
2024-01-14 18:32:40 | ERROR | stderr | INFO: Uvicorn running on http://0.0.0.0:21002 (Press CTRL+C to quit)

执行命令后,FastChat 会自动从 huggingface 上下载 BAAI/bge-base-en-v1.5 模型,下载完成后就会启动 worker 服务,worker 服务会自动连接到 controller 服务。

我们再打开一个终端,使用 FastChat 的命令行工具来启动 兼容 OpenAI API 的 API 服务,命令如下:

1
2
3
4
5
$ python3 -m fastchat.serve.openai_api_server --host 0.0.0.0 --port 8000
2024-01-14 18:37:10 | ERROR | stderr | INFO: Started server process [1405]
2024-01-14 18:37:10 | ERROR | stderr | INFO: Waiting for application startup.
2024-01-14 18:37:10 | ERROR | stderr | INFO: Application startup complete.
2024-01-14 18:37:10 | ERROR | stderr | INFO: Uvicorn running on http://0.0.0.0:8000(Press CTRL+C to quit)

服务启动后,我们可以访问http://localhost:8000/docs来查看 API 服务的 swagger 文档:

可以看到图中的/v1/embeddings接口就是我们需要调用的 Embedding 接口,我们可以通过 curl 命令来测试一下该接口,命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl -X 'POST' \
'https://localhost:8000/v1/embeddings' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"model": "bge-base-en-v1.5",
"input": "hello"
}'

# 显示结果
{
"object": "list",
"data": [
{
"object": "embedding",
"embedding": [0.013750563375651836, …], # 向量数据
"index": 0
}
],
"model": "bge-base-en-v1.5",
"usage": {
"prompt_tokens": 3,
"total_tokens": 3
}
}

我们在请求参数中输入模型名称和需要被向量化的文本,命令执行完成后,我们可以看到返回的结果包含了 embedding 后的向量数据,并且返回格式跟 OpenAI API 的格式是一样的。

FastChat 更多的相关部署内容可以参考 FastChat 的文档

LlamaIndex 文件加载与检索

LlamaIndex 是继 LangChain 之后另外一个 LLM 应用开发框架,整体功能以 RAG 为主,现在也慢慢在开发一些 Agent 相关的功能。该框架的主要编程语言是 Python,具有广泛的社区支持和贡献,包括众多的 forks 和 stars,表明其在开发社区中的受欢迎程度和实用性。

下面我们来介绍使用 LlamaIndex 结合 ES 进行文档加载与检索,在开始编写代码之前,我们需要安装 LlamaIndex 和 ES 的 Python 包,命令如下:

1
pip install llama-index elasticsearch

Embedding 自定义类

安装完依赖包后,我们开始编写相关代码,首先我们需要创建一个自定义的 Embedding 类,这个 Embedding 类会调用我们刚才部署的 Embedding API 接口来实现文本的向量化,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from llama_index.embeddings.base import BaseEmbedding, Embedding
from llama_index.bridge.pydantic import PrivateAttr
from typing import Any, List

class CustomEmbeddings(BaseEmbedding):
"""Custom class for embeddings.

Args:
model_name (str): Mode for embedding.
url(str): Url for embedding model.
"""

_model_name: str = PrivateAttr()
_url: str = PrivateAttr()

def __init__(self, model_name: str, url: str, **kwargs: Any) -> None:
self._model_name = model_name
self._url = url
super().__init__(**kwargs)

@classmethod
def class_name(cls) -> str:
return "custom_embedding"

def _aget_query_embedding(self, query: str) -> Embedding:
return get_embedding(text=query, model_uid=self._model_name, url=self._url)

def _aget_text_embedding(self, text: str) -> Embedding:
return get_embedding(text=text, model_uid=self._model_name, url=self._url)

def _get_query_embedding(self, query: str) -> Embedding:
return get_embedding(text=query, model_uid=self._model_name, url=self._url)

def _get_text_embedding(self, text: str) -> Embedding:
return get_embedding(text=text, model_uid=self._model_name, url=self._url)

def _get_text_embeddings(self, texts: List[str]) -> List[Embedding]:
return get_embeddings(
list_of_text=texts, model_uid=self._model_name, url=self._url
)
  • 使用 LlamaIndex 实现自定义的 Embedding 类,需要继承 BaseEmbedding 类,并实现相关的方法
  • 这里我们实现了_aget_query_embedding_aget_text_embedding_get_query_embedding_get_text_embedding_get_text_embeddings这几个方法,这几个方法会调用其他公共方法来实现文本转向量的功能。

我们再来看一下get_embeddingget_embeddings这两个方法的实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

def send_request(model_uid: str, text: str, url: str):
url = f"{url}/v1/embeddings"
request_body = {"model": model_uid, "input": text}
response = requests.post(url, json=request_body)
if response.status_code != 200:
raise RuntimeError(
f"Failed to create the embeddings, detail: {_get_error_string(response)}"
)
return response.json()

def get_embedding(text: str, model_uid: str, url: str) -> Embedding:
"""Get embedding."""
text = text.replace("\n", " ")
response_data = send_request(model_uid, text, url)
return response_data["data"][0]["embedding"]

def get_embeddings(
list_of_text: List[str], model_uid: str, url: str
) -> List[Embedding]:
"""Get embeddings."""
assert len(list_of_text) <= 2048, "The batch size should not be larger than 2048."

list_of_text = [text.replace("\n", " ") for text in list_of_text]
response_data = send_request(model_uid, list_of_text, url)
return [d["embedding"] for d in response_data["data"]]

  • get_embeddingget_embeddings都使用send_request来获取文本的向量数据,不同的地方在于一个参数是字符串,一个参数是字符串数组
  • send_request方法会发起 HTTP 请求调用 Embedding API 接口来实现文本向量化
  • 参考之前的 API 返回结果,Embedding 向量保存在一个数组中
  • get_embedding获取返回结果的第一个向量数据,get_embeddings获取所有的向量数据

向量化文档

有了自定义 Embedding 类,我们就可以使用 LlamaIndex 来实现文档的向量存储了,首先我们连接 ES 数据库,代码如下:

1
2
3
4
5
6
7
8
9
10
from llama_index.vector_stores import ElasticsearchStore
from llama_index import StorageContext

es_url = "http://{username}:{password}@localhost:9200"
index_name = "my_index"
store = ElasticsearchStore(
es_url=es_url,
index_name=index_name,
)
storage_context = StorageContext.from_defaults(vector_store=store)
  • 新建一个 ES store 来连接 ES,需要指定 ES 的地址和索引名称
  • ES 如果开启了安全认证,需要在 ES 的地址中添加用户名和密码
  • 使用 LlamaIndex 的 StorageContext 来集成 ES 的 store

我们再定义带有 Embedding 模型的 ServiceContext,代码如下:

1
2
3
4
5
6
7
8
9
10
from llama_index import ServiceContext
from custom_embedding import CustomEmbeddings

embedding_model_url = "http://localhost:8000"
embedding_model_name = "bge-base-en-v1.5"
service_context = ServiceContext.from_defaults(
embed_model=CustomEmbeddings(
url=embedding_model_url, model_name=embedding_model_name
),
)
  • embedding_model_url 是我们刚才部署的 Embedding API 的地址,model_name 是模型名称

接着我们来将文档转换为 LlamaIndex 的 Document 对象,我们可以使用 LlamaIndex 的示例文档paul_graham_essay来做演示,这篇文章是 Paul Graham 关于他个人生涯和工作经历的回顾,代码如下:

1
2
3
4
from llama_index import SimpleDirectoryReader

data_path = "./data" # paul_graham_essay.txt 所在的目录
documents = SimpleDirectoryReader(data_path).load_data()
  • SimpleDirectoryReader 对象可以对文件夹中的文件进行解析,txt 文件的解析不需要额外的依赖,但如果是其他格式的文件,比如 pdf,则需要安装相关的依赖 pypdf

我们将以上的对象组装在一起,示例代码如下:

1
2
3
4
5
6
7
from llama_index import VectorStoreIndex

index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
service_context=service_context,
)
  • 使用 VectorStoreIndex 集成 storage_context 和 service_context,并加载 documents
  • 不需要担心 ES 的索引是否已创建,如果没有该索引,LlamaIndex 会自动创建

代码执行后,我们就可以在 ES 中看到索引的文档了,我们通过 elasticvue 来查看索引的文档,如下图所示:

除了可以对整个文件夹进行加载外,我们还可以在已有的索引中添加新的文档,代码如下:

1
2
3
4
5
6
7
8
filepath = "./data/paul_graham_essay.txt"
index = VectorStoreIndex.from_vector_store(
vector_store=store,
storage_context=storage_context,
service_context=service_context,
)
document = SimpleDirectoryReader(input_files=[filepath]).load_data()[0]
index.insert(document)
  • 在 VectorStoreIndex 中传入 ES store 来加载已有的 ES 索引
  • SimpleDirectoryReader 也可以传入单个文件路径,这样就可以加载单个文件
  • 使用 VectorStoreIndex 的 insert 方法来添加新的文档

问题检索与生成

接下来我们再使用 LlamaIndex 来对问题进行检索,代码如下:

1
2
3
4
5
6
7
8
9
query_engine = index.as_query_engine()
response = query_engine.query("What did the author do growing up?")
print(f"response: {response}")

# 显示结果
# response: The author took philosophy courses, but found them boring.
# As a result, the author decided to switch to AI and started teaching
# themselves Lisp, which was regarded as the language of AI at the time.
# The author also reverse-engineered SHRDLU for their undergraduate thesis.
  • LlamaIndex 默认使用 OpenAI 的 LLM 来做生成,因此在执行代码之前,需要将 OPENAI_API_KEY 环境变量设置为你的 API KEY

我们询问了一个关于作者成长经历的问题,LlamaIndex 会先使用向量检索来检索相关的文档,然后再使用 LLM 来生成答案,我们可以看到 LlamaIndex 生成的答案是正确的。

如果我们将 LlamaIndex 中的 LLM 取消,那么 response 的结果会变成结合了相关文档的提示词模板,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
service_context = ServiceContext.from_defaults(
llm=None, # 取消LLM
embed_model=CustomEmbeddings(
url=embedding_model_url, model_name=embedding_model_name
),
)
......
response = query_engine.query("What did the author do growing up?")
print(f"response: {response}")

# 显示结果
# LLM is explicitly disabled. Using MockLLM.
# response: Context information is below.
# ---------------------
# file_path: data/paul_graham_essay.txt
#
# I don't think it was entirely blabla ......
# ---------------------
# Given the context information and not prior knowledge, answer the query.
# Query: What did the author do growing up?
# Answer:
  • 只需在 ServiceContext 中添加参数llm=none即可取消默认的 OpenAI LLM
  • 其他代码与原来的一样

可以看到同样的问题,不使用 LLM 的情况下返回的结果是一个包含了相关文档的提示词模板。

在 response 对象中,我们还可以通过response.source_nodes可以获取到检索到的文档信息,文档的 JSON 信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"py/object": "llama_index.schema.NodeWithScore",
"py/state": {
"__dict__": {
"node": {
"py/object": "llama_index.schema.TextNode",
"py/state": {
"__dict__": {
"metadata": {"file_path": "data/paul_graham_essay.txt",},
"hash": "72baf405cfa89677a1a409d46d58dab2f4c183adcba5602d8b01a27a05d9a7a5",
"text": "blabla...",
"start_char_idx": 53611,
"end_char_idx": 57967
},
}
},
"score": 1.0
},
}
},
{
"py/object": "llama_index.schema.NodeWithScore",
"py/state": {"__dict__": {},}
}
  • 可以看到 LlamaIndex 根据问题检索出 2 个 Node(可以把 Node 理解成文档的分块)
  • 每个 Node 有文本内容 text,匹配分数 score 等属性

LlamaIndex 默认是使用向量检索,我们也可以将其替换为其他检索方式,代码如下:

1
2
3
4
5
6
7
8
9
10
11
from llama_index.vector_stores.types import VectorStoreQueryMode

# 使用关键字检索
query_engine = index.as_query_engine(
vector_store_query_mode=VectorStoreQueryMode.TEXT_SEARCH,
)

# 使用混合检索
query_engine = index.as_query_engine(
vector_store_query_mode=VectorStoreQueryMode.HYBRID,
)

更多的 LlamaIndex 用法可以参考官方文档

总结

RAG 是 LLM 技术的一个重要方向,它不仅可以解决 LLM 中存在的一些问题,而且可以帮助我们打造更高质量的 LLM 应用。本文从 ES 和 Embedding 模型的部署一步步展开,结合 LLM 框架 LlamaIndex 来实现 RAG 的检索增强生成,并介绍了在实践过程中相关的原理和注意事项。希望本文能够帮助大家更好地理解 RAG 技术,如果对文章内容有疑问或者建议,欢迎在评论区留言。

关注我,一起学习各种人工智能和 AIGC 新技术,欢迎交流,如果你有什么想问想说的,欢迎在评论区留言。

]]>
- - - 介绍 Elasticsearch 部署、Embedding 模型部署以及如何使用 LlamaIndex 进行 RAG - - - - - - - - - - - - - - -
- diff --git a/categories/ai/index.html b/categories/ai/index.html index 5a749dd07..b89d47712 100644 --- a/categories/ai/index.html +++ b/categories/ai/index.html @@ -129,6 +129,20 @@

2024

+ + - -
diff --git a/categories/ai/page/2/index.html b/categories/ai/page/2/index.html index 1d1de409f..fd3aaa6f9 100644 --- a/categories/ai/page/2/index.html +++ b/categories/ai/page/2/index.html @@ -129,6 +129,20 @@

2024

+ + -
diff --git a/categories/ai/page/3/index.html b/categories/ai/page/3/index.html index 4d73d971f..dacc0c6a1 100644 --- a/categories/ai/page/3/index.html +++ b/categories/ai/page/3/index.html @@ -129,6 +129,20 @@

2023

+ + - -
diff --git a/categories/ai/page/4/index.html b/categories/ai/page/4/index.html index 624d0f392..f6f50d480 100644 --- a/categories/ai/page/4/index.html +++ b/categories/ai/page/4/index.html @@ -129,6 +129,20 @@

2023

+ + - -
diff --git a/categories/ai/page/5/index.html b/categories/ai/page/5/index.html index 43cadf459..95067e5dc 100644 --- a/categories/ai/page/5/index.html +++ b/categories/ai/page/5/index.html @@ -129,6 +129,20 @@

2023

+ +

部署 LangChain 和 ChatGLM2 来打造自有知识库问答系统

diff --git a/images/post/2024/07/next-generation-python-tools.jpg b/images/post/2024/07/next-generation-python-tools.jpg new file mode 100644 index 000000000..b93e5e727 Binary files /dev/null and b/images/post/2024/07/next-generation-python-tools.jpg differ diff --git a/images/post/2024/07/ruff-compare.png b/images/post/2024/07/ruff-compare.png new file mode 100644 index 000000000..52bce22e9 Binary files /dev/null and b/images/post/2024/07/ruff-compare.png differ diff --git a/images/post/2024/07/uv-compare.png b/images/post/2024/07/uv-compare.png new file mode 100644 index 000000000..cfbd581ad Binary files /dev/null and b/images/post/2024/07/uv-compare.png differ diff --git a/index.html b/index.html index 98aecd9b0..05281ed1f 100644 --- a/index.html +++ b/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 都 2024 年了,你还在用 pip 吗? +

+
+
+
Published on: +
+ +
+ + + +

编程语言 Python 随着 AI 的发展越来越受开发人员的喜爱,目前已经是最流行的编程语言,但由于 Python 是一门相对较老的语言,并且经过 Python2 到 Python3 这一漫长而复杂的迁移历程,使得一些 Python 开发人员可能还在使用一些过时的工具和库。今天我们就来带大家了解当前 Python 生态系统中最流行最实用的开发工具,让你彻底告别那些老古董

+ + + + +
+ +
+
-

- -
-

- 用 API 方式免费使用 GPT 写小说 -

-
-
-
Published on: -
-
Tags: - -chatgpt llm gpt -
-
- - - -

最近 OpenAI 宣布将降低网页版 ChatGPT 的使用门槛,允许没有账号的用户使用,这一好消息使我们可以在网页上免费访问 ChatGPT,但和 API 相比仍然缺乏灵活性,通过 API 开发人员可以编写代码来与 ChatGPT 进行自动化交互。今天我们将介绍如何利用 OpenAI 的这一免费功能,将其转化为 API 的形式来进行使用,并介绍如何通过这种方式来写一篇小说。

- - - - -
-
diff --git a/page/10/index.html b/page/10/index.html index aa056a6bf..00bdebf94 100644 --- a/page/10/index.html +++ b/page/10/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

历年文章

- +
@@ -180,6 +180,32 @@

历年文章

+
+

+ 物极必反 +

+
+
+
Published on: +
+
Tags: + +thinking +
+
+ + +

物极必反是很多人都明白的一个道理,在软件开发中也一样,比如过度设计,这也是为什么Fackbook推崇“完成比完美更重要”的原因。

+ + + + +
+ +
+
- - -
-

- 『我』的产品说明书 -

-
-
-
Published on: -
-
Tags: - -teamwork -
-
- - -

最近使用引导者方法——的产品说明书,为团队做了一次沟通交流,让大家彼此加深了了解,同时从中得到了团队成员的喜好、特长等信息,大家觉得这种方式挺有意思,所以今天在这里分享一下。

- - - - -
-
diff --git a/page/11/index.html b/page/11/index.html index 31a53c570..a458862bf 100644 --- a/page/11/index.html +++ b/page/11/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

历年文章

@@ -180,6 +180,32 @@

历年文章

+
+

+ 『我』的产品说明书 +

+
+
+
Published on: +
+
Tags: + +teamwork +
+
+ + +

最近使用引导者方法——的产品说明书,为团队做了一次沟通交流,让大家彼此加深了了解,同时从中得到了团队成员的喜好、特长等信息,大家觉得这种方式挺有意思,所以今天在这里分享一下。

+ + + + +
+ +
+
- - -
-

- 科学上网利器Shadowsocks -

-
-
-
Published on: -
-
Tags: - -ss vps -
-
- - -

前段时间AppStore出了一款神器Surge,可以让iOS像其他平台使用Shadowsocks(以下简称ss)一样地轻松科学上网,因为以前都是用买的SSH或VPN科学上网,所以对自建的VPN服务这一块没有太多关注,甚至错过了ss这种成熟的工具。最近试用了过后觉得非常方便,所以在这里记录一下。

- - - - -
-
diff --git a/page/12/index.html b/page/12/index.html index 04ffa6e95..05f912cba 100644 --- a/page/12/index.html +++ b/page/12/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,32 @@

历年文章

+
+

+ 科学上网利器Shadowsocks +

+
+
+
Published on: +
+
Tags: + +ss vps +
+
+ + +

前段时间AppStore出了一款神器Surge,可以让iOS像其他平台使用Shadowsocks(以下简称ss)一样地轻松科学上网,因为以前都是用买的SSH或VPN科学上网,所以对自建的VPN服务这一块没有太多关注,甚至错过了ss这种成熟的工具。最近试用了过后觉得非常方便,所以在这里记录一下。

+ + + + +
+ +
+
- - -
-

- 使用Spring-data进行Redis操作 -

-
-
-
Published on: -
-
Tags: - -redis spring -
-
- - -

Redis相信大家都听说过,它是一个开源的key-value缓存数据库,有很多Java的客户端支持,比较有名的有Jedis,JRedis等(见这里)。当然我们可以使用客户端的原生代码实现redis的操作,但实际上在spring中就已经集成了这些客户端的使用,下面我们就以Jedis为例来介绍一下Spring中关于Redis的配置。

- - - - -
-
diff --git a/page/13/index.html b/page/13/index.html index e4fcfc9ba..636b0aaac 100644 --- a/page/13/index.html +++ b/page/13/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,32 @@

历年文章

+
+

+ 使用Spring-data进行Redis操作 +

+
+
+
Published on: +
+
Tags: + +redis spring +
+
+ + +

Redis相信大家都听说过,它是一个开源的key-value缓存数据库,有很多Java的客户端支持,比较有名的有Jedis,JRedis等(见这里)。当然我们可以使用客户端的原生代码实现redis的操作,但实际上在spring中就已经集成了这些客户端的使用,下面我们就以Jedis为例来介绍一下Spring中关于Redis的配置。

+ + + + +
+ +
+
- - -
-

- 使用Docker打造自己的开发环境 -

-
-
-
Published on: -
-
Tags: - -docker -
-
- - -

作为这个时代的程序员真的很幸福,每天不但有一些改变世界的产品出现,而且提高程序员开发效率的工具也是层出不穷。之前介绍过如何使用Vagrant来创建Ceph环境,使用Vagrant可以很方便的管理我们的虚拟机,同时来定制开发团队的开发环境,现在又出现了Docker,让我们有了一个更好的选择。

- - - - -
-
diff --git a/page/14/index.html b/page/14/index.html index c61803c63..97d9d8210 100644 --- a/page/14/index.html +++ b/page/14/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,32 @@

历年文章

+
+

+ 使用Docker打造自己的开发环境 +

+
+
+
Published on: +
+
Tags: + +docker +
+
+ + +

作为这个时代的程序员真的很幸福,每天不但有一些改变世界的产品出现,而且提高程序员开发效率的工具也是层出不穷。之前介绍过如何使用Vagrant来创建Ceph环境,使用Vagrant可以很方便的管理我们的虚拟机,同时来定制开发团队的开发环境,现在又出现了Docker,让我们有了一个更好的选择。

+ + + + +
+ +
+
- - -
-

- 让你的安卓开发更容易(二)——Genymotion -

-
-
-
Published on: -
-
Tags: - -android genymotion -
-
- - -

以前听过一个笑话,说是一个App好不容易拿到100万的融资,但是没几天就花完了,问创始人这钱怎么花的?创始人说:没什么,就是每个型号的Android手机各买了一个来做测试,钱就花完了。

-

Android开发需要有强大的模拟器来避免这种尴尬,Genymotion是一个Android模拟器,比起Google官方的AVD(Android Virtual Devices),它有着启动快速,安装方便,简单上手的特点。

- - - - -
-
diff --git a/page/15/index.html b/page/15/index.html index 5af3bda62..14c14a1d6 100644 --- a/page/15/index.html +++ b/page/15/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 让你的安卓开发更容易(二)——Genymotion +

+
+
+
Published on: +
+
Tags: + +android genymotion +
+
+ + +

以前听过一个笑话,说是一个App好不容易拿到100万的融资,但是没几天就花完了,问创始人这钱怎么花的?创始人说:没什么,就是每个型号的Android手机各买了一个来做测试,钱就花完了。

+

Android开发需要有强大的模拟器来避免这种尴尬,Genymotion是一个Android模拟器,比起Google官方的AVD(Android Virtual Devices),它有着启动快速,安装方便,简单上手的特点。

+ + + + +
+ +
+ - - diff --git a/page/16/index.html b/page/16/index.html index 74f3e2865..5fe3ba62b 100644 --- a/page/16/index.html +++ b/page/16/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,31 @@

历年文章

+ +
- - - diff --git a/page/17/index.html b/page/17/index.html index 36a54b864..cbdd3f5ff 100644 --- a/page/17/index.html +++ b/page/17/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+ +
- - - diff --git a/page/18/index.html b/page/18/index.html index 307b51720..297f732d1 100644 --- a/page/18/index.html +++ b/page/18/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,31 @@

历年文章

+ +
- - -
-

- Jacoco的原理 -

-
-
-
Published on: -
-
Tags: - -jacoco -
-
- -

覆盖率计数器

Jacoco使用一系列的不同的计数器来做覆盖率的度量计算。所有这些计数器都是从java的class文件中获取信息,这些class文件可以(可选)包含调试的信息在里面。即使在没有源码的情况下,这种方法也可以实时有效地对应用程序进行度量和分析。在大部分情况下,收集到的信息可以映射到源码,可视化到每一行代码的粒度。但这种方法还是有一些限制。这些class文件必须使用调试信息来编译,这样才可以计算行的覆盖率和提供出源码的高亮。但不是所有的JAVA语言的结构都可以直接编译成一致的二进制代码。在这种情况下,java 编译器会创建所谓的“合成”代码,会导致产生一些不期望得到的覆盖率结果。

- - - - -
-
diff --git a/page/19/index.html b/page/19/index.html index 90834f47c..33ff18d58 100644 --- a/page/19/index.html +++ b/page/19/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,31 @@

历年文章

+
+

+ Jacoco的原理 +

+
+
+
Published on: +
+
Tags: + +jacoco +
+
+ +

覆盖率计数器

Jacoco使用一系列的不同的计数器来做覆盖率的度量计算。所有这些计数器都是从java的class文件中获取信息,这些class文件可以(可选)包含调试的信息在里面。即使在没有源码的情况下,这种方法也可以实时有效地对应用程序进行度量和分析。在大部分情况下,收集到的信息可以映射到源码,可视化到每一行代码的粒度。但这种方法还是有一些限制。这些class文件必须使用调试信息来编译,这样才可以计算行的覆盖率和提供出源码的高亮。但不是所有的JAVA语言的结构都可以直接编译成一致的二进制代码。在这种情况下,java 编译器会创建所谓的“合成”代码,会导致产生一些不期望得到的覆盖率结果。

+ + + + +
+ +
+
- - -
-

- 在JavaScript中进行文件处理,第三部分:处理事件和错误 -

-
-
-
Published on: -
-
Tags: - -javascript -
-
- -

译注:原文是《JavaScript高级程序设计》的作者Nicholas Zakas写的,本翻译纯属为自己学习而做,仅供参考。原文链接:这里

-
-

FileReader对象用来读取浏览器可以访问的文件的内容。在我前一篇blog中,你学习到了如何使用FileReader对象轻松读取文件,并将文件内容转换为各种形式。FileReader在很多方面和XMLHttpRequest非常相似。

- - - - -
-
diff --git a/page/2/index.html b/page/2/index.html index 118126156..0aabc50cc 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 用 API 方式免费使用 GPT 写小说 +

+
+
+
Published on: +
+
Tags: + +chatgpt llm gpt +
+
+ + + +

最近 OpenAI 宣布将降低网页版 ChatGPT 的使用门槛,允许没有账号的用户使用,这一好消息使我们可以在网页上免费访问 ChatGPT,但和 API 相比仍然缺乏灵活性,通过 API 开发人员可以编写代码来与 ChatGPT 进行自动化交互。今天我们将介绍如何利用 OpenAI 的这一免费功能,将其转化为 API 的形式来进行使用,并介绍如何通过这种方式来写一篇小说。

+ + + + +
+ +
+
- - -
-

- 使用 LlamaIndex 结合 Eleasticsearch 进行 RAG 检索增强生成 -

-
-
-
Published on: -
- -
- - - -

检索增强生成(Retrieval-Augmented Generation,RAG)是一种结合了检索(Retrieval)和生成(Generation)的技术,它有效地解决了大语言模型(LLM)的一些问题,比如幻觉、知识限制等。随着 RAG 技术的发展,RAG 涉及到的向量技术受到了大家的关注,向量数据库也慢慢被大家所了解,一些老牌的数据库厂商也纷纷表示支持向量检索,比如 Elasticsearch 也在最近的版本增加了向量检索的支持。本文将介绍 Elasticsearch 和 RAG 中相关的 Embedding 模型的部署,以及在 LLM 框架 LLamaIndex 中如何使用 Elasticsearch 进行文档索引入库和检索。

- - - - -
-
diff --git a/page/20/index.html b/page/20/index.html index 7d213851a..b08d4e78d 100644 --- a/page/20/index.html +++ b/page/20/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 在JavaScript中进行文件处理,第三部分:处理事件和错误 +

+
+
+
Published on: +
+
Tags: + +javascript +
+
+ +

译注:原文是《JavaScript高级程序设计》的作者Nicholas Zakas写的,本翻译纯属为自己学习而做,仅供参考。原文链接:这里

+
+

FileReader对象用来读取浏览器可以访问的文件的内容。在我前一篇blog中,你学习到了如何使用FileReader对象轻松读取文件,并将文件内容转换为各种形式。FileReader在很多方面和XMLHttpRequest非常相似。

+ + + + +
+ +
+
- - -
-

- jenkins的2个问题 -

-
-
-
Published on: -
-
Tags: - -jenkins -
-
- -

最近CI服务器从老版本的hudson升级为jenkins,遇到了2个问题,记录一下:

- - - - -
-
diff --git a/page/21/index.html b/page/21/index.html index c6566f590..208d96193 100644 --- a/page/21/index.html +++ b/page/21/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,31 @@

历年文章

+
+

+ jenkins的2个问题 +

+
+
+
Published on: +
+
Tags: + +jenkins +
+
+ +

最近CI服务器从老版本的hudson升级为jenkins,遇到了2个问题,记录一下:

+ + + + +
+ +
+
- - -
-

- 在junit中添加fail--有test失败即build failed -

-
-
-
Published on: -
-
Tags: - -ant junit -
-
- -

项目使用jenkins做持续集成,ant来构建,发现在跑junit单元测试的时候,如果有test case失败了,ci的状态是黄色的unstable,而不是红色的failed,看起来很不爽。个人觉得build只有两种状态最好,绿色stable和红色failed,黄色让人看起来很困惑,是要fix好呢还是不fix也可以呢?

- - - - -
-
@@ -438,6 +438,8 @@

+ + diff --git a/page/22/index.html b/page/22/index.html new file mode 100644 index 000000000..f17ff52eb --- /dev/null +++ b/page/22/index.html @@ -0,0 +1,255 @@ + + + + + + Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+ + + + + + + +
+ +
+
+ +
+

+ 在junit中添加fail--有test失败即build failed +

+
+
+
Published on: +
+
Tags: + +ant junit +
+
+ +

项目使用jenkins做持续集成,ant来构建,发现在跑junit单元测试的时候,如果有test case失败了,ci的状态是黄色的unstable,而不是红色的failed,看起来很不爽。个人觉得build只有两种状态最好,绿色stable和红色failed,黄色让人看起来很困惑,是要fix好呢还是不fix也可以呢?

+ + + + +
+ +
+ + + + +
+
+
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/page/3/index.html b/page/3/index.html index 285125a03..e1bc3d525 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 使用 LlamaIndex 结合 Eleasticsearch 进行 RAG 检索增强生成 +

+
+
+
Published on: +
+ +
+ + + +

检索增强生成(Retrieval-Augmented Generation,RAG)是一种结合了检索(Retrieval)和生成(Generation)的技术,它有效地解决了大语言模型(LLM)的一些问题,比如幻觉、知识限制等。随着 RAG 技术的发展,RAG 涉及到的向量技术受到了大家的关注,向量数据库也慢慢被大家所了解,一些老牌的数据库厂商也纷纷表示支持向量检索,比如 Elasticsearch 也在最近的版本增加了向量检索的支持。本文将介绍 Elasticsearch 和 RAG 中相关的 Embedding 模型的部署,以及在 LLM 框架 LLamaIndex 中如何使用 Elasticsearch 进行文档索引入库和检索。

+ + + + +
+ +
+
- - -
-

- 使用 API 生成 Stable Diffustion 文字和二维码隐藏图片 -

-
-
-
Published on: -
- -
- - - -

Stable Diffusion 前段时间有几个比较火的效果,一个是将文字隐藏在图片中,放大看时是一张正常图片,缩小看却可以看到图片中的隐藏文字,另外一个效果与前者类似,但是图片中隐藏的是一个二维码,通过扫描图片可以进入二维码中的网址。由于出图效果好,很多人想要根据自己的需求制作这种图片,甚至有人在网上出售这种图片的定制服务。今天我们就来介绍下如何使用 API 的方式 在 Stable Diffusion 中实现这种效果。

- - - - -
-
diff --git a/page/4/index.html b/page/4/index.html index 31a1d3bfd..c803558ef 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 使用 API 生成 Stable Diffustion 文字和二维码隐藏图片 +

+
+
+
Published on: +
+ +
+ + + +

Stable Diffusion 前段时间有几个比较火的效果,一个是将文字隐藏在图片中,放大看时是一张正常图片,缩小看却可以看到图片中的隐藏文字,另外一个效果与前者类似,但是图片中隐藏的是一个二维码,通过扫描图片可以进入二维码中的网址。由于出图效果好,很多人想要根据自己的需求制作这种图片,甚至有人在网上出售这种图片的定制服务。今天我们就来介绍下如何使用 API 的方式 在 Stable Diffusion 中实现这种效果。

+ + + + +
+ +
+
- - -
-

- 使用 Docker 部署 AI 环境 -

-
-
-
Published on: -
- -
- - - -

之前给大家介绍了主机安装方式——如何在 Ubuntu 操作系统下安装部署 AI 环境,但随着容器化技术的普及,越来越多的程序以容器的形式进行部署,通过容器的方式不仅可以简化部署流程,还可以随时切换不同的环境。实际上很多云服务厂商也是这么干的,用一台带有 NVIDIA 显卡的机器来部署多个容器,然后通过容器的方式来提供给用户使用,这样就可以充分利用显卡资源了。今天给大家介绍一下如何使用 Docker 的方式来部署我们之前部署过的 AI 环境。

- - - - -
-
diff --git a/page/5/index.html b/page/5/index.html index 153a31a86..71e50ddb2 100644 --- a/page/5/index.html +++ b/page/5/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 使用 Docker 部署 AI 环境 +

+
+
+
Published on: +
+ +
+ + + +

之前给大家介绍了主机安装方式——如何在 Ubuntu 操作系统下安装部署 AI 环境,但随着容器化技术的普及,越来越多的程序以容器的形式进行部署,通过容器的方式不仅可以简化部署流程,还可以随时切换不同的环境。实际上很多云服务厂商也是这么干的,用一台带有 NVIDIA 显卡的机器来部署多个容器,然后通过容器的方式来提供给用户使用,这样就可以充分利用显卡资源了。今天给大家介绍一下如何使用 Docker 的方式来部署我们之前部署过的 AI 环境。

+ + + + +
+ +
+
- - -
-

- 大语言模型代码生成工具 -

-
-
-
Published on: -
-
Tags: - -code ai -
-
- - - -

随着大语言模型技术的发展,人工智能的能力应用到了各个领域,包括与开发人员息息相关的代码生成领域,这个领域并不新鲜,但借助大型语言模型的力量,它被赋予了全新的生命力和可能性。在数字化的世界中,代码是一种语言,是人类与机器沟通的桥梁。借助大型语言模型的力量,我们可以让这座桥梁更加强大,更加智能。今天我们将深入探讨大型语言模型在代码生成方面的应用。

- - - - -
-
diff --git a/page/6/index.html b/page/6/index.html index 340fc293a..c5ab2a6df 100644 --- a/page/6/index.html +++ b/page/6/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+
+

+ 大语言模型代码生成工具 +

+
+
+
Published on: +
+
Tags: + +code ai +
+
+ + + +

随着大语言模型技术的发展,人工智能的能力应用到了各个领域,包括与开发人员息息相关的代码生成领域,这个领域并不新鲜,但借助大型语言模型的力量,它被赋予了全新的生命力和可能性。在数字化的世界中,代码是一种语言,是人类与机器沟通的桥梁。借助大型语言模型的力量,我们可以让这座桥梁更加强大,更加智能。今天我们将深入探讨大型语言模型在代码生成方面的应用。

+ + + + +
+ +
+
- - -
-

- 使用 TestCafe 进行 Web 自动化测试 -

-
-
-
Published on: -
- -
- - - -

Web 自动化测试,又叫 UI 自动化测试,国外叫 End-to-End Test(e2e, 端到端测试),可以让重复繁琐的手工测试( 俗称点点点)通过程序自动执行,可以极大地提升测试人员的效率(想象一下以前如果回归测试要测试一天的话,使用自动化测试可能只需要不到 1 小时的时间)。

-

今天介绍一个自动化测试工具新贵——TestCafe,它的功能和开发团队都很棒,但一直比较低调所以没有其他同类工具出名,如果你对自动化测试感兴趣,不妨和我一起来了解它。

- - - - -
-
diff --git a/page/7/index.html b/page/7/index.html index cd26d902a..5cba53a06 100644 --- a/page/7/index.html +++ b/page/7/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,34 @@

历年文章

+
+

+ 使用 TestCafe 进行 Web 自动化测试 +

+
+
+
Published on: +
+ +
+ + + +

Web 自动化测试,又叫 UI 自动化测试,国外叫 End-to-End Test(e2e, 端到端测试),可以让重复繁琐的手工测试( 俗称点点点)通过程序自动执行,可以极大地提升测试人员的效率(想象一下以前如果回归测试要测试一天的话,使用自动化测试可能只需要不到 1 小时的时间)。

+

今天介绍一个自动化测试工具新贵——TestCafe,它的功能和开发团队都很棒,但一直比较低调所以没有其他同类工具出名,如果你对自动化测试感兴趣,不妨和我一起来了解它。

+ + + + +
+ +
+
- - -
-

- 基于 Expo 的 React Native 消息推送 -

-
-
-
Published on: -
- -
- - - -

ExpoReact Native 开发的一个神器,正如 Expo 官网上所说,Expo 之于 React Native 就像 Rails 之于 Ruby,它提供了很多超越原生 React Native API 的功能,包括二维码扫描、存储、内部浏览器等,甚至还可以使用 Expo 进行 APP 的打包,完全不需要使用 XCode 和 Android Studio。

-

而消息推送则是 APP 应用非常常见的一个功能,今天就来介绍一下基于 Expo 的 React Native 消息推送功能是如何开发的吧。

- - - - -
-
diff --git a/page/8/index.html b/page/8/index.html index af139a375..45503e224 100644 --- a/page/8/index.html +++ b/page/8/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,34 @@

历年文章

+
+

+ 基于 Expo 的 React Native 消息推送 +

+
+
+
Published on: +
+ +
+ + + +

ExpoReact Native 开发的一个神器,正如 Expo 官网上所说,Expo 之于 React Native 就像 Rails 之于 Ruby,它提供了很多超越原生 React Native API 的功能,包括二维码扫描、存储、内部浏览器等,甚至还可以使用 Expo 进行 APP 的打包,完全不需要使用 XCode 和 Android Studio。

+

而消息推送则是 APP 应用非常常见的一个功能,今天就来介绍一下基于 Expo 的 React Native 消息推送功能是如何开发的吧。

+ + + + +
+ +
+
- - - diff --git a/page/9/index.html b/page/9/index.html index 5e1972702..cf027054b 100644 --- a/page/9/index.html +++ b/page/9/index.html @@ -133,6 +133,10 @@

最新文章

@@ -170,7 +170,7 @@

标签云

@@ -180,6 +180,33 @@

历年文章

+ +
- - -
-

- 物极必反 -

-
-
-
Published on: -
-
Tags: - -thinking -
-
- - -

物极必反是很多人都明白的一个道理,在软件开发中也一样,比如过度设计,这也是为什么Fackbook推崇“完成比完美更重要”的原因。

- - - - -
-
diff --git a/tags/miniconda/index.html b/tags/miniconda/index.html new file mode 100644 index 000000000..8a8473f7d --- /dev/null +++ b/tags/miniconda/index.html @@ -0,0 +1,187 @@ + + + + + + Tag: miniconda - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2024

+ + + + +
+ + + +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/tags/poetry/index.html b/tags/poetry/index.html new file mode 100644 index 000000000..e47ae9460 --- /dev/null +++ b/tags/poetry/index.html @@ -0,0 +1,187 @@ + + + + + + Tag: poetry - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2024

+ + + + +
+ + + +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/tags/python/index.html b/tags/python/index.html index 8130c1110..545ac67ab 100644 --- a/tags/python/index.html +++ b/tags/python/index.html @@ -127,6 +127,25 @@

+

2024

+ + + +
+ +

2015

diff --git a/tags/ruff/index.html b/tags/ruff/index.html new file mode 100644 index 000000000..cb17b94a4 --- /dev/null +++ b/tags/ruff/index.html @@ -0,0 +1,187 @@ + + + + + + Tag: ruff - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2024

+ + + + +
+ + + +
+ +
+ + + + + + + + + +
+
+ + + + + diff --git a/tags/uv/index.html b/tags/uv/index.html new file mode 100644 index 000000000..b8e045f62 --- /dev/null +++ b/tags/uv/index.html @@ -0,0 +1,187 @@ + + + + + + Tag: uv - Hacker and Geeker's Way + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + + + + + + + + +

2024

+ + + + +
+ + + +
+ +
+ + + + + + + + + +
+
+ + + + +