LangChain实战(二):环境搭建与Hello World(国内开源模型版)

本文是《LangChain实战课》系列的第二篇,将手把手带你完成基于国内开源大模型的LangChain环境配置,并创建你的第一个LangChain应用。

前言
在上一篇文章中,我们基于openai大模型完成了LangChain环境配置,并创建你的第一个LangChain应用。今天,我们将使用国内免费且开源的大模型(如ChatGLM、Qwen、Baichuan等)替代商业API,从零开始搭建LangChain开发环境,并创建第一个能够与大型语言模型对话的简单应用。

环境准备

Python环境要求
LangChain要求Python 3.8或更高版本。如果你还没有安装Python,请按照以下步骤操作:

检查当前Python版本:

bash
python –version

python3 –version
如果版本低于3.8,请从Python官网下载并安装最新版本。

创建虚拟环境
强烈建议使用虚拟环境来管理Python项目依赖,这样可以避免包冲突问题。

使用venv创建虚拟环境:

bash

创建名为langchain-oss-env的虚拟环境

python -m venv langchain-oss-env

激活虚拟环境

Windows

langchain-oss-envScriptsactivate

macOS/Linux

source langchain-oss-env/bin/activate
激活后,命令行提示符前会出现(langchain-oss-env)标识。

安装LangChain和相关依赖
现在我们来安装LangChain核心库以及开源模型相关的包:

bash

安装LangChain核心库

pip install langchain

安装Transformers库(用于本地模型推理)

pip install transformers

安装加速库

pip install accelerate

安装其他可能需要的库

pip install sentencepiece
pip install protobuf

安装模型下载工具

pip install huggingface_hub

安装环境变量管理工具

pip install python-dotenv

安装常用的数据处理工具

pip install chromadb # 轻量级向量数据库

可选:安装更多文档加载器

pip install pypdf2 # 处理PDF文档
pip install docx2txt # 处理Word文档
选择国内开源大模型
国内有多种优秀的开源大模型可供选择,以下是一些常见选项:

ChatGLM系列(清华大学):ChatGLM-6B、ChatGLM2-6B、ChatGLM3-6B

Qwen系列(阿里巴巴):Qwen-7B、Qwen-14B

Baichuan系列(百川智能):Baichuan-7B、Baichuan-13B

InternLM系列(商汤科技):InternLM-7B、InternLM-20B

本文将使用ChatGLM3-6B作为示例,但代码可以轻松适配其他模型。

编写第一个LangChain程序(开源模型版)
现在让我们来创建第一个简单的LangChain应用,使用国内开源模型实现基本的问答功能。

基础版本:直接调用本地模型
创建文件hello_langchain_oss.py:

python
import os
from dotenv import load_dotenv
from langchain.llms.base import LLM
from transformers import AutoTokenizer, AutoModel
from typing import Any, List, Optional, Dict, Iterator
import torch

加载环境变量

load_dotenv()

class ChatGLM(LLM):
model_name: str = “chatglm3-6b”
tokenizer: Any = None
model: Any = None
device: str = “cuda” if torch.cuda.is_available() else “cpu”


def __init__(self, **kwargs: Any):
    super().__init__(**kwargs)
    self._load_model()

def _load_model(self):
    """加载模型和分词器"""
    print("正在加载模型,这可能需要一些时间...")
    model_path = "THUDM/chatglm3-6b"
    
    # 使用本地模型(如果已下载)
    local_path = os.getenv("CHATGLM_MODEL_PATH")
    if local_path and os.path.exists(local_path):
        model_path = local_path
    
    self.tokenizer = AutoTokenizer.from_pretrained(
        model_path, 
        trust_remote_code=True
    )
    
    self.model = AutoModel.from_pretrained(
        model_path,
        trust_remote_code=True,
        device_map="auto" if self.device == "cuda" else None,
        torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
    )
    
    if self.device == "cuda":
        self.model = self.model.cuda()
    else:
        self.model = self.model.float()
    
    self.model = self.model.eval()
    print("模型加载完成!")

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

def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
    """调用模型生成回复"""
    try:
        # 使用模型的chat方法进行对话
        response, history = self.model.chat(
            self.tokenizer,
            prompt,
            history=[],
            max_length=4096,
            temperature=0.7
        )
        return response
    except Exception as e:
        return f"模型调用出错: {str(e)}"

@property
def _identifying_params(self) -> Dict[str, Any]:
    return {"model_name": self.model_name}

使用ChatGLM模型进行简单问答

llm = ChatGLM()
prompt = “请用一句话解释人工智能是什么?”
response = llm(prompt)

print(“=== 直接调用ChatGLM ===”)
print(f”问题: {prompt}“)
print(f”回答: {response}”)
print()
运行这个程序:

bash
python hello_langchain_oss.py
注意:第一次运行时会下载模型(约12GB),这可能需要较长时间。如果已经有本地模型,可以设置环境变量CHATGLM_MODEL_PATH指向模型目录。

轻量级版本:使用量化模型
如果硬件资源有限,可以使用4位量化版本的模型:

创建文件hello_langchain_oss_quantized.py:

python
import os
from dotenv import load_dotenv
from langchain.llms.base import LLM
from transformers import AutoTokenizer, AutoModel
from typing import Any, List, Optional, Dict, Iterator
import torch

加载环境变量

load_dotenv()

class ChatGLMQuantized(LLM):
model_name: str = “chatglm3-6b-int4”
tokenizer: Any = None
model: Any = None


def __init__(self, **kwargs: Any):
    super().__init__(**kwargs)
    self._load_model()

def _load_model(self):
    """加载量化模型和分词器"""
    print("正在加载量化模型,这可能需要一些时间...")
    model_path = "THUDM/chatglm3-6b-int4"
    
    # 使用本地模型(如果已下载)
    local_path = os.getenv("CHATGLM_QUANTIZED_MODEL_PATH")
    if local_path and os.path.exists(local_path):
        model_path = local_path
    
    self.tokenizer = AutoTokenizer.from_pretrained(
        model_path, 
        trust_remote_code=True
    )
    
    self.model = AutoModel.from_pretrained(
        model_path,
        trust_remote_code=True,
        device_map="auto"
    ).float()  # 量化模型需要转换为float
    
    self.model = self.model.eval()
    print("量化模型加载完成!")

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

def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
    """调用模型生成回复"""
    try:
        response, history = self.model.chat(
            self.tokenizer,
            prompt,
            history=[],
            max_length=2048,
            temperature=0.7
        )
        return response
    except Exception as e:
        return f"模型调用出错: {str(e)}"

@property
def _identifying_params(self) -> Dict[str, Any]:
    return {"model_name": self.model_name}

使用量化版本的ChatGLM模型

llm = ChatGLMQuantized()
prompt = “请用一句话解释机器学习是什么?”
response = llm(prompt)

print(“=== 使用量化版ChatGLM ===”)
print(f”问题: {prompt}“)
print(f”回答: {response}”)
3. 进阶版本:使用提示模板
让我们使用提示模板来改进程序:

创建文件hello_prompt_template_oss.py:

python
import os
from dotenv import load_dotenv
from hello_langchain_oss import ChatGLM
from langchain.prompts import PromptTemplate

加载环境变量

load_dotenv()

初始化ChatGLM模型

llm = ChatGLM()

创建提示模板

template = “””
你是一个{role}。请用{style}的风格回答以下问题:

问题:{question}

回答:
“””

prompt_template = PromptTemplate(
input_variables=[“role”, “style”, “question”],
template=template
)

填充模板并生成回答

filled_prompt = prompt_template.format(
role=“AI专家”,
style=“简洁明了”,
question=“Transformer模型在自然语言处理中为什么如此重要?”
)

response = llm(filled_prompt)

print(“=== 使用提示模板 ===”)
print(“生成的提示:”)
print(filled_prompt)
print(“
模型的回答:”)
print(response)
4. 完整示例:简单的本地问答机器人
让我们创建一个更完整的示例,模拟简单的对话交互:

创建文件simple_oss_chatbot.py:

python
import os
from dotenv import load_dotenv
from hello_langchain_oss import ChatGLM
from langchain.schema import HumanMessage
from langchain.prompts import PromptTemplate

加载环境变量

load_dotenv()

class SimpleOSSChatbot:
def init(self):
# 初始化ChatGLM模型
self.llm = ChatGLM()


    # 创建系统提示模板
    self.system_template = """
    你是一个有帮助的AI助手。你的回答应该:
    1. 简洁明了,切中要点
    2. 友好且专业
    3. 如果遇到不知道的问题,诚实地承认
    
    当前对话:
    {history}
    
    用户问题:{input}
    
    请回答:
    """
    
    self.prompt_template = PromptTemplate(
        input_variables=["history", "input"],
        template=self.system_template
    )
    
    # 对话历史
    self.history = []

def chat(self, user_input):
    # 构建提示
    formatted_prompt = self.prompt_template.format(
        history="
".join(self.history[-6:]) if self.history else "无",
        input=user_input
    )
    
    # 获取模型回复
    response = self.llm(formatted_prompt)
    
    # 更新历史
    self.history.append(f"用户: {user_input}")
    self.history.append(f"AI: {response}")
    
    # 保持历史长度
    if len(self.history) > 10:
        self.history = self.history[-10:]
    
    return response

def run(self):
    print("欢迎使用SimpleOSSChatbot!输入'退出'来结束对话。")
    print("=" * 50)
    
    while True:
        user_input = input("
你: ")
        
        if user_input.lower() in ['退出', 'exit', 'quit']:
            print("AI: 再见!期待下次对话。")
            break
        
        try:
            response = self.chat(user_input)
            print(f"AI: {response}")
        except Exception as e:
            print(f"抱歉,出了点问题: {e}")

运行聊天机器人

if name == “main”:
load_dotenv()
bot = SimpleOSSChatbot()
bot.run()
运行这个聊天机器人:

bash
python simple_oss_chatbot.py
现在你可以与本地AI进行真正的对话了!

使用其他开源模型
如果你想使用其他开源模型,如Qwen或Baichuan,只需修改模型加载部分:

Qwen示例:
python
from transformers import AutoTokenizer, AutoModelForCausalLM

class QwenLLM(LLM):
model_name: str = “Qwen/Qwen-7B-Chat”
tokenizer: Any = None
model: Any = None


def _load_model(self):
    print("正在加载Qwen模型...")
    model_path = "Qwen/Qwen-7B-Chat"
    
    self.tokenizer = AutoTokenizer.from_pretrained(
        model_path, 
        trust_remote_code=True
    )
    
    self.model = AutoModelForCausalLM.from_pretrained(
        model_path,
        trust_remote_code=True,
        device_map="auto",
        torch_dtype=torch.float16
    ).eval()
    
    print("Qwen模型加载完成!")

def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
    messages = [
        {"role": "user", "content": prompt}
    ]
    
    text = self.tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True
    )
    
    model_inputs = self.tokenizer([text], return_tensors="pt").to(self.model.device)
    
    generated_ids = self.model.generate(
        **model_inputs,
        max_new_tokens=512,
        temperature=0.7,
        do_sample=True
    )
    
    generated_ids = [
        output_ids[len(input_ids):] for input_ids, output_ids in zip(
            model_inputs.input_ids, generated_ids
        )
    ]
    
    response = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
    return response

Baichuan示例:
python
from transformers import AutoTokenizer, AutoModelForCausalLM

class BaichuanLLM(LLM):
model_name: str = “baichuan-inc/Baichuan2-7B-Chat”
tokenizer: Any = None
model: Any = None


def _load_model(self):
    print("正在加载Baichuan模型...")
    model_path = "baichuan-inc/Baichuan2-7B-Chat"
    
    self.tokenizer = AutoTokenizer.from_pretrained(
        model_path, 
        trust_remote_code=True
    )
    
    self.model = AutoModelForCausalLM.from_pretrained(
        model_path,
        trust_remote_code=True,
        device_map="auto",
        torch_dtype=torch.float16
    ).eval()
    
    print("Baichuan模型加载完成!")

def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
    messages = [
        {"role": "user", "content": prompt}
    ]
    
    input_ids = self.tokenizer.apply_chat_template(
        messages,
        return_tensors="pt"
    ).to(self.model.device)
    
    outputs = self.model.generate(
        input_ids,
        max_new_tokens=512,
        temperature=0.7,
        do_sample=True
    )
    
    response = self.tokenizer.decode(
        outputs[0][input_ids.shape[1]:], 
        skip_special_tokens=True
    )
    
    return response

常见问题解答
Q1: 模型下载太慢怎么办?
A: 可以使用国内镜像源加速下载:

使用HF Mirror: export HF_ENDPOINT=https://hf-mirror.com

使用ModelScope: 从ModelScope下载模型

Q2: 内存不足怎么办?
A:

使用量化版本的模型(如chatglm3-6b-int4)

使用更小的模型(如ChatGLM-6B或Qwen-7B)

使用CPU模式运行(速度较慢)

Q3: 如何加速模型推理?
A:

使用GPU运行(需要CUDA兼容的显卡)

使用量化版本的模型

使用vLLM等高性能推理引擎

Q4: 如何减少显存使用?
A:

使用4位或8位量化

使用梯度检查点(gradient checkpointing)

使用模型并行或张量并行

总结
恭喜!你已经成功完成了:

✅ 搭建了基于国内开源模型的LangChain开发环境

✅ 下载并加载了ChatGLM等开源模型

✅ 创建了自定义的LLM类来集成开源模型

✅ 使用了提示模板来规范化输入

✅ 构建了简单的交互式本地聊天机器人

这只是一个开始,但已经涵盖了LangChain与开源模型集成的基础知识。在接下来的文章中,我们将深入探讨更多高级功能,包括更复杂的提示工程和输出解析技术。

下一步学习建议
尝试不同的开源模型(Qwen、Baichuan等),比较它们的表现

探索模型量化技术,优化内存使用和推理速度

尝试将开源模型与其他LangChain组件(如记忆、代理等)结合使用

欢迎在评论区分享你的体验! 你在开源模型环境搭建过程中遇到了什么问题?你的第一个LangChain程序运行成功了吗?如果有任何疑问,欢迎在评论区留言,我们会尽力解答。

下一篇预告:《LangChain实战:深入理解Model I/O – Prompts模板》 – 我们将深入探讨LangChain的提示模板功能,学习如何创建更复杂和高效的提示工程。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容