LLM

LongChain

Posted by 令德湖周杰伦 on 04-22,2024

1. 背景和介绍

LangChain是一个框架,帮助开发者使用语言模型来构建应用程序,这个框架提供了一系列的工具和组件,让你可以简单的创建大模型应用程序,LangChain可以让你方便管理语言模型的交互,将多个组件链接在一起,并可以访问外部的资源,如果API和数据库等。

类比:LongChain在大模型开发中的位置,相当于Spring在java开发中的位置。

LongChain解决什么问题

目前大模型应用中遇到的问题:

  • Token限制
  • 数据信息滞后
  • 无法联网
  • 没法查询数据库
  • 调用第三方API困难
  • 模型技术选型多

以上问题都可以通过LongChain去优雅的解决。

总结:LongChain是目前大模型应用开发中最好用的一站式开发框架。

2. 核心模块

LongChain的核心模块包括:

  • Model I/0
  • Chains
  • Retrieval
  • Memory
  • Agents
  • Callbacks
  • LongServer

2.1 Model I/0

主要包括以下三个部分:

  • Prompts:一个语言模型的提示是用户提供的一组指令或输入,用于引导模型的响应,帮助它理解上下文并生成相关和连贯的基于语言的输出,例如回答问题、完成句子或进行对话。
    • 提示模板(Prompt Templates):参数化的模型输入
    • 示例选择器(Example Selectors):动态选择要包含在提示中的示例
  • LLMs:LangChain 的核心组件,LangChain并不提供自己的LLMs,而是为与许多不同的LLMs(OpenAI、Cohere、Hugging Face等)进行交互提供了一个标准接口。
    • Chat Models: 语言模型的一种变体。虽然聊天模型在内部使用了语言模型,但它们提供的接口略有不同。与其暴露一个“输入文本,输出文本”的API不同它们提供了一个以“聊天消息”作为输入和输出的接口(类似于Chat Completion)
  • Parser:语言模型输出文本。但是很多时候,你可能希望获得比纯文本更结构化的信息。这就是输出解析器的用处。输出解析器是帮助结构化语言模型响应的类。

可以理解为:选择合适的prompt,调用去调用LLM,返回结果,然后解析为我们想要的格式。

2.2 Chains

LLM中常见的链式操作类型:

  • SequentialChain: 串联式调用语言模型链
    • 在调用语言模型之后,下一步是对语言模型进行一系列的调用。当您希望将一次调用的输出作为另一次调用的输入时,这是特别有用的。
  • RouterChain: 实现条件判断的大模型调用
    • 路由允许您创建非确定性链,其中前一步的输出定义下一步。路由有助于在与LLMs的交互中提供结构和一致性。
  • Transformation: 数据传递过程中进行数据处理。
    • 通常在组件之间传递输入时,我们希望对其进行转换。例如,我们将创建一个虚拟转换,它接收一个超长的文本,将文本筛选为前三段,然后将其传递到一个链中进行摘要。

2.3 Memory

大多数LLM应用程序都具有对话界面。对话的一个重要组成部分是能够引用先前在对话中介绍的信息。至少,一个对话系统应该能够直接访问一些过去消息的窗口。一个更复杂的系统需要有一个不断更新的模型,使其能够保持关于实体及其关系的信息。我们将存储关于过去交互的信息的能力称为"内存"。

LangChain为系统添加内存提供了许多实用工具。这些实用工具可以单独使用,也可以无缝地集成到链中。内存系统需要支持两个基本操作:读取和写入。

请记住,每个链都定义了某些核心执行逻辑,该逻辑期望某些输入。其中一些输入直接来自用户,但某些输入可能来自内存。在给定的运行中,链将两次与其内存系统交互。

  • 在接收到初始用户输入之后但在执行核心逻辑之前,链将从其内存系统中读取并增加用户输入。
  • 在执行核心逻辑后但在返回答案之前,链将将当前运行的输入和输出写入内存,以便在将来的运行中引用。

2.4 Retrieval

  • Document loaders:文档加载器,不同类型的文件加载器如下:
    • CSVLoader
    • TextLoader
  • Document transformers:
    • Recursively split by character:按照字符分割
"text_splitter = RecursiveCharacterTextSplitter(\n",
    "chunk_size = 100,          # 块大小(每个分割文本的字符数量)\n",
    "chunk_overlap  = 20,       # 块重叠(两个相邻块之间重叠的字符数量)\n",
    "length_function = len,     # 长度函数(用于计算文本长度的函数)\n",
    "add_start_index = True,    # 添加起始索引(是否在结果中包含分割文本的起始索引)\n",
    ")"
  • Text embedding models
  • vector store
  • Retriever
    • Ensemble Retriever:集合检索器(Ensemble Retriever)接受一组检索器作为输入,并将它们的get_relevant_documents()方法的结果进行集成,并根据互惠排序,融合算法对结果进行重新排序。通过发挥不同算法的优势,集合检索器可以比单一算法获得更好的性能。
    • 最常见的模式是将稀疏检索器(如BM25)与密集检索器(如嵌入相似度)相结合,因为它们的优势互补。这也被称为“混合搜索”。稀疏检索器擅长基于关键词找到相关文档,而密集检索器擅长基于语义相似度找到相关文档。

2.5 Agent

如果说chains模式是model(prompt - llm - parser)普通链式调用的一层抽象,即可以实现不同链式调用。
那么,agent模式就是chain的更高一层抽象。

设计理念:
AgentExecutor:

  • prompt:
    • 用户输入
    • 模型输入
    • 上下文
  • 思考链模式:
    • React:通过大模型的推理能力,自己通过分析Reason,然后去获取结果,这里可以是function call 或者 各种toolkits
    • Plan-and-execute Agent:按照一定策略来一步一步执行
  • output
    • parser

2.6 Callbacks

回调模块允许接到LLM应用程序的各个阶段,鉴于LLM的幻觉问题,这对于日志记录、监视、流式处理和其他任务非常有用。

2.7 LongServer

LangServe 则提供了将 LCEL 原型部署成产品服务的完整解决方案。它可以将 LCEL 应用链接入到一系列成熟到 Python 的 Web框架(例如 FastAPI、Pydantic、uvloop、asyncio)中并生成一套 RESTful API,开发者无需自己编写这部分逻辑就可以直接得到生产可用的 API,并得以保证 API 在高并发场景下的稳定性与性能。它同时也提供了输入输出数据结构校验、并发请求处理、流式响应等服务化所需的各种功能。有了LangServe,开发者可以“从零到一”无缝地实现 LLM 应用从原型到产品的过渡。

3. 架构设计

3.1 设计目标

  • 常用的操作API能力
  • Agent能力
  • 快速部署能力
  • 监控能力

3.2 架构之道

可以分为3层:

  • 面向Model层:
    • Memory:Buffer、KV DB 、vector DB、Sql DB
    • DataContion:
    • Medol I/O:
  • 面向Chain:
    • 基础大模型
    • 对话QA
    • 检索QA
  • 面向agen
    • ReAct
    • Plan-execute
    • Tools

3.3 特点

从工程角度看:

  • Prompt设计能力是核心
  • 核心使用的是大模型的对语言理解的能力
  • 传统的架构能力依然是核心

能做的:

  • 调整提示词
  • 调整模型
  • 调整描述(function call)
  • 调整思维链
  • 调整Tools

缺点:

  • 强依赖大模型的能力
  • 调用链路过程
  • 迁移能力弱