NVIDIA AI-AGENT夏季训练营
项目名称:AI-AGENT夏季训练营 — RAG都市玄幻小说灵感创作大师
报告日期:2024年8月18日
项目负责人:Austin Xiong
项目概述(必写):
通过大量的玄幻小说素材进行RAG微调,能够输出有创意,且质量能够满足需求的都市玄幻小说的创作灵感。帮助玄幻小说作家结合当下最流行的趋势,结合多个爆款小说进行内容整合,并生成出最新的创意构思,为新的爆款小说的创作提供从0到1的帮助与灵感,并且能够多轮对话,对于作者的想法能够进一步的进行延申与拓展,从而生产出更为符合当下热度趋势的创意,思路。
技术方案与实施步骤
模型选择:
模型选择了baichuan-inc/baichuan2-13b-chat,在NIM平台上进行了检索,该模型对中文的支持比较好,RAG主要针对已有的玄幻小说进行垂类的加深,使大模型的行文风格更为适合都市玄幻小说的创作需求。
数据的构建:
数据构建主要是对于当前较为火爆的玄幻小说进行了下载并进行了整理,通过一些基本的python文本处理进行了数据构建。
实施步骤:
环境搭建(必写):本次实验主要在advantech epc-r7300上完成(nvdia orin nano 8g)
Python环境使用pyenv实现
具体的python环境搭建主要参考了老师提供的博客:
#安装nvidia_ai_endpoint工具
pip install langchain-nvidia-ai-endpoints
#安装Jupyter Lab
pip install jupyterlab
#安装langchain_core
pip install langchain_core
#安装langchain
pip install langchain
#安装matplotlib
pip install matplotlib
#安装Numpy
pip install numpy
#安装faiss, 这里如果没有GPU可以安装CPU版本
pip install faiss-cpu==1.7.2
#安装OPENAI库
pip install openai
代码实现(必写):
库函数调用
import os
from pathlib import Path
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import CharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain_nvidia_ai_endpoints import ChatNVIDIA
def initialize_embeddings_model():
"""
初始化 NVIDIAEmbeddings 对象。
"""
return NVIDIAEmbeddings(model="nvidia/nv-embedqa-e5-v5")
def load_text_data(data_dir="./zh_data/"):
"""
从指定目录加载文本数据。
Args:
data_dir (str): 存放文本数据的目录路径。
Returns:
tuple: 包含数据列表和来源列表的元组。
"""
ps = os.listdir(data_dir)
data = []
sources = []
for p in ps:
if p.endswith('.txt'):
path2file = data_dir + p
with open(path2file, encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
if len(line) >= 1:
data.append(line)
sources.append(path2file)
return data, sources
def preprocess_data(data, sources):
"""
对文本数据进行预处理。
Args:
data (list): 文本数据列表。
sources (list): 数据来源列表。
Returns:
tuple: 包含处理后的文档列表和元数据列表的元组。
"""
text_splitter = CharacterTextSplitter(chunk_size=400, separator=" ")
docs = []
metadatas = []
for i, d in enumerate(data):
splits = text_splitter.split_text(d)
docs.extend(splits)
metadatas.extend([{"source": sources[i]}] * len(splits))
return docs, metadatas
def create_faiss_vectorstore(docs, metadatas, embeddings, save_path="./zh_data/nv_embedding"):
"""
创建并保存 Faiss vectorstore。
Args:
docs (list): 文档列表。
metadatas (list): 元数据列表。
embeddings (object): NVIDIAEmbeddings 对象。
save_path (str): 保存 Faiss vectorstore 的路径。
"""
store = FAISS.from_texts(docs, embeddings, metadatas=metadatas)
store.save_local(save_path)
def load_faiss_vectorstore(load_path="./zh_data/nv_embedding", embeddings=None):
"""
从磁盘加载 Faiss vectorstore。
Args:
load_path (str): 加载 Faiss vectorstore 的路径。
embeddings (object): NVIDIAEmbeddings 对象。
Returns:
object: Faiss vectorstore 对象。
"""
store = FAISS.load_local(load_path, embeddings, allow_dangerous_deserialization=True)
return store
def create_retrieval_qa(llm, store):
"""
创建 RetrievalQA 链条。
Args:
llm (object): ChatNVIDIA 对象。
store (object): Faiss vectorstore 对象。
Returns:
object: RetrievalQA 对象。
"""
retriever = store.as_retriever()
template = (
"你是一位都市玄幻小说创作大师。你的任务是根据提供的上下文,为一本都市玄幻小说创作一个详细的梗概。"
"梗概应该包含但不限于以下元素:主要角色及其性格特点、设定(包括世界观、社会结构、特殊能力等)、情节走向、关键转折点、冲突与解决方案等。"
"你的回答必须完全基于以下上下文:\n"
"并且全程使用中文进行回答:\n"
"<文档>\n"
"{context}\n"
"</文档>\n"
"问题:{question}"
)
# 创建PromptTemplate实例
prompt_template = PromptTemplate(
template=template,
input_variables=["context", "question"]
)
chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": prompt_template},
)
return chain
def main():
# 设置 NVIDIA API 密钥
os.environ.pop("NVIDIA_API_KEY", None)
nvapi_key = "nvapi"
os.environ["NVIDIA_API_KEY"] = nvapi_key
# 初始化向量模型
embeddings = initialize_embeddings_model()
# 加载文本数据
data, sources = load_text_data()
# 预处理数据
docs, metadatas = preprocess_data(data, sources)
# 创建并保存 Faiss vectorstore
create_faiss_vectorstore(docs, metadatas, embeddings)
# 加载 Faiss vectorstore
store = load_faiss_vectorstore(embeddings=embeddings)
# 初始化 NVIDIA 的聊天模型
llm = ChatNVIDIA(model="baichuan-inc/baichuan2-13b-chat")
# 创建 ConversationalRetrievalChain 实例
qa_chain = create_conversational_retrieval_qa(llm, store)
# 开始多轮对话
chat_history = []
while True:
question = input("请输入您的问题 (输入'退出'结束对话): ")
if question.lower() == '退出':
break
result = qa_chain({"question": question, "chat_history": chat_history})
print(result['answer'])
chat_history.append((question, result['answer']))
if __name__ == "__main__":
main()
项目成果与展示:
应用场景展示(必写):
能够帮助玄幻小说作家结合当下最流行的趋势,结合多个爆款小说进行内容整合,并生成出最新的创意构思,为新的爆款小说的创作提供从0到1的帮助与灵感,并且能够多轮对话,对于作者的想法能够进一步的进行延申与拓展,从而生产出更为符合当下热度趋势的创意,思路。
功能演示:
未RAG前(传统热血小说剧情):
故事背景:在一个名为龙腾的大陆上,拥有着神秘的国度与强大的种族。这里的人们信仰龙,尊崇强者。而在这个世界的一角,有一个繁华的都市——龙城。这里是龙的乐园,也是人类的家园。形形色色的龙族与人类共存,共同演绎着一段段热血传奇。
主要角色:
-
林风:本作的主人公,一个年轻的龙族强者,血脉稀有的龙血战士。他拥有着惊人的战斗天赋,却也因为血脉原因而备受歧视。在一系列意外中,林风逐渐揭开了龙腾大陆的秘密,踏上了寻找自己身世之路。
-
苏若雪:林风的爱人,一个美丽的人类女子。她因为自己强大的精神力而受到龙族的觊觎,但在与林风相识后,两人共度难关,感情日渐深厚。
-
铁血:龙城的一位龙族强者,林风的导师与朋友。他曾是龙腾大陆上最强大的战士,却因为一场意外失去了力量。在林风的帮助下,铁血重新找回了自己失去的力量,并成为了林风的得力助手。
-
黑龙:龙腾大陆上最强大的龙族入侵者,他企图征服整个大陆,成为至高无上的统治者。林风与他的对手,展开了一场惊心动魄的较量。
故事梗概:
林风在一次意外中被卷入了一场涉及龙腾大陆生死存亡的争斗。在铁血的指引下,林风逐渐了解自己血脉的奥秘,并掌握了一门堪称逆天的强大技能。在寻找自己身世的过程中,林风结识了苏若雪,两人感情日益加深。然而,苏若雪却成为了黑龙觊觎的目标。为了保护挚爱,林风勇敢地与黑龙展开了决战。
在惊心动魄的决战中,林风凭借着静心的智慧和坚韧的意志,最终战胜了黑龙。而为了保护龙城与人类,林风与苏若雪不得不分离,各自守护着一方天地。在这漫长的岁月里,林风与苏若雪一直在寻找重逢的机会,最终勇敢地跨越了种族与境界的鸿沟,携手共度余生。
《都市龙族》是一部充满热血与玄幻的都市小说。它讲述了一个年轻的龙族强者林风,在寻找自己身世的过程中,与人类女子苏若雪上演了一出跨越种族与境界的真爱传说。在这个过程中,林风逐渐揭开
大模型输出结果:
RAG后大模型输出结果:(更符合当下玄幻小说流行/热度趋势)
一、主要角色及其性格特点:
- 龙飞:本作的男主角,原本是人,却意外变成了一头拥有神奇力量的巨龙。他性格坚韧、正直、聪明,善于观察和思考,但最初对人类的生活和心灵的理解有限。
- 林雪:本作的女主角,美丽、聪明、善良,是龙飞在人类世界的重要引导者和支持者。她敢于追求自己的梦想,坚定信仰,但同时也对龙飞有一种特殊的感情。
- 何师叔:龙飞在修仙门派中的师兄,性格憨厚、忠诚,对龙飞有着深厚的感情。
二、设定(包括世界观、社会结构、特殊能力等):
- 设定一个玄幻的都市世界,其中人类社会中存在着修仙门派和隐世强者。
- 龙飞拥有变身成人形和龙形的特殊能力,以及强大的力量、速度、治愈等能力。
- 社会中存在着各种神秘的玄幻元素,如仙器、灵兽、秘境等。
三、情节走向:
- 龙飞从神秘的秘境中复活,变为一头巨龙,但却失去记忆。
- 龙飞在人类世界中遭遇种种困难,逐渐适应人类生活,并遇到了林雪。
- 龙飞和林雪一起解决各种玄幻事件,揭示龙飞的身世。
- 龙飞恢复记忆,开始寻找自己的使命,最终决定保护人类社会。
四、关键转折点:
- 龙飞在都市中初次变身成巨龙,被人类误会为邪恶生物。
- 龙飞和林雪在探索中发现了他的身世秘密。
- 龙飞恢复记忆,决定全力以赴保护人类社会。
五、冲突与解决方案:
- 最初,龙飞与人类社会的冲突在于其作为巨龙的外貌和能力,以及他失去的记忆。林雪作为引导者,帮助他适应人类生活,理解人类情感。
- 龙飞在解决各种事件的过程中,逐渐理解和接纳人类社会,最终决定成为人类的守护神。
这个故事将都市生活与玄幻元素相结合,展示了一个热血的少年如何在困境中成长,最终找到自己的人生使命。
问题与解决方案:
问题分析: 对于模型的选择,采用llama-3.1-405b-instruct等模型进行RAG时由于中文支持性不好经常出现幻觉等现象
解决措施: 经过对比测试后,根据效果选择了当前模型
项目总结与展望:
项目评估: 基于NIM平台的RAG极大程度的降低了各行业制作自身垂类模型的工作量,经过更多中文支持更好的模型加入后,以及更多的RAG材料加入,会产生出更好的内容。
未来方向: 未来希望能够增加建议的GUI,主要还是基于更为强大的中文支持模型,进行RAG能够创作出更为完善,token更长的创作资料。
附件与参考资料
2024 NVIDIA开发者社区夏令营环境配置指南(Win & Mac)的补充说明
落魄“牛马”的救赎—RAG让你鸟枪换炮,成为投标小能手!