一架梯子,一头程序猿,仰望星空!
LangChain教程(Python版本) > 内容正文

LangChain整合Llama.cpp模型


Llama.cpp

llama-cpp-pythonllama.cpp的Python绑定。

它支持许多LLM的推理,可以在HuggingFace上访问。

该笔记本介绍了如何在LangChain中运行llama-cpp-python

注意:新版本的llama-cpp-python使用GGUF模型文件(参见这里)。

这是一个重大变化。

要将现有的GGML模型转换为GGUF,可以在llama.cpp中运行以下命令:

python ./convert-llama-ggmlv3-to-gguf.py --eps 1e-5 --input models/openorca-platypus2-13b.ggmlv3.q4_0.bin --output models/openorca-platypus2-13b.gguf.q4_0.bin

安装​

有不同的选项可用于安装llama-cpp软件包:

  • 仅使用CPU
  • CPU + GPU(使用多个BLAS后端之一)
  • Metal GPU(使用Apple Silicon芯片的MacOS)

仅使用CPU安装​

pip install llama-cpp-python

使用OpenBLAS / cuBLAS / CLBlast安装​

llama.cpp支持多个BLAS后端,以加快处理速度。使用FORCE_CMAKE=1环境变量强制使用cmake,并为所需的BLAS后端安装pip软件包(source)。

使用cuBLAS后端的示例安装:

CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python

重要提示:如果您已经安装了仅使用CPU的版本的软件包,您需要从头重新安装。考虑使用以下命令:

CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install --upgrade --force-reinstall llama-cpp-python --no-cache-dir

使用Metal安装​

llama.cpp支持苹果硅元素一流公民 - 通过ARM NEON,Accelerate和Metal框架进行了优化。使用FORCE_CMAKE=1环境变量强制使用cmake,并为Metal支持安装pip软件包(source)。

使用Metal支持的示例安装:

CMAKE_ARGS="-DLLAMA_METAL=on" FORCE_CMAKE=1 pip install llama-cpp-python

重要提示:如果您已经安装了仅使用CPU的版本的软件包,您需要从头重新安装:考虑使用以下命令:

CMAKE_ARGS="-DLLAMA_METAL=on" FORCE_CMAKE=1 pip install --upgrade --force-reinstall llama-cpp-python --no-cache-dir

在Windows上安装​

通过从源代码进行编译安装llama-cpp-python库是稳定的。您可以按照存储库中的大部分说明进行操作,但某些特定于Windows的说明可能有用。

安装llama-cpp-python的要求包括:

  • git
  • python
  • cmake
  • Visual Studio Community(确保您按照以下设置进行安装)
    • 桌面开发与C++
    • Python开发
    • 使用C++进行嵌入式Linux开发
  1. 递归克隆git存储库以获取llama.cpp子模块
git clone --recursive -j8 https://github.com/abetlen/llama-cpp-python.git
  1. 打开命令提示符(或anaconda提示符,如果已安装),设置环境变量以进行安装。如果没有GPU,必须设置以下两个变量。
set FORCE_CMAKE=1
set CMAKE_ARGS=-DLLAMA_CUBLAS=OFF

如果有NVIDIA GPU,则可以忽略第二个环境变量。

编译和安装

在同一个命令提示符(Anaconda提示符)中设置变量后,您可以进入llama-cpp-python目录并运行以下命令。

python setup.py clean
python setup.py install

用法

确保您按照安装所有必要的模型文件的说明来操作。

您不需要API_TOKEN,因为您将在本地运行LLM。

值得注意的是,要了解哪些模型适用于所需的计算机。

from langchain.llms import LlamaCpp
from langchain import PromptTemplate, LLMChain
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

API参考:

考虑使用适合您模型的模板!请查看HuggingFace等页面上的模型页面以获取正确的提示模板。

template = """问题:{question}

回答:让我们逐步解决这个问题,以确保我们得到正确的答案。"""

prompt = PromptTemplate(template=template, input_variables=["question"])
callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])

CPU

使用 LLaMA 2 7B 模型的示例

llm = LlamaCpp(
    model_path="/Users/rlm/Desktop/Code/llama.cpp/models/openorca-platypus2-13b.gguf.q4_0.bin",
    temperature=0.75,
    max_tokens=2000,
    top_p=1,
    callback_manager=callback_manager, 
    verbose=True, # 这里需要将 verbose 参数传递给回调管理器
)
prompt = """
Question: 乔恩·斯图尔特和约翰·奥利弗之间的说唱战
"""
llm(prompt)
    乔恩·斯图尔特:
    哟,约翰,我听说你在你的节目中说了我一些坏话。
    让我告诉你,兄弟,我是深夜电视的王者
    我的讽刺比刀还尖锐,比刀切得更深
    而你只是个英国人,用你的口音和机智想要搞笑。
    约翰·奥利弗:
    哦,史蒂芬,别胡说八道了,你可能有收视率,但我拥有真实的言论。
    我的节目是人们真正观看和倾听的节目,不仅仅是为了笑声,还有事实。
    当你忙于说废话时,我正在揭示真相。
    史蒂芬·科尔伯特:
    真相?哈!你认为你的节目是有关真相的?拜托,对你来说都只是个笑话。
    你只是个穿着花裤衩的英国家伙,用你的新闻和笑话想搞笑。
    而我才是那个真正正在有所作为的人,以我的...

    llama_print_timings: 加载时间 =  358.60 毫秒
    llama_print_timings: 采样时间 =  172.55 毫秒 /  256 次运行(平均每个 token 0.67 毫秒,每秒 1483.59 个 token)
    llama_print_timings: prompt 评估时间 =  613.36 毫秒 /   16 个 token(平均每个 token 38.33 毫秒,每秒 26.09 个 token)
    llama_print_timings: 评估时间 = 10151.17 毫秒 /  255 次运行(平均每个 token 39.81 毫秒,每秒 25.12 个 token)
    llama_print_timings: 总时间 = 11332.41 毫秒



    "\n乔恩·斯图尔特:\n哟,约翰,我听说你在你的节目中说了我一些坏话。\n让我告诉你,兄弟,我是深夜电视的王者\n我的讽刺比刀还尖锐,比刀切得更深\n而你只是个英国人,用你的口音和机智想要搞笑。\n约翰·奥利弗:\n哦,史蒂芬,别胡说八道了,你可能有收视率,但我拥有真实的言论。\n我的节目是人们真正观看和倾听的节目,不仅仅是为了笑声,还有事实。\n当你忙于说废话时,我正在揭示真相。\n史蒂芬·科尔伯特:\n真相?哈!你认为你的节目是有关真相的?拜托,对你来说都只是个笑话。\n你只是个穿着花裤衩的英国家伙,用你的新闻和笑话想搞笑。\n而我才是那个真正正在有所作为的人,以我的..."

使用 LLaMA v1 模型的示例

llm = LlamaCpp(
    model_path="./ggml-model-q4_0.bin",
    callback_manager=callback_manager,
    verbose=True
)
llm_chain = LLMChain(prompt=prompt, llm=llm)
question = "贾斯汀·比伯出生那年,哪支 NFL 球队赢得了超级碗?"
llm_chain.run(question)
1. 首先,找出贾斯汀·比伯的出生日期。
2. 我们知道贾斯汀·比伯出生于1994年3月1日。
3. 接下来,我们需要查找那一年超级碗的比赛时间。
4. 超级碗在1995年1月28日进行了比赛。
5. 最后,我们可以利用这些信息回答问题。贾斯汀·比伯出生年份赢得超级碗的 NFL 球队是旧金山 49ers。

llama_print_timings:        加载时间 =   434.15 毫秒
llama_print_timings:      样本时间 =    41.81 毫秒 /   121 次运行   (    每个符号 0.35 毫秒)
llama_print_timings: 交互式评估时间 =  2523.78 毫秒 /    48 个符号 (   每个符号 52.58 毫秒)
llama_print_timings:        评估时间 = 23971.57 毫秒 /   121 次运行   (  每个符号 198.11 毫秒)
llama_print_timings:       总时间 = 28945.95 毫秒



'\n\n1. 首先,找出贾斯汀·比伯的出生日期。\n2. 我们知道贾斯汀·比伯出生于1994年3月1日。\n3. 接下来,我们需要查找那一年超级碗的比赛时间。\n4. 超级碗在1995年1月28日进行了比赛。\n5. 最后,我们可以利用这些信息回答问题。贾斯汀·比伯出生年份赢得超级碗的 NFL 球队是旧金山 49ers.'

GPU

如果使用BLAS后端进行安装正确,你将在模型属性中看到一个BLAS = 1的指示符。

对于GPU的使用,有两个最重要的参数:

  • n_gpu_layers - 确定模型中有多少层被离载到GPU上。
  • n_batch - 并行处理的令牌数量。

正确设置这些参数将极大地提高评估速度(更多细节请参考包装器代码)。

n_gpu_layers = 40  # 根据你的模型和GPU的VRAM池,修改这个值。
n_batch = 512  # 应该在1和n_ctx之间,考虑你的GPU中的VRAM数量。

llm = LlamaCpp(
    model_path="/Users/rlm/Desktop/Code/llama.cpp/models/openorca-platypus2-13b.gguf.q4_0.bin",
    n_gpu_layers=n_gpu_layers,
    n_batch=n_batch,
    callback_manager=callback_manager,
    verbose=True, # 需要将Verbose传递给回调管理器
)
llm_chain = LLMChain(prompt=prompt, llm=llm)
question = "What NFL team won the Super Bowl in the year Justin Bieber was born?"
llm_chain.run(question)


    1. 确定Justin Bieber的出生日期:Justin Bieber的出生日期是1994年3月1日。

    2. 找到那一年的超级碗冠军:NFL的1993赛季,超级碗在1994年1月或1994年。

    3. 确定哪个队赢得了比赛:达拉斯牛仔队在1993年1月31日的超级碗XXVII中对阵布法罗比尔斯队(由于一个错误,年份被错误标记)。达拉斯牛仔赢得了这场比赛。

    所以,Justin Bieber出生时达拉斯牛仔队是NFL超级碗的冠军。


    llama_print_timings:        加载时间 =   427.63 毫秒
    llama_print_timings:      示例时间 =   115.85 毫秒 /   164 次   (    0.71 毫秒每个令牌,  1415.67 令牌每秒)
    llama_print_timings:提示评估时间 =   427.53 毫秒 /    45 个令牌 (    9.50 毫秒每个令牌,   105.26 令牌每秒)
    llama_print_timings:        评估时间 =  4526.53 毫秒 /   163 次   (   27.77 毫秒每个令牌,    36.01 令牌每秒)
    llama_print_timings:       总时间 =  5293.77 毫秒



    "\n\n1. 确定Justin Bieber的出生日期:Justin Bieber的出生日期是1994年3月1日。\n\n2. 找到那一年的超级碗冠军:NFL的1993赛季,超级碗在1994年1月或1994年。\n\n3. 确定哪个队赢得了比赛:达拉斯牛仔队在1993年1月31日的超级碗XXVII中对阵布法罗比尔斯队(由于一个错误,年份被错误标记)。达拉斯牛仔赢得了这场比赛。\n\n所以,Justin Bieber出生时,达拉斯牛仔队是NFL超级碗的冠军。"

Metal

如果安装了Metal,您将在模型属性中看到一个 NEON = 1的指示器。

两个最重要的GPU参数是:

  • n_gpu_layers - 确定将模型的多少层转移到Metal GPU,多数情况下,将其设置为1对于Metal来说已经足够了。
  • n_batch - 并行处理的标记数量,默认为8,可以设置为更大的数值。
  • f16_kv - 由于某些原因,Metal只支持True,否则将会出现错误。

正确设置这些参数将大幅提升评估速度(详见包装代码了解更多细节)。

n_gpu_layers = 1  # Metal设置为1已足够。
n_batch = 512  # 应该介于1和n_ctx之间,考虑您Apple Silicon芯片的RAM量。
llm = LlamaCpp(
    model_path="/Users/rlm/Desktop/Code/llama.cpp/models/openorca-platypus2-13b.gguf.q4_0.bin",
    n_gpu_layers=n_gpu_layers,
    n_batch=n_batch,
    f16_kv=True,  # 必须设置为True,否则在几次调用之后将会遇到问题。
    callback_manager=callback_manager,
    verbose=True,  # verbose必须传递给回调管理器。
)

控制台日志将显示以下内容,以表明Metal已正确启用。

ggml_metal_init: allocating
ggml_metal_init: using MPS
...

您还可以通过监视进程的GPU使用情况来使用Activity Monitor,打开n_gpu_layers=1后,CPU使用率将显著下降。

由于在Metal GPU中编译模型,首次调用LLM时性能可能较慢。

文法

我们可以使用 文法 来约束模型输出。

这将根据文法采样标记。

例如,提供指定 json.gbnf 文件的路径以生成JSON。

n_gpu_layers = 1  # 设置为1即可。
n_batch = 512  # 应在1和n_ctx之间,考虑您的Apple Silicon芯片的内存量。
llm = LlamaCpp(
    model_path="/Users/rlm/Desktop/Code/llama.cpp/models/openorca-platypus2-13b.gguf.q4_0.bin",
    n_gpu_layers=n_gpu_layers,
    n_batch=n_batch,
    f16_kv=True,  # 必须设置为True,否则在调用几次后会遇到问题
    callback_manager=callback_manager,
    verbose=True, # 需要启用Verbose以传递给回调管理器
    grammar_path="/Users/rlm/Desktop/Code/langchain-main/langchain/libs/langchain/langchain/llms/grammars/json.gbnf",
)
result = llm("以JSON格式描述一个人:")
    {
        "姓名": "John Doe",
        "年龄": 34,
        "": {
            "职称": "软件开发人员",
            "公司": "Google"
        },
        "兴趣": [
            "运动",
            "音乐",
            "烹饪"
        ],
        "地址": {
            "街道号": 123,
            "街道名称": "橡树街",
            "城市": "Mountain View",
            "州": "加利福尼亚",
            "邮编": 94040
        }
    }

    llama_print_timings:        加载时间 = 357.51 毫秒
    llama_print_timings:      样本时间 = 1213.30 毫秒 /  144次(每个标记 8.43 毫秒,每秒 118.68 个标记)
    llama_print_timings: 提示评估时间 = 356.78 毫秒 /   9个标记(每个标记 39.64 毫秒,每秒 25.23 个标记)
    llama_print_timings:        评估时间 = 3947.16 毫秒 /  143次(每个标记 27.60 毫秒,每秒 36.23 个标记)
    llama_print_timings:       总时间 = 5846.21 毫秒

我们还可以提供list.gbnf以返回一个列表。

n_gpu_layers = 1
n_batch = 512
llm = LlamaCpp(
    model_path="/Users/rlm/Desktop/Code/llama.cpp/models/openorca-platypus2-13b.gguf.q4_0.bin",
    n_gpu_layers=n_gpu_layers,
    n_batch=n_batch,
    f16_kv=True,  # 必须设置为True,否则在调用几次后会遇到问题
    callback_manager=callback_manager,
    verbose=True,
    grammar_path="/Users/rlm/Desktop/Code/langchain-main/langchain/libs/langchain/langchain/llms/grammars/list.gbnf",
)
result = llm("我最喜欢的三本书:")
    ["麦田里的守望者", "呼啸山庄", "安娜·卡列尼娜"]

    llama_print_timings:        加载时间 = 322.34 毫秒
    llama_print_timings:      样本时间 = 232.60 毫秒 /   26次(每个标记 8.95 毫秒,每秒 111.78 个标记)
    llama_print_timings: 提示评估时间 = 321.90 毫秒 /   11个标记(每个标记 29.26 毫秒,每秒 34.17 个标记)
    llama_print_timings:        评估时间 = 680.82 毫秒 /   25次(每个标记 27.23 毫秒,每秒 36.72 个标记)
    llama_print_timings:       总时间 = 1295.27 毫秒