最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python搭建本地?AI問答系統(tǒng)

 更新時(shí)間:2026年03月24日 08:47:28   作者:我不是呆頭  
這篇文章主要為大家詳細(xì)介紹了如何使用Python從零搭建一個(gè)本地?AI問答系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

想在本地跑一個(gè) AI 問答系統(tǒng)?聽起來很酷,但現(xiàn)實(shí)往往是這樣的:

  • “為什么我的 CUDA 版本和 PyTorch 不兼容?”
  • “為什么 pip install 裝了半天,運(yùn)行時(shí)還是報(bào) ModuleNotFoundError?”
  • “為什么模型加載到一半內(nèi)存就爆了?”

這些問題,90% 的新手都踩過。本文將帶你從零搭建一個(gè)本地 AI 問答系統(tǒng),并系統(tǒng)性地幫你繞開那些"經(jīng)典陷阱"。

一、整體架構(gòu)概覽

在動手之前,先看清楚我們要搭建的是什么:

整個(gè)系統(tǒng)分為三層:

  • 輸入層:用戶問題 + 文本預(yù)處理
  • 檢索層(可選):RAG(檢索增強(qiáng)生成)
  • 推理層:本地 LLM 生成答案

二、新手踩坑分布圖

根據(jù)社區(qū)反饋,新手遇到的問題主要集中在以下幾類:

接下來,我們按照這個(gè)優(yōu)先級,逐一擊破。

三、環(huán)境搭建:最容易翻車的第一步

3.1 用虛擬環(huán)境隔離,別污染全局

新手常見錯(cuò)誤:

pip install torch transformers langchain  # 直接裝到全局

正確做法:用 venvconda 隔離環(huán)境

# 方式一:使用 venv(推薦,Python 內(nèi)置)
python -m venv ai-qa-env
source ai-qa-env/bin/activate        # Linux/macOS
ai-qa-env\Scripts\activate           # Windows
# 方式二:使用 conda
conda create -n ai-qa python=3.11
conda activate ai-qa

為什么要隔離? 不同項(xiàng)目依賴不同版本的庫,全局安裝會導(dǎo)致版本沖突,出了問題極難排查。

3.2 PyTorch 安裝:版本對齊是關(guān)鍵

這是 最高頻的踩坑點(diǎn)。PyTorch 的安裝命令取決于你的 CUDA 版本,不能無腦 pip install torch

第一步:查看你的 CUDA 版本

nvidia-smi  # 查看 GPU 驅(qū)動支持的最高 CUDA 版本
nvcc --version  # 查看已安裝的 CUDA Toolkit 版本

第二步:去官網(wǎng)生成對應(yīng)命令

# CUDA 12.1 對應(yīng)的安裝命令示例
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
# 沒有 GPU,只用 CPU
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

第三步:驗(yàn)證安裝是否成功

import torch

print(f"PyTorch 版本: {torch.__version__}")
print(f"CUDA 是否可用: {torch.cuda.is_available()}")
print(f"GPU 數(shù)量: {torch.cuda.device_count()}")

if torch.cuda.is_available():
    print(f"當(dāng)前 GPU: {torch.cuda.get_device_name(0)}")
    print(f"顯存總量: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB")

3.3 依賴管理:用 requirements.txt 鎖定版本

# 生成當(dāng)前環(huán)境的依賴快照
pip freeze > requirements.txt
# 在新環(huán)境中還原
pip install -r requirements.txt

推薦的 requirements.txt 示例:

torch==2.2.0
transformers==4.38.0
langchain==0.1.9
langchain-community==0.0.24
faiss-cpu==1.7.4
sentence-transformers==2.5.1
ollama==0.1.7
gradio==4.19.2

四、模型下載:別讓網(wǎng)絡(luò)毀了你的心情

4.1 使用 Ollama 管理本地模型(強(qiáng)烈推薦)

Ollama 是目前最省心的本地模型管理工具,一行命令搞定下載和運(yùn)行:

# 安裝 Ollama(macOS/Linux)
curl -fsSL https://ollama.com/install.sh | sh
# 下載并運(yùn)行模型
ollama pull llama3.2        # Meta Llama 3.2 (3B)
ollama pull qwen2.5:7b      # 阿里通義千問 2.5 (7B)
ollama pull deepseek-r1:7b  # DeepSeek R1 (7B)
# 驗(yàn)證模型列表
ollama list

4.2 用 Python 調(diào)用 Ollama

import ollama

def ask_local_llm(question: str, model: str = "qwen2.5:7b") -> str:
    """
    調(diào)用本地 Ollama 模型進(jìn)行問答
    
    Args:
        question: 用戶問題
        model: 模型名稱
    
    Returns:
        模型回答
    """
    response = ollama.chat(
        model=model,
        messages=[
            {
                "role": "system",
                "content": "你是一個(gè)專業(yè)的 AI 助手,請用中文簡潔準(zhǔn)確地回答問題。"
            },
            {
                "role": "user", 
                "content": question
            }
        ]
    )
    return response["message"]["content"]


# 測試
if __name__ == "__main__":
    answer = ask_local_llm("Python 中的 GIL 是什么?")
    print(answer)

五、搭建 RAG 問答系統(tǒng)

RAG(Retrieval-Augmented Generation)是讓 AI 能回答你私有文檔問題的核心技術(shù)。

5.1 RAG 完整流程

5.2 完整代碼實(shí)現(xiàn)

"""
本地 RAG 問答系統(tǒng)
依賴: pip install langchain langchain-community faiss-cpu sentence-transformers ollama
"""

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain.chains import RetrievalQA
from langchain_community.llms import Ollama
import os


class LocalRAGSystem:
    """本地 RAG 問答系統(tǒng)"""

    def __init__(
        self,
        docs_dir: str = "./docs",
        model_name: str = "qwen2.5:7b",
        embedding_model: str = "BAAI/bge-small-zh-v1.5",
        chunk_size: int = 500,
        chunk_overlap: int = 50,
    ):
        self.docs_dir = docs_dir
        self.model_name = model_name
        self.chunk_size = chunk_size
        self.chunk_overlap = chunk_overlap

        print("?? 初始化 Embedding 模型...")
        # 使用本地 Embedding 模型,避免調(diào)用外部 API
        self.embeddings = HuggingFaceEmbeddings(
            model_name=embedding_model,
            model_kwargs={"device": "cpu"},  # 改為 "cuda" 可用 GPU 加速
            encode_kwargs={"normalize_embeddings": True},
        )

        self.vectorstore = None
        self.qa_chain = None

    def load_and_index(self):
        """加載文檔并建立向量索引"""
        print(f"?? 加載文檔目錄: {self.docs_dir}")

        # 支持多種文檔格式
        loader = DirectoryLoader(
            self.docs_dir,
            glob="**/*.txt",
            loader_cls=TextLoader,
            loader_kwargs={"encoding": "utf-8"},
        )
        documents = loader.load()
        print(f"? 加載了 {len(documents)} 個(gè)文檔")

        # 文本分塊
        splitter = RecursiveCharacterTextSplitter(
            chunk_size=self.chunk_size,
            chunk_overlap=self.chunk_overlap,
            separators=["\n\n", "\n", "。", "!", "?", " ", ""],
        )
        chunks = splitter.split_documents(documents)
        print(f"? 分割為 {len(chunks)} 個(gè)文本塊")

        # 建立向量索引
        print("?? 建立向量索引(首次較慢,請耐心等待)...")
        self.vectorstore = FAISS.from_documents(chunks, self.embeddings)
        print("? 向量索引建立完成")

        # 保存索引到本地(下次直接加載,無需重建)
        self.vectorstore.save_local("./faiss_index")
        print("?? 索引已保存到 ./faiss_index")

    def load_existing_index(self):
        """加載已有的向量索引"""
        if os.path.exists("./faiss_index"):
            print("?? 加載已有向量索引...")
            self.vectorstore = FAISS.load_local(
                "./faiss_index",
                self.embeddings,
                allow_dangerous_deserialization=True,
            )
            print("? 索引加載完成")
        else:
            print("??  未找到已有索引,請先調(diào)用 load_and_index()")

    def build_qa_chain(self):
        """構(gòu)建問答鏈"""
        if self.vectorstore is None:
            raise ValueError("請先調(diào)用 load_and_index() 或 load_existing_index()")

        print(f"?? 連接本地 LLM: {self.model_name}")
        llm = Ollama(
            model=self.model_name,
            temperature=0.1,  # 降低隨機(jī)性,讓回答更穩(wěn)定
        )

        retriever = self.vectorstore.as_retriever(
            search_type="similarity",
            search_kwargs={"k": 3},  # 召回最相關(guān)的 3 個(gè)文檔塊
        )

        self.qa_chain = RetrievalQA.from_chain_type(
            llm=llm,
            chain_type="stuff",
            retriever=retriever,
            return_source_documents=True,
        )
        print("? 問答系統(tǒng)就緒!")

    def ask(self, question: str) -> dict:
        """
        提問并獲取答案
        
        Returns:
            dict: {"answer": str, "sources": list}
        """
        if self.qa_chain is None:
            raise ValueError("請先調(diào)用 build_qa_chain()")

        result = self.qa_chain.invoke({"query": question})

        return {
            "answer": result["result"],
            "sources": [
                doc.metadata.get("source", "未知來源")
                for doc in result["source_documents"]
            ],
        }


# ============ 使用示例 ============
if __name__ == "__main__":
    # 初始化系統(tǒng)
    rag = LocalRAGSystem(
        docs_dir="./my_docs",
        model_name="qwen2.5:7b",
    )

    # 首次使用:加載文檔并建立索引
    rag.load_and_index()

    # 后續(xù)使用:直接加載已有索引(更快)
    # rag.load_existing_index()

    # 構(gòu)建問答鏈
    rag.build_qa_chain()

    # 開始問答
    while True:
        question = input("\n? 請輸入問題(輸入 q 退出): ").strip()
        if question.lower() == "q":
            break

        result = rag.ask(question)
        print(f"\n?? 回答:\n{result['answer']}")
        print(f"\n?? 參考來源: {', '.join(result['sources'])}")

六、內(nèi)存/顯存管理:別讓 OOM 毀了你

6.1 顯存需求參考

6.2 顯存不夠?用量化壓縮模型

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

# 4-bit 量化配置(顯存減少約 75%)
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.float16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
)

model_id = "Qwen/Qwen2.5-7B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=quantization_config,
    device_map="auto",  # 自動分配到 GPU/CPU
)

print(f"模型加載完成,占用顯存: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")

6.3 流式輸出,避免等待超時(shí)

import ollama

def stream_answer(question: str, model: str = "qwen2.5:7b"):
    """流式輸出,邊生成邊顯示"""
    print("?? ", end="", flush=True)
    
    for chunk in ollama.chat(
        model=model,
        messages=[{"role": "user", "content": question}],
        stream=True,  # 開啟流式輸出
    ):
        content = chunk["message"]["content"]
        print(content, end="", flush=True)
    
    print()  # 換行


stream_answer("用一句話解釋什么是 Transformer 架構(gòu)")

七、加一個(gè) Web 界面(可選)

用 Gradio 5 分鐘搭一個(gè)好看的 Web 界面:

import gradio as gr
from local_rag import LocalRAGSystem  # 引用上面的代碼

# 初始化 RAG 系統(tǒng)
rag = LocalRAGSystem()
rag.load_existing_index()
rag.build_qa_chain()


def chat(message: str, history: list) -> str:
    """Gradio 聊天回調(diào)函數(shù)"""
    if not message.strip():
        return "請輸入問題"
    
    result = rag.ask(message)
    answer = result["answer"]
    sources = result["sources"]
    
    if sources:
        answer += f"\n\n---\n?? **參考來源**: {', '.join(set(sources))}"
    
    return answer


# 創(chuàng)建 Gradio 界面
demo = gr.ChatInterface(
    fn=chat,
    title="?? 本地 AI 問答系統(tǒng)",
    description="基于本地 LLM + RAG 的私有知識庫問答",
    examples=[
        "這個(gè)系統(tǒng)是如何工作的?",
        "請總結(jié)一下主要內(nèi)容",
    ],
    theme=gr.themes.Soft(),
)

if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,  # 改為 True 可生成公網(wǎng)鏈接
    )

運(yùn)行后訪問 http://localhost:7860 即可使用。

八、常見報(bào)錯(cuò)速查表

報(bào)錯(cuò)信息原因解決方案
CUDA out of memory顯存不足使用量化模型或減小 batch_size
ModuleNotFoundError: No module named 'torch'虛擬環(huán)境未激活激活對應(yīng)的 venv/conda 環(huán)境
RuntimeError: CUDA error: no kernel image is availablePyTorch 與 CUDA 版本不匹配重新安裝對應(yīng) CUDA 版本的 PyTorch
ConnectionRefusedError: [Errno 111]Ollama 服務(wù)未啟動運(yùn)行 ollama serve
OSError: [Errno 28] No space left on device磁盤空間不足清理磁盤或更換存儲路徑
ValueError: Tokenizer class ... not foundtransformers 版本過低pip install -U transformers
huggingface_hub.utils._errors.EntryNotFoundError模型名稱錯(cuò)誤或網(wǎng)絡(luò)問題檢查模型 ID 或使用鏡像源

九、國內(nèi)加速技巧

# 設(shè)置 HuggingFace 鏡像(國內(nèi)訪問加速)
export HF_ENDPOINT=https://hf-mirror.com
# pip 使用清華鏡像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple transformers
# conda 使用清華鏡像
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
# 在代碼中指定鏡像
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"

from transformers import AutoTokenizer
# 之后的下載會自動走鏡像
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")

十、總結(jié):搭建清單

到此這篇關(guān)于使用Python搭建本地 AI問答系統(tǒng)的文章就介紹到這了,更多相關(guān)Python搭建AI問答系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

常州市| 鄱阳县| 襄垣县| 津市市| 霍邱县| 陆良县| 桐城市| 岱山县| 进贤县| 荔波县| 独山县| 河源市| 外汇| 长垣县| 双鸭山市| 夹江县| 莆田市| 土默特左旗| 噶尔县| 忻州市| 金沙县| 康平县| 布尔津县| 上杭县| 镇原县| 龙海市| 德兴市| 博客| 昭平县| 河源市| 金平| 长沙县| 涿鹿县| 新野县| 团风县| 进贤县| 天峨县| 巩留县| 阳朔县| 利津县| 安乡县|