RAG排序策略探索——基于GPT2的PPL的方案

文章介绍了微软的研究成果LLMLingua如何通过PPL技术改进语言模型在长上下文情境下的检索排序性能。实验结果显示虽然不如BERT的bgerank,但效果超出预期,提示了这一方向的潜力。作者还提供了使用GPT2和Cluecorpussmall模型进行PPL排序的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.背景

微软发表了一篇论文《LongLLMLingua: Accelerating and Enhancing LLMs in Long Context Scenarios via Prompt Compression》,里面论述了利用PPL来进行RAG的检索排序,十分有趣。于是在自己业务数据上测试了下,虽然最终效果不敌bge rank, 但是表现已远超预期。

1.准备GPT2大模型

下载模型https://huggingface.co/uer/gpt2-chinese-cluecorpussmall/tree/main

2.计算PPL进行排序

# -*- encoding=utf-8 -*-
import os
import json
import math
import pandas as pd
from typing import List

import torch
import torch.nn as nn
from torch.nn import CrossEntropyLoss
from transformers import AutoModelForCausalLM, AutoTokenizer


def init_ppl_model():
    """
    初始化perplexity
    """
    device = "cpu"
    base_dir = os.path.dirname(os.path.abspath(__file__))
    model_id = os.path.join(base_dir, "./gpt2-chinese-cluecorpussmall")
    model = AutoModelForCausalLM.from_pretrained(model_id, is_decoder=True)
    model = model.to(device)
    tokenizer = AutoTokenizer.from_pretrained(model_id)
    return model, tokenizer


def get_ppl_longllmlingua(text, question, model, tokenizer):
    """
    采用llmlingua计算ppl
    """
    def get_token_length(text: str, add_special_tokens: bool = True):
        return len(
            tokenizer(text, add_special_tokens=add_special_tokens).input_ids
        )

    granularity = "sentence"
    ppl = get_ppl_new(
        model,
        tokenizer,
        text + question,
        granularity=granularity,
        condition_mode="after",
        condition_pos_id=get_token_length(text) - 1,
    )
    return ppl.item()


def get_ppl_new(
            model,
            tokenizer,
            text: str,
            granularity: str = "sentence",
            input_ids=None,
            attention_mask=None,
            past_key_values=None,
            return_kv=False,
            end=None,
            condition_mode: str = "none",
            condition_pos_id: int = 0,
    ):
    device = "cpu"
    if input_ids is None:
        tokenized_text = tokenizer(text, return_tensors="pt")
        input_ids = tokenized_text["input_ids"].to(device)
        attention_mask = tokenized_text["attention_mask"].to(device)
    if past_key_values is not None:
        past_length = past_key_values[0][0].shape[2]
    else:
        past_length = 0
    if end is None:
        end = input_ids.shape[1]
    end = min(end, past_length + 512)
    with torch.no_grad():
        response = model(
            input_ids[:, past_length:end],
            attention_mask=attention_mask[:, :end],
            past_key_values=past_key_values,
            use_cache=True,
        )
        past_key_values = response.past_key_values

    shift_logits = response.logits[..., :-1, :].contiguous()
    shift_labels = input_ids[..., past_length + 1: end].contiguous()
    # Flatten the tokens
    active = (attention_mask[:, past_length:end] == 1)[..., :-1].view(-1)
    active_logits = shift_logits.view(-1, shift_logits.size(-1))[active]
    active_labels = shift_labels.view(-1)[active]
    loss_fct = torch.nn.CrossEntropyLoss(reduction="none")
    loss = loss_fct(active_logits, active_labels)
    #print(loss)
    if condition_mode == "before":
        loss = loss[:condition_pos_id]
    elif condition_mode == "after":
        loss = loss[condition_pos_id:]
    res = loss.mean() if granularity == "sentence" else loss
    return (res, past_key_values) if return_kv else res


def ppl_rerank(retriever_res, ori_query, model, tokenizer):
    """
    利用ppl进行排序
    """
    print("ori_query:", ori_query)
    retriever_res = json.loads(retriever_res)
    pair_list = []
    for index, x in enumerate(retriever_res[0]["list"]):
        generate_text = ori_query + "我们可以从前面的文档中得到这个问题的答案。"
        text_prefix = "{}".format(x["content"][:512 - len(generate_text)])

        ppl = get_ppl_score_fixed_prefix(text_prefix, generate_text, model, tokenizer)
        #ppl = get_ppl_longllmlingua(text_prefix, generate_text, model, tokenizer)
        x["infoMap"]["ppl"] = ppl
        retriever_res[0]["list"][index] = x

    new_retriever_res = sorted(retriever_res[0]["list"], key=lambda x:x["infoMap"]["ppl"], reverse=False)
    retriever_res[0]["list"] = new_retriever_res
    res = json.dumps(retriever_res, ensure_ascii=False)
    #print("res:", res)
    return res


def is_match(x1, x2):
    """
    :param x1:
    :param x2:
    :return:
    """
    x1 = set(x1.strip())
    x2 = set(x2.strip())
    #score = len(x1 & x2) / len(x1 | x2)
    score = len(x1 & x2) / len(x2)
    if score > 0.95:
        return True
    else:
        return False


def parse_rank_res(rank_res, answer):
    """
    :param retriever_res:
    :return:
    """
    print("ori_query:", answer)
    retriever_res = json.loads(rank_res)
    true_index = -1
    for index, x in enumerate(retriever_res[0]["list"]):
        if is_match(x["content"], answer):
            true_index = index + 1
            break
    return true_index



df = pd.read_excel("./基准测试文件_全量QA测试_0119.xlsx")
#df = df[:10]
model, tokenizer = init_ppl_model()

"""
prefix_text = "我不会忘记"
generate_text = "和你一起奋斗的时光。"
get_ppl_longllmlingua(prefix_text, generate_text, model, tokenizer)
"""

df["retrievers_new"] = df.apply(lambda x: ppl_rerank(x["retrievers"], x["Query"], model, tokenizer), axis=1)
df["hit_n"] = df.apply(lambda x: parse_rank_res(x["retrievers_new"], x["预想答案"]), axis=1)
df.to_excel("./基准测试文件_全量QA测试_0119_ppl_rerank_5.xlsx")

3.结论

排序效果一般,目前效果比bge rerank略差,但是这种思想可以取到这么好的排序效果,已经远超预期了。后续可持续关注该方向的进展。

tips:在自己业务数据集上restrictive prompt特别重要,可尝试不同的表述观察实验效果,最后祝你好运~

参考资料

https://huggingface.co/uer/gpt2-chinese-cluecorpussmall/tree/main

https://github.com/microsoft/LLMLingua/blob/main/README.md

https://github.com/microsoft/LLMLingua/blob/main/examples/Retrieval.ipynb

<think>好的,用户想了解智能客服大模型的实现方案和技术架构。首先,我需要回忆相关的引用内容。引用[1]提到智能客服系统的架构和代码示例,引用[2]讨论了架构设计的高效、安全、可靠,引用[3]提到了Agent架构模式,引用[4]则涉及大型预训练模型的应用。接下来,我需要将这些信息整合成一个清晰的方案。 首先,系统架构方面,应该分层处理,包括接入层、对话管理、大模型核心、知识库等。然后,技术架构需要考虑模型选型,比如GPT、BERT或者企业自研的模型。接着是数据处理流程,包括清洗、标注和增强,这部分引用[1]和[4]都有相关内容。对话管理模块需要状态跟踪和策略,引用[3]的Agent架构模式可能适用。知识库的构建需要向量数据库,如Faiss,引用[1]提到RAG技术,可以整合进去。 性能优化方面,模型压缩和缓存机制是关键,引用[2]的安全性和可靠性也需要考虑,比如敏感词过滤和冗余设计。最后,代码示例可能需要一个简化的对话生成示例,使用Hugging Face的Transformers库,这样用户能直观看到实现。 在生成相关问题的时候,需要覆盖架构设计、模型选择、性能优化、数据处理和应用场景等方面,确保用户能进一步深入探索。还要注意引用标记的正确添加,比如在提到RAG时引用[3],模型选型引用[4]等。整个过程要保持结构清晰,语言简洁,符合用户的要求。</think>### 智能客服大模型实现方案与技术架构 #### 一、系统架构设计 智能客服大模型系统通常采用分层架构,包含以下核心模块: 1. **用户接入层** 支持多渠道接入(网页、APP、API),通过$API Gateway$统一管理请求,实现负载均衡与协议转换[^2]。 2. **对话管理模块** 采用状态机跟踪对话流程,结合规则引擎与大模型决策,处理如$$S_{t+1} = f(S_t, U_t)$$的对话状态转移[^3]。 3. **大模型核心层** 基于预训练语言模型(如GPT-3/4、PaLM)构建,通过$Fine-tuning$适配业务场景,支持意图识别、实体抽取、多轮对话等任务。 4. **知识库增强模块** 集成RAG(检索增强生成)架构,使用向量数据库(如FAISS)实现实时知识检索,数学表示为: $$ R(q) = \arg\max_{d \in D} \text{sim}(E(q), E(d)) $$ 其中$E(\cdot)$为文本编码器。 #### 二、关键技术实现 1. **模型选型与优化** - 基础模型:选择参数量级(如175B参数的GPT-3)与领域适配度 - 微调策略:采用LoRA(低秩适应)技术,仅更新部分参数: $$ W' = W + \alpha \cdot BA $$ 其中$B \in \mathbb{R}^{d \times r}$, $A \in \mathbb{R}^{r \times k}$为低秩矩阵[^4] 2. **数据处理流程** - 对话数据清洗:去噪、去重、隐私脱敏 - 多维度标注:意图分类标签$y_i \in \{0,1\}^k$,实体标签序列标注 - 数据增强:通过回译、模板生成扩展训练集 3. **对话质量保障** - 响应评估指标: - 流畅度:$PPL(w_1,...,w_n) = \exp(-\frac{1}{n}\sum_{i=1}^n \log P(w_i|w_{<i}))$ - 相关性:计算响应与问题的余弦相似度 #### 三、典型代码结构 ```python # 基于Hugging Face的对话生成示例 from transformers import AutoTokenizer, AutoModelForCausalLM class ChatAgent: def __init__(self, model_path): self.tokenizer = AutoTokenizer.from_pretrained(model_path) self.model = AutoModelForCausalLM.from_pretrained(model_path) def generate_response(self, query, history=None): prompt = format_dialog(query, history) # 构造对话上下文 inputs = self.tokenizer(prompt, return_tensors="pt") outputs = self.model.generate(**inputs, max_length=500) return self.tokenizer.decode(outputs[0], skip_special_tokens=True) ``` #### 四、性能优化策略 1. **模型压缩** - 量化:FP32INT8(精度损失<2%) - 剪枝:移除贡献度<$\epsilon$的神经元连接 2. **缓存机制** - 高频问题响应缓存(TTL=300s) - 向量检索结果缓存,命中率可达$85\%+$ 3. **安全增强** - 敏感词过滤:正则表达式匹配+语义检测 - 置信度阈值:当$P(y|x) < 0.7$时转人工 #### 五、典型应用场景 1. 电商领域的24小时智能导购 2. 金融行业的合规咨询 3. 政府服务的流程指引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值