RAG检索增强生成(RAG, Retrieval-Augmented Generation)。该架构巧妙地整合了从庞大知识库中检索到的相关信息,并以此为基础,指导大型语言模型生成更为精准的答案,从而显著提升了回答的准确性与深度。
使得生成的结果比较靠谱,原本ai推荐的比较的广泛没有具体的内容,所有采用RAG技术来提高ai的准确率,以及审美水平,具体的RAG流程如下
将网上的一些搭配的技巧和穿搭方式作为数据,然后将数据embedding化,存入数据库作为检索的背景资料。用户提出问题(query),我们利用LLM将问题分解成多个小问题。例如:请问我比较的高瘦应该怎么穿搭——>变成我比较的高瘦该穿什么样的衣服,我比较的高瘦该穿什么样的裤子......利用这样的拆分一条条的检索对应的答案的背景,最后将问题和背景一起返回回去给LLM进行推荐。
用的是streamlit库来制作的demo
以下是拆分出来样式
由于数据库中的数据的比较少,虽然被拆分的问题多,但是返回的结果也没有完全把所有的问题的回答了,回复的答案其实也是比较的“水”。
拆分的效果还是不错的,就是需要不断的增加数据进去,才能有比较好的效果。拆分的prompt也是经历了多次的尝试才得到这个比较好的效果,个人感觉比较的玄学,多试!
以下是部分代码:
建立数据库代码:
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores.chroma import Chroma
from dotenv import load_dotenv, find_dotenv
from zhipu_embedding import ZhipuAIEmbeddings
_ = load_dotenv(find_dotenv())
embedding = ZhipuAIEmbeddings()
file_path = "C:\\Users\\木木\\Desktop\\新建文本文档.txt"
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
raw_documents = TextLoader(file_path, encoding='utf8').load()
texts_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
split_docs = texts_splitter.split_documents(raw_documents)
print(split_docs[2])
persist_directory = "C:\\Users\\木木\\Desktop\\机器算法and data\\chuan_chroma"
vector_db = Chroma.from_documents(
documents=split_docs,
embedding=embedding,
persist_directory=persist_directory
)
vector_db.persist()
print(f"向量库中存储的数量:{vector_db._collection.count()}")
创建数据和封装的embedding代码是参考llm-universe/docs/C3/附LangChain自定义Embedding封装讲解.md at main · datawhalechina/llm-universe (github.com)
主函数:包括了检索和demo的创建(目前还在优化当中,没有单独做封装)
一、加载数据库
from dotenv import load_dotenv, find_dotenv
import os
from zhipuai import ZhipuAI
from langchain.vectorstores.chroma import Chroma
from zhipu_embedding import ZhipuAIEmbeddings
import json
import streamlit as st
persist_directory = "C:\\Users\\木木\\Desktop\\机器算法and data\\chuan_chroma"
_ = load_dotenv(find_dotenv())
client = ZhipuAI(api_key=os.getenv("ZhipuAI_API_KEY"))
# 创建ZhipuAIEmbeddings对象
embeddings = ZhipuAIEmbeddings()
# 加载向量数据库
db = Chroma(
persist_directory=persist_directory,
embedding_function=embeddings
)
# docs = db.similarity_search(question, k=3)
二、初始化模型
# 初始化模型
def get_response(context, temperature=0):
response = client.chat.completions.create(
model="glm-4",
messages=[{"role": "user", "content": context}],
temperature=temperature,
)
return response.choices[0].message.content
三、获取问题的拆分
# 获取问题拆分成多个小问题
class Get_question:
def __init__(self, question):
self.question = question
self.req = '''回复格式为:
{
"1": "我应该带什么眼镜?",
"2": "我应该穿什么裤子?",
"3": "我应该穿什么帽子?"
}'''
def get_question(self):
prompt = f"请将以下问题{self.question}分成多个小问题,并且需要将大问题的主语补充到每一个小问题上\
只输出分割后的信息,并以JSON方式存储 \
:{self.req}"
return prompt
def get_question_response(self):
prompt = self.get_question()
response = get_response(prompt)
print(type(response))
print(response)
data = json.loads(response)
print(data["1"])
questions = []
for v in range(len(data)):
v = v + 1
prompt = data[str(v)]
questions.append(prompt)
return questions
四、创建demo
# 创建一个标题和一个副标题
st.title("💬 Zhipu2.0 穿搭助手")
if "messages" not in st.session_state:
st.session_state["messages"] = []
for i in st.session_state.messages:
st.chat_message(i["role"]).write(i["content"])
if inpt := st.chat_input():
st.session_state.messages.append({"role": "user", "content": inpt})
# 将用户的输入添加到session_state中的messages列表中
st.chat_message("user").write(inpt)
# 在聊天界面上显示用户的输入
get_question = Get_question(inpt)
Q = get_question.get_question_response()
contexts = []
for q in range(len(Q)):
question = str(Q[q])
print('> Question:', question)
cons = db.similarity_search(question, k=3)
for v,context in enumerate(cons):
context = context.page_content
contexts.append(context)
prompt = f'''背景:{contexts}\n问题:{inpt}\n请基于背景,回答问题。只回答问题,不要输出背景。
根据上述问题来输出内容,输出的内容只需要包括问题所问的内容,不需要输出其他无关的内容。输出的每一部分内容都需要另外换行输出。
输出格式的例子为:
衣服:
裤子:
鞋子:
配饰:
'''
ans = get_response(prompt)
# 将模型的输出添加到session_state中的messages列表中
st.session_state.messages.append({"role": "assistant", "content": ans})
# 在聊天界面上显示模型的输出
st.chat_message("assistant").write(ans)