文章目录
前言
langchain的手册里只有使用在线openai接口这一个例子,实际运用中我们大部分还是要用本地的大模型的。所以我们一起尝试写一写,练一练
一、如何替代掉openai呢
替掉openai的关键是根据我们所使用的模型的具体调用方式来实现 generate
方法。LangChain
框架为我们提供了一个通用接口,我们需要根据不同模型的特点和 API 来重写这个接口中的方法,以便能够正确调用本地模型并生成所需的输出。
先看具体步骤
- 定义模型类:创建一个继承自
LangChain
的BaseLLM
类,并根据所使用的本地模型重写generate
方法。- 加载模型和分词器:在模型类的初始化方法中加载你想要使用的本地模型和分词器。
- 实现生成方法:在
generate
方法中,处理输入文本并调用模型的生成函数,返回生成的文本。- 构建管道:使用定义好的模型类和生成方法,构建从用户输入到输出的处理管道。
1. 定义模型类
我们以 GPT-2 为例,定义一个调用本地 GPT-2 模型的 LocalGPT2LLM
类:
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
from langchain.llms import BaseLLM
class LocalGPT2LLM(BaseLLM):
def __init__(self, model_name='gpt2', device='cpu'):
self.tokenizer = GPT2Tokenizer.from_pretrained(model_name)
self.model = GPT2LMHeadModel.from_pretrained(model_name).to(device)
self.device = device
def generate(self, prompt, max_length=50, temperature=0.7):
inputs = self.tokenizer(prompt, return_tensors='pt').to(self.device)
with torch.no_grad():
outputs = self.model.generate(
inputs.input_ids,
max_length=max_length,
temperature=temperature,
pad_token_id=self.tokenizer.eos_token_id
)
return self.tokenizer.decode(outputs[0], skip_special_tokens=True)
2. 构建处理管道
创建一个简单的管道类,整合模型的调用过程:
class NLPipeline:
def __init__(self, llm):
self.llm = llm
def process(self, user_input):
response = self.llm.generate(user_input)
return response
3. 测试与应用
初始化模型和管道,并进行测试:
# 初始化本地模型
local_gpt2_llm = LocalGPT2LLM(device='cuda' if torch.cuda.is_available() else 'cpu')
# 创建 NLP 管道
pipeline = NLPipeline(local_gpt2_llm)
# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."
# 处理用户输入并生成输出
output = pipeline.process(user_input)
print(f"Output: {output}")
4. 扩展支持其他模型
为了支持其他模型(例如 BERT 进行嵌入和 GPT-3 进行生成),可以类似地定义模型类并重写 generate
方法。这里我们以 BERT 嵌入和 GPT-3 生成的组合为例:
from transformers import BertModel, BertTokenizer
import openai
class BERTEmbedder:
def __init__(self, model_name='bert-base-uncased'):
self.tokenizer = BertTokenizer.from_pretrained(model_name)
self.model = BertModel.from_pretrained(model_name)
def embed(self, text):
inputs = self.tokenizer(text, return_tensors='pt')
with torch.no_grad():
outputs = self.model(**inputs)
return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
class GPT3LLM(BaseLLM):
def __init__(self, temperature=0.7, max_tokens=150):
self.temperature = temperature
self.max_tokens = max_tokens
def generate(self, prompt):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
temperature=self.temperature,
max_tokens=self.max_tokens
)
return response.choices[0].text.strip()
# 创建和组合模型
bert_embedder = BERTEmbedder()
gpt3_llm = GPT3LLM()
# 定义组合的管道
class CombinedNLPipeline:
def __init__(self, embedder, llm):
self.embedder = embedder
self.llm = llm
def process(self, user_input):
# 生成嵌入向量
embedding = self.embedder.embed(user_input)
prompt = f"User input embedding: {embedding}\nGenerate response:"
# 使用 GPT-3 生成输出
response = self.llm.generate(prompt)
return response
# 创建组合管道
combined_pipeline = CombinedNLPipeline(bert_embedder, gpt3_llm)
# 测试输入
user_input = "The quick brown fox jumps over the lazy dog."
output = combined_pipeline.process(user_input)
print(f"Output: {output}")
5. 小结
通过这种方法,可以灵活地集成各种本地模型,并将其与 LangChain 框架结合,构建复杂的自然语言处理管道。根据不同的模型和需求,重写 generate
方法,实现多样化的处理和生成任务。
二、怎么用langchain自带的管道符
LangChain
提供了 LLMChain
类,可以更方便地将不同的模型和步骤组合在一起。下面是如何使用 LLMChain
来替代 CombinedNLPipeline
,将 BERT 用于嵌入,GPT-3 用于生成的示例。
1. 安装必要的库
确保你已经安装了所需的库:
pip install transformers openai langchain
2. 定义 BERT 嵌入和 GPT-3 生成模型类
首先,定义用于生成嵌入的 BERT 模型类和用于生成文本的 GPT-3 模型类:
from transformers import BertModel, BertTokenizer
import openai
import torch
from langchain.llms import BaseLLM
# 定义 BERT 嵌入模型类
class BERTEmbedder:
def __init__(self, model_name='bert-base-uncased'):
self.tokenizer = BertTokenizer.from_pretrained(model_name)
self.model = BertModel.from_pretrained(model_name)
def embed(self, text):
inputs = self.tokenizer(text, return_tensors='pt')
with torch.no_grad():
outputs = self.model(**inputs)
return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
# 定义 GPT-3 生成模型类
class GPT3LLM(BaseLLM):
def __init__(self, temperature=0.7, max_tokens=150):
self.temperature = temperature
self.max_tokens = max_tokens
def generate(self, prompt):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
temperature=self.temperature,
max_tokens=self.max_tokens
)
return response.choices[0].text.strip()
3. 使用 LangChain 的 LLMChain
接下来,使用 LangChain 的 LLMChain
类来替代手动定义的管道类。
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.embeddings import Embeddings
# 定义一个模板,将 BERT 的嵌入作为 GPT-3 的输入
prompt_template = PromptTemplate(
template="User input embedding: {embedding}\nGenerate response:",
input_variables=["embedding"]
)
# 实现一个嵌入模型类,用于在 LLMChain 中使用
class EmbeddingsWrapper(Embeddings):
def __init__(self, embedder):
self.embedder = embedder
def embed(self, text):
return self.embedder.embed(text)
# 初始化 BERT 嵌入模型和 GPT-3 生成模型
bert_embedder = BERTEmbedder()
gpt3_llm = GPT3LLM()
# 包装 BERT 嵌入模型
embedding_wrapper = EmbeddingsWrapper(bert_embedder)
# 创建 LLMChain
llm_chain = LLMChain(
prompt_template=prompt_template,
llm=gpt3_llm,
embeddings=embedding_wrapper
)
# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."
# 处理用户输入并生成输出
embedding = bert_embedder.embed(user_input)
output = llm_chain.run({"embedding": embedding})
print(f"Output: {output}")
4. 解释
- BERTEmbedder 类:用于生成 BERT 嵌入。
- GPT3LLM 类:用于调用 GPT-3 生成文本。
- PromptTemplate:定义了 GPT-3 的提示模板,包含 BERT 生成的嵌入。
- EmbeddingsWrapper 类:用于将 BERT 嵌入模型包装为 LangChain 的嵌入接口。
- LLMChain:将 BERT 嵌入模型和 GPT-3 生成模型组合在一起,形成一个完整的处理管道。
5. 使用注意事项
- 输入变量:确保
PromptTemplate
中的input_variables
与实际输入变量匹配。 - 模型配置:根据需要调整 GPT-3 和 BERT 模型的配置,如
temperature
和max_tokens
。
通过这种方式,使用 LangChain
的 LLMChain
类,可以更简洁地实现复杂的模型组合,简化代码结构,并提高可读性和维护性。
三、怎么才能用绝对地址引入本地模型呢
transformers
库支持从本地路径加载模型和分词器。只需要将 model_name
替换为模型和分词器所在的本地目录的绝对路径即可。
1. 使用本地模型路径的示例
假设你已经将 BERT 模型和分词器下载到本地目录 /path/to/local/bert-model
,你可以这样进行修改:
from transformers import BertModel, BertTokenizer
import openai
import torch
from langchain.llms import BaseLLM
# 定义 BERT 嵌入模型类
class BERTEmbedder:
def __init__(self, model_path='/path/to/local/bert-model'):
self.tokenizer = BertTokenizer.from_pretrained(model_path)
self.model = BertModel.from_pretrained(model_path)
def embed(self, text):
inputs = self.tokenizer(text, return_tensors='pt')
with torch.no_grad():
outputs = self.model(**inputs)
return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()
# 定义 GPT-3 生成模型类
class GPT3LLM(BaseLLM):
def __init__(self, temperature=0.7, max_tokens=150):
self.temperature = temperature
self.max_tokens = max_tokens
def generate(self, prompt):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
temperature=self.temperature,
max_tokens=self.max_tokens
)
return response.choices[0].text.strip()
2. 组合使用 LangChain 的 LLMChain
下面是如何使用 LangChain 的 LLMChain
类,结合本地的 BERT 模型和 GPT-3:
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.embeddings import Embeddings
# 定义一个模板,将 BERT 的嵌入作为 GPT-3 的输入
prompt_template = PromptTemplate(
template="User input embedding: {embedding}\nGenerate response:",
input_variables=["embedding"]
)
# 实现一个嵌入模型类,用于在 LLMChain 中使用
class EmbeddingsWrapper(Embeddings):
def __init__(self, embedder):
self.embedder = embedder
def embed(self, text):
return self.embedder.embed(text)
# 初始化本地 BERT 嵌入模型和 GPT-3 生成模型
bert_embedder = BERTEmbedder(model_path='/path/to/local/bert-model')
gpt3_llm = GPT3LLM()
# 包装 BERT 嵌入模型
embedding_wrapper = EmbeddingsWrapper(bert_embedder)
# 创建 LLMChain
llm_chain = LLMChain(
prompt_template=prompt_template,
llm=gpt3_llm,
embeddings=embedding_wrapper
)
# 用户输入
user_input = "The quick brown fox jumps over the lazy dog."
# 处理用户输入并生成输出
embedding = bert_embedder.embed(user_input)
output = llm_chain.run({"embedding": embedding})
print(f"Output: {output}")
3. 解释
- model_path:将模型路径从预训练模型名称替换为本地目录的绝对路径。
- BERTEmbedder 类:加载本地路径中的 BERT 模型和分词器。
- LLMChain:与之前相同,定义一个 LangChain 的
LLMChain
,用于将 BERT 嵌入和 GPT-3 生成结合起来。
通过这种方式,你可以方便地使用本地存储的模型文件,避免了每次使用时都需要从互联网下载模型文件。这样不仅可以节省时间,还可以在没有互联网连接的环境中使用模型。
总结
以上我们用三个章节介绍了如何调用本地模型,如何使用langchain自带的管道方法,以及如何从绝对地址来调用模型。 大家可以清晰的在各段代码里看到改变,可以尝试自己使用自己的方法。