当前位置: 首页 > news >正文

(二)使用 LangChain 搭建本地大模型 RAG 问答应用

上一篇博客介绍了在 Hailo-10 上实现语音识别应用,这次我们来聊聊它的另一个重要功能:本地大模型推理。当然如果只是做离线对话的话,应用场景可能比较有限,下面结合 LangChain 实现一个简单的 RAG 应用。设备仍然使用之前介绍的 ASUS UGen300。

1

环境配置
与音频模型只能在 Linux 上运行不同,本地大模型推理可以在 Windows 上实现。这里是在安装了 Raspberry Pi OS 的 Raspberry Pi 5 上实现的。

安装 HailoRT
首先要安装 HailoRT,这是 Hailo 的运行时库,包含设备驱动、Python 绑定、命令行工具。可以去 Hailo Developer Zone 注册账号下载,也可以在 ASUS 的官网下载。详细步骤见上一篇博客,张高兴的 Hailo-10 开发指南:(一)实现离线语音识别。

安装 Hailo-Ollama
Hailo-Ollama 是 Hailo 官方提供的推理服务,API 和 Ollama 完全兼容,意味着能用 Ollama 的工具(LangChain、Open-WebUI 等)基本都能直接使用。在安装完 ASUS 的驱动捆绑包之后,Hailo-Ollama 也已经安装完成。如果你的 Hailo-10 是 M.2 版本的,可能需要单独安装 Hailo-Ollama,在 Hailo Developer Zone 中下载安装 Hailo Model Zoo GenAI。

2

Python 环境
pip install pdfplumber langchain langchain-ollama langchain-text-splitters
langchain-chroma langchain-huggingface sentence-transformers
chromadb requests
启动 Hailo-Ollama 服务
服务启动很简单,直接在命令行中运行下面的命令,默认监听 0.0.0.0:8000。

hailo-ollama
下面看看 Hailo-10 目前支持哪些模型:

curl --silent http://localhost:8000/hailo/v1/list
可以看到目前支持 deepseek_r1:1.5b、llama3.2:1b、qwen2.5-coder:1.5b、qwen2.5:1.5b、qwen2:1.5b、qwen3:1.7b 这些模型。执行下面的命令拉取 qwen3:1.7b 模型:

curl --silent http://localhost:8000/api/pull
-H ‘Content-Type: application/json’
-d ‘{ “model”: “qwen3:1.7b”, “stream” : true }’
拉取完成后,验证一下模型是否能正常推理:

curl --silent http://localhost:8000/api/chat
-H ‘Content-Type: application/json’
-d ‘{“model”: “qwen3:1.7b”, “messages”: [{“role”: “user”, “content”: “用一句话解释什么是向量数据库”}]}’
到这里,整个链路就通了。接下来你可以通过调用接口的方式在自己的应用里使用这个模型了,也可以使用支持 Ollama 的工具,比如 Open-WebUI 来和模型进行交互。比如拉取 Open-WebUI 的 Docker 镜像:

docker run -d --net=host -e OLLAMA_BASE_URL=http://127.0.0.1:8000 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
3

实现 RAG 应用
模型本身不会主动知道你公司内部文档里写了什么。RAG 是把文档切碎存进向量数据库,提问时先搜索最相关的段落,再把这些段落塞进 prompt 让模型回答。通过 RAG 模型可以理解一些最新的、专业的知识,而不需要模型本身学会这些知识。比如这里使用的是 ASUS UGen300 的用户手册,模型本身不可能学会里面的内容,但通过 RAG 的方式,模型就能理解用户手册里的内容了。当然你也可以替换成其他的文档完成后面的操作。

4

核心流程很简单:文档处理 → 向量化 → RAG 链路 → 问答。下面新建 rag_demo.py 文件.

  1. 引用相关包
    import json
    import os
    import requests
    from typing import Any, Iterator, List, Optional
    from langchain_core.language_models.chat_models import BaseChatModel
    from langchain_core.messages import (
    AIMessage,
    AIMessageChunk,
    BaseMessage,
    HumanMessage,
    SystemMessage,
    )
    from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult
    from langchain_core.documents import Document
    from langchain_text_splitters import RecursiveCharacterTextSplitter
    from langchain_huggingface import HuggingFaceEmbeddings
    from langchain_chroma import Chroma
    import pdfplumber
  2. PDF 文档处理
    用 pdfplumber 逐页解析 PDF,构造 LangChain Document 对象。

PDF_FILES = [
“data/UGen300-manual.pdf”,
]
all_docs = []

for pdf_path in PDF_FILES:
if not os.path.exists(pdf_path):
print(f" 跳过(不存在):{pdf_path}")
continue
count = 0
with pdfplumber.open(pdf_path) as pdf:
for i, page in enumerate(pdf.pages):
text = (page.extract_text() or “”).strip()
all_docs.append(Document(
page_content=text,
metadata={“source”: pdf_path, “page”: i + 1},
))
count += 1

print(f"共加载 {len(all_docs)} 页文本")
3. 文本切分
文档切分成更小的段落,方便后续的向量化和检索。chunk_size 为每个 chunk 最大字符数,chunk_overlap 让相邻 chunk 共享边界内容,避免关键信息被截断。

splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
)
chunks = splitter.split_documents(all_docs)
print(f"共生成 {len(chunks)} 个 chunk")
4. 向量化和存储
使用 HuggingFaceEmbeddings 生成文本的向量表示,并存储到 ChromaDB。all-MiniLM-L6-v2 是最常用的轻量通用 embedding 模型,速度快,在本地运行,不需要 API key,也不依赖 GPU。ChromaDB 是一个轻量的本地向量数据库,适合小规模数据的存储和检索。

CHROMA_DB_DIR = “./chroma_db”
COLLECTION_NAME = “hailo_docs”

embeddings = HuggingFaceEmbeddings(
model_name=“sentence-transformers/all-MiniLM-L6-v2”,
model_kwargs={“device”: “cpu”},
encode_kwargs={“normalize_embeddings”: True}
)
print(“Embedding 模型就绪”)

db_exists = os.path.exists(CHROMA_DB_DIR) and os.listdir(CHROMA_DB_DIR)

if db_exists:
# 数据库已存在,直接加载
vectorstore = Chroma(
collection_name=COLLECTION_NAME,
embedding_function=embeddings,
persist_directory=CHROMA_DB_DIR,
)
print(f"已加载现有数据库 {CHROMA_DB_DIR}“)
else:
# 首次构建
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
collection_name=COLLECTION_NAME,
persist_directory=CHROMA_DB_DIR,
)
print(f"数据库构建完成,已持久化到 {CHROMA_DB_DIR}”)
5. 自定义 HailoChatOllama 类
Hailo-Ollama 的底层用的是 oatpp HTTP 框架,它对请求体的 JSON 字段类型要求很严。LangChain 官方的 ChatOllama 会往请求里附加 options、keep_alive 等额外字段,oatpp 碰到未知字段直接报类型解析错误。

解决方案是继承 BaseChatModel 自己写一个简化版:

class HailoChatOllama(BaseChatModel):
model: str
base_url: str
timeout: int = 120

@property def _llm_type(self) -> str: return "hailo-ollama" def _to_ollama_messages(self, messages: List[BaseMessage]) -> list: role_map = {"system": "system", "human": "user", "ai": "assistant"} return [ {"role": role_map.get(m.type, m.type), "content": m.content} for m in messages ] def _generate( self, messages: List[BaseMessage], stop: Optional[List[str]] = None, run_manager: Any = None, **kwargs: Any, ) -> ChatResult: payload = { "model": self.model, "messages": self._to_ollama_messages(messages), "stream": False, } resp = requests.post( f"{self.base_url}/api/chat", json=payload, timeout=self.timeout, ) resp.raise_for_status() content = resp.json()["message"]["content"] return ChatResult( generations=[ChatGeneration(message=AIMessage(content=content))] )
http://www.jsqmd.com/news/1159199/

相关文章:

  • 深耕北方草本酿造,复盛公六味地黄酒实力派养生酒品牌
  • Meta Muse Video:原生音频支持的AI视频生成技术解析与应用
  • 北京华恒智信为酒店行业构建员工家属关怀体系,破解员工流失难题
  • 2026年7月最新南京万国官方售后服务网点地址及客服电话一览 - 万国中国官方服务中心
  • ExifToolGui完整指南:3分钟学会免费批量管理照片元数据
  • Coze与Dify实战指南:零基础构建AI应用,从智能体到API集成全解析
  • 做公证的流程?做公证一般有什么用?
  • 直流负载管理优化:继电器选型与PWM控制策略
  • 山东大学2025-2026-2计算机体系结构期末回忆版
  • 游戏AI导航与运动控制优化:从NavMesh参数调优到动态避障实战
  • MCP3551与MKV44F128VLH16高精度数据采集系统设计
  • 跨国多学科研究团队发布深度学习情绪识别综述,开启下一代人机交互的情绪理解能力构建
  • STM32 标准库 GPIO 输入模式详解:上拉/下拉/浮空输入3种配置实测
  • Unreal Engine游戏开发入门:从蓝图到可玩世界的完整实践指南
  • 社保与个税基数不一致的AI检测:数据比对算法与合规预警系统架构
  • 权限请求封装:统一处理Android危险权限与iOS隐私描述(118)
  • LangGraph StateGraph核心原理与生产避坑指南
  • Mac mini 4 DFU刷机为何不能用Windows虚拟机
  • 2026年7月最新爱彼南京雨花万象汇维修保养服务电话 - 爱彼中国官方服务中心
  • GPMall 电商平台高并发实战:Redis缓存与Kafka削峰在3大核心场景的应用
  • Mixtral-8x7B推理瓶颈诊断:PyTorch Profiler与record_function实战指南
  • RT-Thread SMP 多核调度策略解析:全局与局部就绪表的2级任务分发机制
  • RK3568 设备树频率修改实战:从 1992MHz 到 2016MHz 的 2 处关键代码修改
  • MP2315GJ-Z 3A同步降压芯片:从4.5V到24V宽压输入,实测效率超92%
  • 【大数据课程设计/毕业设计】济南文旅大数据归集、分析与可视化平台的设计与实现 基于 Hive 数仓的济南旅游季节趋势分析系统【附源码、数据库、万字文档】
  • 《JACS》香港城市大学团队 单分子尺度下的化学键开关:Captodative自由基的新发现
  • AI直播推流链路的通用技术方案与常见问题排查
  • L9958与PIC18LF47K40组合实现高性能电机控制
  • DisplayPort 1.4 接口引脚定义详解:20针脚功能与5根GND实测分析
  • 2026年7月最新石家庄萧邦官方售后联系电话与客户服务中心网点地址 - 萧邦中国官方服务中心