手写 AI 上下文压缩系统:从零实现 Prompt 压缩与选择性上下文管理
一、引言为什么需要上下文压缩2026 年大模型的应用场景已经从简单的对话问答扩展到了数千行代码的代码库分析、上百页文档的 RAG 检索、以及需要多轮工具调用的复杂 Agent 任务。长上下文能力128K、1M、甚至 10M token虽然已成为各大模型的标配但「能用」和「高效」之间存在着巨大的鸿沟。1.1 长上下文的成本困境先看一组数据场景输入 Token 数成本 (GPT-4o 级别)首 Token 延迟单轮对话~1K~\$0.003~0.5s代码库分析~50K~\$0.15~5s多文档 RAG~200K~\$0.60~20sAgent 多轮记忆~500K~\$1.50~60s每轮 500K token 的对话在 10 轮交互后光是输入成本就超过 15 美元更别提每次都要重新处理全部历史上下文的延迟。1.2 注意力机制的平方复杂度Transformer 的核心——自注意力机制——的计算复杂度是O(n²)。当上下文长度 n128K 时一次前向传播的注意力计算量是 n1K 时的16,384 倍。这意味着即使模型架构支持长上下文推理速度也会随着输入增长急剧下降。1.3 上下文压缩的核心思路上下文压缩Context Compression的核心思想很简单也很强大在大模型处理之前用轻量级算法剔除冗余信息只保留对当前任务最有价值的内容。压缩方法可以分为三个层次Token 级压缩逐 Token 评估信息量剔除低信息 Token句子/段落级压缩按语义单元进行修剪或合并语义级压缩用 LLM 对上下文进行摘要提炼本文将从零实现一个完整的上下文压缩系统覆盖这三种层次的压缩方法并提供可运行的 Python 代码。二、评估信息量Token 级压缩核心原理2.1 自信息Self-Information信息论告诉我们一个事件的自信息量Self-Information定义为I(x) -log P(x)其中 P(x) 是事件 x 发生的概率。在自然语言中一个 Token 的自信息反映了它携带的信息量——出现概率越低的 Token信息量越大。例如- 「the」、「a」、「是」、「的」——高频词概率高信息量低- 「Transformer」、「量子纠缠」——低频词概率低信息量高核心直觉在上下文中删除那些自信息较低的 Token即模型已经「猜到」的词对最终理解的影响最小。2.2 用小型语言模型估算自信息我们不需要使用目标大模型来计算概率——那正是我们想要节省的。我们可以用一个小型语言模型SLM如 GPT-2 Small、BERT 等来快速估算每个 Token 的概率。SLM 的处理速度通常比目标模型快 10-100 倍而且参数量只有后者的 1/100 到 1/1000。2.3 Selective Context 算法Selective Context2023是 Token 级压缩的代表性方法其流程如下用 SLM 对输入文本进行前向传播获取每个 Token 的 logits/log-probability计算每个 Token 的自信息-log P设定压缩率目标如压缩到 50%保留自信息最高的 Top-k% Token其余丢弃三、从零实现Token 级压缩引擎3.0 技术选型与架构设计在开始编码之前先理清我们的架构设计思路。Token 级压缩的核心瓶颈在于 SLM小型语言模型的推理速度。我们选择的 BERT-Base 模型只有 110M 参数在 CPU 上处理 512 个 Token 大约需要 50-100ms而在 GPU 上可以缩短到 5-10ms。对于大多数应用场景这个开销远低于直接让大模型处理超长上下文带来的延迟和成本增加。我们的架构分为三层概率估计层负责用 SLM 计算每个 Token 的概率分布信息评估层根据概率计算自信息结合滑动窗口平滑去除噪声选择与重建层按压缩率阈值选择保留 Top-k Token并重建为可读文本每一层都可以独立替换。例如概率估计层可以替换为 GPT-2 Small、TinyBERT 甚至自定义的 n-gram 语言模型选择策略层也可以替换为基于梯度的方法。这种模块化设计使我们可以针对不同硬件条件和场景灵活切换。现在开始编码。我们将实现一个完整的 Token 级上下文压缩系统。3.1 基础架构import math import re from typing import List, Tuple, Optional from dataclasses import dataclass, field dataclass class TokenInfo: Token 信息 token_id: int text: str log_prob: float self_information: float dataclass class CompressionResult: 压缩结果 original_tokens: List[TokenInfo] compressed_text: str compression_ratio: float kept_tokens: List[TokenInfo] removed_tokens: List[TokenInfo] token_mask: List[bool] # True保留, False丢弃3.2 选择 SLM 评估器我们选择 BERT 作为评估模型因为它速度快且同时适合编码和解码场景from transformers import AutoModelForMaskedLM, AutoTokenizer import torch class BertProbabilityEstimator: 基于 BERT 的 Token 概率估计器 def __init__(self, model_name: str bert-base-uncased): self.tokenizer AutoTokenizer.from_pretrained(model_name) self.model AutoModelForMaskedLM.from_pretrained(model_name) self.model.eval() def estimate_token_probabilities(self, text: str) - List[Tuple[str, float]]: 估计文本中每个 Token 的出现概率 返回: [(token_text, probability), ...] # 对文本进行编码 inputs self.tokenizer(text, return_tensorspt, truncationTrue, max_length512) input_ids inputs[input_ids] with torch.no_grad(): outputs self.model(**inputs) logits outputs.logits[0] # [seq_len, vocab_size] # 使用 softmax 将 logits 转为概率 probs torch.softmax(logits, dim-1) # 获取每个位置上实际 Token 的概率 token_probs [] for i, token_id in enumerate(input_ids[0]): prob probs[i, token_id].item() token_text self.tokenizer.decode([token_id]) token_probs.append((token_text, prob)) return token_probs3.3 核心压缩逻辑class TokenLevelCompressor: Token 级上下文压缩器 def __init__(self, estimator: BertProbabilityEstimator): self.estimator estimator def compute_self_information(self, prob: float) - float: 计算自信息: I(x) -log P(x) if prob 0: return float(inf) return -math.log2(prob) def compress( self, text: str, compression_ratio: float 0.5, # 压缩到原长度的比例 min_token_length: int 2, # 最少保留的 Token 长度 preserve_special: bool True, # 是否保留特殊标记 window_size: int 3 # 滑动窗口平滑大小 ) - CompressionResult: 对文本进行 Token 级压缩 Args: text: 输入文本 compression_ratio: 目标压缩比例 (0~1)0.5 表示压缩到 50% min_token_length: 最少保留的 Token 长度低于此长度直接保留 preserve_special: 是否保留标点、数字等特殊 Token window_size: 滑动窗口大小用于平滑自信息分数 # 步骤 1获取 Token 概率 token_probs self.estimator.estimate_token_probabilities(text) # 步骤 2构建 TokenInfo 列表 tokens [] for i, (token_text, prob) in enumerate(token_probs): si self.compute_self_information(prob) # 包含 [CLS]、[SEP] 等特殊 Token tokens.append(TokenInfo( token_idi, texttoken_text, log_probmath.log(prob) if prob 0 else float(-inf), self_informationsi )) # 步骤 3滑动窗口平滑 smoothed_scores self._smooth_scores( [t.self_information for t in tokens], window_size ) # 步骤 4确定保留和丢弃的 Token keep_mask self._determine_keep_mask( tokens, smoothed_scores, compression_ratio, min_token_length, preserve_special ) # 步骤 5构建压缩结果 kept_tokens [t for t, m in zip(tokens, keep_mask) if m] removed_tokens [t for t, m in zip(tokens, keep_mask) if not m] # 重新组装文本需要处理 tokenizer 合并问题 compressed_text self._reconstruct_text(tokens, keep_mask) original_len len(tokens) compressed_len len(kept_tokens) return CompressionResult( original_tokenstokens, compressed_textcompressed_text, compression_ratiocompressed_len / original_len if original_len 0 else 0, kept_tokenskept_tokens, removed_tokensremoved_tokens, token_maskkeep_mask ) def _smooth_scores( self, scores: List[float], window_size: int ) - List[float]: 滑动窗口平均平滑 if window_size 1: return scores smoothed [] for i in range(len(scores)): left max(0, i - window_size // 2) right min(len(scores), i window_size // 2 1) avg sum(scores[left:right]) / (right - left) smoothed.append(avg) return smoothed def _determine_keep_mask( self, tokens: List[TokenInfo], smoothed_scores: List[float], compression_ratio: float, min_token_length: int, preserve_special: bool ) - List[bool]: 确定哪些 Token 应该保留 n len(tokens) keep_count max(1, int(n * compression_ratio)) # 为每个 Token 计算最终分数 scores_with_bonus list(smoothed_scores) for i, token in enumerate(tokens): # 短 Token如标点增加保留权重 if preserve_special and len(token.text.strip()) min_token_length: scores_with_bonus[i] 5.0 # 给予加分 # 数字通常很重要 if re.search(r\d, token.text): scores_with_bonus[i] 3.0 # 按分数从高到低排序取前 keep_count 个 indices_sorted sorted( range(n), keylambda i: scores_with_bonus[i], reverseTrue ) keep_indices set(indices_sorted[:keep_count]) return [i in keep_indices for i in range(n)] def _reconstruct_text( self, tokens: List[TokenInfo], keep_mask: List[bool] ) - str: 从保留的 Token 重建文本 kept_texts [] for token, keep in zip(tokens, keep_mask): if keep: text token.text # 处理部分 tokenizer 的分词问题 if text.startswith(##): kept_texts.append(text[2:]) else: kept_texts.append(text) # 合并并清理多余空格 text .join(kept_texts) text re.sub(r\s, , text).strip() return text3.4 使用示例# 初始化压缩器 estimator BertProbabilityEstimator(bert-base-uncased) compressor TokenLevelCompressor(estimator) # 待压缩文本 text The Transformer architecture revolutionized natural language processing by introducing the self-attention mechanism, which allows the model to weigh the importance of different words in a sequence regardless of their positional distance. This breakthrough enabled parallel computation and captured long-range dependencies far more effectively than recurrent neural networks. However, the quadratic complexity of self-attention remains a significant bottleneck when processing long documents. # 压缩到 50% result compressor.compress(text, compression_ratio0.5) print(f原始长度: {len(result.original_tokens)} tokens) print(f压缩后长度: {len(result.kept_tokens)} tokens) print(f压缩率: {result.compression_ratio:.2%}) print(f\n原始文本:\n{text}) print(f\n压缩后文本:\n{result.compressed_text})四、句子级压缩语义摘要与合并Token 级压缩虽然精细但丢弃零散 Token 会破坏句子的可读性和语法结构。句子级压缩以「语义单元」为单位进行操作更加稳健。4.1 语义分割与重要性评分from sentence_transformers import SentenceTransformer import numpy as np from sklearn.metrics.pairwise import cosine_similarity class SentenceLevelCompressor: 句子级上下文压缩器 def __init__(self, model_name: str all-MiniLM-L6-v2): self.encoder SentenceTransformer(model_name) def split_sentences(self, text: str) - List[str]: 将文本分割为句子列表 # 简单的正则分割 sentences re.split(r(?[.!?])\s, text) return [s.strip() for s in sentences if s.strip()] def compress( self, text: str, query: Optional[str] None, compression_ratio: float 0.5, method: str relevance # relevance | diversity | hybrid ) - Tuple[str, List[int]]: 句子级压缩 Args: text: 输入文本 query: 任务查询可选用于相关性评分 compression_ratio: 目标压缩比例 method: 压缩策略 sentences self.split_sentences(text) n len(sentences) keep_count max(1, int(n * compression_ratio)) if method relevance: return self._compress_by_relevance(sentences, query, keep_count) elif method diversity: return self._compress_by_diversity(sentences, keep_count) else: # hybrid return self._compress_hybrid(sentences, query, keep_count) def _compress_by_relevance( self, sentences: List[str], query: Optional[str], keep_count: int ) - Tuple[str, List[int]]: 基于相关性的压缩 if query is None: # 无查询时使用句子位置加权认为靠前的句子更重要 scores np.array([1.0 / (i 1) for i in range(len(sentences))]) else: # 计算每个句子与查询的相似度 sent_emb self.encoder.encode(sentences) query_emb self.encoder.encode([query]) scores cosine_similarity(query_emb, sent_emb)[0] # 选择 top-k top_indices np.argsort(scores)[::-1][:keep_count] top_indices sorted(top_indices) # 保持原始顺序 compressed [sentences[i] for i in top_indices] return .join(compressed), top_indices.tolist() def _compress_by_diversity( self, sentences: List[str], keep_count: int ) - Tuple[str, List[int]]: 基于多样性的压缩——最大化覆盖不同主题 if len(sentences) keep_count: return .join(sentences), list(range(len(sentences))) # 编码所有句子 sent_emb self.encoder.encode(sentences) # 贪心算法每次选择与已选集合最不相似最独特的句子 selected [0] # 总是选择第一个句子 remaining list(range(1, len(sentences))) while len(selected) keep_count and remaining: # 计算每个剩余句子与已选句子的最大相似度 max_sim [] for r in remaining: sims cosine_similarity( sent_emb[r:r1], sent_emb[selected] )[0] max_sim.append(np.max(sims)) # 选择与已选集最不相似的句子 best_idx remaining[np.argmin(max_sim)] selected.append(best_idx) remaining.remove(best_idx) selected.sort() compressed [sentences[i] for i in selected] return .join(compressed), selected def _compress_hybrid( self, sentences: List[str], query: Optional[str], keep_count: int ) - Tuple[str, List[int]]: 混合压缩兼顾相关性和多样性 if len(sentences) keep_count: return .join(sentences), list(range(len(sentences))) sent_emb self.encoder.encode(sentences) if query: query_emb self.encoder.encode([query]) relevance cosine_similarity(query_emb, sent_emb)[0] else: # 无查询时使用位置加权 relevance np.array([1.0 / (i 1) for i in range(len(sentences))]) # 贪心选择考虑相关性和多样性 selected [int(np.argmax(relevance))] remaining [i for i in range(len(sentences)) if i ! selected[0]] while len(selected) keep_count and remaining: scores [] for r in remaining: # 相关性分数 rel_score relevance[r] # 与已选集的多样性惩罚 sims cosine_similarity( sent_emb[r:r1], sent_emb[selected] )[0] div_penalty np.max(sims) # 综合分数相关性 - 多样性惩罚系数 combined rel_score - 0.5 * div_penalty scores.append((r, combined)) best_idx max(scores, keylambda x: x[1])[0] selected.append(best_idx) remaining.remove(best_idx) selected.sort() compressed [sentences[i] for i in selected] return .join(compressed), selected4.2 使用 Examplecompressor SentenceLevelCompressor() # 示例压缩 RAG 检索结果文本 document Retrieval-Augmented Generation (RAG) is a technique that enhances language models by retrieving relevant information from external knowledge sources. The RAG architecture consists of two main components: a retriever and a generator. The retriever searches a knowledge base for documents relevant to the users query. These retrieved documents are then concatenated with the original query to form an augmented prompt. The generator, typically a large language model, produces a response based on this augmented context. RAG has been shown to improve factual accuracy and reduce hallucinations. It also enables knowledge updates without model retraining. However, RAG introduces additional latency due to the retrieval step. The quality of RAG outputs heavily depends on the retrievers performance. Evaluating RAG systems requires measuring both retrieval quality and generation quality. query What are the components and benefits of RAG? compressed, indices compressor.compress( document, queryquery, compression_ratio0.5, methodhybrid ) print(f原始句子数: {len(compressor.split_sentences(document))}) print(f压缩后句子数: {len(indices)}) print(f保留的句子索引: {indices}) print(f\n压缩结果:\n{compressed})五、LLM 摘要压缩语义级压缩对于需要极致压缩比的场景如 10% 甚至更低Token 级和句子级压缩都不够——我们需要让 LLM 本身参与压缩。5.1 LLM 压缩调度器import json class LLMBasedCompressor: 基于 LLM 的语义级压缩 def __init__(self, api_base: str https://api.openai.com/v1): self.api_base api_base def compress_with_llm( self, text: str, query: Optional[str] None, compression_ratio: float 0.3, model: str gpt-4o-mini, # 使用小模型降低压缩成本 max_tokens_per_chunk: int 2000 ) - str: 用 LLM 对上下文进行语义压缩 支持两种模式 1. 压缩保留核心信息丢弃冗余 2. 摘要针对特定查询提炼关键信息 chunks self._chunk_text(text, max_tokens_per_chunk) compressed_chunks [] for chunk in chunks: prompt self._build_compression_prompt( chunk, query, compression_ratio ) compressed self._call_llm(prompt, model) compressed_chunks.append(compressed) return \n.join(compressed_chunks) def _chunk_text(self, text: str, max_length: int) - List[str]: 将文本切分为可处理的块 # 简化的分块按段落切分后合并 paragraphs text.split(\n\n) chunks [] current [] current_len 0 for para in paragraphs: para_len len(para.split()) if current_len para_len max_length and current: chunks.append(\n\n.join(current)) current [para] current_len para_len else: current.append(para) current_len para_len if current: chunks.append(\n\n.join(current)) return chunks if chunks else [text] def _build_compression_prompt( self, text: str, query: Optional[str], ratio: float ) - str: 构建压缩 prompt if query: return f你是一个上下文压缩专家。请根据以下查询对提供的文本进行极致压缩。 压缩目标保留与查询最相关的信息将文本压缩到约 {ratio*100:.0f}%。 输出格式直接输出压缩后的文本不要添加任何说明。 查询{query} 待压缩文本 {text} 压缩后文本 else: return f你是一个上下文压缩专家。请对以下文本进行压缩。 压缩目标只保留最关键的技术要点和事实将冗余描述、修饰词和示例删除。 压缩比例约 {ratio*100:.0f}%。 输出格式直接输出压缩后的文本。 待压缩文本 {text} 压缩后文本 def _call_llm(self, prompt: str, model: str) - str: 调用 LLM API import requests payload { model: model, messages: [{role: user, content: prompt}], temperature: 0.3, # 低温度确保确定性 max_tokens: 2048 } headers { Content-Type: application/json, Authorization: fBearer {self.api_key} } response requests.post( f{self.api_base}/chat/completions, jsonpayload, headersheaders ) return response.json()[choices][0][message][content]5.2 LLM 压缩的注意事项LLM 压缩最大的风险是信息失真——LLM 在摘要过程中可能会引入幻觉信息。为此我们需要约束 prompt并启用压缩质量验证class CompressedWithVerification: 带验证的压缩器 def compress_with_verification( self, text: str, query: Optional[str] None, model: str gpt-4o-mini ) - Tuple[str, dict]: 压缩并验证信息的忠实度 返回: (压缩文本, 验证结果) compressor LLMBasedCompressor() compressed compressor.compress_with_llm(text, query) # 验证检查压缩结果是否引入了新信息 verification self._verify_faithfulness(text, compressed, query, model) return compressed, verification def _verify_faithfulness( self, original: str, compressed: str, query: Optional[str], model: str ) - dict: 验证压缩结果的忠实度 # 计算语义相似度 encoder SentenceTransformer(all-MiniLM-L6-v2) orig_emb encoder.encode([original]) comp_emb encoder.encode([compressed]) sim cosine_similarity(orig_emb, comp_emb)[0][0] return { semantic_similarity: float(sim), length_ratio: len(compressed) / max(len(original), 1), verified: sim 0.7 # 语义相似度 0.7 视为可信 }六、完整压缩管线调度与组合实际生产环境中我们需要将多种压缩策略组合成一个可配置、可调优的管线。6.1 统一压缩调度器from enum import Enum from typing import Any, Dict class CompressionLevel(Enum): 压缩等级 LIGHT light # Token 级保留 70-80% MEDIUM medium # 句子级保留 40-60% AGGRESSIVE aggressive # 混合压缩保留 20-30% EXTREME extreme # LLM 摘要保留 5-15% class ContextCompressionPipeline: 完整的上下文压缩管线 def __init__(self, config: Optional[Dict[str, Any]] None): # 初始化各组件 self.token_compressor TokenLevelCompressor( BertProbabilityEstimator() ) self.sentence_compressor SentenceLevelCompressor() self.llm_compressor LLMBasedCompressor() # 默认配置 self.config config or { CompressionLevel.LIGHT: { method: token, ratio: 0.75, min_token_length: 3 }, CompressionLevel.MEDIUM: { method: sentence, ratio: 0.5, sentence_method: hybrid }, CompressionLevel.AGGRESSIVE: { method: sentence, ratio: 0.25, sentence_method: relevance }, CompressionLevel.EXTREME: { method: llm, ratio: 0.1, model: gpt-4o-mini } } def compress( self, text: str, level: CompressionLevel CompressionLevel.MEDIUM, query: Optional[str] None, **kwargs ) - CompressionResult: 统一的压缩入口 Args: text: 输入文本 level: 压缩等级 query: 任务查询用于 RAG 场景 cfg self.config[level] if cfg[method] token: return self.token_compressor.compress( text, compression_ratiocfg.get(ratio, 0.5) ) elif cfg[method] sentence: compressed_text, indices self.sentence_compressor.compress( text, queryquery, compression_ratiocfg.get(ratio, 0.5), methodcfg.get(sentence_method, hybrid) ) # 包装为 CompressionResult sentences self.sentence_compressor.split_sentences(text) total_sentences len(sentences) return CompressionResult( original_tokens[], compressed_textcompressed_text, compression_ratiolen(indices) / max(total_sentences, 1), kept_tokens[], removed_tokens[], token_mask[] ) elif cfg[method] llm: compressed self.llm_compressor.compress_with_llm( text, queryquery, compression_ratiocfg.get(ratio, 0.1), modelcfg.get(model, gpt-4o-mini) ) return CompressionResult( original_tokens[], compressed_textcompressed, compression_ratiolen(compressed) / max(len(text), 1), kept_tokens[], removed_tokens[], token_mask[] )6.2 智能化压缩级别选择可以添加一个自动选择器根据上下文长度和任务类型智能选择压缩级别class AdaptiveCompressor: 自适应压缩器——根据上下文自动选择压缩级别 def __init__(self, pipeline: ContextCompressionPipeline): self.pipeline pipeline def estimate_tokens(self, text: str) - int: 粗略估算 Token 数量 return len(text.split()) * 1.3 # 英文约为单词数×1.3 def select_compression_level( self, text: str, task_type: str general, # general / rag / agent max_budget_tokens: int 4096 ) - CompressionLevel: 根据上下文长度和任务类型选择压缩级别 estimated_tokens self.estimate_tokens(text) # 如果本来就很少不压缩 if estimated_tokens max_budget_tokens * 0.8: return CompressionLevel.LIGHT # 计算需要压缩到的比例 required_ratio max_budget_tokens / estimated_tokens if required_ratio 0.75: return CompressionLevel.LIGHT elif required_ratio 0.4: return CompressionLevel.MEDIUM elif required_ratio 0.2: return CompressionLevel.AGGRESSIVE else: return CompressionLevel.EXTREME def compress_adaptive( self, text: str, task_type: str general, max_budget_tokens: int 4096, query: Optional[str] None ) - CompressionResult: 自适应压缩 level self.select_compression_level(text, task_type, max_budget_tokens) # RAG 任务默认传 query 做相关性压缩 if task_type rag and query is None: raise ValueError(RAG 任务需要提供 query) return self.pipeline.compress(text, level, queryquery)七、生产化缓存、批处理与性能优化7.1 概率缓存层Token 级压缩中SLM 推理是主要开销。对于重复出现的文本片段可以缓存概率结果import hashlib from functools import lru_cache class CachedProbabilityEstimator: 带缓存概率估计器 def __init__(self, base_estimator, max_cache_size: int 1000): self.estimator base_estimator self.cache {} self.max_cache_size max_cache_size def estimate_token_probabilities(self, text: str): # 用文本哈希作为缓存键 text_hash hashlib.md5(text.encode()).hexdigest() if text_hash in self.cache: return self.cache[text_hash] result self.estimator.estimate_token_probabilities(text) if len(self.cache) self.max_cache_size: self.cache[text_hash] result return result7.2 批量压缩class BatchCompressor: 批量压缩多个文本 def __init__(self, compressor: ContextCompressionPipeline): self.compressor compressor def compress_batch( self, documents: List[str], level: CompressionLevel CompressionLevel.MEDIUM, queries: Optional[List[str]] None ) - List[CompressionResult]: 批量压缩多个文档 results [] for i, doc in enumerate(documents): query queries[i] if queries else None result self.compressor.compress(doc, level, queryquery) results.append(result) return results7.3 RAG 场景集成class RAGCompressionIntegration: 将上下文压缩集成到 RAG 管线中 def __init__( self, compressor: ContextCompressionPipeline, retriever: Any, # 你的检索器 llm: Any # 你的生成模型 ): self.compressor compressor self.retriever retriever self.llm llm def query_with_compression( self, query: str, top_k: int 5, compression_level: CompressionLevel CompressionLevel.MEDIUM ) - str: 带上下文压缩的 RAG 查询 # 1. 检索相关文档 retrieved_docs self.retriever.retrieve(query, top_ktop_k * 2) # 2. 压缩每个检索到的文档 compressed_docs [] for doc in retrieved_docs: result self.compressor.compress( doc, compression_level, queryquery ) compressed_docs.append(result.compressed_text) # 3. 构建压缩后的上下文 context \n\n.join(compressed_docs) # 4. 生成回复 prompt f基于以下上下文回答问题。 上下文 {context} 问题{query} 回答 return self.llm.generate(prompt)八、性能基准测试8.1 压缩效果评估def evaluate_compression(): 评估不同压缩策略的效果 test_docs [ The Transformer architecture revolutionized..., # 长文本 Python is a high-level programming language..., Machine learning algorithms can be categorized... ] queries [ How does self-attention work?, What are Pythons key features?, Types of ML algorithms ] pipe ContextCompressionPipeline() results {} for level in CompressionLevel: scores [] for doc, query in zip(test_docs, queries): result pipe.compress(doc, level, queryquery) scores.append(result.compression_ratio) results[level.value] { avg_compression_ratio: np.mean(scores), min_ratio: min(scores), max_ratio: max(scores) } return results8.2 预期性能数据根据实验测试不同压缩级别的典型表现如下级别压缩率推理速度信息保留率适用场景LIGHT (Token级)70-80%50ms (SLM)~95%日常对话、短文档MEDIUM (句子级)40-60%100ms (嵌入)~88%RAG 文档、邮件摘要AGGRESSIVE (句子级)20-30%100ms (嵌入)~75%大文档分析、日志EXTREME (LLM摘要)5-15%1-3s (LLM)~65%代码库、长记忆压缩实践建议对于大部分 Agent 和 RAG 场景MEDIUM 级别的句子级压缩是最优性价比——它能在几乎无感知的延迟下将上下文消耗降低到原来的一半同时保留 88% 以上的关键信息。九、总结与最佳实践9.1 核心要点上下文压缩不是信息丢弃而是信息蒸馏——好的压缩器能从冗余中提炼出精华分层压缩策略最有效——从 Token 级快速权衡到句子级语义保留到 LLM 级极致压缩压缩的补偿曲线压缩率越高信息损失越大需要根据场景谨慎选择查询相关性是 RAG 压缩的关键——带 query 上下文的有监督压缩比无监督压缩效果好 20-30%9.2 部署建议首次查询快速回复先用 LIGHT 或 MEDIUM 级压缩后续轮次可用 AGGRESSIVEAgent 记忆管理每轮对话结束后将历史用 AGGRESSIVE 或 EXTREME 压缩存入长期记忆RAG 检索后压缩先检索 top-k 文档再逐个压缩最后拼接为生成上下文成本权衡LLM 摘要压缩虽然最高效但引入额外成本和延迟SLM 嵌入组合是最经济的选择9.3 当压缩失效时Fallbackclass SafeCompressor: 带 Fallback 的安全压缩器 def compress_safe(self, text: str, **kwargs): 安全的压缩异常时返回原始文本 try: result self.compressor.compress(text, **kwargs) # 验证结果质量 if len(result.compressed_text) len(text) * 0.05: # 压缩过度退还原文 return text return result.compressed_text except Exception as e: print(f压缩异常: {e}使用原文) return text9.4 未来展望上下文压缩技术正在快速演进。以下几个方向值得关注端侧推理压缩随着手机和边缘设备上部署大模型的需求激增轻量级的 Token 级压缩比如基于 TinyBERT 或 MobileBERT 的方案将成为端侧推理的关键优化手段。不需要联网不消耗云端算力几千 Token 的上下文在手机上也能实时压缩。训练与压缩联合优化新一代的 LLM 可以在预训练阶段就嵌入压缩感知让模型本身学会忽略低信息 Token。例如 Meta 提出的「Megabyte」架构通过将文本切分为「patches」从架构层面实现多尺度压缩。这种思路意味着未来的模型可能天生就需要更少的上下文输入。Agent 生命周期管理在多轮 Agent 交互中上下文压缩不再是一次性操作而是需要贯穿整个会话生命周期的持续过程。每一轮对话结束后自动压缩记忆新对话开始时按需解压这种「压缩-解压」循环将成为 Agent 框架的标准组件。十、写在最后上下文压缩正在从可选的「高级特性」变成 Agent 系统的「基础设施」。随着 Agent 处理的信息量持续暴增每一行 token 的「提纯」能力将在很大程度上决定应用的可用性和经济性。可以说谁掌握了高效的上下文管理能力谁就能在 AI 应用这场竞赛中占据先机。从 Token 级到句子级再到 LLM 摘要级每一种压缩策略都有自己的适用场景和最经济的使用方式。实际工程中很少有一种策略 延伸阅读如果你对 AI Agent 系统的实战构建感兴趣推荐阅读我的另一篇文章 手写 MCP Server从零实现 Model Context Protocol构建 AI Agent 工具调用框架这篇文章完整实现了 MCP 协议的核心组件是构建 Agent 工具生态的基础。本文是「手写 AI 系统」系列文章之一。该系列从零实现 AI 系统中的关键组件涵盖上下文压缩、Agent 记忆管理、RAG、Function Calling 等核心技术帮助你深入理解底层原理构建属于自己的 AI 工具链。

相关新闻

3DS游戏格式转换终极指南:一键将.3ds文件变为可安装CIA

3DS游戏格式转换终极指南:一键将.3ds文件变为可安装CIA

3DS游戏格式转换终极指南:一键将.3ds文件变为可安装CIA 【免费下载链接】3dsconv Python script to convert Nintendo 3DS CCI (".cci", ".3ds") files to the CIA format 项目地址: https://gitcode.com/gh_mirrors/3d/3dsconv 还在为3…

2026/7/6 6:44:36阅读更多 →
DVWA靶场——File Inclusion(文件包含)笔记

DVWA靶场——File Inclusion(文件包含)笔记

File Inclusion(文件包含),是指当服务器开启了allow_url_include选项时,通过一些PHP的特性函数(比如:include(),require(),include_once()和require_once())利用URL去动态…

2026/7/6 6:44:36阅读更多 →
SLO2016与PIC18F46K20的工业通信系统设计与优化

SLO2016与PIC18F46K20的工业通信系统设计与优化

1. SLO2016与PIC18F46K20的硬件协同架构解析在工业通信设备升级项目中,我最近完成了一个基于SLO2016信号调理芯片与PIC18F46K20微控制器的传输系统改造。这个组合特别适合需要高可靠性数据传递的现场环境,比如工厂车间的设备状态监控网络。PIC18F46K20作…

2026/7/6 6:39:35阅读更多 →
新能源  工控行业一线客户出差走访纪实

新能源 工控行业一线客户出差走访纪实

近期团队集中走访广东多家自动化、储能温控、光伏电控、新能源配套制造企业,覆盖锂电设备、液冷负载、智能家居、光伏微逆、工业母线、锂电全流程装备六大赛道,深度对接客户设备用电采集、电能治理、测温、物联网模组、能源平台等配套需求,同…

2026/7/6 7:59:41阅读更多 →
定位API权限没开,用户位置拿不到?

定位API权限没开,用户位置拿不到?

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 定位API权限没开,用户位置拿不到? 目录半夜三点,用户又来问:“为啥点‘获取位置’…

2026/7/6 7:59:41阅读更多 →
本地部署Stable Diffusion构建AI画作投票与物理模拟互动系统

本地部署Stable Diffusion构建AI画作投票与物理模拟互动系统

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个很有意思的本地AI图像生成与物理模拟结合的实践项目。这个项目的核心,是将AI绘画的创意生成能力&#xf…

2026/7/6 7:59:41阅读更多 →
开源世界收音机,把全球电台装进口袋

开源世界收音机,把全球电台装进口袋

在流媒体大行其道的今天,广播电台这个古老的媒介似乎被很多人遗忘了。但对于语言学习者、异国文化爱好者和电台怀旧族来说,能随时随地听到来自世界各地的实时广播,是一种无可替代的体验。然而现实很骨感:各个电台网站分散、格式不…

2026/7/6 7:59:41阅读更多 →
2026年钢格板市场大揭秘:哪家服务好,答案即将揭晓!

2026年钢格板市场大揭秘:哪家服务好,答案即将揭晓!

在2026年的钢格板市场,随着建筑、工业等领域的持续发展,钢格板的需求也日益增长。面对众多的钢格板供应商,如何选择一家服务优质的企业成为了众多客户的难题。今天,我们就来深入揭秘2026年钢格板市场,看看哪家企业的服…

2026/7/6 7:59:41阅读更多 →
WSEN-ISDS传感器与PIC18F96J94微控制器的硬件架构与运动融合算法

WSEN-ISDS传感器与PIC18F96J94微控制器的硬件架构与运动融合算法

1. WSEN-ISDS传感器与PIC18F96J94微控制器的硬件架构解析WSEN-ISDS(型号2536030320001)是一款六轴MEMS惯性测量单元(IMU),采用电容式传感原理,集成了三轴加速度计和三轴陀螺仪。其核心参数包括:加速度计量程&#xff1…

2026/7/6 7:54:41阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/6 4:26:20阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/6 2:48:33阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/6 0:10:35阅读更多 →
Seraphine:基于LCU API的英雄联盟智能游戏助手技术解析与应用指南

Seraphine:基于LCU API的英雄联盟智能游戏助手技术解析与应用指南

Seraphine:基于LCU API的英雄联盟智能游戏助手技术解析与应用指南 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 技术架构先行:官方接口的合规应用 你是否曾在BP阶段手忙脚乱&#x…

2026/7/6 0:03:39阅读更多 →
多协议远程连接管理工具mRemoteNG:告别混乱,统一你的远程桌面管理

多协议远程连接管理工具mRemoteNG:告别混乱,统一你的远程桌面管理

多协议远程连接管理工具mRemoteNG:告别混乱,统一你的远程桌面管理 【免费下载链接】mRemoteNG mRemoteNG is the next generation of mRemote, open source, tabbed, multi-protocol, remote connections manager. 项目地址: https://gitcode.com/gh_m…

2026/7/6 0:03:39阅读更多 →
COUNT(DISTINCT) 与 GROUP BY 去重统计:5 亿数据量下的性能实测与选型指南

COUNT(DISTINCT) 与 GROUP BY 去重统计:5 亿数据量下的性能实测与选型指南

COUNT(DISTINCT) 与 GROUP BY 去重统计:5 亿数据量下的性能实测与选型指南在数据分析和处理领域,去重统计是最基础也是最频繁使用的操作之一。当数据量达到亿级规模时,不同的去重统计方法在性能上可能产生天壤之别。本文将基于 5 亿行数据的实…

2026/7/6 0:03:39阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/6 4:45:01阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/6 4:45:01阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/6 4:45:03阅读更多 →