RAG优化字典:20种RAG优化方法全解析

关注腾讯云开发者,一手技术干货提前解锁👇

本文系统性地梳理了 RAG(Retrieval-Augmented Generation,检索增强生成)系统从基础到高级的 20 种优化方法,涵盖分块策略、检索增强、查询优化、生成质量控制等多个维度。每种方法均附带核心代码实现(含简要注释),便于读者按需选型与落地实践。

01

语义分块

核心思路:按句子级嵌入相似度切分,而非固定字符数。当相邻句子语义相似度低于阈值时在此处切块,从而保留语义完整性。

断点计算方法:

  • 百分位法(Percentile):相似度低于某百分位的位置作为断点

  • 标准差法(Standard Deviation):相似度低于「均值 − 标准差」的位置

  • 四分位距法(IQR):用四分位距检测异常低的相似度作为断点

# ========== 方法1:语义分块 ==========# 根据相邻句子的嵌入相似度找“语义断点”,在断点处切块,保证块内语义连贯
def compute_breakpoints(similarities, method="percentile", threshold=90):    """    根据相似度序列计算断点索引:相似度突降处 = 语义边界。    method: percentile / standard_deviation / interquartile    """    breakpoints = []
    if method == "percentile":        # 低于 (100-threshold) 分位数的位置视为断点        threshold_value = np.percentile(similarities, 100 - threshold)        for i, sim in enumerate(similarities):            if sim < threshold_value:                breakpoints.append(i)        elif method == "standard_deviation":        # 低于「均值 - 1 个标准差」的位置视为断点        mean_sim = np.mean(similarities)        std_sim = np.std(similarities)        threshold_value = mean_sim - std_sim        for i, sim in enumerate(similarities):            if sim < threshold_value:                breakpoints.append(i)        elif method == "interquartile":        # IQR 法:低于 Q1 - 1.5*IQR 的视为异常低,作为断点        q1 = np.percentile(similarities, 25)        q3 = np.percentile(similarities, 75)        iqr = q3 - q1        threshold_value = q1 - 1.5 * iqr        for i, sim in enumerate(similarities):            if sim < threshold_value:                breakpoints.append(i)        return breakpoints
def split_into_chunks(sentences, breakpoints):    """按断点把句子序列切成多段,每段拼成一块文本"""    chunks = []    start = 0    for bp in breakpoints:        chunk = " ".join(sentences[start:bp + 1])        chunks.append(chunk)        start = bp + 1    if start < len(sentences):        chunks.append(" ".join(sentences[start:]))    return chunks

02

切块大小评估

核心思路:对多种切块大小(如 128、256、512 字符)分别做检索与生成,用忠实度(回复是否紧扣上下文)和相关性(是否答到点上)等指标对比,数据驱动选出最优切块参数。

优势与局限:

  • 优势:避免拍脑袋定 chunk size,有评估依据;适合新语料或新场景的调参。

  • 局限:需要标注或可自动评估的测试集,且评估有一定计算成本。

  • 适用场景:上线前调参、不同领域/文档类型单独优化。

# ========== 方法2:切块大小评估 ==========# 对多种 chunk size 分别建索引、检索、生成,用忠实度/相关性选最优大小
 chunk_sizes = [128, 256, 512]
# 按每种大小切块并保存,便于后续统一评估
text_chunks_dict = {    size: chunk_text(extracted_text, size, size // 5)     for size in chunk_sizes}
# 对每种切块大小:建嵌入 → 检索 → 生成 → 算指标for size in chunk_sizes:    chunks = text_chunks_dict[size]    embeddings = create_embeddings(chunks)    for question in test_questions:        results = semantic_search(question, chunks, embeddings)        context = results[0][0]        response = generate_response(question, context)        # 忠实度:回复是否严格基于上下文,有无幻觉        faithfulness = evaluate_faithfulness(response, context)        # 相关性:回复是否切题、有用        relevancy = evaluate_relevancy(response, question)

03

上下文增强检索

核心思路:检索到最相关的块后,同时带上其前、后相邻块一起作为上下文,避免“孤岛片段”缺少前文/后文而导致理解不全。

优势与局限:

  • 优势:实现简单,无需改索引;能明显改善需要前后文才能理解的内容(如列表、步骤、对比)。

  • 局限:会引入与问题无关的相邻块,可能增加噪声和 token 消耗。

  • 适用场景:分块较细、上下文连贯性重要的场景。

# ========== 方法3:上下文增强检索 ==========# 先按相似度找到 top-k 块,再对每个块扩展其前后 context_size 块,合并后返回
def context_enriched_search(query, text_chunks, embeddings, k=1, context_size=1):    """    检索:取相似度最高的 k 个块,每个块向左右各扩展 context_size 块并拼接。    这样返回的是「中心块 + 前后文」的连续窗口,而非单块。    """    query_embedding = create_embeddings(query)    similarities = [cosine_similarity(query_embedding, emb) for emb in embeddings]    sorted_indices = np.argsort(similarities)[::-1]
    results = []    for idx in sorted_indices[:k]:        # 以当前块为中心,向左右各取 context_size 块        start = max(0, idx - context_size)        end = min(len(text_chunks), idx + context_size + 1)
        context_window = " ".join(text_chunks[start:end])        results.append({            "text": context_window,            "similarity": similarities[idx],            "center_chunk": idx        })
    return results

04

上下文片段标题提取(CCH)

核心思路:用 LLM 为每个文本块生成简短描述性标题,建索引时同时存「块文本嵌入」和「标题嵌入」。检索时用查询分别与文本、标题算相似度,再取平均(或加权)作为该块得分,从而多一个“主题维度”提升检索精度。

优势与局限:

优势:标题浓缩主题,对概括性、概念型查询更友好;可与现有向量检索无缝结合。

局限:预处理阶段要为每块调用 LLM 生成标题,成本和延迟增加。

适用场景:块较长、需要“主题级”匹配的知识库。

# ========== 方法4:上下文片段标题提取(CCH) ==========# 为每块生成标题并嵌入,检索时用 (文本相似度 + 标题相似度) 综合排序
def generate_chunk_header(chunk):    """用 LLM 为单个文本块生成一句简洁标题,概括该块主题"""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": "为以下文本生成一个简洁的描述性标题。"},            {"role": "user", "content": chunk}        ]    )    return response.choices[0].message.content.strip()
def search_with_headers(query, chunks, text_embeddings, header_embeddings):    """检索:查询与「块文本」和「块标题」分别算相似度,取平均作为该块得分"""    query_embedding = create_embeddings(query)
    results = []    for i in range(len(chunks)):        sim_text = cosine_similarity(query_embedding, text_embeddings[i])        sim_header = cosine_similarity(query_embedding, header_embeddings[i])        avg_similarity = (sim_text + sim_header) / 2        results.append({"text": chunks[i], "similarity": avg_similarity})     results.sort(key=lambda x: x["similarity"], reverse=True)    return results

05

文档增强RAG(问题生成)

核心思路:为每个文本块用 LLM 生成若干“该块能回答的问题”,把「问题 + 对应块」一并写入向量库。用户查询时,既匹配块内容,也匹配这些预生成问题,从而拉近“问句”与“陈述句”的语义距离。

优势与局限:

优势:显著缓解 query(问句)与 document(陈述)之间的表述差异,提高召回。

局限:建库时每块要生成多条问题,成本和存储都增加;问题质量依赖模型与 prompt。

适用场景:FAQ、知识问答、用户常以问句形式提问的场景。

# ========== 方法5:文档增强RAG(问题生成) ==========# 为每块生成“该块能回答的问题”,问题与块一起入向量库,检索时 query 可匹配问题或块
def generate_questions(text_chunk, num_questions=5):    """根据块内容,用 LLM 生成若干该块能回答的问题,用于后续检索匹配"""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": f"基于以下文本,生成{num_questions}个该文本能够回答的问题。"},            {"role": "user", "content": text_chunk}        ]    )    questions = response.choices[0].message.content.strip().split("\n")    return [q.strip() for q in questions if q.strip()]
# 建库:块本身 + 其对应问题都写入向量库,并记录问题→块的映射vector_store = SimpleVectorStore()for chunk in chunks:    chunk_embedding = create_embeddings(chunk)    vector_store.add_item(chunk, chunk_embedding, metadata={"type": "chunk"})       questions = generate_questions(chunk)    for question in questions:        q_embedding = create_embeddings(question)        vector_store.add_item(            question, q_embedding,            metadata={"type": "question", "source_chunk": chunk}        )

06

查询转换

核心思路:在检索前对用户原始查询做变换,使检索更准或更全。常用三种策略:

  • 查询重写:把模糊、口语化查询改写成更具体、更贴近文档表述的形式

  • 回退提示(Step-back):生成一个更宽泛的“背景问题”,先检索背景再结合原问题

  • 子查询分解:把多子问题的复杂查询拆成 2~4 个简单子查询,分别检索再合并

优势与局限:

  • 优势:不改索引即可提升检索表现,尤其适合表述不规范或复杂的用户问句。

  • 局限:多一次(或多次)LLM 调用,延迟与成本增加;重写/分解质量依赖 prompt。

  • 适用场景:开放域问答、复杂多步问题、需要“先背景后细节”的检索。

# ========== 方法6:查询转换 ==========# 在检索前对 query 做改写 / 回退 / 分解,再用转换后的查询去检索
def rewrite_query(original_query):    """把模糊或口语化查询重写成更具体、更利于检索的表述(不改变意图)"""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": """你是一个查询重写专家。            将用户查询重写为更具体、更清晰的形式。            只输出重写后的查询,不要添加任何解释。"""},            {"role": "user", "content": original_query}        ]    )    return response.choices[0].message.content.strip()
def generate_step_back_query(original_query):    """生成一个更宽泛的“回退”问题,用于先检索背景知识,再结合原问题作答"""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": """你是一个查询生成专家。            为给定查询生成一个更广泛的"回退"问题,以帮助获取相关背景知识。            只输出回退查询,不要添加解释。"""},            {"role": "user", "content": original_query}        ]    )    return response.choices[0].message.content.strip()
def decompose_query(original_query):    """将复杂问题拆成 2~4 个简单子问题,便于分别检索后综合答案"""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": """将以下复杂问题分解为2-4个更简单的子问题。            每个子问题单独一行。只输出子问题,不要编号或解释。"""},            {"role": "user", "content": original_query}        ]    )    sub_queries = response.choices[0].message.content.strip().split("\n")    return [q.strip() for q in sub_queries if q.strip()]

07

重排序(Reranking)

核心思路:两阶段检索——先用向量(或 BM25)快速召回一批候选文档,再用更精细的模型对「查询-文档」对打分并重排,只保留最相关的若干条送入生成。常用实现:LLM 打 0–10 分,或专用 reranker 模型(如 Cross-Encoder)。

优势与局限:

  • 优势:在不扩大首阶段召回量的前提下显著提升 top-k 精度,减少无关上下文注入。

  • 局限:第二阶段要对每条候选调用模型,延迟和成本随候选数增加。

  • 适用场景:对准确率要求高、候选数可控(如 top-20 内 rerank)。

# ========== 方法7:重排序(Reranking) ==========# 一阶段粗检索得到候选列表,二阶段用 LLM 对「查询-文档」打相关性分并重排
def rerank_with_llm(query, documents, model="gpt-3.5-turbo"):    """对候选文档逐一用 LLM 打 0-10 相关性分,再按分数降序重排"""    reranked = []    for doc in documents:        response = client.chat.completions.create(            model=model,            messages=[                {"role": "system", "content": """你是一个相关性评估专家。                对给定文档与查询的相关性进行0-10打分。                只输出数字分数。"""},                {"role": "user", "content": f"查询: {query}\n\n文档: {doc['text']}"}            ],            temperature=0        )        score = float(response.choices[0].message.content.strip())        reranked.append({**doc, "rerank_score": score})       reranked.sort(key=lambda x: x["rerank_score"], reverse=True)    return reranked

08

相关段落提取(RSE)

核心思路:不为单块打分后简单取 top-k,而是为连续块序列算“价值和”:每块价值 = 相似度 − 惩罚项,再用最大子数组(Kadane)思想找价值和最大的连续段落。这样返回的是一整段连贯文本,而不是零散块。

优势与局限:

优势:上下文连贯、边界更自然,适合需要“一整段话”才能答好的问题。

局限:依赖块顺序与相似度曲线质量;实现和调参(惩罚、最小长度等)略复杂。

适用场景:长文档、叙述性强,且希望按“段落”而非“单块”呈现。

# ========== 方法8:相关段落提取(RSE) ==========# 为每块算「相似度 - 惩罚」作为价值,用最大子数组找“价值和最大”的连续段落
def calculate_chunk_values(similarities, irrelevant_chunk_penalty=0.2):    """把相似度转为价值:相关块为正,不相关块减去惩罚后为负,便于后续求连续最大和"""    values = []    for sim in similarities:        value = sim - irrelevant_chunk_penalty        values.append(value)    return values
def find_best_segments(values, max_segments=3, min_segment_length=1):    """Kadane 思想:在 value 序列上找最多 max_segments 段连续区间,使每段和最大"""    segments = []    n = len(values)
    for _ in range(max_segments):        best_sum = float('-inf')        best_start = best_end = 0        current_sum = 0        current_start = 0           for i in range(n):            current_sum += values[i]            if current_sum > best_sum and (i - current_start + 1) >= min_segment_length:                best_sum = current_sum                best_start = current_start                best_end = i            if current_sum < 0:                current_sum = 0                current_start = i + 1
        if best_sum > 0:            segments.append((best_start, best_end, best_sum))            for i in range(best_start, best_end + 1):                values[i] = 0        return segments
def reconstruct_segments(chunks, segments):    """根据 (start, end) 区间把对应块拼成完整段落文本"""    reconstructed = []    for start, end, score in segments:        segment_text = " ".join(chunks[start:end + 1])        reconstructed.append({            "text": segment_text,            "start": start,            "end": end,            "score": score        })    return reconstructed

09

上下文压缩

核心思路:检索得到多块文本后,不直接全部塞给 LLM,而是先对每块做“压缩”:只保留与当前查询强相关的内容,去掉无关句子或整段,从而减少噪声、节省 token、提高生成质量。

三种压缩策略:

选择性(Selective):从原文中筛选与查询相关的句子,保持原句、原序

摘要(Summary):针对查询写一段只含相关信息的摘要

抽取(Extraction):按查询抽取关键事实或结构化信息

优势与局限:

优势:显著减少无关上下文,降低幻觉与 token 消耗;可与任意检索方式组合。

局限:每块都要过一次 LLM,延迟与成本增加;过度压缩可能丢细节。

适用场景:检索结果偏长、噪声多,或上下文窗口紧张时。

# ========== 方法9:上下文压缩 ==========# 对每个检索到的块,用 LLM 按 query 只保留相关部分(选择性保留/摘要/抽取)
def compress_chunk(chunk, query, compression_type="selective", model="gpt-3.5-turbo"):    """根据 compression_type:选择性保留相关句 / 写相关摘要 / 抽取关键信息"""    if compression_type == "selective":        system_prompt = """You are an expert at information filtering.         Your task is to analyze a document chunk and extract ONLY the sentences         or paragraphs that are directly relevant to the user's query.         Remove all irrelevant content.         Your output should:        1. ONLY include text that helps answer the query        2. Preserve the exact wording of relevant sentences (do not paraphrase)        3. Maintain the original order of the text        4. Include ALL relevant content, even if it seems redundant        5. EXCLUDE any text that isn't relevant to the query"""    elif compression_type == "summary":        system_prompt = """You are an expert at summarization.         Create a concise summary of the provided chunk that focuses ONLY on         information relevant to the user's query."""    else:  # extraction        system_prompt = """You are an expert at information extraction.        Extract key facts and information relevant to the query."""
    response = client.chat.completions.create(        model=model,        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": f"Query: {query}\n\nDocument chunk:\n{chunk}"}        ],        temperature=0    )    return response.choices[0].message.content

10

上下文压缩

核心思路:把用户对回复的评分/反馈纳入闭环:记录「查询–回复–评分」,用 LLM 判断历史反馈与当前查询/文档是否相关,据此动态调整文档相关性得分,并把高质量问答对写入知识库,使系统越用越准。

核心组件:反馈收集 → 相关性调整(按历史反馈修正检索分数)→ 知识积累(优质 Q&A 入向量库)。

优势与局限:

  • 优势:可持续利用真实用户信号,适合客服、知识库等有稳定反馈的场景。

  • 局限:依赖高质量、足量反馈;反馈噪声或冷启动会影响调整效果。

  • 适用场景:有评分/点赞/纠错等用户反馈的在线系统。

# ========== 方法10:反馈回路RAG(摘自 11_反馈回路机制的rag.ipynb)==========
def assess_feedback_relevance(query, doc_text, feedback):    """    使用LLM评估过去的反馈是否与当前查询和文档相关。        参数:        query (str): 当前用户需要信息检索的查询        doc_text (str): 正在评估的文档文本内容        feedback (Dict): 包含'query'和'response'键的过去反馈数据        返回:        bool: 如果反馈被认为与当前查询/文档相关,则返回True,否则返回False    """    system_prompt = """You are an AI system that determines if a past feedback is relevant to a current query and document.    Answer with ONLY 'yes' or 'no'. Your job is strictly to determine relevance, not to provide explanations."""        user_prompt = f"""    Current query: {query}    Past query that received feedback: {feedback['query']}    Document content: {doc_text[:500]}... [truncated]    Past response that received feedback: {feedback['response'][:500]}... [truncated]        Is this past feedback relevant to the current query and document? (yes/no)    """    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )
    answer = response.choices[0].message.content.strip().lower()    return 'yes' in answer
def adjust_relevance_scores(query, results, feedback_data):    """    根据历史反馈调整文档相关性得分,以提高检索质量。
    参数:        query (str): 当前用户的查询        results (List[Dict]): 带有原始相似度得分的检索到的文档        feedback_data (List[Dict]): 包含用户评分的历史反馈数据
    返回:        List[Dict]: 调整后相关性得分的结果,按新的得分排序    """    if not feedback_data:        return results
    print("Adjusting relevance scores based on feedback history...")
    for i, result in enumerate(results):        document_text = result["text"]        relevant_feedback = []        for feedback in feedback_data:            is_relevant = assess_feedback_relevance(query, document_text, feedback)            if is_relevant:                relevant_feedback.append(feedback)        if relevant_feedback:            avg_relevance = sum(f['relevance'] for f in relevant_feedback) / len(relevant_feedback)            modifier = 0.5 + (avg_relevance / 5.0)               original_score = result["similarity"]            adjusted_score = original_score * modifier                result["original_similarity"] = original_score            result["similarity"] = adjusted_score            result["relevance_score"] = adjusted_score            result["feedback_applied"] = True            result["feedback_count"] = len(relevant_feedback)                     print(f"  Document {i+1}: Adjusted score from {original_score:.4f} to {adjusted_score:.4f} based on {len(relevant_feedback)} feedback(s)")    results.sort(key=lambda x: x["similarity"], reverse=True)
    return results
def generate_response(query, context, model="gpt-3.5-turbo"):    """    根据查询和上下文生成回复。    参数:        query (str): 用户查询        context (str): 来自检索到的文档的上下文文本        model (str): 要使用的LLM模型    返回:        str: 生成的回复    """    system_prompt = """You are a helpful AI assistant. Answer the user's question based only on the provided context. If you cannot find the answer in the context, state that you don't have enough information."""    user_prompt = f"""        Context:        {context}               Question: {query}               Please provide a comprehensive answer based only on the context above.    """    response = client.chat.completions.create(        model=model,        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )    return response.choices[0].message.content
def rag_with_feedback_loop(query, vector_store, feedback_data, k=5, model="gpt-3.5-turbo"):    """    完整的RAG管道,结合反馈循环。    参数:        query (str): 用户查询        vector_store (SimpleVectorStore): 包含文档片段的向量存储        feedback_data (List[Dict]): 历史反馈数据        k (int): 检索的文档数量        model (str): 用于回复生成的语言模型    返回:        Dict: 结果字典,包括查询、检索到的文档和回复    """    print(f"\n=== Processing query with feedback-enhanced RAG ===")    print(f"Query: {query}")       query_embedding = create_embeddings(query)    results = vector_store.similarity_search(query_embedding, k=k)    adjusted_results = adjust_relevance_scores(query, results, feedback_data)    retrieved_texts = [result["text"] for result in adjusted_results]    context = "\n\n---\n\n".join(retrieved_texts)    print("Generating response...")    response = generate_response(query, context, model)    result = {        "query": query,        "retrieved_documents": adjusted_results,        "response": response    }
    print("\n=== Response ===")    print(response)
    return result

11

自适应检索

核心思路:先对用户查询做类型分类(事实型 分析型 观点型 / 情境型),再根据类型选用不同检索策略(如事实型偏精确匹配、分析型多召回再压缩等),实现“因问施策”。

优势与局限:

优势:同一套系统可兼顾多类问题,检索更有的放矢。

局限:分类与各策略设计依赖领域知识;分类错误会传导到检索。

适用场景:混合类型问答、客服/咨询等。

# ========== 方法11:自适应检索 ==========# 先对 query 做类型分类,再按类型选择不同检索策略(事实/分析/观点/情境)
def classify_query(query, model="gpt-3.5-turbo"):    """用 LLM 将查询归为四类之一:Factual / Analytical / Opinion / Contextual"""    system_prompt = """Classify the given query into exactly one of these categories:        - Factual: Queries seeking specific, verifiable information.        - Analytical: Queries requiring comprehensive analysis or explanation.        - Opinion: Queries about subjective matters or seeking diverse viewpoints.        - Contextual: Queries that depend on user-specific context.        Return ONLY the category name."""     response = client.chat.completions.create(        model=model,        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": f"Classify this query: {query}"}        ],        temperature=0    )    category = response.choices[0].message.content.strip()    valid_categories = ["Factual", "Analytical", "Opinion", "Contextual"]    for valid in valid_categories:        if valid in category:            return valid    return "Factual"
def adaptive_retrieval(query, vector_store, k=4, user_context=None):    """按分类结果调用对应检索策略:事实型/分析型/观点型/情境型各有实现"""    query_type = classify_query(query)        if query_type == "Factual":        results = factual_retrieval_strategy(query, vector_store, k)    elif query_type == "Analytical":        results = analytical_retrieval_strategy(query, vector_store, k)    elif query_type == "Opinion":        results = opinion_retrieval_strategy(query, vector_store, k)    elif query_type == "Contextual":        results = contextual_retrieval_strategy(query, vector_store, k, user_context)    else:        results = factual_retrieval_strategy(query, vector_store, k)        return results

12

Self-RAG(自适应RAG)

核心思路:在「检索 → 生成」全流程中插入多个反思与决策点:是否要检索、检索到的文档是否相关、生成的回复是否被上下文支撑、回复是否实用等,从而在运行时自适应地决定是否检索、是否重试、是否标注“无依据”。

六个关键组件:

  1. 检索决策:判断当前查询是否需要检索

  2. 文档检索:需要时做向量检索

  3. 相关性评估:评估每个检索文档与查询是否相关

  4. 回复生成:基于相关上下文生成回复

  5. 支持评估:评估回复是否被上下文充分支持

  6. 效用评估:对回复的整体实用性打 1–5 分

优势与局限:

  • 优势:可减少无谓检索与幻觉,输出更可控、可解释。

  • 局限:多次 LLM 调用,延迟与成本高;依赖各环节 prompt 设计。

  • 适用场景:对准确性与可追溯性要求高的场景。

# ========== 方法12:Self-RAG ==========# 流程:是否需要检索 → 检索 → 评估文档相关性 → 生成回复 → 评估支持度与效用 → 选最佳回复import re  # rate_utility 中解析评分用def determine_if_retrieval_needed(query):    """判断给定查询是否需要检索。事实/具体信息类答 Yes,常识或主观类答 No。"""    system_prompt = """You are an AI assistant that determines if retrieval is necessary to answer a query.    For factual questions, specific information requests, or questions about events, people, or concepts, answer "Yes".    For opinions, hypothetical scenarios, or simple queries with common knowledge, answer "No".    Answer with ONLY "Yes" or "No"."""    user_prompt = f"Query: {query}\n\nIs retrieval necessary to answer this query accurately?"    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )    answer = response.choices[0].message.content.strip().lower()    return "yes" in answerdef evaluate_relevance(query, context):    """评估上下文与查询的相关性。返回 'relevant' 或 'irrelevant'。"""    system_prompt = """You are an AI assistant that determines if a document is relevant to a query.    Consider whether the document contains information that would be helpful in answering the query.    Answer with ONLY "Relevant" or "Irrelevant"."""    max_context_length = 2000    if len(context) > max_context_length:        context = context[:max_context_length] + "... [truncated]"    user_prompt = f"""Query: {query}    Document content:    {context}    Is this document relevant to the query? Answer with ONLY "Relevant" or "Irrelevant"."""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )    return response.choices[0].message.content.strip().lower()def assess_support(response, context):    """判断生成的回复是否由上下文充分支持。返回 'fully supported' / 'partially supported' / 'no support'。"""    system_prompt = """You are an AI assistant that determines if a response is supported by the given context.    Evaluate if the facts, claims, and information in the response are backed by the context.    Answer with ONLY one of these three options:    - "Fully supported": All information in the response is directly supported by the context.    - "Partially supported": Some information in the response is supported by the context, but some is not.    - "No support": The response contains significant information not found in or contradicting the context."""    max_context_length = 2000    if len(context) > max_context_length:        context = context[:max_context_length] + "... [truncated]"    user_prompt = f"""Context:    {context}    Response:    {response}    How well is this response supported by the context? Answer with ONLY "Fully supported", "Partially supported", or "No support"."""    api_response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )    return api_response.choices[0].message.content.strip().lower()def rate_utility(query, response):    """对回复的实用性打 1–5 分。"""    system_prompt = """You are an AI assistant that rates the utility of a response to a query.    Consider how well the response answers the query, its completeness, correctness, and helpfulness.    Rate the utility on a scale from 1 to 5. Answer with ONLY a single number from 1 to 5."""    user_prompt = f"""Query: {query}\nResponse:\n{response}\n\nRate the utility of this response on a scale from 1 to 5:"""    resp = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0    )    rating = resp.choices[0].message.content.strip()    rating_match = re.search(r'[1-5]', rating)    return int(rating_match.group()) if rating_match else 3def generate_response(query, context=None):    """根据查询和可选上下文生成回复。无 context 时仅凭模型自身知识回答。"""    system_prompt = """You are a helpful AI assistant. Provide a clear, accurate, and informative response to the query."""    if context:        user_prompt = f"""Context:\n{context}\n\nQuery: {query}\n\nPlease answer the query based on the provided context."""    else:        user_prompt = f"""Query: {query}\n\nPlease answer the query to the best of your ability."""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": user_prompt}        ],        temperature=0.2    )    return response.choices[0].message.content.strip()def self_rag(query, vector_store, top_k=3):    # 第一步:确定是否需要检索    print("Step 1: Determining if retrieval is necessary...")    retrieval_needed = determine_if_retrieval_needed(query)
    # 初始化跟踪Self-RAG过程的指标    metrics = {        "retrieval_needed": retrieval_needed,        "documents_retrieved": 0,        "relevant_documents": 0,        "response_support_ratings": [],        "utility_ratings": []    }
    best_response = None    best_score = -1
    if retrieval_needed:        # 第二步:检索相关文档        print("\nStep 2: Retrieving relevant documents...")        query_embedding = create_embeddings(query)        results = vector_store.similarity_search(query_embedding, k=top_k)        metrics["documents_retrieved"] = len(results)        print(f"Retrieved {len(results)} documents")
        # 第三步:评估每个文档的相关性        print("\nStep 3: Evaluating document relevance...")        relevant_contexts = []
        for i, result in enumerate(results):            context = result["text"]            relevance = evaluate_relevance(query, context)            print(f"Document {i+1} relevance: {relevance}")
            if relevance == "relevant":                relevant_contexts.append(context)
        metrics["relevant_documents"] = len(relevant_contexts)        print(f"Found {len(relevant_contexts)} relevant documents")
        if relevant_contexts:            # 第四步:处理每个相关上下文            print("\nStep 4: Processing relevant contexts...")            for i, context in enumerate(relevant_contexts):                print(f"\nProcessing context {i+1}/{len(relevant_contexts)}...")
                # 基于上下文生成回复                print("Generating response...")                response = generate_response(query, context)
                # 评估回复在多大程度上由上下文支持                print("Assessing support...")                support_rating = assess_support(response, context)                print(f"Support rating: {support_rating}")                metrics["response_support_ratings"].append(support_rating)
                # 对回复的实用性进行评分                print("Rating utility...")                utility_rating = rate_utility(query, response)                print(f"Utility rating: {utility_rating}/5")                metrics["utility_ratings"].append(utility_rating)
                # 计算总体分数(支持度和实用性越高,分数越高)                support_score = {                    "fully supported": 3,                     "partially supported": 1,                     "no support": 0                }.get(support_rating, 0)
                overall_score = support_score * 5 + utility_rating                print(f"Overall score: {overall_score}")
                # 跟踪最佳回复                if overall_score > best_score:                    best_response = response                    best_score = overall_score                    print("New best response found!")
        # 如果没有找到相关上下文或所有回复得分都很低        if not relevant_contexts or best_score <= 0:            print("\nNo suitable context found or poor responses, generating without retrieval...")            best_response = generate_response(query)    else:        # 不需要检索,直接生成回复        print("\nNo retrieval needed, generating response directly...")        best_response = generate_response(query)
    # 最终指标    metrics["best_score"] = best_score    metrics["used_retrieval"] = retrieval_needed and best_score > 0
    print("\n=== Self-RAG Completed ===")
    return {        "query": query,        "response": best_response,        "metrics": metrics    }

13

命题分块

核心思路:不按字符或句子切块,而是把文本拆成原子化、自包含的“命题”(一句一事实,可独立理解)。用命题做检索单元,实现更细粒度的 query–content 匹配。

优势与局限:

  • 优势:检索粒度细,适合事实型、实体型问题;命题可复用、可组合。

  • 局限:建库需对每块做命题抽取,成本高;命题过多时索引与检索开销增大。

  • 适用场景:知识密集型、强调“单事实”准确性的 QA。

# ========== 方法13:命题分块 ==========# 把文本块拆成「单事实、自包含」的命题句,以命题为单元建索引与检索def generate_propositions(chunk):    """用 LLM 将一块文本拆成多条原子命题:每句一个事实、可独立理解、含主谓结构"""    system_prompt = """Break down the following text into simple, self-contained propositions.     Each proposition should:    1. Express a Single Fact    2. Be Understandable Without Context    3. Use Full Names, Not Pronouns    4. Include Relevant Dates/Qualifiers    5. Contain One Subject-Predicate Relationship    Output ONLY the list of propositions."""    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": f"Text to convert:\n\n{chunk['text']}"}        ],        temperature=0    )    raw_propositions = response.choices[0].message.content.strip().split('\n')    # 去掉编号、列表符,过滤过短无效句    clean_propositions = []    for prop in raw_propositions:        cleaned = re.sub(r'^\s*(\d+\.|\-|\*)\s*', '', prop).strip()        if cleaned and len(cleaned) > 10:            clean_propositions.append(cleaned)    return clean_propositionsdef process_document_into_propositions(pdf_path, chunk_size=800, chunk_overlap=100,                                       quality_thresholds=None):    # 如果未提供质量阈值,则设置默认值    if quality_thresholds is None:        quality_thresholds = {            "accuracy": 7,            "clarity": 7,            "completeness": 7,            "conciseness": 7        }
    # 从PDF文件中提取文本    text = extract_text_from_pdf(pdf_path)
    # 从提取的文本创建块    chunks = chunk_text(text, chunk_size, chunk_overlap)
    # 初始化一个列表来存储所有命题    all_propositions = []
    print("Generating propositions from chunks...")    for i, chunk in enumerate(chunks):        print(f"Processing chunk {i+1}/{len(chunks)}...")
        # 为当前块生成命题        chunk_propositions = generate_propositions(chunk)        print(f"Generated {len(chunk_propositions)} propositions")
        # 处理每个生成的命题        for prop in chunk_propositions:            proposition_data = {                "text": prop,                "source_chunk_id": chunk["chunk_id"],                "source_text": chunk["text"]            }            all_propositions.append(proposition_data)
    # 评估生成的命题的质量    print("\nEvaluating proposition quality...")    quality_propositions = []
    for i, prop in enumerate(all_propositions):        if i % 10 == 0:  # 每10个命题更新一次状态            print(f"Evaluating proposition {i+1}/{len(all_propositions)}...")
        # 评估当前命题的质量        scores = evaluate_proposition(prop["text"], prop["source_text"])        prop["quality_scores"] = scores
        # 检查命题是否通过质量阈值        passes_quality = True        for metric, threshold in quality_thresholds.items():            if scores.get(metric, 0) < threshold:                passes_quality = False                break
        if passes_quality:            quality_propositions.append(prop)        else:            print(f"Proposition failed quality check: {prop['text'][:50]}...")
    print(f"\nRetained {len(quality_propositions)}/{len(all_propositions)} propositions after quality filtering")
    return chunks, quality_propositions

14

多模态RAG

核心思路:从 PDF 等文档中同时提取文本与图像,用视觉模型为每张图生成文本描述(caption),将「正文 + 图像描述」统一嵌入并写入同一向量库,实现“以文搜文+以文搜图”的联合检索。

# ========== 方法14:多模态RAG ==========# PDF 中同时抽文本与图像,图像用 VLM 生成 caption,文本+caption 一起入向量库统一检索
def extract_content_from_pdf(pdf_path, output_dir=None):    """按页从 PDF 抽取文本块和图像,图像保存到 output_dir 并记录路径与页码"""    text_data = []    image_paths = []    with fitz.open(pdf_path) as pdf_file:        for page_number in range(len(pdf_file)):            page = pdf_file[page_number]            text = page.get_text().strip()            if text:                text_data.append({"content": text, "metadata": {"page": page_number + 1, "type": "text"}})            for img_index, img in enumerate(page.get_images(full=True)):                xref = img[0]                base_image = pdf_file.extract_image(xref)                if base_image:                    img_path = os.path.join(output_dir, f"page_{page_number+1}_img_{img_index+1}.{base_image['ext']}")                    with open(img_path, "wb") as f:                        f.write(base_image["image"])                    image_paths.append({"path": img_path, "metadata": {"page": page_number + 1, "type": "image"}})    return text_data, image_paths
def generate_image_caption(image_path):    """用多模态模型(如 LLaVA)为图像生成文字描述,便于与文本一起嵌入检索"""    base64_image = encode_image(image_path)    response = client.chat.completions.create(        model="llava-hf/llava-1.5-7b-hf",        messages=[            {"role": "system", "content": "Describe images from academic papers in detail."},            {"role": "user", "content": [                {"type": "text", "text": "Describe this image in detail:"},                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}            ]}        ]    )    return response.choices[0].message.content

15

融合检索

核心思路:向量检索(语义相似)与 BM25(词匹配)同时做,对两路分数分别 Min-Max 归一化 后按 alpha 加权融合:final_score = alpha * norm_vector + (1-alpha) * norm_bm25,再按融合分取 top-k。语义与关键词互补,召回更稳。

# ========== 方法15:融合检索 ==========# 向量检索 + BM25 双路打分,归一化后加权融合,再取 top-k
def bm25_search(bm25, chunks, query, k=5):    """BM25 关键词检索:对 query 分词后算各 chunk 的 BM25 分,按分排序取 top-k"""    query_tokens = query.split()    scores = bm25.get_scores(query_tokens)
    results = []    for i, score in enumerate(scores):        metadata = chunks[i].get("metadata", {}).copy()        metadata["index"] = i        results.append({"text": chunks[i]["text"], "metadata": metadata, "bm25_score": float(score)})
    results.sort(key=lambda x: x["bm25_score"], reverse=True)    return results[:k]
def fusion_retrieval(query, chunks, vector_store, bm25_index, k=5, alpha=0.5):    """融合:向量与 BM25 各算一版分数 → Min-Max 归一化 → 加权合并 → 按最终分取 top-k"""    epsilon = 1e-8
    query_embedding = create_embeddings(query)    vector_results = vector_store.similarity_search_with_scores(query_embedding, k=len(chunks))    bm25_results = bm25_search(bm25_index, chunks, query, k=len(chunks))
    vector_scores_dict = {r["metadata"]["index"]: r["similarity"] for r in vector_results}    bm25_scores_dict = {r["metadata"]["index"]: r["bm25_score"] for r in bm25_results}
    vector_scores = np.array([vector_scores_dict.get(i, 0.0) for i in range(len(chunks))])    bm25_scores = np.array([bm25_scores_dict.get(i, 0.0) for i in range(len(chunks))])
    v_min, v_max = vector_scores.min(), vector_scores.max()    b_min, b_max = bm25_scores.min(), bm25_scores.max()    norm_vector = (vector_scores - v_min) / (v_max - v_min + epsilon)    norm_bm25 = (bm25_scores - b_min) / (b_max - b_min + epsilon)
    final_scores = alpha * norm_vector + (1 - alpha) * norm_bm25
    top_indices = np.argsort(final_scores)[::-1][:k]    return [{"text": chunks[i]["text"], "score": final_scores[i]} for i in top_indices]

16

图RAG(Graph RAG)

核心思路:从每个文本块中抽取概念/实体,以块为节点、以共享概念 + 语义相似度为边权建知识图谱。检索时先命中部分节点,再通过图上的边扩展关联节点,从而把跨多块的相关信息一并拉取。

优势与局限:

优势:能利用“概念共现”“实体关系”做关联扩展,适合概念密集、关系复杂的领域。

局限:建图与概念抽取成本高;图规模大时遍历与索引设计更复杂。

适用场景:知识图谱、领域百科、多实体关系推理。

# ========== 方法16:图RAG(Graph RAG) ==========# 块→节点,块内概念→属性;共享概念+语义相似度→边;检索时可沿边扩展关联块
def build_knowledge_graph(chunks):    """为每个 chunk 抽概念、建节点;根据共享概念与嵌入相似度建边,得到知识图谱"""    graph = nx.Graph()    texts = [chunk["text"] for chunk in chunks]    embeddings = create_embeddings(texts)
    for i, chunk in enumerate(chunks):        concepts = extract_concepts(chunk["text"])  # LLM 抽取概念/实体        graph.add_node(i, text=chunk["text"], concepts=concepts, embedding=embeddings[i])
    for i in range(len(chunks)):        node_concepts = set(graph.nodes[i]["concepts"])        for j in range(i + 1, len(chunks)):            other_concepts = set(graph.nodes[j]["concepts"])            shared_concepts = node_concepts.intersection(other_concepts)
            if shared_concepts:                similarity = np.dot(embeddings[i], embeddings[j]) / (                    np.linalg.norm(embeddings[i]) * np.linalg.norm(embeddings[j]))                concept_score = len(shared_concepts) / min(len(node_concepts), len(other_concepts))                edge_weight = 0.7 * similarity + 0.3 * concept_score
                if edge_weight > 0.6:                    graph.add_edge(i, j, weight=edge_weight, shared_concepts=list(shared_concepts))
    return graph, embeddings

17

分层检索RAG

核心思路:建两层索引——摘要层(如每页/每章一个摘要)和详细层(页内细粒度块)。检索时先查摘要层锁定相关页/章,再只在对应页内查详细块,从而在保证相关性的前提下缩小搜索范围、提升效率。

优势与局限:

优势:适合超长文档、十亿级规模;先筛范围再精查,延迟与算力更可控。

局限:摘要质量与粒度影响第一层召回;若相关分布在多页,需合理设置 k_summaries。

适用场景:长篇报告、书籍、法规、多章节文档。

# ========== 方法17:分层检索RAG ==========# 第一层:页/章摘要向量库;第二层:页内详细块向量库。先搜摘要定范围,再在范围内搜块
def process_document_hierarchically(pdf_path, chunk_size=1000, chunk_overlap=200):    """建两层索引:每页摘要入 summary_store,每页内细块入 detailed_store"""    pages = extract_text_from_pdf(pdf_path)
    summaries = []    for i, page in enumerate(pages):        summary_text = generate_page_summary(page["text"])        summaries.append({"text": summary_text, "metadata": {**page["metadata"], "is_summary": True}})
    detailed_chunks = []    for page in pages:        page_chunks = chunk_text(page["text"], page["metadata"], chunk_size, chunk_overlap)        detailed_chunks.extend(page_chunks)
    summary_store = SimpleVectorStore()    detailed_store = SimpleVectorStore()    # 分别为 summary 与 detailed_chunks 建嵌入并写入对应 store    return summary_store, detailed_store
def retrieve_hierarchically(query, summary_store, detailed_store, k_summaries=3, k_chunks=5):    """先按 query 在摘要层检索出 k_summaries 个相关页,再仅在这些页的详细块里检索"""    query_embedding = create_embeddings(query)
    summary_results = summary_store.similarity_search(query_embedding, k=k_summaries)    relevant_pages = [r["metadata"]["page"] for r in summary_results]
    def page_filter(metadata):        return metadata["page"] in relevant_pages
    detailed_results = detailed_store.similarity_search(        query_embedding, k=k_chunks * len(relevant_pages), filter_func=page_filter    )    return detailed_results

18

假设文档嵌入(HyDE)

核心思路:用户查询往往很短,与长文档在嵌入空间里距离较远。HyDE 的做法是:先用 LLM 根据问题生成一段“假设的”答案文档(风格、长度接近真实文档),再用这段假设文档的嵌入(而非原始 query 的嵌入)去检索真实文档,从而拉近 query 与 document 的表示距离。

优势与局限:

优势:能把短 / 抽象问句补成伪文档,大幅提升检索相关性;不用重建索引,只在检索侧增强 query。

局限:多一次 LLM 生成与嵌入调用;假设文档若偏离真实文档风格,可能引入噪声。

适用场景:短查询、知识问答、知识库规整、关键词匹配差的 RAG 场景。

# ========== 方法18:假设文档嵌入(HyDE) ==========# 用 query 生成一段“假设答案”文档,用该文档的嵌入去检索,而非用 query 嵌入
def generate_hypothetical_document(query, desired_length=1000):    """根据问题生成一段“像标准答案”的假设文档,长度与风格接近真实文档"""    system_prompt = f"""You are an expert document creator.     Given a question, generate a detailed document that would directly answer this question.    The document should be approximately {desired_length} characters long.    Write as if from an authoritative source. Include specific details and facts.    Do not mention that this is a hypothetical document."""
    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": f"Question: {query}\n\nGenerate a document:"}        ],        temperature=0.1    )    return response.choices[0].message.content
def hyde_rag(query, vector_store, k=5):    """HyDE 流程:生成假设文档 → 用假设文档嵌入检索 → 用真实检索结果生成最终答案"""    hypothetical_doc = generate_hypothetical_document(query)
    hypothetical_embedding = create_embeddings([hypothetical_doc])[0]
    retrieved_chunks = vector_store.similarity_search(hypothetical_embedding, k=k)
    response = generate_response(query, retrieved_chunks)    return {"query": query, "hypothetical_document": hypothetical_doc,            "retrieved_chunks": retrieved_chunks, "response": response}

19

动态纠正RAG(CRAG)

核心思路:检索完成后先评估这批文档与 query 的相关性(如 0–1 分),再按分数区间做分支:高相关则只用本地文档;低相关则放弃本地、改用网络搜索;中等则本地 + 网络一起用。从而在“知识不足”时自动纠偏,避免硬用无关文档生成。

优势与局限:

  • 优势:降低“检索到无关文档仍强行生成”的幻觉与错误;适合知识边界不固定、需时效信息的场景。

  • 局限:需要可靠的相关性评估(LLM 或 reranker)和网络搜索接口;阈值需调参。

  • 适用场景:开放域问答、时效性强的场景、本地库覆盖不全时。

# ========== 方法19:动态纠正RAG(CRAG) ==========# 检索 → 评估相关性 → 高/中/低分分别采用「仅本地 / 本地+网络 / 仅网络」
def evaluate_document_relevance(query, document):    """用 LLM 对「query-文档」打 0–1 相关性分,用于 CRAG 分支决策"""    system_prompt = """Rate how relevant the given document is to the query     on a scale from 0 to 1. Provide ONLY the score as a float."""
    response = client.chat.completions.create(        model="gpt-3.5-turbo",        messages=[            {"role": "system", "content": system_prompt},            {"role": "user", "content": f"Query: {query}\n\nDocument: {document}"}        ],        temperature=0, max_tokens=5    )    score_text = response.choices[0].message.content.strip()    score_match = re.search(r'(\d+(\.\d+)?)', score_text)    return float(score_match.group(1)) if score_match else 0.5
def crag_process(query, vector_store, k=3):    """CRAG:检索 → 对 top 文档打相关性分 → 按最高分选策略(仅本地/仅网络/混合)→ 生成"""    query_embedding = create_embeddings(query)    retrieved_docs = vector_store.similarity_search(query_embedding, k=k)
    relevance_scores = []    for doc in retrieved_docs:        score = evaluate_document_relevance(query, doc["text"])        relevance_scores.append(score)        doc["relevance"] = score
    max_score = max(relevance_scores) if relevance_scores else 0
    if max_score > 0.7:        final_knowledge = retrieved_docs[relevance_scores.index(max_score)]["text"]    elif max_score < 0.3:        web_results, web_sources = perform_web_search(query)        final_knowledge = refine_knowledge(web_results)    else:        best_doc = retrieved_docs[relevance_scores.index(max_score)]["text"]        web_results, _ = perform_web_search(query)        final_knowledge = refine_knowledge(best_doc) + "\n" + refine_knowledge(web_results)
    response = generate_response(query, final_knowledge)    return response

20

强化学习增强RAG

核心思路:把 RAG 流程看成强化学习:状态(当前 query、已选上下文、历史回复与奖励)、动作(重写 query、扩展/过滤上下文、生成回复)、奖励(如生成回复与标准答案的语义相似度)。用 epsilon-greedy 等策略根据状态选动作,用奖励迭代优化,使检索与生成策略逐步变好。

优势与局限:

优势:可端到端利用标注或用户反馈优化整条管道;理论上能学到复杂策略。

局限:需要奖励信号(标注答案或用户反馈)、训练循环与稳定性调参。

适用场景:有充足标注或反馈、希望长期自动优化效果的场景。

# ========== 方法20:强化学习增强RAG ==========# 状态-动作-奖励建模;用奖励(如回复与标准答案的相似度)驱动策略选择
def calculate_reward(response: str, ground_truth: str) -> float:    """奖励函数:回复与标准答案的嵌入余弦相似度,范围约 [-1, 1]"""    response_embedding = generate_embeddings([response])[0]    ground_truth_embedding = generate_embeddings([ground_truth])[0]    similarity = cosine_similarity(response_embedding, ground_truth_embedding)    return similarity
def expand_context(query, current_chunks, top_k=3):    """动作之一:在已有 chunks 基础上再检索若干相关块并追加"""    additional_chunks = retrieve_relevant_chunks(query, top_k=top_k + len(current_chunks))    new_chunks = [chunk for chunk in additional_chunks if chunk not in current_chunks]    return current_chunks + new_chunks[:top_k]
def filter_context(query, context_chunks):    """动作之一:按与 query 的相似度只保留最相关的若干块"""    query_embedding = generate_embeddings([query])[0]    chunk_embeddings = [generate_embeddings([chunk])[0] for chunk in context_chunks]
    relevance_scores = [cosine_similarity(query_embedding, emb) for emb in chunk_embeddings]    sorted_chunks = [x for _, x in sorted(zip(relevance_scores, context_chunks), reverse=True)]    return sorted_chunks[:min(5, len(sorted_chunks))]
def policy_network(state, action_space, epsilon=0.2):    """epsilon-greedy:以概率 epsilon 随机探索,否则按启发式选动作(重写/扩展/过滤/生成)"""    if np.random.random() < epsilon:        action = np.random.choice(action_space)    else:        if len(state["previous_responses"]) == 0:            action = "rewrite_query"        elif state["previous_rewards"] and max(state["previous_rewards"]) < 0.7:            action = "expand_context"        elif len(state["context"]) > 5:            action = "filter_context"        else:            action = "generate_response"    return action

   方法总结对比

编号方法优化维度核心思想
1语义分块分块基于语义相似度的智能分割
2切块大小评估分块数据驱动选择最优切块参数
3上下文增强检索检索返回匹配块及其相邻块
4上下文标题提取(CCH)检索标题+文本双维度匹配
5文档增强RAG索引预生成问题弥补语义鸿沟
6查询转换查询重写/回退/分解查询
7重排序检索两阶段:粗检索+精排序
8相关段落提取(RSE)检索最大子数组找连续最优段落
9上下文压缩后处理压缩检索结果去除噪声
10反馈回路系统用户反馈动态调整系统
11自适应检索检索按查询类型选策略
12Self-RAG生成多维度反思评估机制
13命题分块分块原子化事实陈述作为检索单元
14多模态RAG索引图文联合检索
15融合检索检索向量+BM25加权融合
16图RAG检索知识图谱关联发现
17分层检索检索摘要→详细的两级检索
18HyDE查询假设文档嵌入替代查询嵌入
19CRAG系统动态评估并纠正检索质量
20RL增强RAG系统强化学习优化全流程

   优化方法选择指南

  • 分块优化:检索不够精准时,优先考虑语义分块(1)、命题分块(13)或切块大小评估(2)。

  • 检索增强:融合检索(15)性价比高、易落地;图RAG(16)适合概念与关系密集的领域。

  • 查询优化:HyDE(18)对短查询、抽象问句效果好;查询转换(6)适合复杂、多子问题查询。

  • 后处理:重排序(7)+ 上下文压缩(9)能明显提升最终回复质量与可控性。

  • 系统级:CRAG(19)适合对可靠性、时效性要求高的场景;反馈回路(10)适合有持续用户反馈的产品。

  • 端到端:Self-RAG(12)与 RL 增强(20)能力最全面,实现与调参成本也更高,可按需选用。

    -End-

    原创作者|李鑫阳

感谢你读到这里,不如关注一下?👇

你对本文内容有哪些看法?同意、反对、困惑的地方是?欢迎留言,我们将邀请作者针对性回复你的评论,欢迎评论留言补充。我们将选取1则优质的评论,送出腾讯云定制文件袋套装1个(见下图)。3月12日中午12点开奖。

扫码领取腾讯云开发者专属服务器代金券!

图片

相关推荐

大模型的Agent Skill功能,在LLM HTTP底层交互流中是怎么承载的?

网络文章文本的 skill,昨天我实现了之后也就开始好奇起 Skills 的底层原理了——相比起各种花里胡哨的 agrnt 应用,我一直以来都很对大模型在纯粹的 HTTP 交互层面是如何交互的更感兴趣。Skill 的全部"魔法"都发生在 system prompt 的措辞和 SKILL.md 文件的编写质量上——本质上是一种 prompt engineering + 文件系统的组合。但是各种天花乱坠的 skills,是如何在底层的 HTTP 中,与大模型——这个只会嘴遁的工具交互的呢?

QcloudCommunity的博客 401

万字入门AI Infra:深入理解大模型中的数学与Infra优化

关注腾讯云开发者,一手技术干货提前解锁👇AI Infra科普、入门或者进阶 ~~ 不到 5 万字,带你融会贯通理解大模型的数学、算法、硬件到系统工程。任何问题欢迎沟通交流。可怕,我竟然有点认同这句话。当然大概率是因为姚顺宇太懂AI了,而我则是因为无知者无畏。不过仔细想想,大模型推理中的数学逻辑确实不复杂,很多原理只需要高中数学知识就能看懂。但是为什么像 vLLM 这种推理系统这么复杂呢?本文将拆解大模型中几个核心操作(RMSNorm、Softmax、Causal Mask、Sampling)背后的数学与

QcloudCommunity的博客 1158

平平无奇的源码,竟藏着Agent的核心秘密?

System Prompt 是剧本,Skill 是剧本的扩展包,Agent Loop 是演员按剧本行动。欢迎留言,我们将邀请作者针对性回复你的评论,我们将选取1则优质的评论,送出腾讯云定制文件袋套装。,让 Agent 能主动"巡逻",而不只是被动等待用户消息。OpenClaw 的 System Prompt 分层结构。的"行为底线",任何 Skill 或用户命令都无法覆盖它。精华 2:Skill 的"按需加载"避免 token 浪费。精华 1:System Prompt 是"分层乐高积木"

QcloudCommunity的博客 424

QQ音乐Harness Engineering实践

一个看似简单的需求,背后可能牵动服务调用链、配置、灰度、埋点、错误码、接口契约和历史兼容性。当 AI 开始快速生成大量代码,真正的瓶颈就不再是"写不出来",而是"看不完、想不清、管不住"。在对话式编码阶段,一种典型的工作模式逐渐流行:开发者把需求丢给 AI,扫一眼输出"看起来对"就直接采纳,不审 diff、不追问逻辑、不验证边界。以音乐商业化业务为例,一个需求可能从 TAPD 单开始,经过需求评审、技术方案、服务影响面分析、IDL 契约变更、业务代码实现、测试验证、CR、灰度上线,最后才进入稳定运行。

QcloudCommunity的博客 711

从Prompt、Context到Harness,工程的三次进化与终局之战

同时,强制要求散落各处的决策记录(Slack、邮件、文档)全部迁移至代码仓库,确保 Agent 的唯一信息来源是可信的、版本受控的仓库。更坑爹的是,研究表明,当上下文过长时,模型会出现"中间遗忘(Lost in the Middle)"现象:它对开头和结尾的内容记忆较好,对中间大段内容的关注度大幅下降。这篇文章,我想带你完整走一遍这三次进化的逻辑:它们分别解决了什么问题,它们之间是什么关系,它们的边界在哪里,以及:当三者融合,AI 工程师的终极形态究竟是什么?大语言模型的本质,就是这位金鱼助理。

QcloudCommunity的博客 713

让Skill自己训练自己:8阶段Loop、3层评测、5维AND门控,从此实现自进化

所以每一轮改动都是有据可查的,不是「感觉这里可以优化」,而是「Case 41 挂了,因为 agent 把离职问题路由到了邮箱分类,但正确答案在通讯录,所以我改 root_index.md 加个易混淆提示」。但让我最后决定把它记录下来的,不是这的个「吸收」过程,而是它真的在替我探索我不想费脑力触达的边界,这看起来更像是一个机器智能应该有的样子。不准跨层,每轮只改一层的东西。但我经过这 19 轮之后觉得,更准确的描述是互补——你在明处看着,AI 在暗处替你试错,你看不见的那一半就是 AI 能贡献的地方。

QcloudCommunity的博客 1118

只加两行代码,为什么要两天?一文深度理解业务系统的复杂性

关注腾讯云开发者,一手技术干货提前解锁👇业务系统复杂性一直是令开发者头痛的问题。复杂的不是增加一个需求需要耗费多少时间,而是在增加一个需求后带来的蝴蝶效应:其它功能会不会受到影响、要如何去找到这些影响,最终如何实现系统正常运行......功能之间隐秘增加的耦合、不可避免的代码腐化在导致业务复杂性增加。大家都在说的软件开发提效到底在提什么?程序员日常工作中应该如何提升开发效率?敏捷开发、瀑布流式开发孰是孰非?欢迎阅读。业务背景与目标我依然非常清晰地记得某个时候,我所在团队 Leader 曾讲过一段话:“我担

QcloudCommunity的博客 708

从零设计生产级 Multi-Agent Harness:架构、评估、记忆、成本与 MCP 工具接入全拆解

在 AI Agent 领域,Multi-Agent Harness 指的是把多个 Agent 的能力、工具、状态、通信、编排、监控统一收束在一个运行时之内的框架。第三,Agent 路由。一个输入框,一个大模型,几个工具,一段写得很漂亮的 System Prompt,再配上一个炫酷的前端,看起来就像一个能干活的“数字员工”。Multi-Agent 完全不一样——它有计划、有中间步骤、有工具调用、有 Agent 协作、有重试、有反思、有最终合成。增加 Budget、权限、重试、压缩、轨迹评估、审计、回归测试。

QcloudCommunity的博客 705

拆完Hermes源码,我发现Agent的“自我进化“根本不需要训练模型

两个月 5.2 万 Star,Hermes Agent 用一个"LLM 审判官"机制实现了 Agent 的自我进化——不改模型权重,只改"怎么用模型"的策略。OpenClaw(社区昵称"龙虾"🦞)是 2025-2026 年最火的开源 Agent 框架,30 万+ Star,插件市场 ClawHub 里有数千个插件,能接入 Telegram、WhatsApp、Slack、飞书、企业微信——几乎是一个"个人 AI 操作系统"。Skill 是英语写的,Memory 是英语写的,审查 Prompt 也是英语写的。

QcloudCommunity的博客 902

AI Infra 其实没有多少新东西

传统 Infra 追求横向扩展,而 AI Infra 呈现 “AI 大型机”特性,是因为传统后台服务的可以容忍毫秒级延迟,但 AI 集群不行,GPU 的算力是 CPU 的数百倍,微秒级的延时等待也会造成很大的算力损耗,需要硬件的高度集成。在可预见的1-3年的未来,这样的专用硬件+网络的集中式架构很难发生比较大的改变。与之相似,模型推理的批处理就是将多个输入样本打包(batch),将原本串行的 N 次轻量的推理计算,合并为 1 次重量的计算,实现单位时间内处理更多的请求,提高了 GPU 利用率。

QcloudCommunity的博客 819

程序员越早想通这些越好

永远没有正确架构,你永远无法偿还完所有的技术债务,如同你永远不会设计出完美的界面,请避开完美主义的陷阱,永远没有完美的代码,能够满足当前需求,又为未来不管是自己还是他人留有扩展空间,就很好了。我们努力的方向就是将现实世界映射到有限的数据结构中,这就需要用户自定义类型,如果你的代码中包含类似 trader portfolio 这样的概念,你就可以使用他们的名称来建模,而不是使用基本数据类型复杂嵌套表述你的目的。从另一个角度看,代码里的注释都是补丁,是碎片化的,局部的注释很难推导模块整体的顺序及耦合关系。

QcloudCommunity的博客 464

RAG已死?不,是Grep回归了!

这样一来可以直接复用已有的计算缓存,只为新增的增量部分付全价,前面累积的大头按约 1/10 的缓存价计费。所以实际的工具组合方式是灵活的:Grep(默认模式)→ Read 是最常见的路径,但 Grep(content 模式)可以独立使用,LLM 也可以直接调 Read(如果已经知道文件路径),或者一次同时发起多个 Grep 并行搜索。它从零开始构建自己的对话历史,不继承主对话的消息,这意味着它搜索过程中产生的大量 grep 结果、代码片段都留在自己的 context 里,主对话只收到一段总结性的文本结论。

QcloudCommunity的博客 571

深入浅出Harness Engineerring之核心模式与理念

在智能体生命周期的关键节点(如会话开始、工具调用后)自动触发预设动作(如代码格式化),由系统确保关键流程被执行,不依赖可能被模型遗忘的指令。简单讲就是利用向量存储这个技术,来实现模糊检索,原理是:即使字面不同,但语义相近的文本,其向量在数学空间中的位置也很接近。根据命令类型、参数和影响,自动评估其风险等级(安全、有风险、危险),并采取自动执行、请求确认或直接拦截等不同策略。关键特性是可隔离、可重建、可扩展。不是一次判断就定终身,允许你改变、允许情况复杂,通过不断观察、思考、调整,越来越懂真实的你。

QcloudCommunity的博客 621

Harness Engineering实践心得:如何高效驾驭AI?

但如果这些经验被拆成一条条 Rule、一个个 Skill、一项项 Script 检查——"XAML 不能有中文"、"编译要用这个路径的 MSBuild"、"SVN 命令必须带认证参数"——AI 就能在秒级时间里"吸收"十年的踩坑经验。然后可以看到下方的图,我的PM会很顺利的调度其他agent分别负责不同的事项,遇到问题的时候也能准确的找到合适的agent。MCP 本质上是在扩展 AI 的"感知范围"——Rule 管"该怎么做",Skill 管"怎么操作",MCP 管"能看到什么、能碰到什么"。

QcloudCommunity的博客 838

从第一性原理思考 Agentic Engineering

需要注意的是,这一结论是有条件的:如果 AI 缺乏领域知识,过早介入反而可能引入 1.2 节所述的"似是而非"损耗——因此上下文供给(实践 1)是 AI 全链条参与的前提,而非结果。通过一个专门的自迭代 Skill 实现——当 AI 在协作过程中识别到自己被纠正(用户否定了 AI 的输出并给出了正确方向),它自动评估这个错误的根因,搜索现有的 Rules 和 Skills 中是否已有针对该类问题的处理规则。事实上,越是复杂的项目,工程师的认知负担越重(公理 3),AI 分担认知负担的潜在边际价值也越大。

QcloudCommunity的博客 755

万字干货!Harness Engineering如何工程化落地?

关注腾讯云开发者,一手技术干货提前解锁👇Harness Engineering 的概念已经火了有一阵了,全网很多文章基本都是在讲理念,讲为什么今天做 AI 开发,不能只靠一段提示词,也不能把模型当一个“更聪明的代码补全”。但与此同时,一个问题也在持续地发酵:这个问题特别重要。因为 Harness 这个词听上去很大,很像一个抽象的方法论,但它如果不能落到工程、目录、文档、脚本、工作流里,那它最后就只是一句漂亮的话。事实上,不同项目落地出来的 Harness,表面上可能完全不一样。有的项目是 CI 很强,有的

QcloudCommunity的博客 1160

全方位对比:Hermes VS OpenClaw

多账号矩阵运营 如果你的业务涉及同时管理多个社交媒体账号、多个平台的内容分发、多渠道的客户互动——OpenClaw是目前市场上的"无可替代的底座"。一个有专业背景的个人,现在可以快速构建一个垂直领域的AI助手:比如"财务分析Hermes"、"法律咨询Hermes"、"技术架构Hermes",直接通过微信提供服务,积累自己的专业IP。跨平台生态融合 如果你的工作流涉及飞书、Slack、Discord等多个平台的深度集成,需要这些平台之间的数据流转和联动——OpenClaw的生态支持是强大的。

QcloudCommunity的博客 1216

一文讲透:Harness Engineering即控制论!

而研发模式的升级我认为将会是一个飞跃的过程,之所以现在我们仍然需要需要参与编码,一个非常大的原因就是缺乏传感器和基建,仍然需要人来串流程,比如需要人来验证UI是否正确、需要人来告诉AI代码不符合代码规范,因此在有些场景我们仍然感觉 AI 完成的很吃力,但这不是 AI 能力不行,而是我们并没有为 AI 提供友好的环境……控制论中的突变理论介绍了矫枉过正和飞跃现象之间的矛盾,如果质变中经历的中间过渡态是不稳定的,那么他就是一个飞跃的过程,如果中间过渡态是稳定的,那么他就是一个渐变的过程。但是这些阶段要解决的。

QcloudCommunity的博客 1202

神级开源插件!一句话让QClaw变3D小镇,Agent工作可视化,赛博云监工

这个架构是翻了几次车才想通的—原有AI的实现机制是用 setTimeout 猜动画时长导致了幽灵 NPC、工位撞车、越改越崩,后面我停下来换了思路,推翻原有的架构,按照“意图+回传”的架构进行重构,之前的问题一次性全部解决。15 天,我和 AI 吵了 185 次架, 4.5 万行代码,开发了一款 QClaw / OpenClaw 的UGC游戏插件,这可能是人类跟 Agents 交互的新范式,插件已完全开源,有需要的欢迎自取~我天天用,用着用着我就在思考,Agent 产品现在的交互体验,基本都一个样。

QcloudCommunity的博客 1194

一文搞懂Hermes:新顶流Agent如何从经验中自我进化

Voyager 是一个能在 Minecraft 中自主探索、学习技能、无限积累能力的 AI Agent,它提出了 "Skill Library"(技能库)的概念——Agent 将成功的行为序列编码为可复用的技能函数,存储在一个持续增长的代码库中。如果 Skill 的名称和描述不够精准,或者用户的任务描述与 Skill 的触发条件有语义差距,Agent 可能会错过相关的 Skill。如果进程在写入过程中崩溃,目标文件要么是旧内容(还没被替换),要么是新内容(替换已完成),绝不会出现写了一半的损坏文件。

QcloudCommunity的博客 2625

自掏腰包一万元,拥抱AI这一年,我的工具、实践和思考

其实也很好理解,过往的每个领域(比如前端、后端、设计、测试等等)都主要是这个领域的从业者在为它添砖加瓦,但是大模型时代的 AI 应用领域却几乎是所有使用 AI 的人类一起在迭代,无分领域,无分文理,无分老少。因为每个时期的 AI 都有着不同的特点,很多时候当我费尽心思去钻研,自以为有点弄明白 AI 应该怎么玩的时候,基座模型和行业范式常常就会迎来颠覆式的变革,很多过往的经验都会倾覆,然后只能从头再来。过去一年多,被热议的 AI 范式大概是沿着四个阶段递进演化,每一个阶段其实都在解决前一个阶段的核心问题。

QcloudCommunity的博客 626

办公Agent的CI/CD时刻到来了

核心观点是:企业给员工配了一堆 AI 工具,试点跑了几百个,但真正拖慢 AI 转型速度的瓶颈不在模型能力,在"最后一公里":AI 输出和实际工作流之间的那道鸿沟。代码写完,打个 tar 包,开 FTP 传到服务器上,SSH 进去解压,改配置文件,重启服务,刷一下页面祈祷别 500。你复制,切窗口,粘贴到腾讯文档里,发现 Markdown 格式全乱了,手动调标题层级,代码块重新标记语言类型,表格散架了重排一遍。模型是越来越聪明了,但"生成"到"落地"之间那段路,还是你自己在走,一步一步,手动搬运。

QcloudCommunity的博客 607

4亿token买来5个教训:让6个AI Agent连写4天代码发生了什么?

Watchdog 检测到崩溃 → 启动诊断 Agent 分析原因 → 诊断 Agent 跑满 20 轮没搞定 → Watchdog 判定“已修复”,重启系统 → 重启的系统因为诊断 Agent 留下的环境变量被继承,连续 3 次拒绝启动 → 触发连续失败保护退出 → Watchdog 第 3 次巡检,发现进程和记录文件都没了,尝试手动重启,自己也停了。启动前我翻了论文、做了架构设计、写了监控+修复异常的脚本。这个发现让我的情绪从沮丧变成了兴奋——不是那种"终于修好了"的释然,是"我找到根因了"的快感。

QcloudCommunity的博客 583

赛博斗蛐蛐:9大模型决战三国志,天命在谁?

我猜是这样的,当Gemini面临决策的时候,一系列关键词比如 守城,劣势,粮草,三国等等,在语义层面的关联性中LLM发现了竖壁清野这个关键词概率非常高,所以以此为策略,然后再根据这个策略完美执行操作。MiMo 的外交是三方中最精明的。Kimi作为国产模型,也同样颠覆了我对他的看法,最后的比赛他甚至一度是优势者,存在很多夺冠的可能性,要知道他的对手可是claude和gemini,而他经常出兵慢,回过头来想想或许正是他的策略,毕竟中后期他的优势都来自于稳健的发展和较少的战斗频率(和claude比).

QcloudCommunity的博客 870

Claude Code是怎么知道你在骂他的?这 12 条发现值得关注

确实存在——5,500+ 行,集成了消息队列、工具装配、MCP 编排、会话状态、权限、分析、文件持久化和优雅关闭,基本上一个文件干了所有事。对抗虚假声明——"不要在输出显示失败时声称所有测试通过,不要压缩或简化失败的检查来制造绿色结果"。完整的 KAIROS 是一个持续驻留的守护进程,能感知你在不在电脑前、主动寻找有用的工作做,更像是住在终端里的全职同事。源码里藏着一个叫 "Buddy" 的电子宠物系统,完整度令人惊讶——这不是一个 TODO,而是一个从数值系统到 ASCII 动画都实现了的完整功能。

QcloudCommunity的博客 700

逆向深扒Claude Code源码,我发现了什么!?

Anthropic 内部用户获得更严格的质量控制 prompt、更好的验证机制(独立 Verification Agent)、以及针对 model 弱点的专门对策(如 Capybara v8 的 29-30% 错误声明率对策)。这不是代码混乱的标志——它是整个 Agent Loop 的心脏,所有的流式处理、工具调度、上下文压缩、子代理管理都在这个文件中协调。这种"胖核心"设计是刻意的:保持核心循环的原子性,避免分散到多个模块导致的协调复杂度。核心价值:Fork 代理的工具输出不会回到主代理的上下文窗口。

QcloudCommunity的博客 885

一文讲透如何构建Harness——六大组件全解析

本文将从"裸模型的四个硬伤"出发,逐一拆解 Harness 的六大组件——文件系统、Bash + 沙箱、记忆(AGENTS.md)、Web Search + MCP、上下文工程、编排 + Hooks——带你看清 AI Agent 真正的竞争壁垒,不在模型层,而在 Harness 层。如果你用过 Agent 做复杂任务,你一定有过这样的体验:一开始 Agent 的表现很好,但随着对话变长,它开始"变笨"——遗忘之前的约定,重复之前犯过的错误,甚至对同一个问题给出前后矛盾的回答。对于简单的问答场景,这无所谓。

QcloudCommunity的博客 758

Harness Engineering 来了,SDD 还有意义吗?

他们的解法是把「品味」编码进规则,然后用一个定期运行的「doc-gardening」Agent 自动扫描漂移、发起修复 PR——「技术债务就像一笔高息贷款,不断地以小额贷款的方式偿还,总比让债务不断累积要好」。代码仓库本地的、已版本化的工件,才是 Agent 所能看到的全部。在 Vibe Coding 模式下(即不做规划、随意向 AI 提需求的开发方式),大量设计决策、跨服务约定、「为什么不选另一个方案」的讨论,全部停留在一次性的 AI 对话里——下一个人,或者下一次 AI 会话,完全无从获取。

QcloudCommunity的博客 417

零废话!一文讲透从0构建AI Agent

每个工具都要写一套"定义→解析→执行"的胶水代码。上下文管理就是在"记住足够多"和"别超标"之间找平衡,常见策略包括滑动窗口、摘要压缩、RAG 检索增强。上下文窗口是 Agent 的"工作记忆",但它有硬性限制。LLM 负责"动脑"决策,代码负责"动手"执行。这是从"聊天机器人"进化到"Agent"的关键一步。每次调 API 都把完整对话历史发过去,LLM 本身是无状态的,"记忆"完全靠客户端的数组模拟。这样 Agent 一开始就知道自己"在哪里"、"手头有什么",不需要先花一轮工具调用去探索环境。

QcloudCommunity的博客 710

距离AI把小编我裁掉还有72小时

这是一个基于 OpenClaw 开源生态打造的本地化 AI Agent 助手,已于上周开启全量公测,无需复杂配置,三步即可上手,自带安全防护,支持微信直连绑定,内置多款优质国产大模型,现阶段也是完全免费使用,基本上前面提到过的痛点都可以靠它解决。对了,这里特别强调一点,上面的截图让产品同事汗流浃背,再三找我确认 QClaw 思考过程中优美的“草”字说法,不会是默认出现的吧?AI 好,AI 得学,但更重要的是,在你的工作和生活里,哪些东西是能结构化地被 AI 所接入的,不要死守着那些脏活累活不放。

QcloudCommunity的博客 672
上一篇: 深入解析OpenClaw上下文窗口压缩方案 :一切都是为了效果与省钱
下一篇: 全网最细!OpenClaw本地部署教程和常见问题汇总
腾讯云开发者
腾讯云开发者 企业官方账号 企业官方账号
博客等级 码龄10年 6290粉丝 1962原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值