LangChain Model I/O解读

一 总览

模型IO的目标是使开发者无须深入理解各个模型平台的API调用协议就可以方便的与各个大模型进行交互。

概念指南

对消息、提示、LLM与聊天模型以及输出解析器的概念性解释。在开始之前,你应该阅读这部分内容。

快速开始

介绍了开始使用不同类型模型的基础知识。如果你想了解功能概览,应该浏览这个部分。

提示

这一部分深入探讨了不同类型的提示模板以及如何使用它们。

LLM

这一部分涵盖了与LLM类相关的功能。这是一种接收文本字符串作为输入并返回文本字符串的模型。

聊天模型

这一部分涵盖了与ChatModel类相关的功能。这是一种接收消息列表作为输入并返回一条消息的模型。

输出解析器

输出解析器负责将LLM和聊天模型的输出转换为更结构化的数据。这一部分介绍了不同类型的输出解析器。

二 快速开始

快速入门将介绍使用语言模型的基本知识。它将介绍两种不同类型的模型——LLM和ChatModels。然后,它将介绍如何使用PromptTemplates来格式化这些模型的输入,以及如何使用Output Parsers来处理输出。

Models

初始化2种模型 LLM和ChatModels

from langchain_openai import ChatOpenAI
from langchain_openai import OpenAI

llm = OpenAI()
chat_model = ChatOpenAI(model="gpt-3.5-turbo-0125")

llm和chat_mode都是表示特定模型配置的对象。可以使用温度等参数对它们进行初始化,主要区别在于它们的输入和输出模式。LLM对象以字符串作为输入和输出字符串。ChatModel对象以消息列表作为输入和输入消息。

from langchain_core.messages import HumanMessage

text = "What would be a good company name for a company that makes colorful socks?"
messages = [HumanMessage(content=text)]

llm.invoke(text)
# >> Feetful of Fun

chat_model.invoke(messages)
# >> AIMessage(content="Socks O'Color")

LLM返回一个字符串,而ChatModel返回一条消息。

Prompt Templates

大多数LLM应用程序不会将用户输入直接传递到LLM中。通常,他们会将用户输入添加到一段更大的文本中,称为提示模板,为手头的特定任务提供额外的上下文。

在前面的示例中,我们传递给模型的文本包含生成公司名称的指令。对于我们的应用程序,如果用户只需要提供公司/产品的描述,而不必担心给出型号说明,那就太好了。

PromptTemplates正将从用户输入到完全格式化的提示的所有逻辑捆绑在一起。

from langchain.prompts import PromptTemplate

prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
prompt.format(product="colorful socks")

生成的提示词如下

What is a good name for a company that makes colorful socks?

与原始字符串格式相比,使用这些格式有几个优点。可以“部分”输出变量,例如,一次只能格式化部分变量。可以将它们组合在一起,轻松地将不同的模板组合到一个提示中。

PromptTemplates也可以用于生成消息列表。在这种情况下,提示不仅包含有关内容的信息,还包含每条消息(其角色、在列表中的位置等)。在这里,最常见的情况是ChatPromptTemplate 它是ChatMessageTemplates的列表。每个ChatMessageTemplate都包含如何格式化该ChatMessage的说明——它的角色,然后还有它的内容。

from langchain.prompts.chat import ChatPromptTemplate

template = "You are a helpful assistant that translates {input_language} to {output_language}."
human_template = "{text}"

chat_prompt = ChatPromptTemplate.from_messages([
    ("system", template),
    ("human", human_template),
])

chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")

生成的提示词如下

[
SystemMessage(content="You are a helpful assistant that translates English to French.", additional_kwargs={}),
HumanMessage(content="I love programming.")
]

Output parsers

OutputParsers将语言模型的原始输出转换为可在下游使用的格式。有几种主要类型的OutputParser,包括:

将LLM中的文本转换为结构化信息(例如JSON)

将聊天消息转换为字符串

将除了消息之外的调用返回的额外信息(如OpenAI函数调用)转换为字符串

from langchain.output_parsers import CommaSeparatedListOutputParser

output_parser = CommaSeparatedListOutputParser()
output_parser.parse("hi, bye")
# >> ['hi', 'bye']

与LCEL合成

我们现在可以将所有这些组合成一个链。这个链将获取输入变量,将这些变量传递给提示模板以创建提示,将提示传递给语言模型,然后通过(可选)输出解析器传递输出。这是一种将模块化逻辑捆绑在一起的方便方法。

template = "Generate a list of 5 {text}.\n\n{format_instructions}"

chat_prompt = ChatPromptTemplate.from_template(template)
chat_prompt = chat_prompt.partial(format_instructions=output_parser.get_format_instructions())
chain = chat_prompt | chat_model | output_parser
chain.invoke({"text": "colors"})
# >> ['red', 'blue', 'green', 'yellow', 'orange']

请注意,我们使用|语法将这些组件连接在一起。此语法由LangChain表达式语言(LCEL)提供支持,并依赖于所有这些对象实现的通用Runnable接口。

结论

这就是开始使用提示、模型和输出解析器的方法!这只是涵盖了需要学习的内容的表面。有关更多信息,请查看:

概念指南

有关如何使用提示模板的信息的提示部分

有关LLM接口的更多信息

有关ChatModel界面的更多信息

输出解析器部分提供有关不同类型的输出解析器的信息。

三 Prompts

提示模板是为语言模型生成提示的预定义配方PromptTemplate和ChatPromptTemplate实现了Runnable接口,这是LangChain表达式语言(LCEL)的基本构建块。这意味着它们支持invoke、ainvoke、stream、astream、batch、abatch和astream_log调用。

模板可能包括适用于给定任务的说明、少量镜头示例以及特定上下文和问题。

LangChain提供了创建和使用提示模板的工具。

LangChain致力于创建与模型无关的模板,以便于在不同的语言模型中重用现有模板。

通常,语言模型期望提示要么是字符串,要么是聊天消息列表。

PromptTemplate

使用PromptTemplate为字符串提示创建模板。

默认情况下,PromptTemplate使用Python的str.format语法进行模板化。

from langchain.prompts import PromptTemplate

prompt_template = PromptTemplate.from_template(
    "Tell me a {adjective} joke about {content}."
)
prompt_template.format(adjective="funny", content="chickens")

'Tell me a funny joke about chickens.'

ChatPromptTemplate

聊天模型的提示是聊天消息的列表。

每条聊天消息都与内容和一个名为role的附加参数相关联。例如,在OpenAI聊天完成API中,聊天消息可以与AI助手、人或系统角色相关联。

创建一个聊天提示模板,如下所示:

from langchain_core.prompts import ChatPromptTemplate

chat_template = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a helpful AI bot. Your name is {name}."),
        ("human", "Hello, how are you doing?"),
        ("ai", "I'm doing well, thanks!"),
        ("human", "{user_input}"),
    ]
)

messages = chat_template.format_messages(name="Bob", user_input="What is your name?")

例如,除了使用上面使用的(类型,内容)的2元组表示外,还可以传入MessagePromptTemplate或BaseMessage的实例。

from langchain.prompts import HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_openai import ChatOpenAI

chat_template = ChatPromptTemplate.from_messages(
    [
        SystemMessage(
            content=(
                "You are a helpful assistant that re-writes the user's text to "
                "sound more upbeat."
            )
        ),
        HumanMessagePromptTemplate.from_template("{text}"),
    ]
)
messages = chat_template.format_messages(text="I don't like eating tasty things")
print(messages)
[SystemMessage(content="You are a helpful assistant that re-writes the user's text to sound more upbeat."), HumanMessage(content="I don't like eating tasty things")]

LCEL

PromptTemplate和ChatPromptTemplate实现了Runnable接口,这是LangChain表达式语言(LCEL)的基本构建块。这意味着它们支持invoke、ainvoke、stream、astream、batch、abatch和astream_log调用。

PromptTemplate接受(提示变量的)字典并返回StringPromptValue。ChatPromptTemplate接受字典并返回ChatPromptValue。

prompt_val = prompt_template.invoke({"adjective": "funny", "content": "chickens"})
prompt_val
StringPromptValue(text='Tell me a joke')
prompt_val.to_string()
'Tell me a joke'
prompt_val.to_messages()
[HumanMessage(content='Tell me a joke')]
chat_val = chat_template.invoke({"text": "i dont like eating tasty things."})
chat_val.to_messages()
[SystemMessage(content="You are a helpful assistant that re-writes the user's text to sound more upbeat."),
 HumanMessage(content='i dont like eating tasty things.')]
chat_val.to_string()
"System: You are a helpful assistant that re-writes the user's text to sound more upbeat.\nHuman: i dont like eating tasty things."

四 Chat Models

没有使用“text-intext-out”API,而是使用一个“聊天消息”作为输入和输出的接口。

Setup

from langchain_openai import ChatOpenAI
chat = ChatOpenAI(openai_api_key="...")
from langchain_openai import ChatOpenAI
chat = ChatOpenAI()

聊天模型界面基于消息而非原始文本。LangChain中当前支持的消息类型有AIMessage、HumanMessage、SystemMessage、FunctionMessage和ChatMessage——ChatMessage采用任意角色参数。大多数时候,您将只处理HumanMessage、AIMessage和SystemMessage

LCEL

聊天模型实现了Runnable接口,这是LangChain表达式语言(LCEL)的基本构建块。这意味着它们支持invoke、ainvoke、stream、astream、batch、abatch和astream_log调用。

聊天模型接受List[BaseMessage]作为输入,或者接受可以强制为消息的对象,包括str(转换为HumanMessage)和PromptValue。

from langchain_core.messages import HumanMessage, SystemMessage
messages = [
    SystemMessage(content="You're a helpful assistant"),
    HumanMessage(content="What is the purpose of model regularization?"),
]
chat.invoke(messages)
AIMessage(content="The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to fit the noise in the training data, leading to poor generalization on unseen data. Regularization techniques introduce additional constraints or penalties to the model's objective function, discouraging it from becoming overly complex and promoting simpler and more generalizable models. Regularization helps to strike a balance between fitting the training data well and avoiding overfitting, leading to better performance on new, unseen data.")
for chunk in chat.stream(messages):
    print(chunk.content, end="", flush=True)
The purpose of model regularization is to prevent overfitting and improve the generalization of a machine learning model. Overfitting occurs when a model is too complex and learns the noise or random variations in the training data, which leads to poor performance on new, unseen data. Regularization techniques introduce additional constraints or penalties to the model's learning process, discouraging it from fitting the noise and reducing the complexity of the model. This helps to improve the model's ability to generalize well and make accurate predictions on unseen data.
chat.batch([messages])
[AIMessage(content="The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to learn the noise or random fluctuations in the training data, rather than the underlying patterns or relationships. Regularization techniques add a penalty term to the model's objective function, which discourages the model from becoming too complex and helps it generalize better to new, unseen data. This improves the model's ability to make accurate predictions on new data by reducing the variance and increasing the model's overall performance.")]
await chat.ainvoke(messages)
AIMessage(content='The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to memorize the training data instead of learning general patterns and relationships. This leads to poor performance on new, unseen data.\n\nRegularization techniques introduce additional constraints or penalties to the model during training, discouraging it from becoming overly complex. This helps to strike a balance between fitting the training data well and generalizing to new data. Regularization techniques can include adding a penalty term to the loss function, such as L1 or L2 regularization, or using techniques like dropout or early stopping. By regularizing the model, it encourages it to learn the most relevant features and reduce the impact of noise or outliers in the data.')
async for chunk in chat.astream(messages):
    print(chunk.content, end="", flush=True)
The purpose of model regularization is to prevent overfitting in machine learning models. Overfitting occurs when a model becomes too complex and starts to memorize the training data instead of learning the underlying patterns. Regularization techniques help in reducing the complexity of the model by adding a penalty to the loss function. This penalty encourages the model to have smaller weights or fewer features, making it more generalized and less prone to overfitting. The goal is to find the right balance between fitting the training data well and being able to generalize well to unseen data.

LangSmith

所有ChatModels都配有内置的LangSmith跟踪功能。只需设置以下环境变量:

export LANGCHAIN_TRACING_V2=“true”

export LANGCHAIN_API_KEY=<your-API-KEY>

并且任何ChatModel调用(无论是否嵌套在链中)都将被自动跟踪。跟踪将包括输入、输出、延迟、令牌使用、调用参数、环境参数等。请参阅此处的示例:
https://smith.langchain.com/public/a54192ae-dd5c-4f7a-88d1-daa1eaba1af7/r.

然后,在LangSmith中,您可以为任何跟踪提供反馈,为评估结果编译带注释的数据集,在操场上调试性能等等。

_call__

消息输入->消息输出

为了方便起见,您还可以将聊天模型视为可调用模型。您可以通过向聊天模型传递一条或多条消息来完成聊天。响应将是一条消息。

from langchain_core.messages import HumanMessage, SystemMessage

chat(
    [
        HumanMessage(
            content="Translate this sentence from English to French: I love programming."
        )
    ]
)
AIMessage(content="J'adore la programmation.")
messages = [
    SystemMessage(
        content="You are a helpful assistant that translates English to French."
    ),
    HumanMessage(content="I love programming."),
]
chat(messages)
AIMessage(content="J'adore la programmation.")

generate

批量调用,更丰富的输出

您可以更进一步,使用generate为多组消息生成补全。这将返回一个带有附加消息参数的LLMResult。这将包括关于返回消息之外的每个生成的附加信息(例如,完成原因)和关于完整API调用的附加信息,例如,使用的总令牌。

batch_messages = [
    [
        SystemMessage(
            content="You are a helpful assistant that translates English to French."
        ),
        HumanMessage(content="I love programming."),
    ],
    [
        SystemMessage(
            content="You are a helpful assistant that translates English to French."
        ),
        HumanMessage(content="I love artificial intelligence."),
    ],
]
result = chat.generate(batch_messages)
result
LLMResult(generations=[[ChatGeneration(text="J'adore programmer.", generation_info={'finish_reason': 'stop'}, message=AIMessage(content="J'adore programmer."))], [ChatGeneration(text="J'adore l'intelligence artificielle.", generation_info={'finish_reason': 'stop'}, message=AIMessage(content="J'adore l'intelligence artificielle."))]], llm_output={'token_usage': {'prompt_tokens': 53, 'completion_tokens': 18, 'total_tokens': 71}, 'model_name': 'gpt-3.5-turbo'}, run=[RunInfo(run_id=UUID('077917a9-026c-47c4-b308-77b37c3a3bfa')), RunInfo(run_id=UUID('0a70a0bf-c599-4f51-932a-c7d42202c984'))])

您可以从此LLMResult恢复令牌使用等信息:

result.llm_output
{'token_usage': {'prompt_tokens': 53,
  'completion_tokens': 18,
  'total_tokens': 71},
 'model_name': 'gpt-3.5-turbo'}

五 Output Parsers

语言模型输出文本。但很多时候,你可能想要获得更多结构化的信息,而不仅仅是回复文本。这就是输出解析器的用武之地。
输出解析器是帮助构建语言模型响应的类。输出解析器必须实现两种主要方法:
“Get-format-instructions”:一个方法,它返回一个字符串,其中包含语言模型的输出应该如何格式化的指令。
“Parse”:一种接收字符串(假设是来自语言模型的响应)并将其解析为某种结构的方法。
然后是一个可选的:
“Parse with prompt”:它接受一个字符串(假设是来自语言模型的响应)和一个提示(假设是生成这种响应的提示),并将其解析为某种结构。在OutputParser希望以某种方式重试或修复输出时,通常会提供提示,并且需要来自提示的信息。
下面我们将介绍输出解析器的主要类型PydanticOutputParser。

from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_openai import OpenAI

model = OpenAI(model_name="gpt-3.5-turbo-instruct", temperature=0.0)


# 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


# Set up a parser + inject instructions into the prompt template.
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()},
)

# And a query intended to prompt a language model to populate the data structure.
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": "Tell me a joke."})
parser.invoke(output)


结果如下
Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!')


LCEL


输出解析器实现Runnable接口,这是LangChain表达式语言(LCEL)的基本构建块。这意味着它们支持invoke、ainvoke、stream、astream、batch、abatch和astream_log调用。
输出解析器接受字符串或BaseMessage作为输入,并可以返回任意类型。
parser.invoke(output)
Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!')
我们也可以将其添加到我们的Runnable序列中,而不是手动调用解析器:
chain = prompt | model | parser chain.invoke({"query": "Tell me a joke."})
Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!')
虽然所有解析器都支持流式接口,但只有某些解析器可以通过部分解析的对象进行流式传输,因为这在很大程度上取决于输出类型。不能构造部分对象的解析器只会生成完全解析的输出。
例如,SimpleJsonOutputParser可以流式传输部分输出

结构化解析器

当您想要返回多个字段时,可以使用此输出解析器。虽然Pydantic/JSON解析器更强大,但Structured output parser对功能较弱的模型很有用。

response_schemas = [
    ResponseSchema(name="answer", description="answer to the user's question"),
    ResponseSchema(
        name="source",
        description="source used to answer the user's question, should be a website.",
    ),
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

我们现在得到一个字符串,其中包含应如何格式化响应的说明,然后将其插入到提示中。

format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
    template="answer the users question as best as possible.\n{format_instructions}\n{question}",
    input_variables=["question"],
    partial_variables={"format_instructions": format_instructions},
)
model = ChatOpenAI(temperature=0)
chain = prompt | model | output_parser
chain.invoke({"question": "what's the capital of france?"})
{'answer': 'The capital of France is Paris.',
 'source': 'https://en.wikipedia.org/wiki/Paris'}
for s in chain.stream({"question": "what's the capital of france?"}):
    print(s)
{'answer': 'The capital of France is Paris.', 'source': 'https://en.wikipedia.org/wiki/P
  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值