提交 ed7c5485 作者: imClumsyPanda

add delete knowledge base and delete files from knowledge base to webui

上级 331f39cd
...@@ -167,6 +167,7 @@ log/* ...@@ -167,6 +167,7 @@ log/*
vector_store/* vector_store/*
content/* content/*
api_content/* api_content/*
knowledge_base/*
llm/* llm/*
embedding/* embedding/*
......
...@@ -297,6 +297,16 @@ class LocalDocQA: ...@@ -297,6 +297,16 @@ class LocalDocQA:
status = vector_store.update_doc(filepath, docs) status = vector_store.update_doc(filepath, docs)
return status return status
def list_file_from_vector_store(self,
vs_path,
fullpath=False):
vector_store = load_vector_store(vs_path, self.embeddings)
docs = vector_store.list_docs()
if fullpath:
return docs
else:
return [os.path.split(doc)[-1] for doc in docs]
if __name__ == "__main__": if __name__ == "__main__":
# 初始化消息 # 初始化消息
......
# 基于本地知识库的 ChatGLM 等大语言模型应用实现
## 介绍
🌍 [_READ THIS IN ENGLISH_](README_en.md)
🤖️ 一种利用 [langchain](https://github.com/hwchase17/langchain) 思想实现的基于本地知识库的问答应用,目标期望建立一套对中文场景与开源模型支持友好、可离线运行的知识库问答解决方案。
💡 受 [GanymedeNil](https://github.com/GanymedeNil) 的项目 [document.ai](https://github.com/GanymedeNil/document.ai)[AlexZhangji](https://github.com/AlexZhangji) 创建的 [ChatGLM-6B Pull Request](https://github.com/THUDM/ChatGLM-6B/pull/216) 启发,建立了全流程可使用开源模型实现的本地知识库问答应用。现已支持使用 [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B) 等大语言模型直接接入,或通过 [fastchat](https://github.com/lm-sys/FastChat) api 形式接入 Vicuna, Alpaca, LLaMA, Koala, RWKV 等模型。
✅ 本项目中 Embedding 默认选用的是 [GanymedeNil/text2vec-large-chinese](https://huggingface.co/GanymedeNil/text2vec-large-chinese/tree/main),LLM 默认选用的是 [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B)。依托上述模型,本项目可实现全部使用**开源**模型**离线私有部署**
⛓️ 本项目实现原理如下图所示,过程包括加载文件 -> 读取文本 -> 文本分割 -> 文本向量化 -> 问句向量化 -> 在文本向量中匹配出与问句向量最相似的`top k`个 -> 匹配出的文本作为上下文和问题一起添加到`prompt`中 -> 提交给`LLM`生成回答。
📺 [原理介绍视频](https://www.bilibili.com/video/BV13M4y1e7cN/?share_source=copy_web&vd_source=e6c5aafe684f30fbe41925d61ca6d514)
![实现原理图](img/langchain+chatglm.png)
从文档处理角度来看,实现流程如下:
![实现原理图2](img/langchain+chatglm2.png)
🚩 本项目未涉及微调、训练过程,但可利用微调或训练对本项目效果进行优化。
🌐 [AutoDL 镜像](https://www.codewithgpu.com/i/imClumsyPanda/langchain-ChatGLM/langchain-ChatGLM)
📓 [ModelWhale 在线运行项目](https://www.heywhale.com/mw/project/643977aa446c45f4592a1e59)
## 变更日志
参见 [变更日志](docs/CHANGELOG.md)
## 硬件需求
- ChatGLM-6B 模型硬件需求
注:如未将模型下载至本地,请执行前检查`$HOME/.cache/huggingface/`文件夹剩余空间,模型文件下载至本地需要 15 GB 存储空间。
注:一些其它的可选启动项见[项目启动选项](docs/StartOption.md)
模型下载方法可参考 [常见问题](docs/FAQ.md) 中 Q8。
| **量化等级** | **最低 GPU 显存**(推理) | **最低 GPU 显存**(高效参数微调) |
| -------------- | ------------------------- | --------------------------------- |
| FP16(无量化) | 13 GB | 14 GB |
| INT8 | 8 GB | 9 GB |
| INT4 | 6 GB | 7 GB |
- MOSS 模型硬件需求
注:如未将模型下载至本地,请执行前检查`$HOME/.cache/huggingface/`文件夹剩余空间,模型文件下载至本地需要 70 GB 存储空间
模型下载方法可参考 [常见问题](docs/FAQ.md) 中 Q8。
| **量化等级** | **最低 GPU 显存**(推理) | **最低 GPU 显存**(高效参数微调) |
|-------------------|-----------------------| --------------------------------- |
| FP16(无量化) | 68 GB | - |
| INT8 | 20 GB | - |
- Embedding 模型硬件需求
本项目中默认选用的 Embedding 模型 [GanymedeNil/text2vec-large-chinese](https://huggingface.co/GanymedeNil/text2vec-large-chinese/tree/main) 约占用显存 3GB,也可修改为在 CPU 中运行。
## Docker 部署
为了能让容器使用主机GPU资源,需要在主机上安装 [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit)。具体安装步骤如下:
```shell
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit-base
sudo systemctl daemon-reload
sudo systemctl restart docker
```
安装完成后,可以使用以下命令编译镜像和启动容器:
```
docker build -f Dockerfile-cuda -t chatglm-cuda:latest .
docker run --gpus all -d --name chatglm -p 7860:7860 chatglm-cuda:latest
#若要使用离线模型,请配置好模型路径,然后此repo挂载到Container
docker run --gpus all -d --name chatglm -p 7860:7860 -v ~/github/langchain-ChatGLM:/chatGLM chatglm-cuda:latest
```
## 开发部署
### 软件需求
本项目已在 Python 3.8.1 - 3.10,CUDA 11.7 环境下完成测试。已在 Windows、ARM 架构的 macOS、Linux 系统中完成测试。
vue前端需要node18环境
### 从本地加载模型
请参考 [THUDM/ChatGLM-6B#从本地加载模型](https://github.com/THUDM/ChatGLM-6B#从本地加载模型)
### 1. 安装环境
参见 [安装指南](docs/INSTALL.md)
### 2. 设置模型默认参数
在开始执行 Web UI 或命令行交互前,请先检查 [configs/model_config.py](configs/model_config.py) 中的各项模型参数设计是否符合需求。
如需通过 fastchat 以 api 形式调用 llm,请参考 [fastchat 调用实现](docs/fastchat.md)
### 3. 执行脚本体验 Web UI 或命令行交互
> 注:鉴于环境部署过程中可能遇到问题,建议首先测试命令行脚本。建议命令行脚本测试可正常运行后再运行 Web UI。
执行 [cli_demo.py](cli_demo.py) 脚本体验**命令行交互**
```shell
$ python cli_demo.py
```
或执行 [webui.py](webui.py) 脚本体验 **Web 交互**
```shell
$ python webui.py
```
或执行 [api.py](api.py) 利用 fastapi 部署 API
```shell
$ python api.py
```
或成功部署 API 后,执行以下脚本体验基于 VUE 的前端页面
```shell
$ cd views
$ pnpm i
$ npm run dev
```
VUE 前端界面如下图所示:
1. `对话` 界面
![](img/vue_0521_0.png)
2. `知识库问答` 界面
![](img/vue_0521_1.png)
3. `Bing搜索` 界面
![](img/vue_0521_2.png)
WebUI 界面如下图所示:
1. `对话` Tab 界面
![](img/webui_0521_0.png)
2. `知识库测试 Beta` Tab 界面
![](img/webui_0510_1.png)
3. `模型配置` Tab 界面
![](img/webui_0510_2.png)
Web UI 可以实现如下功能:
1. 运行前自动读取`configs/model_config.py``LLM``Embedding`模型枚举及默认模型设置运行模型,如需重新加载模型,可在 `模型配置` Tab 重新选择后点击 `重新加载模型` 进行模型加载;
2. 可手动调节保留对话历史长度、匹配知识库文段数量,可根据显存大小自行调节;
3. `对话` Tab 具备模式选择功能,可选择 `LLM对话``知识库问答` 模式进行对话,支持流式对话;
4. 添加 `配置知识库` 功能,支持选择已有知识库或新建知识库,并可向知识库中**新增**上传文件/文件夹,使用文件上传组件选择好文件后点击 `上传文件并加载知识库`,会将所选上传文档数据加载至知识库中,并基于更新后知识库进行问答;
5. 新增 `知识库测试 Beta` Tab,可用于测试不同文本切分方法与检索相关度阈值设置,暂不支持将测试参数作为 `对话` Tab 设置参数。
6. 后续版本中将会增加对知识库的修改或删除,及知识库中已导入文件的查看。
### 常见问题
参见 [常见问题](docs/FAQ.md)
## Demo
以问题`chatglm-6b 的局限性具体体现在哪里,如何实现改进`为例:
未使用 langchain 接入本地文档时:
>ChatGLM-6B 是一个基于 GPT-3 的聊天机器人,它的局限性主要体现在以下几个方面:
>1. 语言模型的精度:GPT-3 是一种大型的语言模型,它的精度比较高,但是仍然有一些局限性。例如,它可能无法准确地理解某些方言、口音或者复杂的句子结构。
>2. 知识图谱的完整性:GPT-3 可以生成一些知识图谱,但是其完整性和准确性可能不够。例如,它可能无法准确地理解某些领域的专业知识和术语。
>3. 对话生成的连贯性:GPT-3 可以生成一些连贯的对话,但是其生成的对话可能不够自然。例如,它可能会生成一些虚假的、不连贯的对话或者误解用户的意图。
>
>为了改进 ChatGLM-6B,可以考虑以下几个方面:
>1. 提高语言模型的精度:可以通过增加训练数据、使用更好的语言模型架构、优化模型训练过程等方式来提高语言模型的精度。
>2. 增强知识图谱的完整性:可以通过增加知识图谱的维度、使用更好的知识图谱构建方法、优化知识图谱的匹配算法等方式来增强知识图谱的完整性。
>3. 提高对话生成的连贯性:可以通过增加对话生成模型的上下文信息、使用更好的上下文信息提取方法、优化对话生成模型的算法等方式来提高对话生成的连贯性。
>4. 引入更多的人类反馈:人类反馈可以帮助 ChatGLM-6B 更好地理解用户的意图和需求,从而提高对话生成的质量和准确性。可以通过引入更多的人类客服、使用人类反馈收集器等方式来引入更多的人类反馈。
使用 langchain 接入 ChatGLM-6B 项目的 README.md 文件后 ChatGLM 的回答:
>ChatGLM-6B 是一个基于深度学习的自然语言处理模型,它在回答问题方面表现出色。但是,它也有一些局限性,具体如下:
>1. 语言理解有限:ChatGLM-6B 只学习了中文自然语言,对于其他语言可能会存在理解上的局限性。
>2. 知识储备不足:ChatGLM-6B 的训练数据集只包含了中文语料,因此它可能无法回答一些非中文的问题或者某些特定领域的问题。
>3. 数据量有限:ChatGLM-6B 的训练数据集只有几百万条记录,因此它可能无法回答一些非常具体或者复杂的问题。
>
>为了改进 ChatGLM-6B,可以考虑以下几个方面:
>1. 学习更多的语言知识:可以学习其他语言的自然语言处理技术,扩大语言理解的范围。
>2. 扩大知识储备:可以收集更多的中文语料,或者使用其他语言的数据集来扩充知识储备。
>3. 增加数据量:可以使用更大的数据集来训练 ChatGLM-6B,提高模型的表现。
>4. 引入更多的评估指标:可以引入更多的评估指标来评估模型的表现,从而发现 ChatGLM-6B 存在的不足和局限性。
>5. 改进模型架构:可以改进 ChatGLM-6B 的模型架构,提高模型的性能和表现。例如,可以使用更大的神经网络或者改进的卷积神经网络结构。
## 路线图
- [ ] Langchain 应用
- [x] 接入非结构化文档(已支持 md、pdf、docx、txt 文件格式)
- [x] jpg 与 png 格式图片的 OCR 文字识别
- [x] 搜索引擎接入
- [ ] 本地网页接入
- [ ] 结构化数据接入(如 csv、Excel、SQL 等)
- [ ] 知识图谱/图数据库接入
- [ ] Agent 实现
- [x] 增加更多 LLM 模型支持
- [x] [THUDM/chatglm-6b](https://huggingface.co/THUDM/chatglm-6b)
- [x] [THUDM/chatglm-6b-int8](https://huggingface.co/THUDM/chatglm-6b-int8)
- [x] [THUDM/chatglm-6b-int4](https://huggingface.co/THUDM/chatglm-6b-int4)
- [x] [THUDM/chatglm-6b-int4-qe](https://huggingface.co/THUDM/chatglm-6b-int4-qe)
- [x] [ClueAI/ChatYuan-large-v2](https://huggingface.co/ClueAI/ChatYuan-large-v2)
- [x] [fnlp/moss-moon-003-sft](https://huggingface.co/fnlp/moss-moon-003-sft)
- [x] 支持通过调用 [fastchat](https://github.com/lm-sys/FastChat) api 调用 llm
- [x] 增加更多 Embedding 模型支持
- [x] [nghuyong/ernie-3.0-nano-zh](https://huggingface.co/nghuyong/ernie-3.0-nano-zh)
- [x] [nghuyong/ernie-3.0-base-zh](https://huggingface.co/nghuyong/ernie-3.0-base-zh)
- [x] [shibing624/text2vec-base-chinese](https://huggingface.co/shibing624/text2vec-base-chinese)
- [x] [GanymedeNil/text2vec-large-chinese](https://huggingface.co/GanymedeNil/text2vec-large-chinese)
- [x] [moka-ai/m3e-small](https://huggingface.co/moka-ai/m3e-small)
- [x] [moka-ai/m3e-base](https://huggingface.co/moka-ai/m3e-base)
- [ ] Web UI
- [x] 基于 gradio 实现 Web UI DEMO
- [x] 基于 streamlit 实现 Web UI DEMO
- [x] 添加输出内容及错误提示
- [x] 引用标注
- [ ] 增加知识库管理
- [x] 选择知识库开始问答
- [x] 上传文件/文件夹至知识库
- [x] 知识库测试
- [ ] 删除知识库中文件
- [x] 支持搜索引擎问答
- [ ] 增加 API 支持
- [x] 利用 fastapi 实现 API 部署方式
- [ ] 实现调用 API 的 Web UI Demo
- [x] VUE 前端
## 项目交流群
![二维码](img/qr_code_30.jpg)
🎉 langchain-ChatGLM 项目交流群,如果你也对本项目感兴趣,欢迎加入群聊参与讨论交流。
ChatGPT是OpenAI开发的一个大型语言模型,可以提供各种主题的信息,
# 如何向 ChatGPT 提问以获得高质量答案:提示技巧工程完全指南
## 介绍
我很高兴欢迎您阅读我的最新书籍《The Art of Asking ChatGPT for High-Quality Answers: A complete Guide to Prompt Engineering Techniques》。本书是一本全面指南,介绍了各种提示技术,用于从ChatGPT中生成高质量的答案。
我们将探讨如何使用不同的提示工程技术来实现不同的目标。ChatGPT是一款最先进的语言模型,能够生成类似人类的文本。然而,理解如何正确地向ChatGPT提问以获得我们所需的高质量输出非常重要。而这正是本书的目的。
无论您是普通人、研究人员、开发人员,还是只是想在自己的领域中将ChatGPT作为个人助手的人,本书都是为您编写的。我使用简单易懂的语言,提供实用的解释,并在每个提示技术中提供了示例和提示公式。通过本书,您将学习如何使用提示工程技术来控制ChatGPT的输出,并生成符合您特定需求的文本。
在整本书中,我们还提供了如何结合不同的提示技术以实现更具体结果的示例。我希望您能像我写作时一样,享受阅读本书并从中获得知识。
<div style="page-break-after:always;"></div>
## 第一章:Prompt 工程技术简介
什么是 Prompt 工程?
Prompt 工程是创建提示或指导像 ChatGPT 这样的语言模型输出的过程。它允许用户控制模型的输出并生成符合其特定需求的文本。
ChatGPT 是一种先进的语言模型,能够生成类似于人类的文本。它建立在 Transformer 架构上,可以处理大量数据并生成高质量的文本。
然而,为了从 ChatGPT 中获得最佳结果,重要的是要了解如何正确地提示模型。 提示可以让用户控制模型的输出并生成相关、准确和高质量的文本。 在使用 ChatGPT 时,了解它的能力和限制非常重要。
该模型能够生成类似于人类的文本,但如果没有适当的指导,它可能无法始终产生期望的输出。
这就是 Prompt 工程的作用,通过提供清晰而具体的指令,您可以引导模型的输出并确保其相关。
**Prompt 公式是提示的特定格式,通常由三个主要元素组成:**
- 任务:对提示要求模型生成的内容进行清晰而简洁的陈述。
- 指令:在生成文本时模型应遵循的指令。
- 角色:模型在生成文本时应扮演的角色。
在本书中,我们将探讨可用于 ChatGPT 的各种 Prompt 工程技术。我们将讨论不同类型的提示,以及如何使用它们实现您想要的特定目标。
<div style="page-break-after:always;"></div>
## 第二章:指令提示技术
现在,让我们开始探索“指令提示技术”,以及如何使用它从ChatGPT中生成高质量的文本。
指令提示技术是通过为模型提供具体指令来引导ChatGPT的输出的一种方法。这种技术对于确保输出相关和高质量非常有用。
要使用指令提示技术,您需要为模型提供清晰简洁的任务,以及具体的指令以供模型遵循。
例如,如果您正在生成客户服务响应,您将提供任务,例如“生成响应客户查询”的指令,例如“响应应该专业且提供准确的信息”。
提示公式:“按照以下指示生成[任务]:[指令]”
示例:
**生成客户服务响应:**
- 任务:生成响应客户查询
- 指令:响应应该专业且提供准确的信息
- 提示公式:“按照以下指示生成专业且准确的客户查询响应:响应应该专业且提供准确的信息。”
**生成法律文件:**
- 任务:生成法律文件
- 指令:文件应符合相关法律法规
- 提示公式:“按照以下指示生成符合相关法律法规的法律文件:文件应符合相关法律法规。”
使用指令提示技术时,重要的是要记住指令应该清晰具体。这将有助于确保输出相关和高质量。可以将指令提示技术与下一章节中解释的“角色提示”和“种子词提示”相结合,以增强ChatGPT的输出。
<div style="page-break-after:always;"></div>
## 第三章:角色提示
角色提示技术是通过为ChatGPT指定一个特定的角色来引导其输出的一种方式。这种技术对于生成针对特定上下文或受众的文本非常有用。
要使用角色提示技术,您需要为模型提供一个清晰具体的角色。
例如,如果您正在生成客户服务回复,您可以提供一个角色,如“客户服务代表”。
提示公式:“作为[角色]生成[任务]”
示例:
**生成客户服务回复:**
- 任务:生成对客户查询的回复
- 角色:客户服务代表
- 提示公式:“作为客户服务代表,生成对客户查询的回复。”
**生成法律文件:**
- 任务:生成法律文件
- 角色:律师
- 提示公式:“作为律师,生成法律文件。”
将角色提示技术与指令提示和种子词提示结合使用可以增强ChatGPT的输出。
**下面是一个示例,展示了如何将指令提示、角色提示和种子词提示技术结合使用:**
- 任务:为新智能手机生成产品描述
- 指令:描述应该是有信息量的,具有说服力,并突出智能手机的独特功能
- 角色:市场代表 种子词:“创新的”
- 提示公式:“作为市场代表,生成一个有信息量的、有说服力的产品描述,突出新智能手机的创新功能。该智能手机具有以下功能[插入您的功能]”
在这个示例中,指令提示用于确保产品描述具有信息量和说服力。角色提示用于确保描述是从市场代表的角度书写的。而种子词提示则用于确保描述侧重于智能手机的创新功能。
<div style="page-break-after:always;"></div>
## 第四章:标准提示
标准提示是一种简单的方法,通过为模型提供一个特定的任务来引导ChatGPT的输出。例如,如果您想生成一篇新闻文章的摘要,您可以提供一个任务,如“总结这篇新闻文章”。
提示公式:“生成一个[任务]”
例如:
**生成新闻文章的摘要:**
- 任务:总结这篇新闻文章
- 提示公式:“生成这篇新闻文章的摘要”
**生成一篇产品评论:**
- 任务:为一款新智能手机撰写评论
- 提示公式:“生成这款新智能手机的评论”
此外,标准提示可以与其他技术(如角色提示和种子词提示)结合使用,以增强ChatGPT的输出。
**以下是如何将标准提示、角色提示和种子词提示技术结合使用的示例:**
- 任务:为一台新笔记本电脑撰写产品评论
- 说明:评论应客观、信息丰富,强调笔记本电脑的独特特点
- 角色:技术专家
- 种子词:“强大的”
- 提示公式:“作为一名技术专家,生成一个客观而且信息丰富的产品评论,强调新笔记本电脑的强大特点。”
在这个示例中,标准提示技术用于确保模型生成产品评论。角色提示用于确保评论是从技术专家的角度写的。而种子词提示用于确保评论侧重于笔记本电脑的强大特点。
<div style="page-break-after:always;"></div>
## 第五章:零、一和少样本提示
零样本、一样本和少样本提示是用于从ChatGPT生成文本的技术,最少或没有任何示例。当特定任务的数据有限或任务是新的且未定义时,这些技术非常有用。
当任务没有可用的示例时,使用零样本提示技术。模型提供一个通用任务,根据对任务的理解生成文本。
当任务只有一个示例可用时,使用一样本提示技术。模型提供示例,并根据对示例的理解生成文本。
当任务只有有限数量的示例可用时,使用少样本提示技术。模型提供示例,并根据对示例的理解生成文本。
提示公式:“基于[数量]个示例生成文本”
例如:
**为没有可用示例的新产品编写产品描述:**
- 任务:为新的智能手表编写产品描述
- 提示公式:“基于零个示例为这款新智能手表生成产品描述”
**使用一个示例生成产品比较:**
- 任务:将新款智能手机与最新的iPhone进行比较
- 提示公式:“使用一个示例(最新的iPhone)为这款新智能手机生成产品比较”
**使用少量示例生成产品评论:**
- 任务:为新的电子阅读器撰写评论
- 提示公式:“使用少量示例(3个其他电子阅读器)为这款新电子阅读器生成评论”
这些技术可用于根据模型对任务或提供的示例的理解生成文本。
<div style="page-break-after:always;"></div>
## 第六章:“让我们思考一下”提示
“让我们思考一下”提示是一种技巧,可鼓励ChatGPT生成反思和思考性的文本。这种技术适用于撰写论文、诗歌或创意写作等任务。
“让我们思考一下”提示的公式非常简单,即“让我们思考一下”后跟一个主题或问题。
例如:
**生成一篇反思性论文:**
- 任务:就个人成长主题写一篇反思性论文
- 提示公式:“让我们思考一下:个人成长”
**生成一首诗:**
- 任务:写一首关于季节变化的诗
- 提示公式:“让我们思考一下:季节变化”
这个提示要求对特定主题或想法展开对话或讨论。发言者邀请ChatGPT参与讨论相关主题。
模型提供了一个提示,作为对话或文本生成的起点。
然后,模型使用其训练数据和算法生成与提示相关的响应。这种技术允许ChatGPT根据提供的提示生成上下文适当且连贯的文本。
**要使用“让我们思考一下提示”技术与ChatGPT,您可以遵循以下步骤:**
1. 确定您要讨论的主题或想法。
2. 制定一个明确表达主题或想法的提示,并开始对话或文本生成。
3. 用“让我们思考”或“让我们讨论”开头的提示,表明您正在启动对话或讨论。
**以下是使用此技术的一些提示示例:**
- 提示:“让我们思考气候变化对农业的影响”
- 提示:“让我们讨论人工智能的当前状态”
- 提示:“让我们谈谈远程工作的好处和缺点” 您还可以添加开放式问题、陈述或一段您希望模型继续或扩展的文本。
提供提示后,模型将使用其训练数据和算法生成与提示相关的响应,并以连贯的方式继续对话。
这种独特的提示有助于ChatGPT以不同的视角和角度给出答案,从而产生更具动态性和信息性的段落。
使用提示的步骤简单易行,可以真正提高您的写作水平。尝试一下,看看效果如何吧。
<div style="page-break-after:always;"></div>
## 第七章:自洽提示
自洽提示是一种技术,用于确保ChatGPT的输出与提供的输入一致。这种技术对于事实核查、数据验证或文本生成中的一致性检查等任务非常有用。
自洽提示的提示公式是输入文本后跟着指令“请确保以下文本是自洽的”。
或者,可以提示模型生成与提供的输入一致的文本。
提示示例及其公式:
**示例1:文本生成**
- 任务:生成产品评论
- 指令:评论应与输入中提供的产品信息一致
- 提示公式:“生成与以下产品信息一致的产品评论[插入产品信息]”
**示例2:文本摘要**
- 任务:概括一篇新闻文章
- 指令:摘要应与文章中提供的信息一致
- 提示公式:“用与提供的信息一致的方式概括以下新闻文章[插入新闻文章]”
**示例3:文本完成**
- 任务:完成一个句子
- 指令:完成应与输入中提供的上下文一致
- 提示公式:“以与提供的上下文一致的方式完成以下句子[插入句子]”
**示例4:**
1. **事实核查:**
任务:检查给定新闻文章的一致性
输入文本:“文章中陈述该城市的人口为500万,但后来又说该城市的人口为700万。”
提示公式:“请确保以下文本是自洽的:文章中陈述该城市的人口为500万,但后来又说该城市的人口为700万。”
2. **数据验证:**
任务:检查给定数据集的一致性
输入文本:“数据显示7月份的平均温度为30度,但最低温度记录为20度。”
提示公式:“请确保以下文本是自洽的:数据显示7月份的平均温度为30度,但最低温度记录为20度。”
<div style="page-break-after:always;"></div>
## 第八章:种子词提示
种子词提示是一种通过提供特定的种子词或短语来控制ChatGPT输出的技术。种子词提示的提示公式是种子词或短语,后跟指令“请根据以下种子词生成文本”。
示例:
**文本生成:**
- 任务:编写一篇有关龙的故事
- 种子词:“龙”
- 提示公式:“请根据以下种子词生成文本:龙”
**语言翻译:**
- 任务:将一句话从英语翻译成西班牙语
- 种子词:“你好”
- 提示公式:“请根据以下种子词生成文本:你好”
这种技术允许模型生成与种子词相关的文本并对其进行扩展。这是一种控制模型生成文本与某个特定主题或背景相关的方式。
种子词提示可以与角色提示和指令提示相结合,以创建更具体和有针对性的生成文本。通过提供种子词或短语,模型可以生成与该种子词或短语相关的文本,并通过提供有关期望输出和角色的信息,模型可以以特定于角色或指令的风格或语气生成文本。这样可以更好地控制生成的文本,并可用于各种应用程序。
以下是提示示例及其公式:
**示例1:文本生成**
- 任务:编写一首诗
- 指令:诗应与种子词“爱”相关,并以十四行诗的形式书写。
- 角色:诗人
- 提示公式:“作为诗人,根据以下种子词生成与“爱”相关的十四行诗:”
**示例2:文本完成**
- 任务:完成一句话
- 指令:完成应与种子词“科学”相关,并以研究论文的形式书写。
- 角色:研究员
- 提示公式:“作为研究员,请在与种子词“科学”相关且以研究论文的形式书写的情况下完成以下句子:[插入句子]”
**示例3:文本摘要**
- 任务:摘要一篇新闻文章
- 指令:摘要应与种子词“政治”相关,并以中立和公正的语气书写。
- 角色:记者
- 提示公式:“作为记者,请以中立和公正的语气摘要以下新闻文章,与种子词“政治”相关:[插入新闻文章]”
<div style="page-break-after:always;"></div>
## 第九章:知识生成提示
知识生成提示是一种从ChatGPT中引出新的、原创的信息的技术。
知识生成提示的公式是“请生成关于X的新的和原创的信息”,其中X是感兴趣的主题。
这是一种利用模型预先存在的知识来生成新的信息或回答问题的技术。
要将此提示与ChatGPT一起使用,需要将问题或主题作为输入提供给模型,以及指定所生成文本的任务或目标的提示。
提示应包括有关所需输出的信息,例如要生成的文本类型以及任何特定的要求或限制。
以下是提示示例及其公式:
**示例1:知识生成**
- 任务:生成有关特定主题的新信息
- 说明:生成的信息应准确且与主题相关
- 提示公式:“生成有关[特定主题]的新的准确信息”
**示例2:问答**
- 任务:回答问题
- 说明:答案应准确且与问题相关
- 提示公式:“回答以下问题:[插入问题]”
**示例3:知识整合**
- 任务:将新信息与现有知识整合
- 说明:整合应准确且与主题相关
- 提示公式:“将以下信息与有关[特定主题]的现有知识整合:[插入新信息]”
**示例4:数据分析**
- 任务:从给定的数据集中生成有关客户行为的见解
- 提示公式:“请从这个数据集中生成有关客户行为的新的和原创的信息”
<div style="page-break-after:always;"></div>
## 第十章:知识整合提示
这种技术利用模型的现有知识来整合新信息或连接不同的信息片段。
这种技术对于将现有知识与新信息相结合,以生成更全面的特定主题的理解非常有用。
**如何与ChatGPT一起使用:**
- 模型应该提供新信息和现有知识作为输入,以及指定生成文本的任务或目标的提示。
- 提示应包括有关所需输出的信息,例如要生成的文本类型以及任何特定的要求或限制。
提示示例及其公式:
**示例1:知识整合**
- 任务:将新信息与现有知识整合
- 说明:整合应准确且与主题相关
- 提示公式:“将以下信息与关于[具体主题]的现有知识整合:[插入新信息]”
**示例2:连接信息片段**
- 任务:连接不同的信息片段
- 说明:连接应相关且逻辑清晰
- 提示公式:“以相关且逻辑清晰的方式连接以下信息片段:[插入信息1] [插入信息2]”
**示例3:更新现有知识**
- 任务:使用新信息更新现有知识
- 说明:更新的信息应准确且相关
- 提示公式:“使用以下信息更新[具体主题]的现有知识:[插入新信息]”
<div style="page-break-after:always;"></div>
## 第十一章:多项选择提示
这种技术向模型提供一个问题或任务以及一组预定义的选项作为潜在答案。
该技术对于生成仅限于特定选项集的文本非常有用,可用于问答、文本完成和其他任务。模型可以生成仅限于预定义选项的文本。
要使用ChatGPT的多项选择提示,需要向模型提供一个问题或任务作为输入,以及一组预定义的选项作为潜在答案。提示还应包括有关所需输出的信息,例如要生成的文本类型以及任何特定要求或限制。
提示示例及其公式:
**示例1:问答**
- 任务:回答一个多项选择题
- 说明:答案应该是预定义的选项之一
- 提示公式:“通过选择以下选项之一回答以下问题:[插入问题] [插入选项1] [插入选项2] [插入选项3]”
**示例2:文本完成**
- 任务:使用预定义选项之一完成句子
- 说明:完成应该是预定义的选项之一
- 提示公式:“通过选择以下选项之一完成以下句子:[插入句子] [插入选项1] [插入选项2] [插入选项3]”
**示例3:情感分析**
- 任务:将文本分类为积极、中立或消极
- 说明:分类应该是预定义的选项之一
- 提示公式:“通过选择以下选项之一,将以下文本分类为积极、中立或消极:[插入文本] [积极] [中立] [消极]”
<div style="page-break-after:always;"></div>
## 第十二章:可解释的软提示
可解释的软提示是一种技术,可以在提供一定的灵活性的同时控制模型生成的文本。它通过提供一组受控输入和关于所需输出的附加信息来实现。这种技术可以生成更具解释性和可控性的生成文本。
提示示例及其公式:
**示例1:文本生成**
- 任务:生成一个故事
- 指令:故事应基于一组给定的角色和特定的主题
- 提示公式:“基于以下角色生成故事:[插入角色]和主题:[插入主题]”
**示例2:文本完成**
- 任务:完成一句话
- 指令:完成应以特定作者的风格为基础
- 提示公式:“以[特定作者]的风格完成以下句子:[插入句子]”
**示例3:语言建模**
- 任务:以特定风格生成文本
- 指令:文本应以特定时期的风格为基础
- 提示公式:“以[特定时期]的风格生成文本:[插入上下文]”
<div style="page-break-after:always;"></div>
## 第十三章:控制生成提示
控制生成提示是一种技术,可让模型在生成文本时对输出进行高度控制。
这可以通过提供一组特定的输入来实现,例如模板、特定词汇或一组约束条件,这些输入可用于指导生成过程。
以下是一些示例和它们的公式:
**示例1:文本生成**
- 任务:生成一个故事
- 说明:该故事应基于特定的模板
- 提示公式:“根据以下模板生成故事:[插入模板]”
**示例2:文本补全**
- 任务:完成一句话
- 说明:完成应使用特定的词汇
- 提示公式:“使用以下词汇完成以下句子:[插入词汇]:[插入句子]”
**示例3:语言建模**
- 任务:以特定风格生成文本
- 说明:文本应遵循一组特定的语法规则
- 提示公式:“生成遵循以下语法规则的文本:[插入规则]:[插入上下文]”
通过提供一组特定的输入来指导生成过程,控制生成提示使得生成的文本更具可控性和可预测性。
<div style="page-break-after:always;"></div>
## 第十四章:问答提示
问答提示是一种技术,可以让模型生成回答特定问题或任务的文本。通过将问题或任务与可能与问题或任务相关的任何其他信息一起作为输入提供给模型来实现此目的。
一些提示示例及其公式如下:
**示例1:事实问题回答**
- 任务:回答一个事实性问题
- 说明:答案应准确且相关
- 提示公式:“回答以下事实问题:[插入问题]”
**示例2:定义**
- 任务:提供一个词的定义
- 说明:定义应准确
- 提示公式:“定义以下词汇:[插入单词]”
**示例3:信息检索**
- 任务:从特定来源检索信息
- 说明:检索到的信息应相关
- 提示公式:“从以下来源检索有关[特定主题]的信息:[插入来源]” 这对于问答和信息检索等任务非常有用。
<div style="page-break-after:always;"></div>
## 第十五章:概述提示
概述提示是一种技术,允许模型在保留其主要思想和信息的同时生成给定文本的较短版本。
这可以通过将较长的文本作为输入提供给模型并要求其生成该文本的摘要来实现。
这种技术对于文本概述和信息压缩等任务非常有用。
**如何在ChatGPT中使用:**
- 应该向模型提供较长的文本作为输入,并要求其生成该文本的摘要。
- 提示还应包括有关所需输出的信息,例如摘要的所需长度和任何特定要求或限制。
提示示例及其公式:
**示例1:文章概述**
- 任务:概述新闻文章
- 说明:摘要应是文章主要观点的简要概述
- 提示公式:“用一句简短的话概括以下新闻文章:[插入文章]”
**示例2:会议记录**
- 任务:概括会议记录
- 说明:摘要应突出会议的主要决策和行动
- 提示公式:“通过列出主要决策和行动来总结以下会议记录:[插入记录]”
**示例3:书籍摘要**
- 任务:总结一本书
- 说明:摘要应是书的主要观点的简要概述
- 提示公式:“用一段简短的段落总结以下书籍:[插入书名]”
<div style="page-break-after:always;"></div>
## 第十六章:对话提示
对话提示是一种技术,允许模型生成模拟两个或更多实体之间对话的文本。通过为模型提供一个上下文和一组角色或实体,以及它们的角色和背景,并要求模型在它们之间生成对话。
因此,应为模型提供上下文和一组角色或实体,以及它们的角色和背景。还应向模型提供有关所需输出的信息,例如对话或交谈的类型以及任何特定的要求或限制。
提示示例及其公式:
**示例1:对话生成**
- 任务:生成两个角色之间的对话
- 说明:对话应自然且与给定上下文相关
- 提示公式:“在以下情境中生成以下角色之间的对话[插入角色]”
**示例2:故事写作**
- 任务:在故事中生成对话
- 说明:对话应与故事的角色和事件一致
- 提示公式:“在以下故事中生成以下角色之间的对话[插入故事]”
**示例3:聊天机器人开发**
- 任务:为客服聊天机器人生成对话
- 说明:对话应专业且提供准确的信息
- 提示公式:“在客户询问[插入主题]时,为客服聊天机器人生成专业和准确的对话”
因此,这种技术对于对话生成、故事写作和聊天机器人开发等任务非常有用。
<div style="page-break-after:always;"></div>
## 第十七章:对抗性提示
对抗性提示是一种技术,它允许模型生成抵抗某些类型的攻击或偏见的文本。这种技术可用于训练更为稳健和抵抗某些类型攻击或偏见的模型。
要在ChatGPT中使用对抗性提示,需要为模型提供一个提示,该提示旨在使模型难以生成符合期望输出的文本。提示还应包括有关所需输出的信息,例如要生成的文本类型和任何特定要求或约束。
提示示例及其公式:
**示例1:用于文本分类的对抗性提示**
- 任务:生成被分类为特定标签的文本
- 说明:生成的文本应难以分类为特定标签
- 提示公式:“生成难以分类为[插入标签]的文本”
**示例2:用于情感分析的对抗性提示**
- 任务:生成难以分类为特定情感的文本
- 说明:生成的文本应难以分类为特定情感
- 提示公式:“生成难以分类为具有[插入情感]情感的文本”
**示例3:用于语言翻译的对抗性提示**
- 任务:生成难以翻译的文本
- 说明:生成的文本应难以翻译为目标语言
- 提示公式:“生成难以翻译为[插入目标语言]的文本”
<div style="page-break-after:always;"></div>
## 第十八章:聚类提示
聚类提示是一种技术,它可以让模型根据某些特征或特点将相似的数据点分组在一起。
通过提供一组数据点并要求模型根据某些特征或特点将它们分组成簇,可以实现这一目标。
这种技术在数据分析、机器学习和自然语言处理等任务中非常有用。
**如何在ChatGPT中使用:**
应该向模型提供一组数据点,并要求它根据某些特征或特点将它们分组成簇。提示还应包括有关所需输出的信息,例如要生成的簇数和任何特定的要求或约束。
提示示例及其公式:
**示例1:客户评论的聚类**
- 任务:将相似的客户评论分组在一起
- 说明:应根据情感将评论分组
- 提示公式:“将以下客户评论根据情感分组成簇:[插入评论]”
**示例2:新闻文章的聚类**
- 任务:将相似的新闻文章分组在一起
- 说明:应根据主题将文章分组
- 提示公式:“将以下新闻文章根据主题分组成簇:[插入文章]”
**示例3:科学论文的聚类**
- 任务:将相似的科学论文分组在一起
- 说明:应根据研究领域将论文分组
- 提示公式:“将以下科学论文根据研究领域分组成簇:[插入论文]”
<div style="page-break-after:always;"></div>
## 第十九章:强化学习提示
强化学习提示是一种技术,可以使模型从过去的行动中学习,并随着时间的推移提高其性能。要在ChatGPT中使用强化学习提示,需要为模型提供一组输入和奖励,并允许其根据接收到的奖励调整其行为。提示还应包括有关期望输出的信息,例如要完成的任务以及任何特定要求或限制。这种技术对于决策制定、游戏玩法和自然语言生成等任务非常有用。
提示示例及其公式:
**示例1:用于文本生成的强化学习**
- 任务:生成与特定风格一致的文本
- 说明:模型应根据为生成与特定风格一致的文本而接收到的奖励来调整其行为
- 提示公式:“使用强化学习来生成与以下风格一致的文本[插入风格]”
**示例2:用于语言翻译的强化学习**
- 任务:将文本从一种语言翻译成另一种语言
- 说明:模型应根据为生成准确翻译而接收到的奖励来调整其行为
- 提示公式:“使用强化学习将以下文本[插入文本]从[插入语言]翻译成[插入语言]”
**示例3:用于问答的强化学习**
- 任务:回答问题
- 说明:模型应根据为生成准确答案而接收到的奖励来调整其行为
- 提示公式:“使用强化学习来回答以下问题[插入问题]”
<div style="page-break-after:always;"></div>
## 第二十章:课程学习提示
课程学习是一种技术,允许模型通过先训练简单任务,逐渐增加难度来学习复杂任务。
要在ChatGPT中使用课程学习提示,模型应该提供一系列任务,这些任务逐渐增加难度。
提示还应包括有关期望输出的信息,例如要完成的最终任务以及任何特定要求或约束条件。
此技术对自然语言处理、图像识别和机器学习等任务非常有用。
提示示例及其公式:
**示例1:用于文本生成的课程学习**
- 任务:生成与特定风格一致的文本
- 说明:模型应该在移动到更复杂的风格之前先在简单的风格上进行训练。
- 提示公式:“使用课程学习来生成与以下风格[插入风格]一致的文本,按照以下顺序[插入顺序]。”
**示例2:用于语言翻译的课程学习**
- 任务:将文本从一种语言翻译成另一种语言
- 说明:模型应该在移动到更复杂的语言之前先在简单的语言上进行训练。
- 提示公式:“使用课程学习将以下语言[插入语言]的文本翻译成以下顺序[插入顺序]。”
**示例3:用于问题回答的课程学习**
- 任务:回答问题
- 说明:模型应该在移动到更复杂的问题之前先在简单的问题上进行训练。
- 提示公式:“使用课程学习来回答以下问题[插入问题],按照以下顺序[插入顺序]生成答案。”
<div style="page-break-after:always;"></div>
## 第二十一章:情感分析提示
情感分析是一种技术,允许模型确定文本的情绪色彩或态度,例如它是积极的、消极的还是中立的。
要在ChatGPT中使用情感分析提示,模型应该提供一段文本并要求根据其情感分类。
提示还应包括关于所需输出的信息,例如要检测的情感类型(例如积极的、消极的、中立的)和任何特定要求或约束条件。
提示示例及其公式:
**示例1:客户评论的情感分析**
- 任务:确定客户评论的情感
- 说明:模型应该将评论分类为积极的、消极的或中立的
- 提示公式:“对以下客户评论进行情感分析[插入评论],并将它们分类为积极的、消极的或中立的。”
**示例2:推文的情感分析**
- 任务:确定推文的情感
- 说明:模型应该将推文分类为积极的、消极的或中立的
- 提示公式:“对以下推文进行情感分析[插入推文],并将它们分类为积极的、消极的或中立的。”
**示例3:产品评论的情感分析**
- 任务:确定产品评论的情感
- 说明:模型应该将评论分类为积极的、消极的或中立的
- 提示公式:“对以下产品评论进行情感分析[插入评论],并将它们分类为积极的、消极的或中立的。”
这种技术对自然语言处理、客户服务和市场研究等任务非常有用。
<div style="page-break-after:always;"></div>
## 第二十二章:命名实体识别提示
命名实体识别(NER)是一种技术,它可以使模型识别和分类文本中的命名实体,例如人名、组织机构、地点和日期等。
要在ChatGPT中使用命名实体识别提示,需要向模型提供一段文本,并要求它识别和分类文本中的命名实体。
提示还应包括有关所需输出的信息,例如要识别的命名实体类型(例如人名、组织机构、地点、日期)以及任何特定要求或约束条件。
提示示例及其公式:
**示例1:新闻文章中的命名实体识别**
- 任务:在新闻文章中识别和分类命名实体
- 说明:模型应识别和分类人名、组织机构、地点和日期
- 提示公式:“在以下新闻文章[插入文章]上执行命名实体识别,并识别和分类人名、组织机构、地点和日期。”
**示例2:法律文件中的命名实体识别**
- 任务:在法律文件中识别和分类命名实体
- 说明:模型应识别和分类人名、组织机构、地点和日期
- 提示公式:“在以下法律文件[插入文件]上执行命名实体识别,并识别和分类人名、组织机构、地点和日期。”
**示例3:研究论文中的命名实体识别**
- 任务:在研究论文中识别和分类命名实体
- 说明:模型应识别和分类人名、组织机构、地点和日期
- 提示公式:“在以下研究论文[插入论文]上执行命名实体识别,并识别和分类人名、组织机构、地点和日期。”
<div style="page-break-after:always;"></div>
## 第二十三章:文本分类提示
文本分类是一种技术,它可以让模型将文本分成不同的类别。这种技术对于自然语言处理、文本分析和情感分析等任务非常有用。
需要注意的是,文本分类和情感分析是不同的。情感分析特别关注于确定文本中表达的情感或情绪。这可能包括确定文本表达了积极、消极还是中性的情感。情感分析通常用于客户评论、社交媒体帖子和其他需要表达情感的文本。
要在ChatGPT中使用文本分类提示,模型需要提供一段文本,并要求它根据预定义的类别或标签进行分类。提示还应包括有关所需输出的信息,例如类别或标签的数量以及任何特定的要求或约束。
提示示例及其公式:
**示例1:对客户评论进行文本分类**
- 任务:将客户评论分类为不同的类别,例如电子产品、服装和家具
- 说明:模型应根据评论的内容对其进行分类
- 提示公式:“对以下客户评论 [插入评论] 进行文本分类,并根据其内容将其分类为不同的类别,例如电子产品、服装和家具。”
**示例2:对新闻文章进行文本分类**
- 任务:将新闻文章分类为不同的类别,例如体育、政治和娱乐
- 说明:模型应根据文章的内容对其进行分类
- 提示公式:“对以下新闻文章 [插入文章] 进行文本分类,并根据其内容将其分类为不同的类别,例如体育、政治和娱乐。”
**示例3:对电子邮件进行文本分类**
- 任务:将电子邮件分类为不同的类别,例如垃圾邮件、重要邮件或紧急邮件
- 说明:模型应根据电子邮件的内容和发件人对其进行分类
- 提示公式:“对以下电子邮件 [插入电子邮件] 进行文本分类,并根据其内容和发件人将其分类为不同的类别,例如垃圾邮件、重要邮件或紧急邮件。”
<div style="page-break-after:always;"></div>
## 第二十四章:文本生成提示
文本生成提示与本书中提到的其他提示技术相关,例如:零、一、几次提示,受控生成提示,翻译提示,语言建模提示,句子补全提示等。这些提示都与生成文本有关,但它们在生成文本的方式和放置在生成文本上的特定要求或限制方面有所不同。文本生成提示可用于微调预训练模型或训练新模型以执行特定任务。
提示示例及其公式:
**示例1:故事创作的文本生成**
- 任务:根据给定的提示生成故事
- 说明:故事应至少包含1000个单词,并包括一组特定的角色和情节。
- 提示公式:“根据以下提示[插入提示]生成一个至少包含1000个单词,包括角色[插入角色]和情节[插入情节]的故事。”
**示例2:语言翻译的文本生成**
- 任务:将给定的文本翻译成另一种语言
- 说明:翻译应准确并符合习惯用语。
- 提示公式:“将以下文本[插入文本]翻译成[插入目标语言],并确保其准确且符合习惯用语。”
**示例3:文本完成的文本生成**
- 任务:完成给定的文本
- 说明:生成的文本应与输入文本连贯一致。
- 提示公式:“完成以下文本[插入文本],并确保其连贯一致且符合输入文本。”
<div style="page-break-after:always;"></div>
## 结语
正如本书中所探讨的那样,快速工程是一种利用像ChatGPT这样的语言模型获得高质量答案的强大工具。通过精心设计各种技巧的提示,我们可以引导模型生成符合我们特定需求和要求的文本。
在第二章中,我们讨论了如何使用指令提示向模型提供清晰明确的指导。在第三章中,我们探讨了如何使用角色提示生成特定的语音或风格的文本。在第四章中,我们研究了如何使用标准提示作为微调模型性能的起点。我们还研究了几种高级提示技术,例如Zero、One和Few Shot Prompting、Self-Consistency、Seed-word Prompt、Knowledge Generation Prompt、Knowledge Integration prompts、Multiple Choice prompts、Interpretable Soft Prompts、Controlled generation prompts、Question-answering prompts、Summarization prompts、Dialogue prompts、Adversarial prompts、Clustering prompts、Reinforcement learning prompts、Curriculum learning prompts、Sentiment analysis prompts、Named entity recognition prompts和Text classification prompts(对应章节的名字)。
这些技术中的每一种都可以以不同的方式使用,以实现各种不同的结果。随着您继续使用ChatGPT和其他语言模型,值得尝试不同的技巧组合,以找到最适合您特定用例的方法。
最后,您可以查看我写的其他主题的书籍。
感谢您阅读整本书。期待在我的其他书中与您见面。
(本文翻译自《The Art of Asking ChatGPT for High-Quality Answers A Complete Guide to Prompt Engineering Techniques》这本书,本文的翻译全部由ChatGpt完成,我只是把翻译内容给稍微排版了一下。做完了才发现这个工作早就有人做过了...下面是我以此事件让New Bing编写的一个小故事,希望大家喜欢)
> 他终于画完了他的画,心满意足地把它挂在了墙上。他觉得这是他一生中最伟大的作品,无人能及。他邀请了所有的朋友来欣赏,期待着他们的赞美和惊叹。 可是当他们看到画时,却没有一个人说话。他们只是互相对视,然后低头咳嗽,或者假装看手机。他感到很奇怪,难道他们都不懂艺术吗?难道他们都没有眼光吗? 他忍不住问其中一个朋友:“你觉得我的画怎么样?” 朋友犹豫了一下,说:“嗯……其实……这个画……我以前在哪里见过。” “见过?你在哪里见过?”他惊讶地问。 “就在……就在那边啊。”朋友指了指墙角的一个小框架,“那不就是你上个月买回来的那幅名画吗?你怎么把它照抄了一遍? ——New Bing
[这就是那幅名画]: http://yesaiwen.com/art-of-asking-chatgpt-for-high-quality-answ-engineering-techniques/#i-3 "《如何向ChatGPT提问并获得高质量的答案》"
\ No newline at end of file
from langchain.vectorstores import FAISS from langchain.vectorstores import FAISS
from langchain.vectorstores.base import VectorStore from langchain.vectorstores.base import VectorStore
from langchain.vectorstores.faiss import dependable_faiss_import from langchain.vectorstores.faiss import dependable_faiss_import
from typing import Any, Callable, List, Tuple, Dict from typing import Any, Callable, List, Dict
from langchain.docstore.base import Docstore from langchain.docstore.base import Docstore
from langchain.docstore.document import Document from langchain.docstore.document import Document
import numpy as np import numpy as np
...@@ -109,15 +109,22 @@ class MyFAISS(FAISS, VectorStore): ...@@ -109,15 +109,22 @@ class MyFAISS(FAISS, VectorStore):
docs.append(doc) docs.append(doc)
return docs return docs
def delete_doc(self, source): def delete_doc(self, source: str or List[str]):
try: try:
if isinstance(source, str):
ids = [k for k, v in self.docstore._dict.items() if v.metadata["source"] == source] ids = [k for k, v in self.docstore._dict.items() if v.metadata["source"] == source]
else:
ids = [k for k, v in self.docstore._dict.items() if v.metadata["source"] in source]
if len(ids) == 0:
return f"docs delete fail"
else:
for id in ids: for id in ids:
index = list(self.index_to_docstore_id.keys())[list(self.index_to_docstore_id.values()).index(id)] index = list(self.index_to_docstore_id.keys())[list(self.index_to_docstore_id.values()).index(id)]
self.index_to_docstore_id.pop(index) self.index_to_docstore_id.pop(index)
self.docstore._dict.pop(id) self.docstore._dict.pop(id)
return f"docs delete success" return f"docs delete success"
except: except Exception as e:
print(e)
return f"docs delete fail" return f"docs delete fail"
def update_doc(self, source, new_docs): def update_doc(self, source, new_docs):
...@@ -125,5 +132,9 @@ class MyFAISS(FAISS, VectorStore): ...@@ -125,5 +132,9 @@ class MyFAISS(FAISS, VectorStore):
delete_len = self.delete_doc(source) delete_len = self.delete_doc(source)
ls = self.add_documents(new_docs) ls = self.add_documents(new_docs)
return f"docs update success" return f"docs update success"
except: except Exception as e:
print(e)
return f"docs update fail" return f"docs update fail"
def list_docs(self):
return list(set(v.metadata["source"] for v in self.docstore._dict.values()))
import gradio as gr import gradio as gr
import os
import shutil import shutil
from chains.local_doc_qa import LocalDocQA from chains.local_doc_qa import LocalDocQA
from configs.model_config import * from configs.model_config import *
import nltk import nltk
from models.base import (BaseAnswer,
AnswerResult)
import models.shared as shared import models.shared as shared
from models.loader.args import parser from models.loader.args import parser
from models.loader import LoaderCheckPoint from models.loader import LoaderCheckPoint
import os
nltk.data.path = [NLTK_DATA_PATH] + nltk.data.path nltk.data.path = [NLTK_DATA_PATH] + nltk.data.path
...@@ -161,20 +159,26 @@ def get_vector_store(vs_id, files, sentence_size, history, one_conent, one_conte ...@@ -161,20 +159,26 @@ def get_vector_store(vs_id, files, sentence_size, history, one_conent, one_conte
file_status = "模型未完成加载,请先在加载模型后再导入文件" file_status = "模型未完成加载,请先在加载模型后再导入文件"
vs_path = None vs_path = None
logger.info(file_status) logger.info(file_status)
return vs_path, None, history + [[None, file_status]] return vs_path, None, history + [[None, file_status]], \
gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path) if vs_path else [])
def change_vs_name_input(vs_id, history): def change_vs_name_input(vs_id, history):
if vs_id == "新建知识库": if vs_id == "新建知识库":
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, history return gr.update(visible=True), gr.update(visible=True), gr.update(visible=False), None, history,\
gr.update(choices=[]), gr.update(visible=False)
else: else:
vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store") vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store")
if "index.faiss" in os.listdir(vs_path): if "index.faiss" in os.listdir(vs_path):
file_status = f"已加载知识库{vs_id},请开始提问" file_status = f"已加载知识库{vs_id},请开始提问"
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), \
vs_path, history + [[None, file_status]], \
gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path)), gr.update(visible=True)
else: else:
file_status = f"已选择知识库{vs_id},当前知识库中未上传文件,请先上传文件后,再开始提问" file_status = f"已选择知识库{vs_id},当前知识库中未上传文件,请先上传文件后,再开始提问"
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), \ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), \
vs_path, history + [[None, file_status]] vs_path, history + [[None, file_status]], \
gr.update(choices=[]), gr.update(visible=True)
knowledge_base_test_mode_info = ("【注意】\n\n" knowledge_base_test_mode_info = ("【注意】\n\n"
...@@ -217,7 +221,7 @@ def add_vs_name(vs_name, chatbot): ...@@ -217,7 +221,7 @@ def add_vs_name(vs_name, chatbot):
vs_status = "与已有知识库名称冲突,请重新选择其他名称后提交" vs_status = "与已有知识库名称冲突,请重新选择其他名称后提交"
chatbot = chatbot + [[None, vs_status]] chatbot = chatbot + [[None, vs_status]]
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update( return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(
visible=False), chatbot visible=False), chatbot, gr.update(visible=False)
else: else:
# 新建上传文件存储路径 # 新建上传文件存储路径
if not os.path.exists(os.path.join(KB_ROOT_PATH, vs_name, "content")): if not os.path.exists(os.path.join(KB_ROOT_PATH, vs_name, "content")):
...@@ -228,7 +232,7 @@ def add_vs_name(vs_name, chatbot): ...@@ -228,7 +232,7 @@ def add_vs_name(vs_name, chatbot):
vs_status = f"""已新增知识库"{vs_name}",将在上传文件并载入成功后进行存储。请在开始对话前,先完成文件上传。 """ vs_status = f"""已新增知识库"{vs_name}",将在上传文件并载入成功后进行存储。请在开始对话前,先完成文件上传。 """
chatbot = chatbot + [[None, vs_status]] chatbot = chatbot + [[None, vs_status]]
return gr.update(visible=True, choices=get_vs_list(), value=vs_name), gr.update( return gr.update(visible=True, choices=get_vs_list(), value=vs_name), gr.update(
visible=False), gr.update(visible=False), gr.update(visible=True), chatbot visible=False), gr.update(visible=False), gr.update(visible=True), chatbot, gr.update(visible=True)
# 自动化加载固定文件间中文件 # 自动化加载固定文件间中文件
...@@ -252,6 +256,38 @@ def reinit_vector_store(vs_id, history): ...@@ -252,6 +256,38 @@ def reinit_vector_store(vs_id, history):
def refresh_vs_list(): def refresh_vs_list():
return gr.update(choices=get_vs_list()), gr.update(choices=get_vs_list()) return gr.update(choices=get_vs_list()), gr.update(choices=get_vs_list())
def delete_file(vs_id, files_to_delete, chatbot):
vs_path = os.path.join(KB_ROOT_PATH, vs_id, "vector_store")
content_path = os.path.join(KB_ROOT_PATH, vs_id, "content")
status = local_doc_qa.delete_file_from_vector_store(vs_path=vs_path,
filepath=[os.path.join(content_path, file) for file in files_to_delete])
rested_files = local_doc_qa.list_file_from_vector_store(vs_path)
if "fail" in status:
vs_status = "文件删除失败。"
elif len(rested_files)>0:
vs_status = "文件删除成功。"
else:
vs_status = f"文件删除成功,知识库{vs_id}中无已上传文件,请先上传文件后,再开始提问。"
logger.info(",".join(files_to_delete)+vs_status)
chatbot = chatbot + [[None, vs_status]]
return gr.update(choices=local_doc_qa.list_file_from_vector_store(vs_path)), chatbot
def delete_vs(vs_id, chatbot):
try:
shutil.rmtree(os.path.join(KB_ROOT_PATH, vs_id))
status = f"成功删除知识库{vs_id}"
logger.info(status)
chatbot = chatbot + [[None, status]]
return gr.update(choices=get_vs_list(), value=get_vs_list()[0]), gr.update(visible=True), gr.update(visible=True), \
gr.update(visible=False), chatbot, gr.update(visible=False)
except Exception as e:
logger.error(e)
status = f"删除知识库{vs_id}失败"
chatbot = chatbot + [[None, status]]
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), \
gr.update(visible=True), chatbot, gr.update(visible=True)
block_css = """.importantButton { block_css = """.importantButton {
background: linear-gradient(45deg, #7e0570,#5d1c99, #6e00ff) !important; background: linear-gradient(45deg, #7e0570,#5d1c99, #6e00ff) !important;
...@@ -318,6 +354,7 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as ...@@ -318,6 +354,7 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as
interactive=True, interactive=True,
visible=True) visible=True)
vs_add = gr.Button(value="添加至知识库选项", visible=True) vs_add = gr.Button(value="添加至知识库选项", visible=True)
vs_delete = gr.Button("删除本知识库", visible=False)
file2vs = gr.Column(visible=False) file2vs = gr.Column(visible=False)
with file2vs: with file2vs:
# load_vs = gr.Button("加载知识库") # load_vs = gr.Button("加载知识库")
...@@ -336,28 +373,40 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as ...@@ -336,28 +373,40 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as
file_count="directory", file_count="directory",
show_label=False) show_label=False)
load_folder_button = gr.Button("上传文件夹并加载知识库") load_folder_button = gr.Button("上传文件夹并加载知识库")
with gr.Tab("删除文件"):
files_to_delete = gr.CheckboxGroup(choices=[],
label="请从知识库已有文件中选择要删除的文件",
interactive=True)
delete_file_button = gr.Button("从知识库中删除选中文件")
vs_refresh.click(fn=refresh_vs_list, vs_refresh.click(fn=refresh_vs_list,
inputs=[], inputs=[],
outputs=select_vs) outputs=select_vs)
vs_add.click(fn=add_vs_name, vs_add.click(fn=add_vs_name,
inputs=[vs_name, chatbot], inputs=[vs_name, chatbot],
outputs=[select_vs, vs_name, vs_add, file2vs, chatbot]) outputs=[select_vs, vs_name, vs_add, file2vs, chatbot, vs_delete])
vs_delete.click(fn=delete_vs,
inputs=[select_vs, chatbot],
outputs=[select_vs, vs_name, vs_add, file2vs, chatbot, vs_delete])
select_vs.change(fn=change_vs_name_input, select_vs.change(fn=change_vs_name_input,
inputs=[select_vs, chatbot], inputs=[select_vs, chatbot],
outputs=[vs_name, vs_add, file2vs, vs_path, chatbot]) outputs=[vs_name, vs_add, file2vs, vs_path, chatbot, files_to_delete, vs_delete])
load_file_button.click(get_vector_store, load_file_button.click(get_vector_store,
show_progress=True, show_progress=True,
inputs=[select_vs, files, sentence_size, chatbot, vs_add, vs_add], inputs=[select_vs, files, sentence_size, chatbot, vs_add, vs_add],
outputs=[vs_path, files, chatbot], ) outputs=[vs_path, files, chatbot, files_to_delete], )
load_folder_button.click(get_vector_store, load_folder_button.click(get_vector_store,
show_progress=True, show_progress=True,
inputs=[select_vs, folder_files, sentence_size, chatbot, vs_add, inputs=[select_vs, folder_files, sentence_size, chatbot, vs_add,
vs_add], vs_add],
outputs=[vs_path, folder_files, chatbot], ) outputs=[vs_path, folder_files, chatbot, files_to_delete], )
flag_csv_logger.setup([query, vs_path, chatbot, mode], "flagged") flag_csv_logger.setup([query, vs_path, chatbot, mode], "flagged")
query.submit(get_answer, query.submit(get_answer,
[query, vs_path, chatbot, mode], [query, vs_path, chatbot, mode],
[chatbot, query]) [chatbot, query])
delete_file_button.click(delete_file,
show_progress=True,
inputs=[select_vs, files_to_delete, chatbot],
outputs=[files_to_delete, chatbot])
with gr.Tab("知识库测试 Beta"): with gr.Tab("知识库测试 Beta"):
with gr.Row(): with gr.Row():
with gr.Column(scale=10): with gr.Column(scale=10):
...@@ -488,9 +537,9 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as ...@@ -488,9 +537,9 @@ with gr.Blocks(css=block_css, theme=gr.themes.Default(**default_theme_args)) as
load_model_button.click(reinit_model, show_progress=True, load_model_button.click(reinit_model, show_progress=True,
inputs=[llm_model, embedding_model, llm_history_len, no_remote_model, use_ptuning_v2, inputs=[llm_model, embedding_model, llm_history_len, no_remote_model, use_ptuning_v2,
use_lora, top_k, chatbot], outputs=chatbot) use_lora, top_k, chatbot], outputs=chatbot)
load_knowlege_button = gr.Button("重新构建知识库") # load_knowlege_button = gr.Button("重新构建知识库")
load_knowlege_button.click(reinit_vector_store, show_progress=True, # load_knowlege_button.click(reinit_vector_store, show_progress=True,
inputs=[select_vs, chatbot], outputs=chatbot) # inputs=[select_vs, chatbot], outputs=chatbot)
demo.load( demo.load(
fn=refresh_vs_list, fn=refresh_vs_list,
inputs=None, inputs=None,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论