• 微信:WANCOME
  • 扫码加微信,提供专业咨询
  • 服务热线
  • 13215191218
    13027920428

  • 微信扫码访问本页
LangGraph加载本地模型
LangGraph加载本地HuggingFace模型指南

如何在 LangGraph 中加载和使用 HuggingFace 下载的本地 LLM 模型?

问题分析

LangGraph 作为 LangChain 生态中的状态管理框架,其核心设计围绕图结构的状态流转。然而,在实际部署场景中,开发者往往已经通过 HuggingFace CLI 或镜像站下载了大型模型文件(如 Llama、Qwen、Mistral 等),存储在本地磁盘。直接调用 LangGraph 的默认接口时,框架会尝试从远程仓库重新拉取模型,这不仅浪费带宽,在某些网络受限的环境下更是无法完成。

问题的本质在于:LangGraph 本身不直接处理模型加载逻辑,它依赖 LangChain 的 LLM 抽象层。因此,正确路径是通过 LangChain 的自定义 LLM 包装器或 HuggingFace Pipeline 集成来桥接本地模型,再将该组件注入 LangGraph 的节点执行逻辑中。

此外,本地模型存在多种格式(PyTorch .bin、Safetensors .safetensors、GGUF 等),不同格式对应的加载方式各异。PyTorch 格式需要 transformers 库,GGUF 格式需要 llama-cpp-python,量化模型需要 bitsandbytesauto-gptq。理解这些差异是解决问题的前提。

解决原理

LangGraph 的架构采用消息传递模式,节点(Node)是状态转换的基本单元。每个节点接收当前状态,执行业务逻辑,返回状态更新。当我们在 LangGraph 中使用 LLM 时,实际上是在某个节点中调用 LLM 推理。

要将本地 HuggingFace 模型接入 LangGraph,核心步骤有三:

  1. 模型实例化:使用 transformers 库的 AutoModelForCausalLMAutoTokenizer 从本地路径加载模型权重和分词器。指定 local_files_only=True 确保不触发网络请求。
  2. LangChain 适配:将原生 transformers 对象包装为 LangChain 兼容的 LLM 实例。LangChain 提供了 HuggingFacePipelineHuggingFaceHub 两种方式,前者适合本地推理,后者适合远程 API。本地场景选择 HuggingFacePipeline
  3. LangGraph 集成:将 LangChain LLM 实例注入 LangGraph 节点的执行函数中。节点函数通过状态对象获取输入,调用 LLM 生成响应,将结果写入状态的输出字段。

关于硬件加速,如果本地有 NVIDIA GPU,加载时应指定 device_map="auto"accelerate 库自动分配设备。对于显存不足的场景,可以使用 load_in_8bit=Trueload_in_4bit=True 进行量化加载,但这需要 bitsandbytes 库支持。Windows 平台的 CUDA 支持相对复杂,需要确保 PyTorch 版本与 CUDA 版本匹配。

程序实现与说明

# 导入必要的库
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from langchain_community.llms import HuggingFacePipeline
from langgraph.graph import StateGraph, MessagesState
from typing import TypedDict, Annotated
import torch

# 定义状态结构,继承 MessagesState 获得消息历史管理能力
class GraphState(TypedDict):
    # 用户输入的提示词
    prompt: str
    # 模型生成的响应
    response: str
    # 消息历史(LangGraph 内置类型)
    messages: Annotated[list, "add_messages"]

# 第一步:从本地路径加载模型
# 假设模型已下载到 D:\models\Qwen2-7B-Instruct
model_path = r"D:\models\Qwen2-7B-Instruct"

# 加载分词器,local_files_only=True 强制本地加载
tokenizer = AutoTokenizer.from_pretrained(
    model_path,
    local_files_only=True,  # 禁止联网下载
    trust_remote_code=False  # 安全考虑,不执行远程代码
)

# 加载模型,指定自动设备映射(GPU 优先)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    local_files_only=True,
    device_map="auto",  # 自动选择 GPU 或 CPU
    torch_dtype=torch.float16,  # 使用半精度减少显存占用
    trust_remote_code=False
)

# 第二步:创建 transformers pipeline
# pipeline 是 transformers 的高层接口,简化推理调用
text_generation_pipeline = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
    max_new_tokens=512,  # 生成最大 token 数
    temperature=0.7,  # 控制随机性,越低越确定
    do_sample=True,  # 启用采样生成
    pad_token_id=tokenizer.eos_token_id  # 避免警告
)

# 第三步:包装为 LangChain LLM 实例
# HuggingFacePipeline 将 pipeline 转换为 LangChain 兼容接口
llm = HuggingFacePipeline(
    pipeline=text_generation_pipeline,
    # pipeline_kwargs 可传递额外的生成参数
    pipeline_kwargs={"max_new_tokens": 512}
)

# 第四步:定义 LangGraph 节点函数
# 节点函数接收状态,返回状态更新(字典形式)
def generate_response(state: GraphState) -> dict:
    """
    核心推理节点:调用本地 LLM 生成响应
    """
    # 从状态中提取用户提示词
    user_prompt = state.get("prompt", "")
    
    # 调用 LangChain LLM 实例的 invoke 方法
    # invoke 返回 AIMessage 对象,content 属性为文本内容
    response_message = llm.invoke(user_prompt)
    
    # 返回状态更新字典,LangGraph 会合并到总状态
    return {
        "response": response_message,
        "messages": [{"role": "assistant", "content": response_message}]
    }

# 第五步:构建 LangGraph 图结构
# StateGraph 管理状态在各节点间的流转
workflow = StateGraph(GraphState)

# 添加节点,第一个参数是节点 ID,第二个是执行函数
workflow.add_node("generate", generate_response)

# 设置入口点,图从这里开始执行
workflow.set_entry_point("generate")

# 设置终点,图在这里结束
workflow.set_finish_point("generate")

# 第六步:编译图
# 编译后的图可以执行 invoke 或 stream
app = workflow.compile()

# 第七步:运行测试
if __name__ == "__main__":
    # 构造初始状态
    initial_state = {
        "prompt": "请用一句话解释什么是 LangGraph。",
        "messages": []
    }
    
    # 执行图,invoke 返回最终状态
    final_state = app.invoke(initial_state)
    
    # 打印结果
    print("=" * 50)
    print("用户输入:", initial_state["prompt"])
    print("=" * 50)
    print("模型响应:", final_state["response"])
    print("=" * 50)

关键代码行解析

代码说明
local_files_only=True这是解决问题的核心参数,强制 transformers 库仅从本地磁盘加载,不发起任何网络请求。如果本地文件缺失,会抛出 OSError 而非静默下载。
device_map="auto"利用 HuggingFace 的 accelerate 库自动分配模型层到不同设备。在单 GPU 场景下会将整个模型放入 GPU;多 GPU 场景下会切分模型层;无 GPU 场景下回退到 CPU。
torch_dtype=torch.float16现代 GPU(如 RTX 30/40 系列)对 FP16 有硬件加速,相比 FP32 可节省约一半显存,推理速度也有提升。但注意某些旧模型可能需要 FP32。
HuggingFacePipeline(pipeline=...)LangChain 的适配层。它实现了 BaseLLM 接口,提供 invokebatchstream 等统一方法,使 LangGraph 可以像操作 OpenAI API 一样操作本地模型。
StateGraph(GraphState)LangGraph 的核心类。泛型参数 GraphState 定义了图的状态结构,LangGraph 会基于此进行状态校验和类型推断。
workflow.add_node("generate", generate_response)注册节点。节点 ID 字符串用于定义边(edge),节点函数实现具体逻辑。一个图可以有多个节点,通过边连接形成流程。
app.invoke(initial_state)同步执行图。对于需要流式输出的场景,可使用 app.stream(initial_state) 获取生成器。

注意事项

  1. 模型路径中避免使用中文或特殊字符,Windows 路径使用原始字符串(r"...")或双反斜杠。
  2. 首次加载时,device_map="auto" 会执行模型分层分析,大模型可能耗时数分钟。可预先运行 accelerate launch 或在代码中缓存 device_map 结果。
  3. 如果遇到 CUDA 相关错误,检查 PyTorch 版本与 CUDA 版本是否匹配。使用 torch.cuda.is_available() 验证 GPU 可用性。
  4. 对于 GGUF 格式模型(如从 TheBloke 下载),需要使用 llama-cpp-python 库,通过 LlamaCpp 类加载,而非 transformers 的 AutoModelForCausalLM
  5. 生产环境建议添加异常处理,捕获 torch.cuda.OutOfMemoryError 并提供降级方案(如切换到 CPU 或更小模型)。