天苍苍,野茫茫,钱包空空无处藏。不会记账?不会分析支出?花钱大手大脚?现在是时候用AI来管一管了!

nullskymc 2024-09-09 10:01:04 阅读 80

项目名称:每日花钱助手——RAG-Agent智能对话机器人

报告日期:2024年8月18日

项目负责人:吃不饱的null

项目概述:

本项目旨在开发一个基于RAG(Retrieval-Augmented Generation)的智能对话机器人,能够进行文字形式的聊天,并拓展了Agent智能体。通过了解用户的每日花钱记录,计算支出总额,理解支出的类型与特点,帮助用户更好的管理财务。

本项目使用langchain作为处理项目逻辑的核心库,langchain是一个用于拓展LLM能力,实现Agent等功能的库。

通常情况下,LLM的知识是静态的,停留在模型训练时的知识。因此,当LLM接受到一个问题,它只能回答它已知的部分,遇到现有知识无法回答的问题,LLM会编造错误的回答或是重复问题,这一现象称为“大模型幻觉”。

为了解决这一问题,我们引入了RAG(Retrieval-Augmented Generation)模型。RAG模型结合了检索和生成的优势,通过特定领域的向量数据库,能够在对话过程中提供更加准确的回答。同时,鉴于微调模型需要耗费大量计算资源,使用RAG是更经济效率的选择。

技术方案与实施步骤

模型选择:

本项目使用NVIDIA NIM平台上的microsoft/phi-3-small-128k-instruct模型,用于处理文本数据,分析情感,执行外部tools,为用户提供每日贴心tips。

数据的构建:

针对特定领域进行数据构建,包括对话语料、知识库等。通过向量化处理,将文本数据转换为向量形式,方便模型处理。

向量化处理就是通过embedding模型将各种文本或多模态的数据标注为词向量,存入到向量数据库中。LLM在接收到问题时,会先通过检索模块在向量数据库中找到相似的知识,据此生成回答。

通过向量化处理文本或多模态的知识,可以有效避免LLM的“大模型幻觉”,提高对话的准确性,在特定领域的应用中具有广泛的前景。

功能整合:

在RAG的基础上,通过langchain的agent的模块,可以让LLM从局限的文本对话中拓展到多功能的Agent智能体,能够执行外部任务,获取外部信息。

比如,LLM并不知道现在的时间,知识库实际上也无法解决这个问题。但是,通过拓展tools,LLM可以调用时间API,获取当前时间,并返回给用户。

创建一个Agent,能够把用户的每日花钱记录,计算支出总额,合成为一个合适的sqlite表,作为tools使用,定义一个代码解释器,让LLM执行生成的代码,从数据库中获取数据,计算支出特点,最终实现完整的主动性Agent chain。

实施步骤:

在实现以上基础函数后,就可以搭建一个基于RAG的智能对话机器人了。下面是一个实现:

环境搭建:

创建一个新的virtualenv环境,安装必要的库:

<code>python -m venv env

source env/bin/activate

pip install langchain, faiss-cpu, langchain_community, langchain_nvidia_ai_endpoints,openai

这里使用NVIDIANIM平台的模型,需要在NIM平台上注册并获取API key。

from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings,ChatNVDIA

embedings = NVIDIAEmbeddings(model="NV-Embed-QA")code>

llm = ChatNVIDIA(model="microsoft/phi-3-small-128k-instruct", nvidia_api_key=<YOUR_API_KEY>, max_tokens=1024)code>

导入必要的模块:

from langchain_community.document_loaders import TextLoader

from langchain_community.vectorstores import FAISS

from langchain_text_splitters import CharacterTextSplitter

from langchain.chains.combine_documents import create_stuff_documents_chain

from langchain.chains.retrieval import create_retrieval_chain

from langchain_core.prompts import ChatPromptTemplate

代码实现:

实现RAG的核心代码如下:

在本项目中,使用faiss这个轻量化的向量数据库构造retriver模块,实现检索功能。代码简单演示如下:

在这里导入embediings模型,用于向量化数据,使用text_loader将文本文件转换为可接受的输入格式。

使用CharacterTextSplitter将文档切分为合适的大小,其中chunk_size是切分文档的大小,根据文档大小调整,不同的文档大小会影响检索的效率。

embedder = NVIDIAEmbeddings(model="NV-Embed-QA")code>

def text_loader(url):

# 文本文档加载器

loader = TextLoader(url)

docs = loader.load()

return docs

def create_vector_db(data_path, db_path, loader):

text_splitter = CharacterTextSplitter(chunk_size=2048)

data = loader(data_path)

docs = text_splitter.split_documents(data)

db = FAISS.from_documents(docs, embeddings)

db.save_local(db_path) # 保存路径

create_vector_db("data.txt", "db", text_loader)

使用ChatPromptTemplate生成问题模板,根据context和input生成问题。context即为知识库检索后的文本内容,用于提交与用户问题相近的知识。

需要注意的是FAISS.load_local()函数,需要设置allow_dangerous_deserialization=True,以允许从本地加载向量数据库。

通过langchain包装完全的create_stuff_documents_chain和create_retrieval_chain,实现检索功能。

def rag(msg):

prompt = ChatPromptTemplate.from_template(

"""

以下问题基于提供的 context,分析问题并给出合理的建议回答:

<context>

{context}

</context>

Question: {input}

"""

)

new_db = FAISS.load_local("db", embedder, allow_dangerous_deserialization=True)

document_chain = create_stuff_documents_chain(llm, prompt)

retriever = new_db.as_retriever() # 从向量数据库中检索

retrieval_chain = create_retrieval_chain(retriever, document_chain)

gpt_response = retrieval_chain.invoke({ "input": msg})

response = gpt_response['answer']

return response

print(rag("你好"))

到现在就实现了一个简单的RAG过程,LLM根据知识库的知识,给出了一个回答。但是,为了实现Agent的功能,还需要进一步拓展。

LLM需要执行外部任务,获取外部信息,这就需要使用tools模块。定义合适可用的tools,让LLM执行生成的代码,保存到数据库等等。

把实现RAG的retriever包装成一个tool,这样LLM可以基于已有的知识库来进行之后的外部tools执行,强化LLM的主动性。

db_path = "db"

new_db = FAISS.load_local(db_path, embeddings, allow_dangerous_deserialization=True)

retriever = new_db.as_retriever() # 从向量数据库中检索

retriever_tool = create_retriever_tool(

retriever,

"知识库",

"这里存储着有关于问题的背景资料,you must use this tool!",

)

在这里,我们定义一个代码解释器,让LLM执行生成的代码,使用langchain提供的tool装饰器。

from langchain.agents import initialize_agent

from langchain.memory import ConversationBufferWindowMemory

from langchain.tools import tool

from langchain.tools.retriever import create_retriever_tool

def execute_and_return(x):

code = extract_python_code(x.content)[0]

try:

result = exec(str(code))

return "exec result: " + result

except ExceptionType:

return "The code is not executable, don't give up, try again!"

@tool

def interpreter(code: str) -> str:

"""

此函数解释并执行提供的代码,严格去除首行出现的缩进并保证代码符合Python语法。

"""

return execute_and_return(code)

@tool

def save_to_db(data: str) -> str:

"""

此函数将数据保存到数据库中。

"""

db = sqlite3.connect('data.db')

cursor = db.cursor()

cursor.execute(data)

db.commit()

db.close()

return "Data saved to database."

@tool

def get_from_db(data: str) -> str:

"""

此函数从数据库中获取数据。

"""

db = sqlite3.connect('data.db')

cursor = db.cursor()

cursor.execute(data)

result = cursor.fetchall()

db.close()

return result

tools = [interpreter, save_to_db, get_from_db, retriever_tool]

后面就可以使用这些tools,实现Agent的功能,让LLM执行外部任务,获取外部信息。

conversation_buffer_window_memory是一个用于存储对话历史的内存模块,可以用于实现对话的记忆功能。在这里,我们使用它来存储对话历史,实现对话的连贯性。

initialize_agent函数用于初始化一个Agent,可以指定tools,memory,verbose等参数,实现Agent的功能。

memory = ConversationBufferWindowMemory(memory_key='chat_history', k=3, return_messages=True)code>

chat_agent = initialize_agent(

agent='chat-conversational-react-description',code>

tools=tools,

memory=memory,

verbose=True,

max_interations=3,

llm=llm,

handle_prasing_error=True

)

query = "今天买菜花了30,买了一些蔬菜和水果。"

response = chat_agent.invoke(query)

print(response)

query = "到数据库中查询今天的花费"

response = chat_agent.invoke(query)

print(response)

项目成果与展示:

应用场景展示:

助手适合个人或家庭在生活中使用,以自然语言的方式记录每日花费,计算支出总额,理解支出的类型与特点,帮助用户更好的管理财务。

功能演示:

根据自然语言输入,用户将个人的每日花费,支出类型等信息输入到助手中,Agent执行外部代码,从外部数据库中CURD数据,个性化总结,理解用户,提供更好的建议。

问题与解决方案:

实际使用中,受限于最大Token和问题,LLM很可能不会使用外部的tools,导致回答偏离预期。

问题分析:

问题不够明确,没有主动引导LLM使用tools,导致LLM无法执行外部任务,获取外部信息。

解决措施:

强化prompt,绝对引导LLM使用tools,保证LLM执行外部任务,获取外部信息。

项目总结与展望:

项目评估:

技术实现初步达到预期,RAG模型能够在特定领域提供更加准确的回答,但是在数值理解和具体的财务分析上,还有待提高。

未来方向:

优化RAG模式,采取GraphRAG或更多rag方式,优化获取信息的模式,并存取更高质量的数据,提高对话的准确性。建立一个美观的前端界面,提供更好的用户体验。

附件与参考资料

Microsoft-Phi-3-NvidiaNIMWorkshop

Langchain doc



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。