本文介绍了LangChain框架,它能够将大型语言模型与其他计算或知识来源相结合,从而实现功能更加强大的应用。接着,对LangChain的关键概念进行了详细说明,并基于该框架进行了一些案例尝试,旨在帮助读者更轻松地理解LangChain的工作原理。
引言
近期,大型语言模型(LLM)如GPT系列模型引领了人工智能领域的一场技术革命。开发者们都在利用这些LLM进行各种尝试,虽然已经产生了许多有趣的应用,但是单独使用这些LLM往往难以构建功能强大的实用应用。
LangChain通过将大型语言模型与其他知识库、计算逻辑相结合,实现了功能更加强大的人工智能应用。简单来说,个人理解LangChain可以被视为开源版的GPT插件,它提供了丰富的大语言模型工具,可以在开源模型的基础上快速增强模型的能力。
在此,我总结了最近对LangChain的学习内容,欢迎各位同学前来交流。LangChain使得语言技术的运用更加活跃多元,它有望在人工智能领域发挥重要作用,推动我们工作效率的变革。我们正处在人工智能爆发的前夜,积极拥抱新技术将会带来全新的体验。
LangChain主要概念与示例
LangChain提供了一系列的工具帮助我们更好的使用大语言模型(LLM)。可以认为主要有6种不同类型的工具:
▐ 模型(Models)
LangChain的一个核心价值就是它提供了标准的模型接口;然后我们可以自由的切换不同的模型,当前主要有两种类型的模型,但是考虑到使用场景,对我们一般用户来说就是使用一种模型即文本生成模型。
说到模型,大家就理解模型就是ChatGPT就可以。单纯的模型只能生成文本内容。
- 语言模型(Language Models)
用于文本生成,文字作为输入,输出也是文字。
- 普通LLM:接收文本字符串作为输入,并返回文本字符串作为输出
- 聊天模型:将聊天消息列表作为输入,并返回一个聊天消息
代码案例:
from langchain.schema import HumanMessage from langchain.llms import OpenAI from langchain.chat_models import ChatOpenAI llm = OpenAI() chat_model = ChatOpenAI() print(llm("say hi!")) print(chat_model.predict("say hi!"))
- 文本嵌入模型(Text Embedding Models)
把文字转换为浮点数形式的描述:
这些模型接收文本作为输入并返回一组浮点数。这些浮点数通常用于表示文本的语义信息,以便进行文本相似性计算、聚类分析等任务。文本嵌入模型可以帮助开发者在文本之间建立更丰富的联系,提高基于大型语言模型的应用的性能。
from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() text = "This is a test document." query_result = embeddings.embed_query(text) doc_result = embeddings.embed_documents([text]) print(doc_result)
▐ 提示词(Prompts)
提示词是我们与模型交互的方式,或者是模型的输入,通过提示词可以让模型返回我们期望的内容,比如让模型按照一定的格式返回数据给我们。
LangChain提供了一些工具,可以方便我们更容易的构建出我们想要的提示词,主要工具如下:
了解这些工具都是更方便的让我们构造提示词就行了。
- PromptTemplates
语言模型提示词模板PromptTemplates,提示模板可以让我们重复的生成提示,复用我们的提示。它包含一个文本字符串(“模板”),从用户那里获取一组参数并生成提示,包含:
- 对语言模型的说明,应该扮演什么角色
- 一组少量示例,以帮助LLM生成更好的响应,
- 具体的问题
代码案例:
from langchain.embeddings import OpenAIEmbeddings embeddings = OpenAIEmbeddings() text = "This is a test document." query_result = embeddings.embed_query(text) doc_result = embeddings.embed_documents([text]) print(doc_result)
- ChatPrompt Templates
from langchain.prompts import ( ChatPromptTemplate, PromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) from langchain.schema import ( AIMessage, HumanMessage, SystemMessage ) template="You are a helpful assistant that translates {input_language} to {output_language}." system_message_prompt = SystemMessagePromptTemplate.from_template(template) human_template="{text}" human_message_prompt = HumanMessagePromptTemplate.from_template(human_template) chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt]) # get a chat completion from the formatted messages print(chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages())
聊天模型提示词模板ChatPrompt Templates, ChatModels接受聊天消息列表作为输入。列表一般是不同的提示,并且每个列表消息一般都会有一个角色。
- Example Selectors
示例选择器Example Selectors,如果有多个案例的时候,使用ExampleSelectors选择一个案例让提示词使用:
- 自定义的案例选择器
- 基于长度的案例选择器,输入长的时候按理会少一点,输入多的时候,案例会多一些。
- 相关性选择器,选择一个和输入最相关的案例
from langchain.prompts.example_selector.base import BaseExampleSelector from typing import Dict, List import numpy as np class CustomExampleSelector(BaseExampleSelector): def __init__(self, examples: List[Dict[str, str]]): self.examples = examples def add_example(self, example: Dict[str, str]) -> None: """Add new example to store for a key.""" self.examples.append(example) def select_examples(self, input_variables: Dict[str, str]) -> List[dict]: """Select which examples to use based on the inputs.""" return np.random.choice(self.examples, size=2, replace=False) examples = [ {"foo": "1"}, {"foo": "2"}, {"foo": "3"} ] # Initialize example selector. example_selector = CustomExampleSelector(examples) # Select examples print(example_selector.select_examples({"foo": "foo"})) # -> array([{'foo': '2'}, {'foo': '3'}], dtype=object) # Add new example to the set of examples example_selector.add_example({"foo": "4"}) print(example_selector.examples) # -> [{'foo': '1'}, {'foo': '2'}, {'foo': '3'}, {'foo': '4'}] # Select examples print(example_selector.select_examples({"foo": "foo"})) # -> array([{'foo': '1'}, {'foo': '4'}], dtype=object)
- OutputParsers
输出解析器OutputParsers,可以让LLM输出更加结构化的信息:
- 指示模型如何格式化输出:get_format_instructions
- 输出解析为所需的格式:parse(str)
主要的Parsers:
- CommaSeparatedListOutputParser,让LLM按照逗号分隔的形式返回。['Vanilla', 'Chocolate', 'Strawberry', 'Mint Chocolate Chip', 'Cookies and Cream']
- StructuredOutputParser 无需定义对象,直接生成结构化的内容。 和PydanticOutputParser比较像,但是不用定义对象。
- PydanticOutputParser定义一个对象模型,让LLM按照这个模型返回数据
可以看到我们定义了Joke类,然后PydanticOutputParser可以让LLM按照我们定义对象的格式返回数据给我们。
from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate from langchain.llms import OpenAI from langchain.chat_models import ChatOpenAI from langchain.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field, validator from typing import List model_name = 'text-davinci-003' temperature = 0.0 model = OpenAI(model_name=model_name, temperature=temperature) # Define your desired data structure. class Joke(BaseModel): setup: str = Field(description="question to set up a joke") punchline: str = Field(description="answer to resolve the joke") # You can add custom validation logic easily with Pydantic. @validator('setup') def question_ends_with_question_mark(cls, field): if field[-1] != '?': raise ValueError("Badly formed question!") return field parser = PydanticOutputParser(pydantic_object=Joke) prompt = PromptTemplate( template="Answer the user query.\n{format_instructions}\n{query}\n", input_variables=["query"], partial_variables={"format_instructions": parser.get_format_instructions()} ) joke_query = "Tell me a joke." _input = prompt.format_prompt(query=joke_query) output = model(_input.to_string()) print(parser.get_format_instructions()) print(output) print(parser.parse(output))