在第五节我们只介绍了RAG中向量数据库的创建,但是没有说如何检索?
这里先说好,前提环境还是和之前一样

  • 初始化好一个LLM大模型 ×1
  • Embeddings模型 ×1
  • vectorstore(向量数据库)×1
    -

好啦,我们有上面那三个,那我们现在想要实现的就是,在我们提问大模型的时候,程序会带着问题去检索向量数据库找到最相似的片段,然后喂给大模型。
你可能会想,是不是还得手动实现vectorstore向量库搜索,什么相似度分析,然后再手动分析?但不是的哦。Langchain都实现了自动化,我们需要用到一个很重要的东西就是retriever,我们需要把vectorstore变成这玩意才能给大模型用哦(但你不嫌麻烦手写也是可以的)

1.第一步 转换格式

1
retriever = vectorstore.as_retriever()

2.第二步 设计一个rag提示词

我这里用的是hub的提示词,从from langchain import hub。这个其实就是约束大模型根据我们rag检索到数据库的知识回答减少产生幻觉 过后面主播发现这个库已经废弃了。。

就直接用模板提示词了

1
2
# Prompt
prompt = hub.pull("rlm/rag-prompt")

rlm/rag-prompt的中文翻译版

1
2
3
您是问答任务的助手。请使用以下检索到的上下文信息来 回答问题。
如果您不知道答案,请直接说明您不知道。答案最多使用三句话,
并保持简洁。 问题:{question} 上下文:{context} 答案:

3.构造链

1
2
3
4
5
6
7
rag_chain=(
    #RunnablePassthrough 用于将输入传递给下一个链中的函数,也就是占位符
    {'context':retriever|format_function,'question':RunnablePassthrough()}
    |prompt
    |llm
    |StrOutputParser()
)

这边用到了一个函数哈,因为链条需要的是字符穿,直接检索给的是Liat[Document]这不中

1
2
3
4
5
6
def format_function(docs):
    """
    格式化档内容,将每个文档的页面内容用 "\n\n" 分隔
    因为retriever 检索返回的文档列表List[Document]
    """
    return "\n\n".join(doc.page_content for doc in docs)

4.调用

这边别传字典啊。主播犯了一个很蠢的错误。。。因为第一个链的话,会把字典也传给检索器导致报错。

1
rag_chain.invoke('what is Task Decomposition')

总结

这边总结一下简单RAG使用吧

  • 1 先加载数据。langchain提供了不同的loader,从from langchain_community.document_loaders这个库引入就好了,比如txt ,csv html.doc都可以。
  • 2 加载文档doc=loader.load(),这里可以选择load_lazy()懒加载应对文本数量多的时候
  • 3 定义文本切割器。使用的是RecursiveCharacterTextSplitter,里面需要传递的是切片Chunk的大小和重叠度。ps;这里得到的是List[Document]
  • 4 进行切割 chunks=text_splitter.split_documents(doc),ps;这里得到的还是List[Document]。只不过是小份的
  • 5 初始化Embeddings模型
  • 6 初始化向量数据库,必须传递的是Embeddings模型,切片好的list[Document]
  • 7 设置rag提示词,和对应的链条