1. 大语言模型组件快速入门

大型语言模型(LLMs)是 LangChain 的核心组件。
LangChain 并不提供自己的 LLMs,而是为与许多不同的 LLMs 交互提供了一个标准接口。

有许多 LLM 供应商(OpenAI、Cohere、Hugging Face 等)- LLM 类被设计为为所有这些供应商提供一个标准接口。

在这个演示中,我们将使用 OpenAI 的 LLM 封装器,尽管突出显示的功能对所有 LLM 类型都是通用的。

设置

在这个示例中,我们需要安装 OpenAI Python 包:

pip install openai

访问 API 需要一个 API 密钥,您可以通过创建帐户并转到这里来获取它。一旦我们有了密钥,我们将希望通过运行以下命令将其设置为环境变量:

export OPENAI_API_KEY="..."

如果您不想设置环境变量,可以在初始化 OpenAI LLM 类时直接通过 openai_api_key 命名参数传递密钥:

from langchain_openai import OpenAI

llm = OpenAI(openai_api_key="...")

否则,您可以不带任何参数初始化:

from langchain_openai import OpenAI

llm = OpenAI()

LCEL

LLMs 实现了Runnable 接口,这是LangChain 表达语言(LCEL)的基本构建块。这意味着它们支持 invokeainvokestreamastreambatchabatchastream_log 调用。

LLMs 接受字符串作为输入,或者可以被强制转换为字符串提示的对象,包括 List[BaseMessage]PromptValue

llm.invoke(
    "关于失业和通货膨胀之间关系的一些理论是什么?"
)
'\n\n1. 菲利普斯曲线理论:这表明失业率和通货膨胀率之间存在反向关系,即失业率较低时,通货膨胀率较高,反之亦然。\n\n2. 货币主义理论:该理论认为失业率和通货膨胀之间的关系较弱,货币供应的变化更重要。\n\n3. 资源利用理论:该理论认为,当失业率较低时,企业能够提高工资和价格,以利用对其产品和服务的需求增加。这导致通货膨胀。'
for chunk in llm.stream(
    "关于失业和通货膨胀之间关系的一些理论是什么?"
):
    print(chunk, end="", flush=True)
1. 菲利普斯曲线理论:该理论指出失业率和通货膨胀率之间存在反向关系。随着失业率的降低,通货膨胀率增加,反之亦然。

2. 成本推动通货膨胀理论:该理论表明,失业率的增加导致总需求减少,这会导致由于供应减少而价格上涨。

3. 工资推动通货膨胀理论:该理论指出,当失业率较低时,由于劳动力竞争,工资往往会上涨,从而导致价格上涨。

4. 货币主义理论:该理论指出失业率和通货膨胀之间没有直接关系,而是货币供应的增加导致通货膨胀,这可能是由失业率的增加引起的。
llm.batch(
    [
        "关于失业和通货膨胀之间关系的一些理论是什么?"
    ]
)
['\n\n1. 菲利普斯曲线理论:该理论表明失业率和通货膨胀之间存在反向关系,即失业率降低时,通货膨胀上升,失业率增加时,通货膨胀下降。该理论基于这样一个观点,即当经济状况良好时,对商品和服务的需求更高,导致价格上涨。\n\n2. 成本推动理论:该理论表明,当生产成本增加时,会导致价格上涨和产量下降。这可能导致失业率上升,最终导致通货膨胀。\n\n3. 需求拉动理论:该理论表明,当商品和服务的需求增加时,会导致价格上涨,最终导致通货膨胀。这可能导致失业率上升,因为企业无法满足更高的需求。\n\n4. 结构性失业理论:该理论表明,当失业率较高时,失业人口的技能与就业市场所需技能不匹配,导致失业率上升,最终导致通货膨胀。']
await llm.ainvoke(
    "关于失业和通货膨胀之间关系的一些理论是什么?"
)
'\n\n1. 菲利普斯曲线理论:该理论认为通货膨胀和失业之间存在反向关系。随着失业率降低,通货膨胀上升,反之亦然。\n\n2. 成本推动理论:该理论认为通货膨胀是由成本上升引起的,这可能是由失业率的增加引起的。随着失业率的上升,企业无法满足需求,必须提高价格以补偿。\n\n3. 需求拉动理论:该理论认为通货膨胀是由商品和服务需求增加引起的。当需求高时,价格必须上涨以满足需求。这导致通货膨胀。\n\n4. 货币理论:该理论认为货币供应和通货膨胀与失业有关。当货币供应增加时,价格上涨,导致通货膨胀。如果失业率高,那么货币供应增加,导致通货膨胀。'
async for chunk in llm.astream(
    "关于失业和通货膨胀之间关系的一些理论是什么?"
):
    print(chunk, end="", flush=True)
1. 菲利普斯曲线理论:该理论表明失业率和通货膨胀之间存在反向关系,即失业率较低时,通货膨胀上升,反之亦然。

2. 成本推动理论:该理论表明通货膨胀是由生产成本上升引起的,如工资、原材料和能源。它指出,当成本上升时,企业必须将这些成本转嫁给消费者,从而提高商品和服务的价格,导致通货膨胀。

3. 需求拉动理论:该理论表明通货膨胀是由商品和服务需求增加引起的,导致价格上涨。它指出,当失业率较低时,人们有更多的钱可以花费,这种增加的需求推高了价格。

4. 货币理论:该理论指出通货膨胀是由货币供应增加引起的。它指出,当货币供应增加时,人们有更多的钱可以花费,导致价格上涨。
await llm.abatch(
    [
        "关于失业和通货膨胀之间关系的一些理论是什么?"
    ]
)
['\n\n1. 菲利普斯曲线理论:该理论指出失业率和通货膨胀之间存在反向关系。失业率较低时,工资上涨,导致价格上涨和整体通货膨胀。\n\n2. 成本推动理论:该理论指出通货膨胀是由生产成本上升引起的,如工资、商品和服务。当生产成本上升时,商品和服务的价格也必须上涨,导致通货膨胀。\n\n3. 需求拉动理论:该理论指出通货膨胀是由商品和服务的总需求增加引起的。需求高时,价格必须上涨以满足需求,导致通货膨胀。\n\n4. 结构性失业理论:该理论指出,当失业率较高时,劳动力供应过剩。劳动力供应过剩会导致工资下降,这可能导致通货膨胀,因为人们愿意接受较低的工资来完成同样的工作。']
async for chunk in llm.astream_log(
    "关于失业和通货膨胀之间关系的一些理论是什么?"
):
    print(chunk)
    RunLogPatch({'op': 'replace',
      'path': '',
      'value': {'final_output': None,
                'id': 'baf410ad-618e-44db-93c8-809da4e3ed44',
                'logs': {},
                'streamed_output': []}})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '1'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '.'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 菲利普'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '斯'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '曲'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '线'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '理'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '论'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ':'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '该'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '理'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '论'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '表'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '明'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '失'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '业'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '率'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '和'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '通'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '货'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '膨'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '胀'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '之'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '间'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '关'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '系'})

    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 通货膨胀'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 当'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 失业率'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 较低'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 时'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ','})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 通货膨胀'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 往往'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 较高'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ','})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '而'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 当'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 失业率'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 较高'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 时'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ','})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 通货膨胀'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 往往'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 较低'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' '})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '2'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 自然失业率理论:'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 这一理论认为存在一种自然失业率,也称为非加速通货膨胀失业率(NAIRU)。根据这一理论,当失业率低于NAIRU时,通货膨胀会上升,而当失业率高于NAIRU时,通货膨胀会下降。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '3'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 成本推动通货膨胀理论:'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 这一理论认为高失业率导致较高的工资,进而导致较高的价格,从而推动通货膨胀。'})

    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' 和更高的通货膨胀'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '。'})
    RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ''})
    RunLogPatch({'op': 'replace',
      'path': '/final_output',
      'value': {'generations': [[{'generation_info': {'finish_reason': 'stop',
                                                      'logprobs': None},
                                  'text': '\n'
                                          '\n'
                                          '1. 菲利普斯曲线理论:该理论表明失业率与通货膨胀之间存在反向关系。当失业率低时,通货膨胀往往较高;当失业率高时,通货膨胀往往较低。\n'
                                          '\n'
                                          '2. NAIRU 理论:该理论认为存在自然失业率,也称为非加速通货膨胀失业率(NAIRU)。根据该理论,当失业率低于 NAIRU 时,通货膨胀将增加;当失业率高于 NAIRU 时,通货膨胀将减少。\n'
                                          '\n'
                                          '3. 成本推动通货膨胀理论:该理论认为高失业率导致工资上涨,进而导致价格上涨和通货膨胀加剧。'}]],
                'llm_output': None,
                'run': None}})

LangSmith

所有 LLM 都配备了内置的 LangSmith 追踪功能。只需设置以下环境变量:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=<your-api-key>

然后任何 LLM 调用(无论是嵌套在链中还是独立调用)都将自动被追踪。追踪将包括输入、输出、延迟、令牌使用情况、调用参数、环境参数等。点击此处查看示例:https://smith.langchain.com/public/7924621a-ff58-4b1c-a2a2-035a354ef434/r。

在 LangSmith 中,您可以为任何追踪提供反馈,编译带注释的数据集进行评估,在 playground 中调试性能等。

2. 自定义大语言模型

本文介绍如何创建一个自定义的大语言模型(LLM)包装器,以便您可以使用自己的LLM或与LangChain支持的不同包装器。自定义LLM只需要实现两个必需的内容:

  • 一个 _call 方法,接受一个字符串和一些可选的停用词,并返回一个字符串。
  • 一个 _llm_type 属性,返回一个字符串,仅用于日志记录目的。

还有一个可选的内容:

  • 一个 _identifying_params 属性,用于帮助打印此类。应返回一个字典。

让我们实现一个非常简单的自定义LLM,它只返回输入的前n个字符。

from typing import Any, List, Mapping, Optional

from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
class CustomLLM(LLM):
    n: int

    @property
    def _llm_type(self) -> str:
        return "custom"

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        if stop is not None:
            raise ValueError("stop kwargs are not permitted.")
        return prompt[: self.n]

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """获取标识参数。"""
        return {"n": self.n}

现在我们可以像使用其他LLM一样使用这个自定义LLM。

llm = CustomLLM(n=10)
llm.invoke("This is a foobar thing")
'This is a '

我们还可以打印LLM并查看其自定义打印。

print(llm)
CustomLLM
参数: {'n': 10}

3. LLM缓存

LangChain为LLMs提供了一个可选的缓存层。这有两个好处:

  • 如果您经常多次请求相同的完成结果,它可以通过减少您向LLM提供者发出的API调用次数来为您节省金钱。
  • 通过减少您向LLM提供者发出的API调用次数,它可以加快您的应用程序速度。
from langchain.globals import set_llm_cache
from langchain_openai import OpenAI

# 为了让缓存效果更加明显,让我们使用一个速度较慢的模型。
llm = OpenAI(model_name="gpt-3.5-turbo-instruct", n=2, best_of=2)
%%time
from langchain.cache import InMemoryCache

set_llm_cache(InMemoryCache())

# 第一次调用时,因为尚未缓存,所以应该需要更长的时间
llm.predict("Tell me a joke")
CPU times: user 13.7 ms, sys: 6.54 ms, total: 20.2 ms
Wall time: 330 ms

"\n\n为什么自行车不能自己站起来?因为它太累了!"
%%time
# 第二次调用时,因为已经缓存,所以速度更快
llm.predict("Tell me a joke")
CPU times: user 436 µs, sys: 921 µs, total: 1.36 ms
Wall time: 1.36 ms

"\n\n为什么自行车不能自己站起来?因为它太累了!"

SQLite缓存

!rm .langchain.db
# 我们可以使用SQLite缓存做同样的事情
from langchain.cache import SQLiteCache

set_llm_cache(SQLiteCache(database_path=".langchain.db"))
%%time
# 第一次调用时,因为尚未缓存,所以应该需要更长的时间
llm.predict("Tell me a joke")
CPU times: user 29.3 ms, sys: 17.3 ms, total: 46.7 ms
Wall time: 364 ms



'\n\n为什么番茄变红了?\n\n因为它看到了沙拉酱!'
%%time
# 第二次调用时,因为已经缓存,所以速度更快
llm.predict("Tell me a joke")
CPU times: user 4.58 ms, sys: 2.23 ms, total: 6.8 ms
Wall time: 4.68 ms

'\n\n为什么番茄变红了?\n\n因为它看到了沙拉酱!'

4. LLM数据流

所有 LLM 都实现了 Runnable 接口,该接口带有所有方法的默认实现,即 ainvoke、batch、abatch、stream、astream。这使得所有 LLM 都具有基本的数据流支持。

数据流支持默认返回一个迭代器(在异步数据流的情况下为 AsyncIterator),其中包含底层 LLM 提供程序返回的最终结果。这显然不能实现逐标记的数据流,这需要 LLM 提供程序的原生支持,但可以确保您的代码可以适用于我们任何 LLM 集成,期望获得标记的迭代器。

查看哪些集成支持逐标记的数据流请点击这里

from langchain_openai import OpenAI

llm = OpenAI(model="gpt-3.5-turbo-instruct", temperature=0, max_tokens=512)
for chunk in llm.stream("Write me a song about sparkling water."):
    print(chunk, end="", flush=True)
诗歌第一节:
气泡在我的玻璃杯中跳舞
清澈而爽口,简直太棒了
提神的味道,就像是一场梦
气泡水,你让我笑逐颜开

合唱:
哦,气泡水,你是我的快乐
每一口,让我感觉如此美好
你就像我的口中派对
我欲罢不能,我被迷住了

诗歌第二节:
无糖,无卡路里,纯粹的幸福
你是完美的饮料,我必须承认
从柠檬到青柠,有很多口味可选
气泡水,你总能逗乐我

合唱:
哦,气泡水,你是我的快乐
每一口,让我感觉如此美好
你就像我的口中派对
我欲罢不能,我被迷住了

桥段:
有人可能说你只是普通的水
但对我来说,你远不止如此
你给我的一天带来了闪光
在每一个方面

合唱:
哦,气泡水,你是我的快乐
每一口,让我感觉如此美好
你就像我的口中派对
我欲罢不能,我被迷住了

结尾:
所以,向你,我亲爱的气泡水,干杯
你将永远是我永远的首选饮料
以你的气泡和清爽的味道
你将永远有一个特殊的位置。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐