当前位置:   article > 正文

Chroma + Ollama 搭建本地RAG应用

gradio和ollama交互

> 本文作者为 360 奇舞团前端开发工程师

本篇文章我们将基于Ollama本地运行大语言模型LLM),并结合ChormaDBLangchain来建立一个小型的基于网页内容进行本地问答的RAG应用。

概念介绍

先简单了解下这些术语:

LLM (A large language model) 是通过使用海量的文本数据集(书籍、网站等)训练出来的,具备通用语言理解和生成的能力。虽然它可以推理许多内容,但它们的知识仅限于特定时间点之前用于训练的数据。

LangChain 是一个用于开发由大型语言模型(LLM)驱动的应用程序的框架。提供了丰富的接口、组件、能力简化了构建LLM应用程序的过程。

Ollama 是一个免费的开源框架,可以让大模型很容易的运行在本地电脑上。

RAGRetrieval Augmented Generation)是一种利用额外数据增强 LLM 知识的技术,它通过从外部数据库获取当前或相关上下文信息,并在请求大型语言模型(LLM)生成响应时呈现给它,从而解决了生成不正确或误导性信息的问题。

工作流程图解如下:

2c444914744df3d5a48058f1a0cd32f9.png ab5e10adcb8aa91c608e86fe178d82d3.png

基于上述RAG步骤,接下来我们将使用代码完成它。

开始搭建

1. 依据Ollama使用指南完成大模型的本地下载和的运行。

  1. # LLM
  2. ollama pull llama3
  3. # Embedding Model
  4. ollama pull nomic-embed-text

2. 安装langchainlangchain-communitybs4

pip install langchain langchain-community bs4

3. 初始化langchain提供的Ollama对象

  1. from langchain_community.llms import Ollama
  2. from langchain.callbacks.manager import CallbackManager
  3. from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
  4. 1. 初始化llm, 让其流式输出
  5. llm = Ollama(model="llama3"
  6.              temperature=0.1
  7.              top_p=0.4
  8.              callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
  9.              )

temperature控制文本生成的创造性,0时响应是可预测,始终选择下一个最可能的单词,这对于事实和准确性非常重要的答案是非常有用的。1时生成文本会选择更多的单词,会产生更具创意但不可能预测的答案。

top_p 或 核心采样 决定了生成时要考虑多少可能的单词。top_p值意味着模型会考虑更多可能的单词,甚至是可能性较低的单词,从而使生成的文本更加多样化。

较低的temperature和较高的top_p,可以产生具有创意的连贯文字。由于temperature较低,答案通常具有逻辑性和连贯性,但由于top_p较高,答案仍然具有丰富的词汇和观点。比较适合生成信息类文本,内容清晰且能吸引读者。

较高的temperature和较低的top_p,可能会把单词以难以预测的方式组合在一起。生成的文本创意高,会出现意想不到的结果,适合创作。

4. 获取RAG检索内容并分块

  1. #`BeautifulSoup'解析网页内容:按照标签、类名、ID 等方式来定位和提取你需要的内容
  2. import bs4 
  3. #Load HTML pages using `urllib` and parse them with `BeautifulSoup'
  4. from langchain_community.document_loaders import WebBaseLoader
  5. #文本分割
  6. from langchain_text_splitters import RecursiveCharacterTextSplitter
  7. loader = WebBaseLoader(
  8.     web_paths=("https://vuejs.org/guide/introduction.html#html",),
  9.     bs_kwargs=dict(
  10.         parse_only=bs4.SoupStrainer(
  11.             class_=("content",),
  12.             # id=("article-root",)
  13.         )
  14.     ),
  15. )
  16. docs = loader.load()
  17. # chunk_overlap:分块的重叠部分
  18. text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
  19. splits = text_splitter.split_documents(docs)

chunk_overlap:分块的重叠部分,重叠有助于降低将语句与与其相关的重要上下文分开的可能性。chunk_size:分块的大小,合理的分词设置会提高RAG的效果

  1. 内容基于本地的词嵌入模型 nomic-embed-text 嵌入向量数据库中

  1. # 向量嵌入 ::: conda install onnxruntime -c conda-forge
  2. from langchain_community.vectorstores import Chroma
  3. # 有许多嵌入模型
  4. from langchain_community.embeddings import OllamaEmbeddings
  5. # 基于ollama运行嵌入模型 nomic-embed-text :A high-performing open embedding model with a large token context window.
  6. vectorstore = Chroma.from_documents(documents=splits,
  7.                                     embedding=OllamaEmbeddings(model="nomic-embed-text"))
  8. # 相似搜索
  9. # vectorstore.similarity_search("vue")

此处的嵌入模型也可以使用其他的比如llama3mistral,但是在本地运行太慢了,它们和nomic-embed-text 一样不支持中文的词嵌入。如果想试试建立一个中文的文档库,可以试试 herald/dmeta-embedding-zh词嵌入的模型,支持中文。

ollama pull herald/dmeta-embedding-zh:latest
  1. 设置Prompt规范输出

  1. from langchain_core.prompts import PromptTemplate
  2. prompt = PromptTemplate(
  3.     input_variables=['context''question'],
  4.     template=
  5.     """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the 
  6.     question. you don't know the answer, just say you don't know 
  7.     without any explanation Question: {question} Context: {context} Answer:""",
  8. )
  1. 基于langchain实现检索问答

  1. from langchain.chains import RetrievalQA
  2. # 向量数据库检索器
  3. retriever = vectorstore.as_retriever()
  4. qa_chain = RetrievalQA.from_chain_type(
  5.     llm,
  6.     retriever=retriever,
  7.     chain_type_kwargs={"prompt": prompt}
  8. )
  9. # what is Composition API?
  10. question = "what is vue?"
  11. result = qa_chain.invoke({"query": question})
  12. # output
  13. # I think I know this one! Based on the context, 
  14. # Vue is a JavaScript framework for building user interfaces 
  15. # that builds on top of standard HTML, CSS, and JavaScript. 
  16. # It provides a declarative way to use Vue primarily in 
  17. # low-complexity scenarios or for building full applications with 
  18. # Composition API + Single-File Components.

如果我问的问题与文档无关它的回答是怎样呢?

  1. question = "what is react?"
  2. result = qa_chain.invoke({"query": question})

最终执行后输出了I don't know.

构建用户界面

Gradio是一个用于构建交互式机器学习界面的Python库。Gradio使用非常简单。你只需要定义一个有输入和输出的函数,然后Gradio将自动为你生成一个界面。用户可以在界面中输入数据,然后观察模型的输出结果。

整合上述代码,构建可交互的UI:

  1. import gradio as gr
  2. from langchain_community.llms import Ollama
  3. from langchain.callbacks.manager import CallbackManager
  4. from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
  5. from langchain_community.document_loaders import WebBaseLoader
  6. from langchain_text_splitters import RecursiveCharacterTextSplitter
  7. from langchain_community.vectorstores import Chroma
  8. from langchain_community.embeddings import OllamaEmbeddings
  9. from langchain.chains import RetrievalQA
  10. from langchain_core.prompts import PromptTemplate
  11. def init_ollama_llm(model, temperature, top_p):
  12.     return Ollama(model=model,
  13.                   temperature=temperature,
  14.                   top_p=top_p,
  15.                   callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
  16.                   )
  17. def content_web(url):
  18.     loader = WebBaseLoader(
  19.         web_paths=(url,),
  20.     )
  21.     docs = loader.load()
  22.     # chunk_overlap:分块的重叠部分,重叠有助于降低将语句与与其相关的重要上下文分开的可能性,
  23.     # 设置了chunk_overlap效果会更好
  24.     # 合理的分词会提高RAG的效果
  25.     text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
  26.     splits = text_splitter.split_documents(docs)
  27.     return splits
  28. def chroma_retriever_store_content(splits):
  29.     # 基于ollama运行嵌入模型 nomic-embed-text :A high-performing open embedding model with a large token context window.
  30.     vectorstore = Chroma.from_documents(documents=splits,
  31.                                         embedding=OllamaEmbeddings(model="nomic-embed-text"))
  32.     return vectorstore.as_retriever()
  33. def rag_prompt():
  34.     return PromptTemplate(
  35.         input_variables=['context''question'],
  36.         template=
  37.         """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the 
  38.         question. you don't know the answer, just say you don't know 
  39.         without any explanation Question: {question} Context: {context} Answer:""",
  40.     )
  41. def ollama_rag_chroma_web_content(web_url, question,temperature,top_p):
  42.     llm = init_ollama_llm('llama3', temperature, top_p)
  43.     splits = content_web(web_url)
  44.     retriever = chroma_retriever_store_content(splits)
  45.     qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={"prompt": rag_prompt()})
  46.     return qa_chain.invoke({"query": question})["result"]
  47. demo = gr.Interface(
  48.     fn=ollama_rag_chroma_web_content,
  49.     inputs=[gr.Textbox(label="web_url",value="https://vuejs.org/guide/introduction.html",info="爬取内容的网页地址"),
  50.             "text",
  51.             gr.Slider(01,step=0.1),
  52.             gr.Slider(01,step=0.1)],
  53.     outputs="text",
  54.     title="Ollama+RAG Example",
  55.     description="输入网页的URL,然后提问, 获取答案"
  56. )
  57. demo.launch()

运行后会输出网页地址Running on local URL: http://127.0.0.1:7860, 打开后效果如下:47a0e018b36e7672f3150d0b08766757.png

参考

https://github.com/ollama/ollama

https://python.langchain.com/

https://partee.io/2022/08/11/vector-embeddings/

https://jalammar.github.io/illustrated-word2vec/

- END -

如果您关注前端+AI 相关领域可以扫码加群交流

36fca1b803487b333e4e3f2cc1281b2c.png

关于奇舞团

奇舞团是 360 集团最大的大前端团队,非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

6cda90e3b48635c32505356ecefdd9c1.png

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/750287
推荐阅读
相关标签
  

闽ICP备14008679号