commit f17d26addff5f75e7d28dfbbc99e655bb3d8d745 Author: littlepanda0716 Date: Fri Mar 31 20:09:40 2023 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e1ca07 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# 基于本地知识的 ChatGLM 应用实现 + +## 介绍 + +🌍 [_READ THIS IN ENGLISH_](README_en.md) + +🤖️ 一种利用 [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B) + [langchain](https://github.com/hwchase17/langchain) 实现的基于本地知识的 ChatGLM 应用。 + +💡 受 [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) 启发,建立了全部基于开源模型实现的本地知识问答应用。 + +✅ 本项目中 Embedding 选用的是 [GanymedeNil/text2vec-large-chinese](https://huggingface.co/GanymedeNil/text2vec-large-chinese/tree/main),LLM 选用的是 [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B)。依托上述模型,本项目可实现局域网环境下的**开源**模型**离线部署**。 + +## 使用方式 + +### 1. 安装 python 依赖包 +```commandline +pip install -r requirements +``` +注:使用 langchain.document_loaders.UnstructuredFileLoader 进行非结构化文件接入时,可能需要依据文档进行其他依赖包的安装,请参考 [langchain 文档](https://python.langchain.com/en/latest/modules/indexes/document_loaders/examples/unstructured_file.html) + +### 2. 执行 [knowledge_based_chatglm.py](knowledge_based_chatglm.py) 脚本 +```commandline +python knowledge_based_chatglm.py +``` +## 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 的模型架构,提高模型的性能和表现。例如,可以使用更大的神经网络或者改进的卷积神经网络结构。 + + + + +## 路线图 +- [x] 实现 langchain + ChatGLM-6B 本地知识应用 +- [x] 基于 langchain 实现非结构化文件接入 +- [ ] 基于 langchain 实现更多类型本地知识文件接入 +- [ ] 利用 gradio/streamlit 实现 web ui DEMO +- [ ] 利用 fastapi 实现 API 部署方式,并实现调用 API 的 web ui DEMO + diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000..c60cfcb --- /dev/null +++ b/README_en.md @@ -0,0 +1,32 @@ +# ChatGLM Application Based on Local Knowledge + +## Introduction + +🌍 [_中文文档_](README.md) + +🤖️ A local knowledge based LLM Application with [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B) and [langchain](https://github.com/hwchase17/langchain). + +💡 Inspired by [document.ai](https://github.com/GanymedeNil/document.ai) by [GanymedeNil](https://github.com/GanymedeNil) and [ChatGLM-6B Pull Request](https://github.com/THUDM/ChatGLM-6B/pull/216) by [AlexZhangji](https://github.com/AlexZhangji). + +✅ In this project, [GanymedeNil/text2vec-large-chinese](https://huggingface.co/GanymedeNil/text2vec-large-chinese/tree/main) is used as Embedding Model,and [ChatGLM-6B](https://github.com/THUDM/ChatGLM-6B) used as LLM。Based on those models,this project can be deployed **offline** with all **open source** models。 + +## Usage + +### 1. install python packages +```commandline +pip install -r requirements +``` +Attention: With langchain.document_loaders.UnstructuredFileLoader used to connect with local knowledge file, you may need some other dependencies as mentioned in [langchain documentation](https://python.langchain.com/en/latest/modules/indexes/document_loaders/examples/unstructured_file.html) + +### 2. Run [knowledge_based_chatglm.py](knowledge_based_chatglm.py) script +```commandline +python knowledge_based_chatglm.py +``` + +## Roadmap +- [x] local knowledge based application with langchain + ChatGLM-6B +- [x] unstructured files loaded with langchain +- [ ] more different file format loaded with langchain +- [ ] implement web ui DEMO with gradio/streamlit +- [ ] implement API with fastapi,and web ui DEMO with API + diff --git a/chatglm_llm.py b/chatglm_llm.py new file mode 100644 index 0000000..8c00685 --- /dev/null +++ b/chatglm_llm.py @@ -0,0 +1,49 @@ +from langchain.llms.base import LLM +from typing import Optional, List +from langchain.llms.utils import enforce_stop_tokens +from transformers import AutoTokenizer, AutoModel + +"""ChatGLM_G is a wrapper around the ChatGLM model to fit LangChain framework. May not be an optimal implementation""" + + +class ChatGLM(LLM): + max_token: int = 10000 + temperature: float = 0.1 + top_p = 0.9 + history = [] + tokenizer = AutoTokenizer.from_pretrained( + "THUDM/chatglm-6b", + trust_remote_code=True + ) + model = ( + AutoModel.from_pretrained( + "THUDM/chatglm-6b", + trust_remote_code=True) + .half() + .cuda() + ) + + + def __init__(self): + super().__init__() + + @property + def _llm_type(self) -> str: + return "ChatGLM" + + def _call(self, + prompt: str, + stop: Optional[List[str]] = None) -> str: + response, updated_history = self.model.chat( + self.tokenizer, + prompt, + history=self.history, + max_length=self.max_token, + temperature=self.temperature, + + ) + print("history: ", self.history) + if stop is not None: + response = enforce_stop_tokens(response, stop) + self.history = updated_history + return response diff --git a/knowledge_based_chatglm.py b/knowledge_based_chatglm.py new file mode 100644 index 0000000..c273ca4 --- /dev/null +++ b/knowledge_based_chatglm.py @@ -0,0 +1,70 @@ +from langchain.prompts.prompt import PromptTemplate +from langchain.chains import ChatVectorDBChain +from langchain.prompts.chat import ( + ChatPromptTemplate, + SystemMessagePromptTemplate, + HumanMessagePromptTemplate, +) +from langchain.embeddings.huggingface import HuggingFaceEmbeddings +from langchain.vectorstores import FAISS +from langchain.document_loaders import UnstructuredFileLoader +from chatglm_llm import ChatGLM + + +def init_knowledge_vector_store(filepath): + embeddings = HuggingFaceEmbeddings(model_name="GanymedeNil/text2vec-large-chinese", ) + loader = UnstructuredFileLoader(filepath, mode="elements") + docs = loader.load() + + vector_store = FAISS.from_documents(docs, embeddings) + return vector_store + + +def get_wiki_agent_answer(query, vector_store, chat_history=[]): + system_template = """基于以下内容,简洁和专业的来回答用户的问题。 + 如果无法从中得到答案,请说 "不知道" 或 "没有足够的相关信息",不要试图编造答案。答案请使用中文。 + ---------------- + {context} + ---------------- + """ + messages = [ + SystemMessagePromptTemplate.from_template(system_template), + HumanMessagePromptTemplate.from_template("{question}"), + ] + prompt = ChatPromptTemplate.from_messages(messages) + + condese_propmt_template = """任务: 给一段对话和一个后续问题,将后续问题改写成一个独立的问题。确保问题是完整的,没有模糊的指代。 + ---------------- + 聊天记录: + {chat_history} + ---------------- + 后续问题:{question} + ---------------- + 改写后的独立、完整的问题:""" + new_question_prompt = PromptTemplate.from_template(condese_propmt_template) + chatglm = ChatGLM() + chatglm.history = chat_history + knowledge_chain = ChatVectorDBChain.from_llm( + llm=chatglm, + vectorstore=vector_store, + qa_prompt=prompt, + condense_question_prompt=new_question_prompt, + ) + + knowledge_chain.return_source_documents = True + knowledge_chain.top_k_docs_for_context = 10 + + result = knowledge_chain({"question": query, "chat_history": chat_history}) + return result, chatglm.history + + +if __name__ == "__main__": + filepath = input("Input your local knowledge file path 请输入本地知识文件路径:") + vector_store = init_knowledge_vector_store(filepath) + history = [] + while True: + query = input("Input your question 请输入问题:") + resp, history = get_wiki_agent_answer(query=query, + vector_store=vector_store, + chat_history=history) + print(resp) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1dcbad6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +langchain +transformers +unstructured[local-inference] +"detectron2@git+https://github.com/facebookresearch/detectron2.git@v0.6#egg=detectron2" +layoutparser[layoutmodels,tesseract] +nltk +sentence-transformers \ No newline at end of file