LangChain学习笔记一

首先先有一个概念

LangChain 是一个基于语言模型开发应用程序的框架,它可以实现以下功能:

  • 数据感知:将语言模型连接到其他数据源

  • 自主性:允许语言模型与其环境进行交互

LangChain 的主要价值在于:

  • 组件化:为使用语言模型提供抽象层,以及每个抽象层的一组实现。组件是模块化且易于使用的,无论您是否使用 LangChain 框架的其余部分。

  • 现成的链:结构化的组件集合,用于完成特定的高级任务

现成的链使得入门变得容易。对于更复杂的应用程序和微妙的用例,组件化使得定制现有链或构建新链变得更容易。

大语言模型技术栈由四个主要部分组成:

  • 数据预处理流程(data preprocessing pipeline)

  • 嵌入端点(embeddings endpoint )+向量存储(vector store)

  • LLM 终端(LLM endpoints)

  • LLM 编程框架(LLM programming framework)

数据预处理流程

该步骤包括与数据源连接的连接器(例如 S3 存储桶或 CRM)、数据转换层以及下游连接器(例如向矢量数据库)。通常,输入到 LLM 中的最有价值的信息也是最难处理的(如 PDF、PPTX、HTML 等),但同时,易于访问文本的文档(例如.DOCX)中也包含用户不希望发送到推理终端的信息(例如广告、法律条款等)。

因为涉及的数据源繁杂(数千个 PDF、PPTX、聊天记录、抓取的 HTML 等),这步也存在大量的 dirty work,使用 OCR 模型、Python 脚本和正则表达式等方式来自动提取、清理和转换关键文档元素(例如标题、正文、页眉/页脚、列表等),最终向外部以 API 的方式提供 JSON 数据,以便嵌入终端和存储在向量数据库中。

嵌入端点和向量存储

使用嵌入端点(用于生成和返回诸如词向量、文档向量等嵌入向量的 API 端点)和向量存储(用于存储和检索向量的数据库或数据存储系统)代表了数据存储和访问方式的重大演变。以前,嵌入主要用于诸如文档聚类之类的特定任务,在新的架构中,将文档及其嵌入存储在向量数据库中,可以通过 LLM 端点实现关键的交互模式。直接存储原始嵌入,意味着数据可以以其自然格式存储,从而实现更快的处理时间和更高效的数据检索。此外,这种方法可以更容易地处理大型数据集,因为它可以减少训练和推理过程中需要处理的数据量。

LLM 终端

LLM 终端是接收输入数据并生成 LLM 输出的终端。LLM 终端负责管理模型的资源,包括内存和计算资源,并提供可扩展和容错的接口,用于向下游应用程序提供 LLM 输出。

LLM 编程框架

LLM 编程框架提供了一套工具和抽象,用于使用语言模型构建应用程序。在现代技术栈中出现了各种类型的组件,包括:LLM 提供商、嵌入模型、向量存储、文档加载器、其他外部工具(谷歌搜索等),这些框架的一个重要功能是协调各种组件。

Prompts

Prompts 用来管理 LLM 输入的工具,在从 LLM 获得所需的输出之前需要对提示进行相当多的调整,最终的 Promps 可以是单个句子或多个句子的组合,它们可以包含变量和条件语句。

Chains

是一种将 LLM 和其他多个组件连接在一起的工具,以实现复杂的任务。

Agents

是一种使用 LLM 做出决策的工具,它们可以执行特定的任务并生成文本输出。Agents 通常由三个部分组成:Action、Observation 和 Decision。Action 是代理执行的操作,Observation 是代理接收到的信息,Decision 是代理基于 Action 和 Observation 做出的决策。

Memory

是一种用于存储数据的工具,由于 LLM 没有任何长期记忆,它有助于在多次调用之间保持状态。

信息检索功能

使用谷歌搜索获取最新信息,使用向量数据库 Chroma 存储嵌入后的文本向量,检索相关上下文

def _get_web_research_retriever(self):
        vectorstore = Chroma(
            embedding_function=OpenAIEmbeddings(), persist_directory="./chroma_db"
        )
        search = GoogleSearchAPIWrapper()
        web_research_retriever = WebResearchRetriever.from_llm(
            vectorstore=vectorstore,
            llm=self.llm,
            search=search,
        )
        return web_research_retriever

def _get_context(self, user_intent: str)-> list[str]:
    "从搜索引擎获取相关信息"
    retriever = self._get_web_research_retriever()
    docs = retriever.get_relevant_documents(user_intent)
    context = [doc.page_content for doc in docs]
    return context
结合上下文(检索增强生成)

结合历史对话记录,回答用户问题

def _rag(self, context: list[str], query: str)-> str:
        self.chat_history.add_message(query)
        context_str = "\n\n".join(context)
        system_template = (
            "你是一个中文AI助手,请使用您在上下文中可以找到的信息来回答用户的问题,如果用户的问题与上下文中的信息无关,请说你不知道。"
            "上下文内容:```{context_str}```\n"
        )

        user_template = ChatPromptTemplate(
            messages=[SystemMessagePromptTemplate.from_template(system_template)] + self.chat_history.messages
        )

        llm_chain = LLMChain(llm=self.llm, prompt=user_template)
        response = llm_chain({"context_str": context_str}).get("text")
        self.chat_history.add_ai_message(response)
        return response

问答函数实现

def ask(self, query: str) -> str:
        # 识别意图
        user_intent = self._summarize_user_intent(query)
        # 获取上下文
        context_list = self._get_context(user_intent)
        # 根据上下文结合问答内容回答
        response = self._rag(context_list,query)
        print(
            "========\n"
            f"问题:{query}\n"
            f"用户意图:{user_intent}\n"
            f"回答:{response}\n"
            "========\n"
        )
        return response

结论

优势:丰富的组件支持,以WebResearchRetriever的封装实现为例,将向量数据库和搜索引擎结合起来,只需几行代码就可以完成复杂功能,加速 MVP 实现,需求验证。

劣势:过度封装,Prompt 模板组件做这么抽象实在没必要,应用调试和生产环境可观测性方面都不太友好,可以关注下下一篇 Semantic Kernel的实现思路。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值