Skip to content

Commit

Permalink
Merge pull request #29 from liuxianyi/rqa-goog
Browse files Browse the repository at this point in the history
Add RQA tools for Tianji
  • Loading branch information
sanbuphy authored Feb 22, 2024
2 parents f25300e + ad29da5 commit 6db168c
Show file tree
Hide file tree
Showing 10 changed files with 422 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ __pycache__/
build/
tianji.egg-info/
temp/
*.bin
38 changes: 38 additions & 0 deletions docs/RQA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 知识外挂 RQA 使用说明

一共包含3个步骤:

1. 准备数据
1. 构建embdding数据库
1. 根据自定义embdding数据库,实现知识外挂 RQA

# 数据准备

参考[text](Tianji/tianji/knowledges/RQA/script/process_data.py)

# 构建embdding数据库

填写配置文件

```python
# 原始数据位置 online 设置为空
ORIGIN_DATA = ""
# 持久化数据库位置,例如 chroma/liyi/
PERSIST_DIRECTORY = ""
# Sentence-Transformer词向量模型权重位置
HF_SENTENCE_TRANSFORMER_WEIGHT = (
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
```

运行脚本,基于Chroma构建向量数据库

```python
python Tianji/tianji/knowledges/RQA/emb.py
```

# 运行 Demo

```python
python Tianji/run/tianji_rqa_demo.py
```
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ transformers_stream_generator==0.0.4
modelscope
tiktoken
einops

# for RQA
langchain==0.0.292
gradio==3.50.2
95 changes: 95 additions & 0 deletions run/tianji_rqa_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from tianji.knowledges.RQA.model import Zhipu_LLM
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from tianji.knowledges.RQA.config import RQA_ST_Liyi_Chroma_Config


def load_chain():
embeddings = HuggingFaceEmbeddings(
model_name=RQA_ST_Liyi_Chroma_Config.HF_SENTENCE_TRANSFORMER_WEIGHT
)

persist_directory = RQA_ST_Liyi_Chroma_Config.PERSIST_DIRECTORY
vectordb = Chroma(
persist_directory=persist_directory,
embedding_function=embeddings,
)

llm = Zhipu_LLM()

template = """使用以下上下文中文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。尽量使答案调理清楚,内容详实。总是在回答的最后说”谢谢你的提问!“。
{context}
问题: {question}
详细真实的答案:"""

QA_CHAIN_PROMPT = PromptTemplate(
input_variables=["context", "question"], template=template
)

qa_chain = RetrievalQA.from_chain_type(
llm,
retriever=vectordb.as_retriever(),
return_source_documents=True,
chain_type_kwargs={"prompt": QA_CHAIN_PROMPT},
)

return qa_chain


class Model_center:
"""
模型广场,目前支持智浦AI
"""
def __init__(self):
self.chain = load_chain()

def qa_chain_self_answer(self, question: str, chat_history: list = []):
if question is None or len(question) < 1:
return "", chat_history
try:
chat_history.append((question, self.chain({"query": question})["result"]))
return "", chat_history
except Exception as e:
return e, chat_history


import gradio as gr

model_center = Model_center()
block = gr.Blocks()
with block as demo:
with gr.Row(equal_height=True):
with gr.Column(scale=15):
gr.Markdown(
"""<h1><center>InternLM</center></h1>
<center>人情世故</center>
"""
)

with gr.Row():
with gr.Column(scale=4):
chatbot = gr.Chatbot(height=450, show_copy_button=True)
msg = gr.Textbox(label="Prompt/问题")

with gr.Row():
db_wo_his_btn = gr.Button("Chat")
with gr.Row():
clear = gr.ClearButton(components=[chatbot], value="Clear console")

db_wo_his_btn.click(
model_center.qa_chain_self_answer,
inputs=[msg, chatbot],
outputs=[msg, chatbot],
)

gr.Markdown(
"""提醒:<br>
1. 初始化数据库时间可能较长,请耐心等待。
2. 使用中如果出现异常,将会在文本输入框进行展示,请不要惊慌。 <br>
"""
)
gr.close_all()
demo.launch()
8 changes: 8 additions & 0 deletions test/knowledges/test_rqa_zhipu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from tianji.knowledges.RAG.demo import model_center

if __name__ == "__main__":
model = model_center()
question = "如何给长辈敬酒?"
chat_history = []
_, response = model.qa_chain_self_answer(question, chat_history)
print(response)
16 changes: 16 additions & 0 deletions tianji/knowledges/RQA/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# from metagpt.const import METAGPT_ROOT as TIANJI_PATH
class RQA_ST_Liyi_Chroma_Config:
"""
检索问答增强(RQA)配置文件:
基于Chroma检索数据库;
基于Sentence-Transformer词向量模型构建的外挂礼仪(Liyi)知识库。
"""

# 原始数据位置 online 设置为空
ORIGIN_DATA = ""
# 持久化数据库位置,例如 chroma/liyi/
PERSIST_DIRECTORY = ""
# Sentence-Transformer词向量模型权重位置
HF_SENTENCE_TRANSFORMER_WEIGHT = (
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)
22 changes: 22 additions & 0 deletions tianji/knowledges/RQA/emb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from langchain.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma

from . import RQA_ST_Liyi_Chroma_Config

if __name__ == "__main__":
persist_directory = RQA_ST_Liyi_Chroma_Config.PERSIST_DIRECTORY
data_directory = RQA_ST_Liyi_Chroma_Config.ORIGIN_DATA
loader = DirectoryLoader(data_directory, glob="*.txt", loader_cls=TextLoader)

text_splitter = RecursiveCharacterTextSplitter(chunk_size=3000, chunk_overlap=150)
split_docs = text_splitter.split_documents(loader.load())

embeddings = HuggingFaceEmbeddings(
model_name="/root/weights/model/sentence-transformer"
)
vectordb = Chroma.from_documents(
documents=split_docs, embedding=embeddings, persist_directory=persist_directory
)
vectordb.persist()
1 change: 1 addition & 0 deletions tianji/knowledges/RQA/model/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .langchain.model import InternLM_LLM, Zhipu_LLM, OpenAI_LLM
118 changes: 118 additions & 0 deletions tianji/knowledges/RQA/model/langchain/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import os


class InternLM_LLM(LLM):
tokenizer: AutoTokenizer = None
model: AutoModelForCausalLM = None

def __init__(self, model_path: str):
super().__init__()
print("正在从本地加载模型...")
self.tokenizer = AutoTokenizer.from_pretrained(
model_path, trust_remote_code=True
)
self.model = (
AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)
.to(torch.bfloat16)
.cuda()
)
self.model = self.model.eval()
print("完成本地模型的加载")

def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any
):
system_prompt = """你是一名AI助手名为天机(SocialAI),也可称为来事儿AI。它能够处理中国传统人情世故的任务,例如如何敬酒、如何说好话、如何会来事儿等。
"""
messages = [(system_prompt, "")]
response, history = self.model.chat(self.tokenizer, prompt, history=messages)
return response

@property
def _llm_type(self) -> str:
return "InternLM"


class Zhipu_LLM(LLM):
tokenizer: AutoTokenizer = None
model: AutoModelForCausalLM = None
client: Any = None

def __init__(self):
super().__init__()
from zhipuai import ZhipuAI

print("初始化模型...")
self.client = ZhipuAI(api_key=os.environ.get("zhupuai_key"))
print("完成模型初始化")

def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any
):
system_prompt = """你是一名AI助手名为天机(SocialAI),也可称为来事儿AI。它能够处理中国传统人情世故的任务,例如如何敬酒、如何说好话、如何会来事儿等。
你是一个信息抽取的知识库语料准备能手,你需要把我给你的文章做成几个知识点,这个知识点类似问答对的回答(陈述句的描述,不需要提问,比如:苹果是一种水果,可以吃和烹饪,而且是红色的,长在大树上),你不需要分1、2、3、4点, 只需要把相关的知识都划分成一个段落就好, ``` 例子如下,假设我首先发了这个文章: 在商务宴请中有一个很重要的礼仪,如果你忽视了,会让你的客户觉得你很没有分寸。大家都知道在饭桌上谈生意,往往会比在办公室正儿八经坐着谈成的几率会更大。在这其中当然离不开酒的路牢,所以在商务宴请中敬酒的礼仪是非常重要的。 敬酒时先给对方斟酒,然后再给自己斟酒。右手拿酒杯,左手托杯底。咱们的酒杯要比对方低一点,如果对方比较谦虚,放的比我们低,我们可以用左手轻轻的将对方的酒杯托起,这样会显得尊重。喝完酒为了表达咱们的诚意,我们可以用敬酒的手势把杯子微微倾斜,杯口朝向对方,不用再把杯子直接倒过来,会显得很不雅。大家在敬酒的时候呢,还有哪些注意事项呢?咱们可以留言一起讨论一下。 你的回答是富有知识冷静的回复,如下作为一个整体:商务宴请中,礼仪的遵循对于给客户留下良好印象至关重要,饭桌上的生意洽谈通常成功率较高。在敬酒环节,应优先为对方斟酒,随后再为自己斟,且需用右手持杯,左手托底。敬酒时,酒杯应保持低于对方酒杯,以示尊敬;若对方酒杯位置更低,可轻轻用左手托起对方酒杯。喝完酒后,应以敬酒手势将杯子微微倾斜,杯口朝向对方,避免直接倒转酒杯,以维持礼貌和风度。 ``` 接下来你帮我解析新的知识,你只需要回复这个新的知识文章相关的内容就好,不要回复例子的内容!文章如下: ``` 你知道一场正式饭局的喝酒流程和敬酒节奏吗?如果不知道这个视频,一定要点赞收藏,因为你早晚用的上一场商务酒局。一般有这六个阶段,而大部分人在第二和第五阶段最容易犯错。接下来咱分别说说,先说这酒局第一阶段开场的共同酒喝多少你得看主场。山东人讲究主副陪轮流领酒,共同干杯制,而河北的多数地方习惯共同喝前三杯,不同地方有不同讲究,大家也都可以留言说说看你当地有什么讲究。如果大家点赞关注够热情,我后期可以专门出一集全国各地喝酒习俗的总结。 这第二阶段就是东道主开始敬酒了。这时候一般都是东道主或主陪率先从主宾开始依次向每一位客人敬酒,这个阶段依次和轮流意识很重要。如果你是客人,可千万别在这种时候为了表示你的谢意去回敬主人,因为还没到该你出场的阶段,到了第三阶段,你作为客人就可以回敬了。可以由你方领头的带着大家先共同回敬,然后再分别回敬。 接着进入第四阶段,喝主题酒及重点酒,根据被情者与主题的关系把主题点出来,喝进去是桌上人明白为啥喝这场酒。嘿嘿这第五阶段就是自由酒阶段了。跟谁投脾气就可以过去跟他喝杯相见恨晚酒。跟谁还有未了的话题可以用酒来讨教,看谁不顺眼也可以用酒来挑战。尤其是带着任务来了,一定要抓紧时间落实任务,因为过了这阶段就不自由了。 在第六阶段,也就是最后喝满堂红了,差不多该散席了。主陪一般都会发话,大家各扫门前酒,共喝满堂红。这杯酒喝下去意味着酒事正式结束,下面的节目能吃吃该吐吐。商务宴请中,礼仪的遵循对于给客户留下良好印象至关重要,饭桌上的生意洽谈通常成功率较高。在敬酒环节,应优先为对方斟酒,随后再为自己斟,且需用右手持杯,左手托底。敬酒时,酒杯应保持低于对方酒杯,以示尊敬;若对方酒杯位置更低,可轻轻用左手托起对方酒杯。喝完酒后,应以敬酒手势将杯子微微倾斜,杯口朝向对方,避免直接倒转酒杯,以维持礼貌和风度。 ```
"""
response = self.client.chat.completions.create(
model="glm-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content

@property
def _llm_type(self) -> str:
return "ZhipuLM"


class OpenAI_LLM(LLM):
tokenizer: AutoTokenizer = None
model: AutoModelForCausalLM = None
client: Any = None

def __init__(self, base_url="https://api.deepseek.com/v1"):
super().__init__()
from openai import OpenAI

print("初始化模型...")
self.client = OpenAI(
api_key=os.environ.get("openai_key", None), base_url=base_url
)
print("完成模型初始化")

def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any
):
system_prompt = """你是一名AI助手名为天机(SocialAI),也可称为来事儿AI。它能够处理中国传统人情世故的任务,例如如何敬酒、如何说好话、如何会来事儿等。
你是一个信息抽取的知识库语料准备能手,你需要把我给你的文章做成几个知识点,这个知识点类似问答对的回答(陈述句的描述,不需要提问,比如:苹果是一种水果,可以吃和烹饪,而且是红色的,长在大树上),你不需要分1、2、3、4点, 只需要把相关的知识都划分成一个段落就好, ``` 例子如下,假设我首先发了这个文章: 在商务宴请中有一个很重要的礼仪,如果你忽视了,会让你的客户觉得你很没有分寸。大家都知道在饭桌上谈生意,往往会比在办公室正儿八经坐着谈成的几率会更大。在这其中当然离不开酒的路牢,所以在商务宴请中敬酒的礼仪是非常重要的。 敬酒时先给对方斟酒,然后再给自己斟酒。右手拿酒杯,左手托杯底。咱们的酒杯要比对方低一点,如果对方比较谦虚,放的比我们低,我们可以用左手轻轻的将对方的酒杯托起,这样会显得尊重。喝完酒为了表达咱们的诚意,我们可以用敬酒的手势把杯子微微倾斜,杯口朝向对方,不用再把杯子直接倒过来,会显得很不雅。大家在敬酒的时候呢,还有哪些注意事项呢?咱们可以留言一起讨论一下。 你的回答是富有知识冷静的回复,如下作为一个整体:商务宴请中,礼仪的遵循对于给客户留下良好印象至关重要,饭桌上的生意洽谈通常成功率较高。在敬酒环节,应优先为对方斟酒,随后再为自己斟,且需用右手持杯,左手托底。敬酒时,酒杯应保持低于对方酒杯,以示尊敬;若对方酒杯位置更低,可轻轻用左手托起对方酒杯。喝完酒后,应以敬酒手势将杯子微微倾斜,杯口朝向对方,避免直接倒转酒杯,以维持礼貌和风度。 ``` 接下来你帮我解析新的知识,你只需要回复这个新的知识文章相关的内容就好,不要回复例子的内容!文章如下: ``` 你知道一场正式饭局的喝酒流程和敬酒节奏吗?如果不知道这个视频,一定要点赞收藏,因为你早晚用的上一场商务酒局。一般有这六个阶段,而大部分人在第二和第五阶段最容易犯错。接下来咱分别说说,先说这酒局第一阶段开场的共同酒喝多少你得看主场。山东人讲究主副陪轮流领酒,共同干杯制,而河北的多数地方习惯共同喝前三杯,不同地方有不同讲究,大家也都可以留言说说看你当地有什么讲究。如果大家点赞关注够热情,我后期可以专门出一集全国各地喝酒习俗的总结。 这第二阶段就是东道主开始敬酒了。这时候一般都是东道主或主陪率先从主宾开始依次向每一位客人敬酒,这个阶段依次和轮流意识很重要。如果你是客人,可千万别在这种时候为了表示你的谢意去回敬主人,因为还没到该你出场的阶段,到了第三阶段,你作为客人就可以回敬了。可以由你方领头的带着大家先共同回敬,然后再分别回敬。 接着进入第四阶段,喝主题酒及重点酒,根据被情者与主题的关系把主题点出来,喝进去是桌上人明白为啥喝这场酒。嘿嘿这第五阶段就是自由酒阶段了。跟谁投脾气就可以过去跟他喝杯相见恨晚酒。跟谁还有未了的话题可以用酒来讨教,看谁不顺眼也可以用酒来挑战。尤其是带着任务来了,一定要抓紧时间落实任务,因为过了这阶段就不自由了。 在第六阶段,也就是最后喝满堂红了,差不多该散席了。主陪一般都会发话,大家各扫门前酒,共喝满堂红。这杯酒喝下去意味着酒事正式结束,下面的节目能吃吃该吐吐。商务宴请中,礼仪的遵循对于给客户留下良好印象至关重要,饭桌上的生意洽谈通常成功率较高。在敬酒环节,应优先为对方斟酒,随后再为自己斟,且需用右手持杯,左手托底。敬酒时,酒杯应保持低于对方酒杯,以示尊敬;若对方酒杯位置更低,可轻轻用左手托起对方酒杯。喝完酒后,应以敬酒手势将杯子微微倾斜,杯口朝向对方,避免直接倒转酒杯,以维持礼貌和风度。 ```
"""
response = self.client.chat.completions.create(
model="glm-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt},
],
)
return response.choices[0].message.content

@property
def _llm_type(self) -> str:
return "OpenAILM"
Loading

0 comments on commit 6db168c

Please sign in to comment.