You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加快RetrievalQA链运行速度?本地部署优化问询

问题描述

在配备Apple M2 Max芯片、64GB内存、12核的Macbook Pro本地运行RetrievalQA链时,使用TheBloke提供的量化版Mixtral 8x7B-Instruct模型生成文本耗时1-2分钟,速度过慢。单独运行Mixtral模型仅需数秒,已尝试增大n_gpu_layers、n_batch参数,添加n_threads=8,均无明显提升。

相关代码:

from dotenv import find_dotenv, load_dotenv
import box
import yaml
from langchain.llms import LlamaCpp
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

# Load environment variables from .env file
load_dotenv(find_dotenv())

# Import config vars
with open('config/config.yml', 'r', encoding='utf8') as ymlfile:
    cfg = box.Box(yaml.safe_load(ymlfile))


def build_llm(model_path):
        callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])

        n_gpu_layers = 1 # Metal set to 1 is enough. # ausprobiert mit mehreren
        n_batch = 1024 # Should be between 1 and n_ctx, consider the amount of RAM of your Apple Silicon Chip.

        llm = LlamaCpp(
                max_tokens =cfg.MAX_TOKENS,
                #model_path="/Documents/rag_example/Modelle/mixtral-8x7b-instruct-v0.1.Q5_K_M.gguf",
                model_path=model_path,
                temperature=0.1,
                f16_kv=True,
                n_ctx=28000, # 28k because Mixtral can take up to 32k  
                n_gpu_layers=n_gpu_layers,
                n_batch=n_batch,
                callback_manager=callback_manager, 
                verbose=True, # Verbose is required to pass to the callback manager
                top_p=0.75,
                top_k=40,
                model_kwargs={
                        'repetition_penalty': 1.1,
                        'mirostat': 2,
                },
        )
        
        return llm

mistral_prompt = """
<s> [INST] Du bist ein hilfreicher Chat-Assistent names Mixtral, der nur auf Deutsch antworten kann.
Deine Aufgabe ist es, die Fragen des Nutzers ausschließlich auf Deutsch zu beantworten.
Nutze den gefundenen Kontext, um die Fragen zu beantworten. 
Falls du die Antwort nicht weißt, sag einfach, dass du die Antwort nicht kennst.
Falls sich die Antwort nicht im Kontext befindet, antworte: "Es gibt nicht genug Informationen im Kontext, um die Frage zu beantworten.".
Halte deine Antworten präzise und vermeide spekulative oder erfundene Informationen.
Erfinde nichts, falls du die Antwort nicht kennst oder du dir nicht sicher bist!
Ein Konversationsverlauf steht dir nach "Chat History" zur Verfügung.
Wenn du merkst, dass der Nutzer Smalltalk betreibt, führe Smalltalk mit ihm.

Chat History: {chat_history}

Context: {context} 

Question: {question} 
Answer: [/INST]
"""

def set_mistral_prompt():
    """
    Prompt template for QA retrieval for each vectorstore
    """
    prompt = PromptTemplate(template=mistral_prompt,
                            input_variables=['chat_history', 'context', 'question'])
    return prompt

def build_retrieval_qa(llm, prompt, vectordb, chain_type="RetrievalQA"):
    chain_type_kwargs={
        #"verbose": True,
        "prompt": prompt,
        "memory": ConversationBufferMemory(
            memory_key="chat_history",
            input_key="question",
            #output_key="answer",
            return_messages=True),
        "verbose": False
        }
    
    if chain_type == "RetrievalQA":
        dbqa = RetrievalQA.from_chain_type(llm=llm,
                                        chain_type='stuff',
                                        retriever=vectordb.as_retriever(search_kwargs={'k': cfg.VECTOR_COUNT, 'score_treshold': cfg.SCORE_TRESHOLD}, search_type="similarity"), # search_type="mmr" for Similarity AND diversity
                                        return_source_documents=cfg.RETURN_SOURCE_DOCUMENTS,
                                        chain_type_kwargs=chain_type_kwargs,
                                        verbose=False
                                        )
    return dbqa




from langchain.embeddings import HuggingFaceBgeEmbeddings, HuggingFaceEmbeddings, SentenceTransformerEmbeddings
from langchain.vectorstores import FAISS
import pickle
from src.utils import setup_dbqa, build_retrieval_qa, set_mistral_prompt
from src.utils import setup_dbqa
from src.text_preprocess import clean_document, clean_document_confluence
from src.llm import build_llm

# Load documents
with open(f'confluence_docs.pkl', 'rb') as documents:
    documents = pickle.load(documents)
    
# Preprocess the text before chunking
documents = clean_document_confluence(documents)
embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large",
                                       model_kwargs={'device': 'mps'})

vectorstore = FAISS.from_documents(documents, embeddings)

chat_history = []    
qa_prompt = set_mistral_prompt()
llm = build_llm(model_path="/Users/mweissenba001/Documents/rag_example/Modelle/mixtral-8x7b-instruct-v0.1.Q5_K_M.gguf")
mixtral_qa = build_retrieval_qa(llm=llm,prompt=qa_prompt,vectordb=vectorstore)

mixtral_qa({'query': "Wer ist Dr. Nicolai Bieber?", "chat_history": []}) # takes longer than 1min
优化方案

1. 最大化Apple Silicon硬件利用

  • 全量GPU层卸载:将n_gpu_layers设为-1,让LlamaCpp自动把所有可卸载的模型层转移到Metal GPU,彻底释放CPU算力。
  • 多核线程优化:设置n_threads=16(12核CPU的1.5倍线程数),同时添加n_threads_batch=16,让批处理和推理阶段都充分利用多核资源。
  • 调整上下文窗口:如果业务场景不需要28k的超大上下文,将n_ctx降到8192或16384,减少推理时的KV缓存占用和计算量。
  • 增大批处理量:M2 Max的64GB内存可支持更大的n_batch,比如设为2048,提升推理吞吐量。

修改后的build_llm示例:

def build_llm(model_path):
        callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])

        n_gpu_layers = -1  # 自动卸载所有可GPU加速的层
        n_threads = 16
        n_threads_batch = 16
        n_batch = 2048
        n_ctx = 16384  # 根据实际需求调整

        llm = LlamaCpp(
                max_tokens = cfg.MAX_TOKENS,
                model_path=model_path,
                temperature=0.1,
                f16_kv=True,
                n_ctx=n_ctx,
                n_gpu_layers=n_gpu_layers,
                n_batch=n_batch,
                n_threads=n_threads,
                n_threads_batch=n_threads_batch,
                callback_manager=callback_manager, 
                verbose=True,
                top_p=0.75,
                top_k=40,
                cache_capacity="100%",  # 充分利用内存缓存KV数据
                model_kwargs={
                        'repetition_penalty': 1.1,
                        'mirostat': 2,
                },
        )
        
        return llm

2. 精简RetrievalQA链的输入与流程

  • 减少检索文档数量:如果cfg.VECTOR_COUNT大于3,将其降到2-3个。过多的上下文会拉长Prompt长度,直接增加模型推理时间。
  • 压缩Prompt模板:移除冗余的指令描述,减少输入token数,比如精简后的Prompt:
mistral_prompt = """
<s> [INST] Du bist ein hilfreicher deutscher Chat-Assistent. Nutze ausschließlich den gegebenen Kontext, um die Frage zu beantworten. Wenn du die Antwort nicht weißt oder sie nicht im Kontext steht, antworte: "Es gibt nicht genug Informationen im Kontext, um die Frage zu beantworten." Halte Antworten präzise.

Chat History: {chat_history}
Context: {context}
Question: {question}
Answer: [/INST]
"""
  • 关闭非必要功能:如果不需要返回源文档,将return_source_documents设为False,省去后续文档处理的开销。

3. 优化Embeddings环节

  • 切换轻量Embedding模型:如果检索精度可接受,将intfloat/multilingual-e5-large换成intfloat/multilingual-e5-base,减少嵌入计算的耗时。
  • 预保存向量库:初始化vectorstore后调用vectorstore.save_local("faiss_db"),后续直接用FAISS.load_local("faiss_db", embeddings)加载,避免每次启动都重新生成向量。

4. 其他细节优化

  • 关闭流式输出:如果不需要实时打印生成文本,移除StreamingStdOutCallbackHandler,减少IO交互的开销。
  • 更新依赖库:升级到最新版的llama-cpp-python和langchain,新版本通常会修复Apple Silicon的性能问题。

内容的提问来源于stack exchange,提问作者Maxl Gemeinderat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:05:56