项目名称:AI-AGENT夏季训练营 — 基于RAG构建的城市旅游攻略智能助手(以武汉为例)
报告日期:2024年8月18日
项目负责人:Oswald
目录
项目概述
本项目借助英伟达NIM平台设计并实现了一个城市旅游攻略智能助手,项目利用较小参数的大语言模型实现,能够在资源受限的设备上高效运行,如移动设备、嵌入式系统等,并通过RAG技术解决大语言模型在“知识库不足”情况下出现的“幻觉”现象,实现了在垂直细分领域下得到更专业、更准确的回答。
技术方案与实施步骤
模型选择
- llama-3.1-8b-instruct
- ai-embed-qa-4
数据的构建
本次项目以武汉为例,在携程网上针对武汉的著名景点和美食进行了相关信息的收集,得到两个txt文件,用于后续外部知识库的构建
文本原始数据预览
food.txt |
热干面是武汉最出名的小吃之一,有多种做法,其采用碱水面,并以食油、芝麻酱、色拉油、香油、红油、细香葱、大蒜、萝卜丁、酸豆角、卤水汁、生抽、醋等为辅助材料。热干面色泽黄而油润,味道鲜美,由于热量高,也可以当作主食,营养早餐,补充人体所需的能量。 武汉蛋酒是武汉过早点单率非常高的饮品,蛋酒香浓可口,色淡而甘甜,口感尚佳,基本上是早上搭配油条,面窝食用。 武昌鱼是我国重要的草食性鱼类,具有味美、头小、含肉量高的特点。烹饪方法多样,清蒸、油焖、红烧、花酿等等。选用鲜活鱼,清蒸时辅以火腿、冬菇、冬笋和高汤,上笼清蒸,严格控制火候,使之恰到好处。成品鱼形完整、色白明亮、晶莹似玉,鱼身缀以红、白、黑配料,颜色非常好看。肉质细嫩,吃起来还有浓浓的香味扑鼻。 |
scenic.txt |
黄鹤楼(Yellow Crane Tower),位于湖北武汉武昌长江南岸蛇山峰岭之上。始建于三国时代吴黄武二年(公元223年),历代屡建屡毁,今天看到的黄鹤楼,是1985年重建的。黄鹤楼是国家5A级景点,享有“天下绝景” 、“天下江山第一楼”之称,是武汉的城市地标之一,因唐代诗人崔颢“昔人已乘黄鹤去,此地空余黄鹤楼”的诗句而名扬天下,李白等都为黄鹤楼留下了诗词。登上黄鹤楼远眺,可以看到滚滚长江和武汉三镇风光。 黄鹤楼公园有东门、南门、西门3个入口,东门位于近首义广场一侧,有专门的停车场,停车较方便;南门位于长江大桥武昌侧引桥处,有专门的公交车站,公共交通较方便;西门位于长江大桥上,便于步行游览长江大桥及从户部巷上长江大桥的游客进入。 |
实施步骤
环境搭建
准备好anconda,创建虚拟环境,python版本大于等于3.8
需要的第三方库
- langchain-nvidia-ai-endpoints
- jupyterlab
- langchain_core
- langchain
- matplotlib
- numpy
- faiss-cpu==1.7.2
- openai
详细的安装过程可以参考文章
代码实现
设置api_key
if os.environ.get("NVIDIA_API_KEY", "").startswith("nvapi-"):
print("Valid NVIDIA_API_KEY already in environment. Delete to reset")
else:
nvapi_key = getpass.getpass("NVAPI Key (starts with nvapi-): ")
assert nvapi_key.startswith("nvapi-"), f"{nvapi_key[:5]}... is not a valid key"
os.environ["NVIDIA_API_KEY"] = nvapi_key
外部知识库的构建
初始向量化模型
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
embedder = NVIDIAEmbeddings(model="ai-embed-qa-4")
获取文本数据集并初步清洗
import os
from tqdm import tqdm
from pathlib import Path
# Here we read in the text data and prepare them into vectorstore
ps = os.listdir("./data/")
data = []
sources = []
for p in ps:
if p.endswith('.txt'):
path2file="./data/"+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)
documents=[d for d in data if d != '\n']
用向量模型将文档处理到 faiss vectorstore 并将其保存
from operator import itemgetter
from langchain.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain.text_splitter import CharacterTextSplitter
from langchain_nvidia_ai_endpoints import ChatNVIDIA
import faiss
# 只需要执行一次,后面可以重读已经保存的向量存储
text_splitter = CharacterTextSplitter(chunk_size=400, separator=" ")
docs = []
metadatas = []
for i, d in enumerate(documents):
splits = text_splitter.split_text(d)
#print(len(splits))
docs.extend(splits)
metadatas.extend([{"source": sources[i]}] * len(splits))
store = FAISS.from_texts(docs, embedder , metadatas=metadatas)
store.save_local('./data/nv_embedding')
# 重读之前处理并保存的 Faiss Vectore 存储
store = FAISS.load_local("./data/nv_embedding", embedder,allow_dangerous_deserialization=True)
提出问题并基于llama-3.1-8b-instruct模型进行RAG检索
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct", nvidia_api_key=nvapi_key, max_tokens=512)
retriever = store.as_retriever()
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Answer solely based on the following context:\n<Documents>\n{context}\n</Documents>",
),
("user", "{question}"),
]
)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain.invoke("帮我制定去武汉的旅游计划,去玩三天,一共两个人,出发地为长沙,其中我想去黄鹤楼")
项目成果与展示
我们可以看一看在没有利用RAG技术时,我们向模型提问,会得到怎样的回答
可以看到,由于我们使用的llama-3.1-8B模型是使用英文语料训练的,在回答中文问题上出现了严重的语言偏差。为此我们重新用英文再提问一次。
用英文提问后,模型虽然给出了回答,但回答中包含不少幻觉现象,出现了许多凭空捏造的武汉地区或景点。
如Er Dao Qiao area(二道桥区),实际上二道桥为乌鲁木齐市的地区。
Yellow Crane Mountain Park(黄鹤山公园),正确的表述应该是黄鹤楼公园。
QinChuan SinhPlace ( Wine Town ) ,百度翻译为秦川新地(酒乡),文心一言的翻译为秦川酒庄(酒镇),比较合理的解释是,模型混淆了武汉市的晴川桥(Qingchuan Bridge)。
现在,再让我们看看使用了RAG之后的回答。
可以看到,模型能够回答出如热干面,武汉通,锦江酒店等进一步更精确的回答,但是受限于外部知识库的数据不足(景点信息只收集了6条,美食信息只收集了10条),幻觉现象仍没有完全消失,但是在更完备的外部知识库下,模型的表现也一定会随之提升。
问题与解决方案
- 在部署环境时,不需要网络代理,避免在下载包时出现网络连接超时等问题。
- API_KEY需要在英伟达NIM平台申请Try NVIDIA NIM APIs
项目总结与展望
本次AI-AGENT夏季训练营项目——基于RAG构建的城市旅游攻略智能助手(以武汉为例),利用较小参数的大语言模型(llama-3.1-8b-instruct)和RAG(Retriever-Augmented Generation)技术,在垂直细分领域下得到更专业、更准确的回答。通过英伟达NIM平台及langchain框架的支持,结合外部知识库完成了RAG技术的复现并验证了其技术可行性。
同时,后续也可以往更加专业、精细的方向发展,如利用爬虫技术,扩大我们知识库数据量,来进一步提升小参数模型的表现,以及利用gradio等框架,构建前端页面,封装成一个完整的智能助手,提高用户体验,