跳转至

19 如何在项目中使用开源模型

你好,我是郑晔!

上一讲,我们讲了如何使用 Hugging Face 上的开源模型。这一讲,我们看看如何在实际的项目中使用这些模型。

最简单的方式,当然是把上一讲的代码直接拿过来用。不过,有些项目可能需要依赖于不同的模型,比如,既有开源模型,又有供应商提供的大模型。在这种情况下,我们就需要做一层封装,保证代码的灵活性。

这一讲,我们就来谈谈两种常见的封装:使用 LangChain 和使用集中接入。

使用 LangChain

前面我们讲 LangChain,重点在于它提供的不同抽象,帮助我们搭建各种大模型应用。现在,让我们回到 LangChain 最基础的抽象——模型。

LangChain 的模型就是 LangChain 给我们提供的一层封装,屏蔽掉了不同大模型之间的差异,让我们可以方便地在不同大模型之间进行切换。任何想要接入 LangChain 体系的大模型,只要实现了相应的接口,就可以无缝地嵌入到 LangChain 的体系中去,Hugging Face 的模型就是这么做的。

我们之所以要把 Hugging Face 模型嵌入到 LangChain的体系中,主要是因为我们希望使用 LangChain 提供的其它抽象。

要使用 Hugging Face 相关的代码,首先需要安装相应的包:

pip install langchain-huggingface

langchain-huggingface 是 Hugging Face 和 LangChain 共同维护的一个包,其目标是缩短将 Hugging Face 生态的新功能带给 LangChain 用户的时间。它里面包含了很多功能:

  • 有各种模型的实现,比如聊天模型和 Embedding 模型;
  • 有数据集的实现,它实现成了 DocumentLoader;
  • 有工具的实现,比如文本分类、文本转语音等。

从提供的内容上来看,这个包封装了 Hugging Face 上的主要能力——模型和数据集。其中,不同的模型因为能力上的差异做了不同归结:属于大语言模型的,就归结到了 LangChain 模型上,而无法归结的,就以工具的形式提供。

有了最基本的了解,我们来实现一个简单的功能:

import torch
from langchain_huggingface import HuggingFacePipeline, ChatHuggingFace

device = 0 if torch.cuda.is_available() else -1

llm = HuggingFacePipeline.from_model_id(
    model_id="Qwen/Qwen2.5-0.5B-Instruct",
    task="text-generation",
    device=device,
    pipeline_kwargs=dict(
        max_new_tokens=512,
        return_full_text=False,
    ),
)


chat_model = ChatHuggingFace(llm=llm)


result = chat_model.invoke("写一首赞美秋天的五言绝句。")
print(result.content)

这里我们也是先构建了一个管道,通过上一讲的学习,这个构建管道的过程我们其实并不陌生,无非就是设定模型 ID、模型用途(task)以及其它一些配置参数。虽然从命名上看,我们是在构建一个管道,但这里的 HuggingFacePipeline 是一个 LangChain 的 LLM 类型。

之所以要强调一下这点,是因为这里的用途(task)只能是与文本相关的能力。相比之下,pipeline 里的参数就会丰富很多,比如,图像分类(image-classification)、视频分类(video-classification)。

llm = HuggingFacePipeline.from_model_id(
    model_id="Qwen/Qwen2.5-0.5B-Instruct",
    task="text-generation",
    device=device,
    pipeline_kwargs=dict(
        max_new_tokens=512,
        return_full_text=False,
    ),
)

有了 HuggingFacePipeline,我们再把它转成一个 ChatModel,实际上就是做了一层封装:

chat_model = ChatHuggingFace(llm=llm)

ChatModel 我们之前已经谈了很多,有了 ChatModel,接下来它就可以与我们熟悉的那些 LangChain 抽象配合在一起了。在我们的示例里,我们就是直接调用它。

result = chat_model.invoke("写一首赞美秋天的五言绝句。")
print(result.content)

前面我们说过,在 LangChain 的体系下,有 ChatModel 和 LLM 两种抽象都可以处理大模型。我们这里定义出的 HuggingFacePipeline 就是 LLM,它也完全可以拿过来单独使用。

llm.invoke("写一首赞美秋天的五言绝句。")

在我写下这段文字的时候,langchain-huggingface 这个包的发布时间并不算很长,实现上还有一些不够完善的地方。比如,ChatHuggingFace 的流式应答支持得就不算特别好。在 langchain-community 这个包里,还有一个旧版的 ChatHuggingFace,它本身提供了流的支持,只不过,它需要与旧的一套代码配合使用,而这套代码都处于被舍弃的状态(Deprecated)。

虽然我们可以在代码中支持不同模型的封装,但其实我们还有另外一种选择,就是采用集中接入的方案,彻底摆脱在代码中集成模型。

使用集中接入

无论是直接使用 Hugging Face 的 API,还是使用 LangChain 的 Hugging Face 封装,我们都是把接入管理在自己的代码里。在第 17 讲中,我们介绍了集中接入的工程实践,主要目的就是把接入复杂度从代码里拿出去,放到大模型代理中。除了接入 OpenAI API 之外,接入不同的模型也是一种接入,显然,它也可以放到大模型代理去处理。

我们继续以 One-API 为例。在创建新渠道的时候,类型是有很多选项的,它决定着后端会接入到哪个供应商的模型上。其中的一个选项是 Ollama:

Ollama 是什么呢?它是一个可以在本地运行大模型的轻量级框架。同我们在本地运行代码访问大模型类似,它可以在本地启动一个服务,我们可以通过这个服务去使用相应的大模型。类似的东西也有不少,比如 vllmgpt4all 等。

有一个运行在本地的大模型,我们就可以做很多的事情了。比如,搭建一个属于自己的聊天机器人,尝试不同的大模型,还有一些新的 AI 编码工具,也是可以接入到本地的大模型。单纯从一个用户的角度,我也推荐每个程序员尝试着在本地运行大模型,做一些不同的事情,它会加深你对大模型的理解。

站在开发的角度,运行在本地的大模型,也就意味着我们可以做私有的部署。我们前面提到的几个本地运行大模型的工具,都提供了服务部署的能力,我们完全可以把它部署到自己的服务器上,通过接口去访问相应的模型,而且,这些工具都提供了 OpenAI API 兼容接口,这使得它们可以与市面上的很多工具配合到一起。

下面我就以 Ollama 为例,介绍一下基本的用法。安装 Ollama 只要找到对应的安装包即可,如果是 Linux,我们可以通过命令行进行安装:

curl -fsSL https://ollama.com/install.sh | sh

理解 Ollama 的使用,可以类比于 Docker,所以,在 Ollama 的命令中,我们会看到 pull、push、run 等命令。要想使用大模型,我们首先要把大模型拉到本地:

ollama pull qwen2.5

同一个模型会有多个不同的版本,比如,通义千问 2.5 就有 0.5B、1.5B、3B、7B、14B、32B、72B 等不同规模的版本。即便是同一个规模,还会有不同配置的版本。在 Ollama 中,这些不同的版本是通过 Tag 区分的,比如,如果我们想使用 0.5B 版本的,可以这样拉取。

ollama pull qwen2.5:0.5b

如果想做一些简单的测试,我们可以直接在本地把它运行起来。

ollama run qwen2.5

启动之后,就是一个命令行版的对话框,对于程序员来说,这就比较熟悉了。

>>> 写一首诗
春风吹绿江南岸,芳草萋萋野花开。
千帆过尽江心月,独坐闲庭听流水。

风送花香满庭院,鸟语花香醉晚晴。
时光荏苒如白驹,岁月静好待人来。

启动 Ollama 实际上是启动了一个服务,所以,我们也可以通过 API 访问这个服务。Ollama 提供了两类 API,一类是它自身定义的 API,另一类就是 OpenAI 兼容 API。下面就是通过它自身 API 访问服务的示例。

curl http://127.0.0.1:11434/api/chat -d '{
  "model": "qwen2.5",
  "messages": [
    {
      "model": "qwen2.5","prompt": "写一首关于AI的诗"
    }
  ]
}'

有很多 AI 工具都提供了配置本地服务的能力,我们完全可以通过 Ollama 用一个本地模型来辅助我们工作。有了本地模型,我们可以节省大模型的使用成本,也可以保证自己的数据不外流。下面是一个辅助开发的工具 Cline (也就是曾经的 Claude Dev)的配置界面,我们就可以配置 Ollama 提供服务:

你现在知道了,既然 Ollama 提供了服务,One API 当然可以通过服务接口连接它。配置Ollama 服务,主要是根据自己的需要配置所需的模型。

我们可以通过 list 命令查看已经安装的模型。

ollama list

NAME                                               ID              SIZE      MODIFIED
qwen2.5:0.5b                                       a8b0c5157701    397 MB    16 hours ago
qwen2.5-coder:32b                                  4bd6cbf2d094    19 GB     2 days ago
qwen2.5:latest                                     845dbda0ea48    4.7 GB    7 days ago
llama3.2:latest                                    a80c4f17acd5    2.0 GB    8 days ago

在 One API 中填写的就是这里的 NAME 字段,比如,我们在配置中添加了 qwen2.5:0.5b。配置好之后,我们就可以在代码中直接指定模型名为 qwen2.5:0.5b。

completion = client.chat.completions.create(
      model="qwen2.5:0.5b",
      messages=self.messages,
      temperature=0
)

你看到了,这里我们用到 OpenAI 的程序库,但我在这里指定的模型是 qwen2.5:0.5b,并不是 OpenAI 提供的模型。这也是我们集中接入采用 OpenAI 兼容 API 的意义所在。我们在代码层面上,不用考虑模型的差异,因为集中接入层做了这层封装,把不同的供应商屏蔽了,从而保证了我们代码的稳定性。

顺便说一下,Ollama 本身也提供了一个程序库,LangChain 也提供了 Ollama 的封装。如果有需要,可以自行查看。

细心的同学可能发现了,我们在讨论 Ollama 的过程中,并没有提到 Hugging Face。Ollama 相当于本身提供了一个仓库,我们是从 Ollama 的仓库里拉取的模型。但说到模型的丰富程度,肯定是 Hugging Face 更胜一筹的。我们可以使用 Hugging Face 的模型吗?答案是可以。

在 Ollama 上使用模型,运行的命令是后面这样。

ollama run hf.co/{username}/{repository}

不过,有一点要说明一下,并不是所有的模型都可以使用 Ollama 运行的。为了确认这一点,你可以在模型的说明页上查看一下。点击 “Use this model”,如果下拉菜单中有 Ollama,那就是可以使用,你可以复制相应的命令去执行;否则,这个模型可能无法直接使用。

下图我提供了一个示例。

图片

总结时刻

这一讲,我们讲了在工程上如何使用开源模型。为了让不同的大模型协调一致,我们需要一层封装,保证代码的灵活性。我们讲了两种封装方案:

  • 在代码中封装,主要是讲了 LangChain 的封装。
  • 采用集中接入,也就是在大模型代理中接入不同的模型。

LangChain 的核心抽象中的模型主要就是解决这个问题的。如果想集成 Hugging Face 的模型,我们只要引入 langchain-huggingface 这个包。它提供了各种模型的实现,有数据集的实现,还有工具的实现。

集中接入的方案中,我们以 One API 接入 Ollama 为主线讲解了如何使用开源模型。Ollama 本身是一个非常强大的工具。我们可以用它来提供服务,也可以用它在本地运行大模型,给自己的 AI 工具提供后端。

如果今天的内容你只能记住一件事,那请记住,在本地运行大模型,增进对大模型的了解。

思考题

我在这里只介绍了 langchain-huggingface 中大模型部分,我建议你去了解一下 Embeddings、数据集和工具,增加对 Hugging Face 上模型的了解。欢迎在留言区分享你的学习心得。

精选留言(1)
  • 张申傲 👍(1) 💬(0)

    第19讲打卡~

    2025-02-13