基于智谱AI和本地小模型使用Ragas评估Rag结果(不使用默认的OpenAI模型)

我们在使用Ragas评价Rag结果时,由于Ragas默认使用的是gpt模型,对于国内用户来说难免比较麻烦。于是我就结合Ragas和LangChain的官方手册对这位大佬的代码进行了一定的修改,只需要使用免费的智谱AI Key以及很小的本地embedding模型来替换原来默认的gpt模型,照样实现原有功能(当然效果肯定会差一些)。

强烈建议可以先看看这个视频,下面的大部分代码都来自这位博主(这位大佬的视频质量非常高):

【如何利用RAGAs评估RAG系统的好坏】https://www.bilibili.com/video/BV1Jz421Q7Lw?vd_source=c5c396652c0c83be15efe54e0c348c90

接下来就来到了正题,我就直接给出我修改完的代码了(看不懂的先看看上面链接的视频)。

from langchain.document_loaders import ArxivLoader
from langchain.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.embeddings import Embeddings
from sentence_transformers import SentenceTransformer
from typing import List
from langchain import PromptTemplate
from openai import OpenAI
from datasets import Dataset
from ragas import evaluate
from ragas.llms import LangchainLLMWrapper
from langchain_community.chat_models import ChatZhipuAI
import pandas as pd

import os

os.environ["ZHIPUAI_API_KEY"] = "###################################" # 替换为你自己的智谱API密钥(如果不知道怎么得到自己的Key,可以看我上一篇文章)

paper_docs = ArxivLoader(query="2309.15217", load_max_docs=1).load()


# 这里由于直接加载的本地embedding模型,所以需添加两个函数
class HuggingFaceEmbeddings(Embeddings):
    def __init__(self, model_path: str):
        self.model = SentenceTransformer(model_path)

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        return self.model.encode(texts).tolist()

    def embed_query(self, text: str) -> List[float]:
        return self.model.encode([text])[0].tolist()


text_splitter = RecursiveCharacterTextSplitter(chunk_size=600)

docs = text_splitter.split_documents(paper_docs)

# 这里需要去HuggingFace下载对应的模型,模型很小不用担心
model_path = "E:\HuggingFace\sentence-transformers\sentence-t5-large"
embeddings = HuggingFaceEmbeddings(model_path)

vectorstore = Chroma.from_documents(docs, embeddings)

base_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

relevant_docs = base_retriever.get_relevant_documents("What is Retrieval Augmented Generation?")


template = """You are an assistant for question-answering tasks. 
Use the following pieces of retrieved context to answer the question. 
If you don't know the answer, just say that you don't know. 

Question: {question} 

Context: {context} 

Answer:
"""

prompt = PromptTemplate(
    template=template,
    input_variables=["context", "question"]
)


client = OpenAI(
    api_key="###################################",  # 替换为你自己的智谱API密钥(如果不知道怎么得到自己的Key,可以看我上一篇文章)
    base_url="https://open.bigmodel.cn/api/paas/v4/"  # 这里的url不用改
)

# Ragas 数据集格式要求  ['question', 'answer', 'contexts', 'ground_truths']
'''
{
    "question": [], <-- 问题基于Context的
    "answer": [], <-- 答案基于LLM生成的
    "contexts": [], <-- context
    "ground_truths": [] <-- 标准答案
}
'''

questions = ["What is faithfulness ?",
             "How many pages are included in the WikiEval dataset, and which years do they cover information from?",
             "Why is evaluating Retrieval Augmented Generation (RAG) systems challenging?",
             ]

ground_truths = ["Faithfulness refers to the idea that the answer should be grounded in the given context.",
                 "To construct the dataset, we first selected 50 Wikipedia pages covering events that have happened since the start of 2022.",
                 "Evaluating RAG architectures is, however, challenging because there are several dimensions to consider: the ability of the retrieval system to identify relevant and focused context passages, the ability of the LLM to exploit such passages in a faithful way, or the quality of the generation itself."]

answers = []
contexts = []

# 生成答案
for query in questions:
    context = base_retriever.get_relevant_documents(query)
    enhanced_prompt = prompt.format(question=query, context=context)
    # 生成请求,这里不明白的可以去看智谱的官方手册
    completion = client.chat.completions.create(
        model="GLM-4-Flash-250414",
        messages=[
            {
                "role": "system",
                "content": "你是一个根据用户要求回答问题得机器人助手。"
            },
            {
                "role": "user",
                "content": enhanced_prompt
            }
        ],
        top_p=0.7,
        temperature=0.9,
        max_tokens=1000
    )
    answers.append(completion.choices[0].message.content)
    contexts.append([docs.page_content for docs in base_retriever.get_relevant_documents(query)])

# 构建数据
data = {
    "question": questions,
    "answer": answers,
    "contexts": contexts,
    "ground_truth": ground_truths
}
dataset = Dataset.from_dict(data)


llm = ChatZhipuAI(
    model="GLM-4-Flash-250414",
    temperature=0.5,
)

evaluator_llm = LangchainLLMWrapper(llm)

# 这里如果不指定metrics,默认就是metrics = [answer_relevancy, context_precision, faithfulness, context_recall],不清楚的可以看看evaluate源码,写的很清楚
# 这里需要传入我们自定义的llm,以及自定义的embedding模型(不指定会报错的,因为有些评价指标需要指定)。读者也可以看看evaluate源码,就明白了。
# 然后有小伙伴可能会好奇我是怎么知道要怎么修改的,可以看看https://docs.ragas.io/en/latest/getstarted/rag_eval/#collect-evaluation-data,Ragas的官方手册,里面写的很清楚。
#这里的embedding模型是不是需要和我传入的llm模型的embedding模型匹配呢?有了解的可以评论一下,解答疑惑。
result = evaluate(dataset=dataset, llm=evaluator_llm, embeddings=embeddings)

pd.set_option("display.max_colwidth", None)

df = result.to_pandas()

print(df)

运行结果如下(这里有一个警告,不用管)

<think>嗯,用户问的是Spring AI中的RAG怎么使用。首先,我需要确认用户对RAGSpring AI的基础了解程度。RAG是检索增强生成,结合了检索生成模型,而Spring AI是一个集成AI能力的框架。用户可能已经知道这些概念,但可能需要具体的实现步骤。 用户可能是在开发一个需要结合外部知识库的AI应用,比如客服系统或者智能问答系统。他们可能遇到的问题是,生成模型在回答特定领域问题时够准确,所以希望通过RAG来提升效果。 接下来,我需要考虑Spring AIRAG的具体实现方式。可能需要用到文档加载、向量存储、检索生成模型集成。要分步骤讲解,从环境配置到代码示例,确保新手也能理解。 可能需要注意的点包括:依赖项的引入,如何准备文档,向量数据库的选择(比如Redis、PgVector),检索策略的设置,以及与OpenAI本地模型的结合。还要提醒用户处理可能出现的异常,比如API连接问题或文档解析错误。 用户可能还想知道实际应用中的优化技巧,比如分块策略、元数据过滤模型选择。这些内容可以作为进阶部分加入,帮助他们进一步提升效果。最后,给出一个完整的代码示例,让用户可以直接参考实现。</think>以下是Spring AIRAG(检索增强生成)的完整使用指南,包含代码示例最佳实践: ```java // 基础环境配置(pom.xml关键依赖) <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>0.8.1</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store</artifactId> <version>0.8.1</version> </dependency> // 核心实现类示例 @RestController public class RagController { @Autowired private VectorStore vectorStore; @Autowired private ChatClient chatClient; // 文档入库处理 @PostMapping("/ingest") public void ingestDocuments(@RequestParam("path") String docPath) { DocumentReader reader = new PdfDocumentReader(docPath); TextSplitter splitter = new TokenTextSplitter(1000, 200); List<Document> documents = splitter.apply(reader.get()); vectorStore.add(documents.stream() .map(doc -> new Document( doc.getId(), doc.getContent(), Metadata.of("source", docPath)) ).collect(Collectors.toList())); } // RAG问答接口 @GetMapping("/ask") public String askQuestion(@RequestParam String question) { // 向量检索(带相似度阈值过滤) List<Document> contexts = vectorStore.similaritySearch( SearchRequest.query(question) .withTopK(5) .withSimilarityThreshold(0.7) ); // 构造增强提示词 String augmentedPrompt = String.format( "基于以下上下文:\n%s\n\n请回答:%s", contexts.stream() .map(Document::getContent) .collect(Collectors.joining("\n---\n")), question ); // 调用生成模型 return chatClient.generate( new Prompt(augmentedPrompt, OpenAiChatOptions.builder() .withTemperature(0.3) .build() )).getGeneration().getContent(); } } ``` **关键配置项(application.yml):** ```yaml spring: ai: vectorstore: pgvector: dimensions: 1536 # 适配OpenAI嵌入维度 openai: api-key: ${OPENAI_API_KEY} embedding-model: text-embedding-3-small chat-model: gpt-3.5-turbo ``` **最佳实践:** 1. **分块策略优化** ```java // 使用语义分块替代固定长度分块 TextSplitter splitter = new SemanticTextSplitter() .withWindowSize(512) .withOverlap(128); ``` 2. **混合检索增强** ```java // 结合关键词检索向量检索 List<Document> keywordResults = vectorStore.keywordSearch(question, 3); List<Document> vectorResults = vectorStore.similaritySearch(...); List<Document> hybridResults = mergeResults(keywordResults, vectorResults); ``` 3. **元数据过滤** ```java // 添加文档时携带元数据 Document doc = new Document() .withContent(content) .withMetadata(Metadata.of("department", "HR")); // 检索时过滤 SearchRequest request = SearchRequest.query(question) .withFilterExpression("department == 'HR'"); ``` **常见问题处理:** 1. 长上下文优化: ```java // 启用长上下文优化模式 OpenAiChatOptions.builder() .withModel("gpt-3.5-turbo-16k") .withMaxTokens(4000); ``` 2. 结果验证: ```java // 添加引用溯源 response += "\n\n参考资料:\n" + contexts.stream() .map(d -> "• " + d.getMetadata().get("source")) .collect(Collectors.joining("\n")); ``` **性能优化建议:** - 使用本地嵌入模型降低成本: ```yaml spring: ai: embedding-model: onnx://microsoft/all-MiniLM-L6-v2 ``` - 启用缓存机制: ```java @Cacheable(value = "ragCache", key = "#question.hashCode()") public String getCachedResponse(String question) { ... } ``` 完整项目建议包含: 1. 异常处理(处理API限流、文档解析错误) 2. 日志记录(记录检索上下文生成结果) 3. 评估模块(使用RAGAS指标评估效果) 4. 异步处理(使用@Async进行批量文档处理)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值