Skip to content

大模型(LLMs)LangChain 面试指南

来源:AiGC面试宝典 作者:宁静致远 日期:2023年09月16日

---## 1. 什么是 LangChain?

LangChain 是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序。它提供了一套工具、组件和接口,可简化创建由大型语言模型(LLM)和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,并集成额外的资源,例如 API 和数据库。

📝通俗解释:LangChain 就像一个"乐高积木"系统,它把和大语言模型交互的各种功能模块化,开发人员可以像拼积木一样,把提示词管理、模型调用、数据处理等功能组合在一起,快速搭建AI应用。


2. LangChain 包含哪些核心概念?

2.1 LangChain 中 Components 和 Chains 是什么?

  • Component(组件):模块化的构建块,可以组合起来创建强大的应用程序;
  • Chain(链):组合在一起以完成特定任务的一系列 Components(或其他 Chain);

注:一个 Chain 可能包括一个 Prompt 模板、一个语言模型和一个输出解析器,它们一起工作以处理用户输入、生成响应并处理输出。

📝通俗解释:Component 就像是单独的螺丝、齿轮,而 Chain 就是把这些零件组装成的完整机器。比如一个"回答问题的链" = 问题模板 + 语言模型 + 答案解析器。

2.2 LangChain 中 Prompt Templates and Values 是什么?

  • Prompt Template 作用:负责创建 PromptValue,这是最终传递给语言模型的内容
  • Prompt Template 特点:有助于将用户输入和其他动态信息转换为适合语言模型的格式。PromptValues 是具有方法的类,这些方法可以转换为每个模型类型期望的确切输入类型(如文本或聊天消息)。

📝通俗解释:Prompt Template 就像是一个"填空模板",把用户的输入填入预定义好的格式中,生成最终给大模型的"提问"。比如"请用一句话解释{概念}",用户输入"人工智能",就变成"请用一句话解释人工智能"。

2.3 LangChain 中 Example Selectors 是什么?

  • 作用:当您想要在 Prompts 中动态包含示例时,Example Selectors 很有用。它们接受用户输入并返回一个示例列表以在提示中使用,使其更强大和特定于上下文。

📝通俗解释:比如用户问"怎么写情书",Example Selectors 会自动从例子库中挑选最相关的情书范例,动态加入到提示词中,帮助模型更好地理解你想要什么风格的回复。

2.4 LangChain 中 Output Parsers 是什么?

  • 作用负责将语言模型响应构建为更有用的格式
  • 实现方法
    • 一种用于提供格式化指令
    • 另一种用于将语言模型的响应解析为结构化格式
  • 特点:使得在您的应用程序中处理输出数据变得更加容易。

📝通俗解释:Output Parser 就像"翻译官",把大模型输出的原始文字转换成程序能直接使用的结构化数据(比如JSON格式),方便后续处理。

2.5 LangChain 中 Indexes and Retrievers 是什么?

  • Index(索引):一种组织文档的方式,使语言模型更容易与它们交互;
  • Retrievers(检索器):用于获取相关文档并将它们与语言模型组合的接口;

注:LangChain 提供了用于处理不同类型的索引和检索器的工具和功能,例如矢量数据库和文本拆分器。

📝通俗解释:Index 就像是图书馆的目录系统,Retrievers 则是图书管理员。当用户提问时,检索器会从"图书馆"中找到最相关的文档,交给大模型来回答问题。

2.6 LangChain 中 Chat Message History 是什么?

  • Chat Message History 作用:负责记住所有以前的聊天交互数据,然后可以将这些交互数据传递回模型、汇总或以其他方式组合;
  • 优点:有助于维护上下文并提高模型对对话的理解

📝通俗解释:就像聊天记录一样,让大模型能"记住"之前对话的内容,这样它就不会"失忆",能理解对话的前后上下文。

2.7 LangChain 中 Agents 和 Toolkits 是什么?

  • Agent(代理):在 LangChain 中推动决策制定的实体。他们可以访问一套工具,并可以根据用户输入决定调用哪个工具;
  • Toolkit(工具包):一组工具,当它们一起使用时,可以完成特定的任务。代理执行器负责使用适当的工具运行代理。

📝通俗解释:Agent 就像一个"智能助手",它会根据用户的需求,决定调用什么工具来完成任务。比如用户问"今天天气怎么样",Agent 会决定调用"天气查询工具"来获取信息。


3. 什么是 LangChain Agent?

  • 介绍:LangChain Agent 是框架中驱动决策制定的实体。它可以访问一组工具,并可以根据用户的输入决定调用哪个工具
  • 优点:LangChain Agent 帮助构建复杂的应用程序,这些应用程序需要自适应和特定于上下文的响应。当存在取决于用户输入和其他因素的未知交互链时,它们特别有用。

📝通俗解释:Agent 就像一个"全能管家",它不是简单地执行固定流程,而是会根据情况自主决策。比如用户说"帮我订一个下周去上海的机票",Agent 会自己决定:先查航班 -> 比价 -> 订票 -> 发送确认。


4. 如何使用 LangChain?

要使用 LangChain,开发人员首先要导入必要的组件和工具,例如 LLMs、chat models、agents、chains、内存功能。这些组件组合起来创建一个可以理解、处理和响应用户输入的应用程序。

📝通俗解释:使用 LangChain 就像搭积木,先把需要的零件(模型、提示模板、工具等)导入进来,然后按需求组装成完整的应用。


5. LangChain 支持哪些功能?

  • 针对特定文档的问答:根据给定的文档回答问题,使用这些文档中的信息来创建答案。
  • 聊天机器人:构建可以利用 LLM 的功能生成文本的聊天机器人。
  • Agents:开发可以决定行动、采取这些行动、观察结果并继续执行直到完成的代理。

📝通俗解释:这就是 LangChain 的三大核心应用场景:

  1. 文档问答 = 企业的"智能客服",能根据产品手册回答问题
  2. 聊天机器人 = 智能对话助手
  3. Agents = 能自主完成复杂任务的智能助手

6. 什么是 LangChain Model?

LangChain model 是一种抽象,表示框架中使用的不同类型的模型。LangChain 中的模型主要分为三类:

6.1 LLM(大型语言模型)

这些模型将文本字符串作为输入并返回文本字符串作为输出。它们是许多语言模型应用程序的支柱。

📝通俗解释:最基础的模型,输入一段文字,输出一段文字。比如 GPT、Claude、GLM 等。

6.2 聊天模型(Chat Model)

聊天模型由语言模型支持,但具有更结构化的 API。他们将聊天消息列表作为输入并返回聊天消息。这使得管理对话历史记录和维护上下文变得容易。

📝通俗解释:专门为对话场景优化的模型,输入是"消息列表"(包含角色和内容),输出也是消息。方便管理多轮对话。

6.3 文本嵌入模型(Text Embedding Models)

这些模型将文本作为输入并返回表示文本嵌入的浮点列表。这些嵌入可用于文档检索、聚类和相似性比较等任务。

📝通俗解释:把文字转换成"向量"的模型。文字在计算机里变成了坐标相近的数字,这样就可以用数学方法比较文字的相似度,用于搜索、分类等场景。

开发人员可以为他们的用例选择合适的 LangChain 模型,并利用提供的组件来构建他们的应用程序。


7. LangChain 包含哪些特点?

LangChain 旨在为六个主要领域的开发人员提供支持:

7.1 LLM 和提示

LangChain 使管理提示、优化它们以及为所有 LLM 创建通用接口变得容易。此外,它还包括一些用于处理 LLM 的便捷实用程序。

📝通俗解释:统一管理各种大模型的"提示词工具箱",不用每个模型都写一套代码。

7.2 链(Chain)

这些是对 LLM 或其他实用程序的调用序列。LangChain 为链提供标准接口,与各种工具集成,为流行应用提供端到端的链。

📝通俗解释:把多个处理步骤串联起来的"流水线",比如"问题 -> 检索 -> 整理 -> 输出"这样的固定流程。

7.3 数据增强生成

LangChain 使链能够与外部数据源交互以收集生成步骤的数据。例如,它可以帮助总结长文本或使用特定数据源回答问题。

📝通俗解释:让大模型能"查资料"后再生成回答,比如先从文档库中找到相关内容,再根据内容回答问题。

7.4 Agents(代理)

Agents 让 LLM 做出有关行动的决定,采取这些行动,检查结果,并继续前进直到工作完成。LangChain 提供了代理的标准接口,多种代理可供选择,以及端到端的代理示例。

📝通俗解释:让模型能"自己做事"而不仅仅是"回答问题",可以自主调用工具、规划步骤。

7.5 内存(Memory)

LangChain 有一个标准的内存接口,有助于维护链或代理调用之间的状态。它还提供了一系列内存实现和使用内存的链或代理的示例。

📝通俗解释:让应用能"记住"之前发生过的事情,比如记住对话历史、记住用户的偏好设置。

7.6 评估(Evaluation)

很难用传统指标评估生成模型。这就是为什么 LangChain 提供提示和链来帮助开发者自己使用 LLM 评估他们的模型。

📝通俗解释:用 AI 来评估 AI 输出的质量,因为大模型的输出很难用传统指标(如准确率)来衡量。


8. LangChain 如何使用?

8.1 LangChain 如何调用 LLMs 生成回复?

Models:指各类训练好大语言模型(如:ChatGPT(未开源)、ChatGLM、Vicuna 等)

python
# 官方 LLM 使用 OpenAI 接口
from langchain.llms import OpenAI
llm = OpenAI(model_name="text-davinci-003")
prompt = "你好"
response = llm(prompt)
# 你好,我是 chatGPT, 很高兴能够和你聊天。有什么我可以帮助你的吗?

下面用 ChatGLM 来演示该过程,封装一下即可:

python
from transformers import AutoTokenizer, AutoModel

class ChatGLM:
    def __init__(self, model_name) -> None:
        self.tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
        self.model = AutoModel.from_pretrained(model_name, trust_remote_code=True).half().cuda().eval()

    def __call__(self, prompt) -> Any:
        response, _ = self.model.chat(self.tokenizer, prompt)  # 这里演示未使用流式接口
        return response

    def stream_chat(self, prompt):
        """流式输出接口"""
        for response, history in self.model.stream_chat(self.tokenizer, prompt):
            yield response

llm = ChatGLM(model_name="THUDM/chatglm-6b")
prompt = "你好"
response = llm(prompt)
print("response: %s" % response)
"""
response: 你好!我是人工智能助手 ChatGLM-6B,很高兴见到你,欢迎问我任何问题。
"""

📝通俗解释:这就是调用大模型的基本方式,就像调用一个函数一样简单。不同的模型只是换了个"引擎",接口用法都差不多。

8.2 LangChain 如何修改提示模板?

langchain.PromptTemplate:langchain 中的提示模板类。根据不同的下游任务设计不同的 prompt 模板,然后填入内容,生成新的 prompt。目的其实就是为了通过设计更准确的提示词,来引导大模型输出更合理的内容。

python
from langchain import PromptTemplate

# 英文模板
template = """
Explain the concept of {concept} in couple of lines
"""
prompt = PromptTemplate(input_variables=["concept"], template=template)
prompt = prompt.format(concept="regularization")
print("prompt=%s" % prompt)
# '\nExplain the concept of regularization in couple of lines\n'

# 中文模板
template = "请给我解释一下{concept}的意思"
prompt = PromptTemplate(input_variables=["concept"], template=template)
prompt = prompt.format(concept="人工智能")
print("prompt=%s" % prompt)
# '\n请给我解释一下人工智能的意思\n'

📝通俗解释:Prompt Template 就是"模板引擎",把用户输入的变量填入预定义的格式中,生成最终的提问。这比直接拼接字符串更规范、更安全。

8.3 LangChain 如何链接多个组件处理一个特定的下游任务?

python
# 使用 LangChain 官方链
from langchain.chains import LLMChain

chain = LLMChain(llm=openAI(), prompt=promptTem)
print(chain.run("你好"))

# 自定义链示例(因为 ChatGLM 对象不符合 LLMChain 类 llm 对象要求)
class DemoChain:
    def __init__(self, llm, prompt) -> None:
        self.llm = llm
        self.prompt = prompt

    def run(self, query) -> Any:
        prompt = self.prompt.format(concept=query)
        print("query=%s -> prompt=%s" % (query, prompt))
        response = self.llm(prompt)
        return response

chain = DemoChain(llm=llm, prompt=promptTem)
print(chain.run(query="天道酬勤"))

"""
query=天道酬勤 -> prompt=请给我解释一下天道酬勤的意思
天道酬勤是指自然界的规律认为只要一个人勤奋努力,就有可能会获得成功。这个成语的意思是说,尽管一个人可能需要付出很多努力才能取得成功,但只要他/她坚持不懈地努力,就有可能会得到回报。
"""

📝通俗解释:Chain 就是把"输入处理 -> 调用模型 -> 输出处理"这几个步骤串联起来,形成一个完整的工作流。用户只需要调用一次,整个流程就自动完成。

8.4 LangChain 如何 Embedding & Vector Store?

Embedding 这个过程想必大家很熟悉,简单理解就是把现实中的信息通过各类算法编码成一个高维向量,便于计算机快速计算。

  1. 深度学习的语言模型建模一般开头都是 word embedding,看情况会加 position embedding。比如咱们的 LLM 的建模
  2. 常规检索一般是把 reference 数据都先 Embedding 入库,服务阶段 query 进来 Embedding 后再快速在库中查询相似 topk。比如 LangChain-ChatGLM 的本地知识库 QA 系统的入库和检测过程。
  3. 多模态的方案:同时把语音、文字、图片用不同的模型做 Embedding 后,再做多模态的模型建模和多模态交互。比如 Visual-ChatGLM。

8.4.1 使用 OpenAI Embedding

python
# 官方示例代码,用的 OpenAI 的 ada 的文本 Embedding 模型
# 1) Embedding model
from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model_name="ada")
query_result = embeddings.embed_query("你好")

# 2) 文本切割
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=100, chunk_overlap=0
)
texts = """天道酬勤"并不是鼓励人们不劳而获,而是提醒人们要遵循自然规律,通过不断的努力和付出来追求自己的目标。\n这种努力不仅仅是指身体上的劳动,
也包括精神上的努力和思考,以及学习和适应变化的能力。\n只要一个人具备这些能力,它就有可能会获得成功。"""
texts = text_splitter.create_documents([texts])
print(texts[0].page_content)

# 3) 入库检索,官方使用的 Pinecone
import pinecone
from langchain.vectorstores import Pinecone

pinecone.init(api_key=os.getenv(""), environment=os.getenv(""))

index_name = "demo"
search = Pinecone.from_documents(texts=texts, embeddings, index_name=index_name)
query = "What is magical about an autoencoder?"
result = search.similarity_search(query)

8.4.2 使用本地 Embedding(以中文模型为例)

python
# 1) Embedding model: text2vec-large-chinese
from langchain.embeddings.huggingface import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(
    model_name="GanymedeNil/text2vec-large-chinese",
    model_kwargs={'device': 'cuda'}
)
query_result = embeddings.embed_query("你好")

# 2) 文本分割
texts = """天道酬勤"并不是鼓励人们不劳而获,而是提醒人们要遵循自然规律,通过不断的努力和付出来追求自己的目标。\n这种努力不仅仅是指身体上的劳动,
也包括精神上的努力和思考,以及学习和适应变化的能力。\n只要一个人具备这些能力,它就有可能会获得成功。"""

from langchain.text_splitter import CharacterTextSplitter
from langchain.docstore.document import Document

class TextSplitter(CharacterTextSplitter):
    def __init__(self, separator: str = "\n\n", **kwargs: Any):
        super().__init__(separator, **kwargs)

    def split_text(self, text: str) -> List[str]:
        texts = text.split("\n")
        texts = [Document(page_content=t, metadata={"from": "知识库.txt"}) for t in texts]
        return texts

text_splitter = TextSplitter()
texts = text_splitter.split_text(texts)

# 3) 直接本地存储(使用 FAISS)
vs_path = "./demo-vs"
from langchain.vectorstores import FAISS

docs = embeddings.embed_documents([t.page_content for t in texts])
vector_store = FAISS.from_documents(texts, embeddings)
vector_store.save_local(vs_path)

# 加载并检索
vector_store = FAISS.load_local(vs_path, embeddings)
related_docs_with_score = vector_store.similarity_search_with_score(query, k=2)

📝通俗解释:Embedding 就是把文字变成"坐标"的过程。比如"猫"和"狗"的坐标会很近,因为它们都是动物;而"猫"和"石头"的坐标会很远。这样计算机就能快速找到相似的内容了。


9. LangChain 存在哪些问题及解决方案?

9.1 LangChain 低效的令牌使用问题

  • 问题:LangChain 的一个重要问题是它的令牌计数功能,对于小数据集来说,它的效率很低。虽然一些开发人员选择创建自己的令牌计数函数,但也有其他解决方案可以解决这个问题。
  • 解决方案:Tiktoken 是 OpenAI 开发的 Python 库,用于更有效地解决令牌计数问题。它提供了一种简单的方法来计算文本字符串中的令牌,而不需要使用像 LangChain 这样的框架来完成这项特定任务。

📝通俗解释:Token(令牌)就像大模型"收费"的字数单位。LangChain 自带的计数功能比较慢,Tiktoken 是专门优化过的快速计数工具。

9.2 LangChain 文档的问题

  • 问题:文档是任何框架可用性的基石,而 LangChain 因其不充分且经常不准确的文档而受到指责。误导性的文档可能导致开发项目中代价高昂的错误,并且还经常有 404 错误页面。这可能与 LangChain 还在快速发展有关,由于快速的版本迭代,文档的延后性问题

📝通俗解释:LangChain 更新太快,文档经常跟不上代码更新的速度,有时候文档里说的和实际用法不一样。

9.3 LangChain 太多概念容易混淆,过多的"辅助"函数问题

  • 问题:LangChain 的代码库因很多概念让人混淆而备受批评,这使得开发人员很难理解和使用它。这种问题的一个方面是存在大量的"helper"函数,仔细检查就会发现它们本质上是标准 Python 函数的包装器。开发人员可能更喜欢提供更清晰和直接访问核心功能的框架,而不需要复杂的中间功能。

📝通俗解释:LangChain 提供了很多"封装函数",但有些封装得过于复杂,反而让人看不清底层到底是什么。开发人员可能更愿意直接使用 Python 原生功能。

简单的分割函数示例:

python
class CharacterTextSplitter(TextSplitter):
    """Implementation of splitting text that looks at characters."""

    def __init__(self, separator: str = "\n\n", **kwargs: Any):
        """Create a new TextSplitter."""
        super().__init__(**kwargs)
        self._separator = separator

    def split_text(self, text: str) -> List[str]:
        """Split incoming text and return chunks."""
        # First we naively split the large input into a bunch of smaller ones.
        if self._separator:
            splits = text.split(self._separator)
        else:
            splits = list(text)
        return splits

9.4 LangChain 行为不一致并且隐藏细节问题

  • 问题:LangChain 因隐藏重要细节和行为不一致而受到批评,这可能导致生产系统出现意想不到的问题。
  • 举例:LangChain ConversationRetrievalChain 的一个有趣的方面,它涉及到输入问题的重新措辞。这种重复措辞有时会非常广泛,甚至破坏了对话的自然流畅性,使对话脱离了上下文。

📝通俗解释:有时候 LangChain 会"偷偷"修改用户的问题来适应内部逻辑,但这样可能导致回答偏离用户的本意,而且这种行为往往不容易被发现。

9.5 LangChain 缺乏标准的可互操作数据类型问题

  • 问题:缺乏表示数据的标准方法。这种一致性的缺乏可能会阻碍与其他框架和工具的集成,使其在更广泛的机器学习工具生态系统中工作具有挑战性。

📝通俗解释:LangChain 有自己的数据格式,但和其他工具对接时可能需要"翻译",不够方便。


10. LangChain 替代方案

是否有更好的替代方案可以提供更容易使用、可扩展性、活跃性和特性?

10.1 LlamaIndex

LlamaIndex 是一个数据框架,它可以很容易地将大型语言模型连接到自定义数据源。它可用于存储、查询和索引数据,还提供了各种数据可视化分析工具。

📝通俗解释:专注于"让大模型读取私有数据"的框架,比如让 AI 读取你的笔记、文档来回答问题。

10.2 Deepset Haystack

Deepset Haystack 是另外一个开源框架,用于使用大型语言模型构建搜索和问答应用程序。它基于 Hugging Face Transformers,提供了多种查询和理解文本数据的工具。

📝通俗解释:基于 Hugging Face 的开源问答框架,特别适合构建企业级的搜索和问答系统。


参考来源https://articles.zsxq.com/id_ve2dgaiqrjzv.html

基于 MIT 许可发布