参考网址:
1、简介
LangChain 是一个用于开发由大型语言模型 (LLM) 驱动的应用程序的框架。
LangChain简化了LLM申请生命周期的每个阶段:
具体来说,该框架由以下开源库组成:
- langchain-core:基本抽象和 LangChain 表达式语言。
- langchain-community:第三方集成。
- 合作伙伴包(例如 langchain-openai、langchain-anthropic 等):一些集成已进一步拆分为自己的轻量级包,仅依赖于 langchain-core。
- langchain:构成应用程序认知架构的链、代理和检索策略。
- langgraph:通过将步骤建模为图中的边和节点,使用 LLM 构建健壮且有状态的多参与者应用程序。
- langserve:将 LangChain 链部署为 REST API。
更广泛的生态系统包括:
- LangSmith:一个开发者平台,可让您调试、测试、评估和监控LLM应用程序,并与LangChain无缝集成。
1、如何安装 LangChain、设置环境并开始构建。
https://python.langchain.com/docs/get_started/installation/
2、如果您想要构建特定的东西或者更多的是实践学习者,请查看我们的用例。 它们是常见端到端任务的演练和技术,例如:
3、Expression Language
LangChain表达式语言(LCEL)是LangChain许多组件的基础,是一种声明式的链组成方式。 LCEL 从第一天起就被设计为支持将原型投入生产,从最简单的“提prompt + LLM”链到最复杂的链,无需更改代码。
- Get started LCEL and its benefits
- Runnable interface: The standard interface for LCEL objects
- Primitives: More on the primitives LCEL includes
2、示例
2.1、RAG
Llm支持的最强大的应用程序之一是复杂的问答 (Q&A) 聊天机器人。 这些应用程序可以回答有关特定源信息的问题。 这些应用程序使用一种称为检索增强生成(RAG)的技术。
RAG 是一种利用额外数据增强 LLM 知识的技术。
Llm可以推理广泛的主题,但他们的知识仅限于他们接受培训的特定时间点的公共数据。 如果您想要构建能够推理私有数据或模型截止日期之后引入的数据的 AI 应用程序,您需要使用模型所需的特定信息来增强模型的知识。 引入适当的信息并将其插入模型提示的过程称为检索增强生成 (RAG)。
LangChain 有许多组件旨在帮助构建问答应用程序,以及更广泛的 RAG 应用程序。
2.1.1、典型的 RAG 应用程序有两个主要组件
-
索引:用于从源获取数据并为其建立索引的管道。 这通常发生在离线状态。
-
检索和生成:实际的 RAG 链,它在运行时接受用户查询并从索引中检索相关数据,然后将其传递给模型。
从原始数据到答案的最常见的完整序列如下所示:
2.1.2、索引
-
load:首先我们需要加载数据。 这是通过 DocumentLoaders 完成的。
-
Split:文本分割器将大文档分成更小的块。 这对于索引数据和将其传递到模型都很有用,因为大块更难搜索并且不适合模型的有限上下文窗口。
-
store:我们需要某个地方来存储和索引我们的分割,以便以后可以搜索它们。 这通常是使用 VectorStore 和 Embeddings 模型来完成的。
2.1.3、检索和生成
-
Retrieve: 给定用户输入,使用Retriever从存储中检索相关拆分。
-
Generate: LLM生成一个使用包含问题和检索到的数据的提示进行回答。
2.1.4、代码示例
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass()
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo-0125")
# Load, chunk and index the contents of the blog.
loader = WebBaseLoader(
web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
bs_kwargs=dict(
parse_only=bs4.SoupStrainer(
class_=("post-content", "post-title", "post-header")
)
),
)
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())
# Retrieve and generate using the relevant snippets of the blog.
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
rag_chain.invoke("What is Task Decomposition?")
'Task decomposition is a technique used to break down complex tasks into smaller and simpler steps. It can be done through prompting techniques like Chain of Thought or Tree of Thoughts, or by using task-specific instructions or human inputs. Task decomposition helps agents plan ahead and manage complicated tasks more effectively.'
# cleanup
vectorstore.delete_collection()
2.2、Extracting structured output
信息提取的经典解决方案依赖于人员、(许多)手工制定的规则(例如正则表达式)和自定义微调的 ML 模型的组合。随着时间的推移,此类系统往往会变得复杂,维护成本也越来越高,增强起来也越来越困难。只需向法学硕士提供适当的说明和适当的参考示例,即可快速适应特定的提取任务。本指南将向您展示如何使用法学硕士进行提取应用程序!
2.2.1、方法
使用法学硕士进行信息提取有 3 种广泛的方法:
- 工具/函数调用模式:一些法学硕士支持工具或函数调用模式。 这些法学硕士可以根据给定的模式构建输出。一般来说,这种方法最容易使用,并且有望产生良好的结果。
- JSON 模式:某些法学硕士可以强制输出有效的 JSON。 这类似于工具/函数调用 方法,只不过架构是作为提示的一部分提供的。 一般来说,我们的直觉是,这比工具/函数调用方法表现更差,自己的用例进行验证
- 基于提示:可以很好地遵循说明的法学硕士可以被指示生成所需格式的文本。 生成的文本可以使用现有的输出解析器或使用自定义解析器转换为 JSON 等结构化格式。 此方法可用于不支持 JSON 模式或工具/函数调用模式的 LLM。 这种方法具有更广泛的适用性,但可能会比针对提取或函数调用进行微调的模型产生更差的结果。
2.2.2、具体示例
调用函数/工具的聊天模型来从文本中提取信息。
1、模式
首先,我们需要描述我们想要从文本中提取哪些信息。使用 Pydantic 定义一个示例架构来提取个人信息。
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel, Field
class Person(BaseModel):
"""Information about a person."""
# ^ Doc-string for the entity Person.
# This doc-string is sent to the LLM as the description of the schema Person,
# and it can help to improve extraction results.
# Note that:
# 1. Each field is an `optional` -- this allows the model to decline to extract it!
# 2. Each field has a `description` -- this description is used by the LLM.
# Having a good description can help improve extraction results.
name: Optional[str] = Field(default=None, description="The name of the person")
hair_color: Optional[str] = Field(
default=None, description="The color of the peron's hair if known"
)
height_in_meters: Optional[str] = Field(
default=None, description="Height measured in meters"
)
定义架构时有两种最佳实践:
- 记录属性和模式本身:此信息被发送到法学硕士并用于提高信息提取的质量。
- 不要强迫LLM编造信息! 上面我们使用Optional作为属性,允许LLM在不知道答案时输出None。
2、提取器
让我们使用上面定义的模式创建一个信息提取器。
from typing import Optional
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
# Define a custom prompt to provide instructions and any additional context.
# 1) You can add examples into the prompt template to improve extraction quality
# 2) Introduce additional parameters to take context into account (e.g., include metadata
# about the document from which the text was extracted.)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are an expert extraction algorithm. "
"Only extract relevant information from the text. "
"If you do not know the value of an attribute asked to extract, "
"return null for the attribute's value.",
),
# Please see the how-to about improving performance with
# reference examples.
# MessagesPlaceholder('examples'),
("human", "{text}"),
]
)
我们需要使用支持函数/工具调用的模型。
请查看结构化输出以获取可与此 API 一起使用的一些模型的列表。
from langchain_mistralai import ChatMistralAI
llm = ChatMistralAI(model="mistral-large-latest", temperature=0)
runnable = prompt | llm.with_structured_output(schema=Person)
Let's test it out
text = "Alan Smith is 6 feet tall and has blond hair."
runnable.invoke({"text": text})
输出结果为:
Person(name='Alan Smith', hair_color='blond', height_in_meters='1.8288')
2.3、ChatBot
聊天机器人是LLM最流行的用例之一。 聊天机器人的核心特征是它们可以进行长时间运行的、有状态的对话,并可以使用相关信息回答用户问题。
设计聊天机器人需要考虑具有不同优点和权衡的各种技术,具体取决于您希望它处理什么类型的问题。
聊天机器人通常对私有数据使用RAG生成,以更好地回答特定领域的问题。 您还可以选择在多个数据源之间进行路由,以确保它仅使用最热门的上下文来回答最终问题,或者选择使用更专业类型的聊天历史记录或内存,而不仅仅是来回传递消息。
2.3.1、示例
我们将通过一个示例来说明如何设计和实现由法学硕士支持的聊天机器人。 以下是我们将使用的一些高级组件:
- ChatModel: 聊天机器人界面基于消息而不是原始文本,因此最适合聊天模型而不是文本法学硕士。 有关聊天模型集成的列表,请参阅此处;有关 LangChain 中聊天模型接口的文档,请参阅此处。 您也可以将法学硕士(请参阅此处)用于聊天机器人,但聊天模型具有更具对话性的语气,并且本身支持消息界面。
- 提示模板,简化了组合默认消息、用户输入、聊天历史记录和(可选)附加检索上下文的提示的组装过程。
- 聊天历史记录,它允许聊天机器人“记住”过去的互动,并在回答后续问题时将其考虑在内。 浏览此处获取更多信息。
- 检索器(可选),如果您想要构建一个可以使用特定领域的最新知识作为上下文来增强其响应的聊天机器人,则检索器非常有用。 有关检索系统的深入文档,请参阅此处。
我们将介绍如何将上述组件组合在一起以创建强大的对话聊天机器人。
1、chatmodel
from langchain_openai import ChatOpenAI
chat = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0.2)
2、prompt template
让我们定义一个提示模板以使格式化更容易一些。 我们可以通过将其传递到模型中来创建一条链:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a helpful assistant. Answer all questions to the best of your ability.",
),
MessagesPlaceholder(variable_name="messages"),
]
)
chain = prompt | chat
3、Message history
作为管理聊天历史记录的快捷方式,我们可以使用 MessageHistory 类,它负责保存和加载聊天消息。 有许多内置消息历史记录集成可将消息保存到各种数据库,但在本快速入门中,我们将使用名为 ChatMessageHistory 的内存中演示消息历史记录。
下面是直接使用它的示例:
from langchain.memory import ChatMessageHistory
demo_ephemeral_chat_history = ChatMessageHistory()
demo_ephemeral_chat_history.add_user_message("hi!")
demo_ephemeral_chat_history.add_ai_message("whats up?")
demo_ephemeral_chat_history.messages
输出为:
[HumanMessage(content='hi!'), AIMessage(content='whats up?')]
一旦我们这样做了,我们就可以将存储的消息作为参数直接传递到我们的链中:
demo_ephemeral_chat_history.add_user_message(
"Translate this sentence from English to French: I love programming."
)
response = chain.invoke({"messages": demo_ephemeral_chat_history.messages})
response
输出:
AIMessage(content='The translation of "I love programming" in French is "J\'adore la programmation."')
现在我们有了一个基本的聊天机器人!
虽然这条链本身就可以作为一个有用的聊天机器人,只需要模型的内部知识,但引入某种形式的检索增强生成(简称 RAG),通过特定领域的知识来使我们的聊天机器人更加专注,通常很有用。 我们接下来会介绍这个。
4、Retrievers检索器
我们可以设置并使用检索器来为我们的聊天机器人提取特定领域的知识。
接下来,我们将使用文档加载器从网页中提取数据:
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
data = loader.load()
接下来,我们将其分割成 LLM 上下文窗口可以处理的更小的块,并将其存储在向量数据库中:
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
all_splits = text_splitter.split_documents(data)
然后我们将这些块嵌入并存储在矢量数据库中:
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
And finally, let's create a retriever from our initialized vectorstore:
# k is the number of chunks to retrieve
retriever = vectorstore.as_retriever(k=4)
docs = retriever.invoke("how can langsmith help with testing?")
docs
输出:
[Document(page_content='You can also quickly edit examples and add them to datasets to expand the surface area of your evaluation sets or to fine-tune a model for improved quality or reduced costs.Monitoring\u200bAfter all this, your app might finally ready to go in production. LangSmith can also be used to monitor your application in much the same way that you used for debugging. You can log all traces, visualize latency and token usage statistics, and troubleshoot specific issues as they arise. Each run can also be', metadata={'description': 'Building reliable LLM applications can be challenging. LangChain simplifies the initial setup, but there is still work needed to bring the performance of prompts, chains and agents up the level where they are reliable enough to be used in production.', 'language': 'en', 'source': 'https://docs.smith.langchain.com/overview', 'title': 'LangSmith Overview and User Guide |
标签:教程,Francisco,prompt,San,langchain,2024,LangSmith
From: https://www.cnblogs.com/xine/p/18186168