如何在LlamaIndex中调用LlamaCPP获得与纯LlamaCPP一致的结果?
我尝试将纯LlamaCPP Python中针对葡萄牙语法律PDF文件的查询逻辑迁移到LlamaIndex中,但二者输出结果不一致。
纯LlamaCPP实现代码
from llama_cpp import Llama import os, re, sys from pypdf import PdfReader reader = PdfReader('inicial_pg10_teste.pdf') total_pages = len(reader.pages) texto_inicial = '' for page_num in range(total_pages): page = reader.pages[page_num] texto_inicial += page.extract_text() model_name = 'mistral-br-pt-q4_k_m.gguf' llm = Llama( model_path=f"llms/{model_name}", n_gpu_layers=20, n_ctx=7000, ) response = llm.create_chat_completion( messages = [ { "role": "user", "content": f"""Quem são os réus desta ação? {texto_inicial}""" } ] ) print(response['choices'][0]['message']['content'])
正确输出结果
Os réus neste processo trabalhista são:
Degustare e Servir Alimentação e Serviços Técnicos Ltda. (empresa de
direito privado, inscrita no CNPJ nº: 17.104.821/0001 -70, com sede na
Avenida do Rio Branco, nº 869, Centro, Niterói, Rio de Janeiro, CEP:
24020 -006) Secretaria de Estado de Educação do Rio de Janeiro (SEERJ)
(pessoa jurídica de direito público interno, inscrita no CNPJ sob o nº
42.498.600/0001 -71, com sede na Rua Pinheiro Machado, s/n°, Palácio da Guanaba, Laranjeiras, Rio de Janeiro/RJ, CEP 22.231 -901)
LlamaIndex实现代码
import os, re, sys from pathlib import Path from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, download_loader, ServiceContext, PromptTemplate from llama_index.llms.llama_cpp import LlamaCPP from llama_index.readers.file import PDFReader loader = PDFReader() documents = loader.load_data(file=Path('inicial_pg10_teste.pdf')) model_name = 'mistral-br-pt-q4_k_m.gguf' llm = LlamaCPP( model_path=f"llms/{model_name}", model_kwargs={"n_gpu_layers": 20}, context_window=7000, ) service_context = ServiceContext.from_defaults( llm=llm, embed_model="local", chunk_size=6235 ) index = VectorStoreIndex.from_documents(documents, service_context=service_context) template = ( "<s> [INST] {query_str} {context_str} [/INST]" ) custom_prompt = PromptTemplate(template) query_engine = index.as_query_engine(text_qa_template=custom_prompt) question = "Quem são os réus desta ação?" response = query_engine.query(question) print(response)
错误输出结果
Os réus neste processo são a Reclamada e a 2ª Reclamada.
解决方法
1. 完全对齐纯LlamaCPP的输入逻辑
纯LlamaCPP是将完整PDF文本直接拼接在问题后作为单条输入,LlamaIndex默认的分块检索逻辑会改变输入结构。要得到一致结果,可绕过向量检索,直接将完整文档传入LLM:
# 替换LlamaIndex代码中索引及查询引擎部分 # 合并所有文档内容为完整文本 full_text = "\n".join([doc.text for doc in documents]) # 构造与纯LlamaCPP一致的输入prompt prompt = f"""Quem são os réus desta ação? {full_text}""" # 直接调用LLM生成结果 response = llm.complete(prompt) print(response.text)
2. 保留检索能力的前提下调整策略
若不想放弃分块检索,需确保能召回包含完整被告信息的片段:
- 调整分块参数:增大
chunk_size(比如设为7000,匹配模型上下文窗口),同时设置chunk_overlap=200,避免关键信息被拆分到不同片段中。 - 优化检索范围:使用
RetrieverQueryEngine并设置similarity_top_k=10,确保召回所有相关片段后再拼接传入LLM。 - 强化Prompt指令:补充明确要求,避免模型返回泛称:
template = ( "<s> [INST] Você é um assistente jurídico especializado em processos brasileiros. " "Com base no contexto fornecido, responda a pergunta com os nomes completos das partes réus, incluindo dados como CNPJ e sede. " "Pergunta: {query_str} " "Contexto: {context_str} [/INST]" )
3. 统一PDF文本提取方式
纯LlamaCPP用pypdf提取文本,LlamaIndex的PDFReader可能使用不同底层库,导致文本内容差异。可强制LlamaIndex使用pypdf:
# 替换PDF加载部分 from pypdf import PdfReader from llama_index.core import Document def load_pdf_with_pypdf(file_path): reader = PdfReader(file_path) text = "\n".join([page.extract_text() for page in reader.pages]) return [Document(text=text)] documents = load_pdf_with_pypdf('inicial_pg10_teste.pdf')
内容的提问来源于stack exchange,提问作者celsowm

