一、引言
随着大模型在智能客服、对话机器人、RAG相关场景的大规模落地,单次对话早已不是一问一答的孤立请求,而是多轮连续会话。用户会持续追加问题、回溯历史对话、上传长文档、粘贴大段业务文案,这就带来了我们实践过程经常会遇到的高频问题:
- 第一,多轮对话上下文不断累积Token,极易超出模型上下文窗口上限,引发模型报错、回答错乱、上下文遗忘等问题;
- 第二,大量并发长会话会持续占用服务器显存与内存资源,造成会话过载,导致服务响应变慢、接口超时、整机算力被耗尽;
- 第三,用户随意提交数万字超长Prompt、恶意拼接冗余文本,会浪费昂贵的大模型调用算力与计费成本;
- 第四,用户输入违规、辱骂、诱导类敏感内容,若没有前置风控熔断,会产生合规风险、内容安全风险甚至平台监管处罚。
我们应用实践过程中应该都遇到过这些问题,大模型会话状态管理由此必不可少,状态管理负责维护每一个用户会话的生命周期、历史上下文、会话标识、多租户隔离与持久化存储;上下文风控则包含会话过载控制、上下文自动裁剪、超长Prompt 拦截、敏感内容熔断四大核心能力,共同构成大模型应用落地的前置网关防护层。如果大模型应用只能支撑简单单轮对话,则无法商用落地,更无法保证服务稳定性、成本可控性与内容合规性。今天我们从实际业务痛点出发,重点探讨会话管理与上下文风控,深入了解这套大模型线上生产环境的基础必备架构。
二、核心概念基础
1. 会话状态
会话状态是指大模型每一个独立对话会话在全生命周期中留存的所有结构化数据集合;
核心包含:会话唯一ID、用户ID、会话创建时间、最后交互时间、历史消息列表(用户提问 + 模型回复)、当前上下文总Token数、会话状态标识(活跃、闲置、过期、冻结)、租户标识、设备标识、风控标记位等。会话状态的核心作用是让大模型记住多轮历史对话,同时便于后台进行会话过期清理、资源回收、权限隔离与风控追溯。
会话状态:分为内存级临时会话与数据库持久化会话,内存级响应速度快但重启丢失,持久化可跨设备、跨服务实例恢复历史对话,是应用实践落地标配。
2. 上下文窗口
上下文窗口是大模型出厂设定的最大可接收Token总量,包含用户当前提问Token + 历史多轮对话Token + 系统提示词Token。例如7B模型常见4K、8K上下文窗口,34B、70B模型支持32K、64K甚至128K窗口。
一旦总Token超出上下文窗口上限,模型无法正常推理,会直接截断报错或逻辑崩坏,这也是上下文裁剪与过载控制的核心依据。
3. 核心风控能力定义
会话过载控制:针对单用户会话并发数、全局在线会话总数、单会话显存或内存占用进行阈值管控,超出阈值则拒绝新建会话、限流排队或闲置会话自动下线,避免服务雪崩。
上下文自动裁剪:当多轮历史对话累积Token临近上下文窗口上限时,按照预设策略自动淘汰早期无关历史消息,保留关键上下文,保证总Token始终在模型可接受范围内。
超长Prompt拦截:对用户单次输入的当前提问进行Token检测,超出单条Prompt阈值直接前置拦截,不进入模型推理,返回友好提示,节省算力与计费。
敏感内容熔断拦截:通过关键词匹配、语义风控模型、正则规则三层检测,识别用户输入与历史上下文敏感内容,触发熔断后终止当前会话、屏蔽违规内容并记录风控日志。
4. 核心基础
4.1 Token基础机制
Token是大模型处理文本的最小单位,中文约1个汉字对应1.5~2个Token,英文1个单词对应1个Token,标点、空格、换行均占用Token。
- 大模型推理、上下文窗口限制、计费计价、显存占用全部以Token为计量单位。
- 理解Token是掌握上下文裁剪、超长拦截、过载控制的前提:所有阈值设置都不能按字符数直接判定,必须先做文本转Token计算,否则会出现判定不准、误拦截或漏拦截的情况。
- 主流实现均采用模型配套的Tokenizer进行精准Token 统计。
4.2 大模型会话完整生命周期
一个标准大模型会话分为五个阶段:会话创建→多轮交互→闲置等待→过期冻结→资源销毁。
- 会话创建时分配唯一SessionID、初始化空历史上下文;
- 多轮交互时持续追加用户消息与模型回复,累积Token;
- 闲置等待阶段无新请求,后台定时检测闲置时长;
- 达到闲置阈值则标记为过期冻结,不再接收新消息;
- 最终定时任务清理过期会话、释放内存与数据库存储资源。
会话状态管理本质就是对这五个生命周期阶段的全流程管控。
4.3 上下文存储与传递原理
大模型本身无记忆能力,无法主动存储历史对话,所有多轮上下文都由应用层维护:应用端把系统提示词 + 历史对话消息 + 当前用户提问拼接成完整Prompt,一次性传入大模型推理。
- 模型只负责基于拼接后的上下文生成回复,记忆完全依赖应用层的上下文存储与拼接逻辑。
- 这一原理决定了:上下文裁剪、状态管理全部在应用网关层实现,无需改动大模型底层权重与推理逻辑,属于业务架构层面的轻量化改造,落地成本极低。
4.4 线上服务资源关联逻辑
每一个活跃大模型会话都会占用:内存(存储历史消息与会话状态)、显存(模型推理时上下文 KV Cache 缓存)、网络带宽、数据库存储。
- 会话数量越多、单会话上下文越长,KV Cache占用显存越高,整机并发承载能力越低。
- 会话过载控制的本质,就是通过管控会话数量与上下文长度,限制 KV Cache 显存无序增长,保障服务并发稳定性。
4.5 Token与模型推理显存关联
- 大模型推理时,历史上下文会生成KV Cache缓存存储在显存,上下文越长、会话越多,KV Cache占用显存越高。
- 会话管理与裁剪的核心底层逻辑,就是控制KV Cache无序增长,通过限制上下文Token长度与会话数量,稳定显存占用,保障并发推理能力。
4.6 注意力机制与上下文窗口限制
- 大模型注意力机制需要对所有上下文Token做权重计算,Token越多计算量越大、推理速度越慢。
- 超出窗口后注意力维度不匹配,模型无法正常生成文本,出现乱码、逻辑断裂、无限重复等现象,这也是必须做自动裁剪的模型底层原因。
三、会话状态管理完整体系
1. 会话唯一标识设计
采用分布式全局唯一SessionID,拼接用户UID、时间戳、随机串、租户ID,保证多租户环境下会话不冲突。
- 同时支持绑定设备ID、IP标识,用于异常会话识别、异地登录风控、恶意会话追溯。
- 每个会话独立隔离,不同用户、不同租户的历史上下文完全互不干扰,是多商户SaaS版大模型应用的基础设计。
2. 会话状态字段结构化设计
标准会话状态结构体包含:session_id、user_id、tenant_id、status(active/idle/expire/ban)、create_time、last_interact_time、messages(列表存储 role/content)、total_token、max_context_token、risk_flag、overload_flag。
所有字段可持久化到Redis+轻量数据库,Redis做热数据高速读写,轻量数据库做冷数据持久化归档,兼顾性能与数据安全。
3. 会话持久化与冷热分离
- 活跃会话、近7天交互会话存入Redis,支持毫秒级读取历史上下文;
- 超过7天闲置会话转入轻量数据库归档,释放Redis内存资源;
- 用户再次访问归档会话时,自动从轻量数据库回载入Redis,恢复会话状态。
- 冷热分离是大规模会话管理的核心优化手段,避免Redis存储无限膨胀。
4. 会话过期与自动清理机制
配置闲置超时阈值,如30分钟无交互自动闲置,2小时自动过期,后台定时任务轮询扫描会话状态,将过期会话标记为冻结,清理内存缓存、释放KV Cache关联资源,仅保留数据库归档记录。
同时限制单用户最大并发会话数,如每人最多5个在线会话,超出则禁止新建,从源头控制会话过载。
5. 多租户会话隔离
SaaS场景下不同企业租户共享大模型推理服务,但会话数据、上下文历史、风控规则完全隔离,租户只能查看与操作自身会话,无法越权访问其他租户数据。
会话状态中加入tenant_id维度,所有查询、更新、裁剪操作均携带租户过滤条件,保障数据隔离与企业数据安全。
四、上下文过载控制
1. 会话过载的成因
大模型会话过载主要来自三个维度:
- 1. 全局在线会话数量过多;
- 2. 单用户同时开启大量长会话;
- 3. 单会话上下文Token持续暴涨导致KV Cache显存占用过高。
三者叠加会造成推理队列阻塞、接口响应延迟飙升、服务实例CPU或显存打满,严重时直接服务宕机。
2. 过载控制三层阈值体系
- 全局阈值:设置服务最大在线活跃会话总数,达到上限后新用户新建会话进入排队队列或提示服务繁忙。
- 用户级阈值:限制单用户最大并发会话数、单用户单会话最大允许Token上限,防止单个用户占用过多资源。
- 资源阈值:实时监控服务器显存使用率、内存使用率、推理队列长度,达到阈值自动触发限流、禁止新会话创建、闲置会话强制下线。
3. 过载控制执行逻辑
- 网关层接收用户请求后,首先校验:全局会话数是否超限→用户并发会话数是否超限→服务器资源是否超限→会话自身Token是否临近上限。
- 任意一项触发过载阈值,直接执行限流策略:返回服务繁忙、排队等待、禁止新建会话、强制裁剪当前上下文。
- 过载控制前置在模型推理之前,不浪费任何一次无效推理调用,同时从资源层面守住服务稳定性底线。
4. 过载降级策略
- 轻度过载:开启请求排队、限制单用户请求频率;
- 中度过载:停止新用户会话创建、自动下线闲置低活跃会话;
- 重度过载:临时关闭非核心业务会话、只保留付费企业租户会话、扩容推理节点。
- 分级降级让服务在流量洪峰下不至于彻底崩溃,实现柔性可控。
五、上下文自动裁剪策略
1. 自动裁剪触发时机
两种触发条件:
- 一是每次多轮对话结束后,重新计算总 Token,若超过预警阈值(如上下文窗口的80%)自动触发裁剪;
- 二是定时巡检所有活跃会话,对超阈值后台会话批量裁剪,无需等待用户新请求。
双重触发保证上下文始终维持在安全区间。
2. 主流上下文裁剪算法
- 时间顺序淘汰法:最简单常用,优先删除最早的一轮用户 + 模型对话,保留最新对话,适合绝大多数通用对话场景,实现简单、稳定性高。
- 重要性权重裁剪法:对历史消息做语义权重打分,保留业务关键问题、核心指令,删除闲聊、无关冗余对话,适合知识库RAG、专业咨询场景。
- 滑动窗口裁剪法:固定保留最近N轮对话,超出轮数直接淘汰旧内容,轮数可控、逻辑直观。
- 摘要压缩裁剪法:对早期长历史对话生成简短摘要,替换原始大段文本,大幅节省Token,适合超长周期连续会话。
3. 裁剪优先级规则
- 固定保留优先级:系统提示词 > 当前最新用户提问 > 近期关键对话 > 早期闲聊对话。
- 绝不裁剪系统提示词与当前用户输入,只对中间历史对话做精简,保证模型基础指令与当前问题不丢失,裁剪后回答逻辑不跑偏。
4. 裁剪后状态更新
裁剪完成后重新统计总Token、更新会话状态中的messages列表与total_token字段,同步更新Redis缓存与数据库,下一轮请求直接使用裁剪后的上下文拼接推理,实现无感知自动治理,用户完全不会察觉到历史被裁剪。
六、超长Prompt拦截机制
1. 超长Prompt的危害
用户单次提交超大篇幅文本,如万字文档、批量复制内容、恶意冗余字符,会直接拉高单次推理Token消耗、占用大量显存、拉长推理耗时,同时增加计费成本,甚至直接触发模型上下文窗口溢出。
- 前置超长Prompt拦截是低成本高收益的防护手段。
2. 双层判定规则
不使用字符数粗略判定,采用Token精准判定:
- 第一层设置单条用户Prompt最大Token阈值,如单次提问最大1000Token;
- 第二层结合会话已有上下文,计算“已有Token + 当前Prompt Token”总和,预判是否超出模型窗口。
- 任意一层超标立即拦截。
3. 分级拦截与友好降级
- 轻度超长:提示用户精简内容、分段发送;
- 重度超长:直接拒绝请求,返回规范引导文案;
- 恶意重复超长请求:触发用户级限流,短时间内禁止继续提问。
- 同时支持白名单机制,企业付费用户可放宽Prompt长度阈值,兼顾风控与业务灵活性。
4. 拦截位置与架构
超长Prompt拦截部署在API网关层,位于请求入口,在进入模型推理、RAG检索之前完成检测,无效请求直接拦截闭环,不占用下游任何计算资源,架构轻量化、性能损耗极低。
七、敏感内容熔断拦截机制
1. 熔断三层检测体系
- 基础关键词正则:内置敏感词库、违规句式正则匹配,毫秒级检测,性能最高。
- 语义小模型风控:轻量级文本分类模型,识别隐晦违规、诱导性内容,弥补关键词漏判。
- 上下文关联风控:结合多轮历史对话语义,识别逐句诱导、分步提问的规避式敏感内容,防止拆分话术绕过检测。
2. 多级熔断策略
- 一级预警:标记敏感日志、提醒用户规范发言,不终止会话;
- 二级限制:屏蔽当前违规消息,返回合规提示,会话保持可继续交互;
- 三级熔断:直接冻结当前会话、禁止后续提问、记录用户风控档案;
- 四级封禁:限制账号新建会话、接入人工审核。
3. 熔断后置处理
- 触发熔断后立即终止本次模型调用,不生成违规回复;
- 同时写入风控日志,记录会话ID、用户ID、敏感内容、触发规则、时间戳,用于后续追溯、报表统计与规则迭代。
- 支持对接平台风控后台,实现违规内容统一管理。
八、完整执行流程
该流程对用户请求进行会话校验、过载检测、超长拦截及敏感内容过滤后,拼接并裁剪上下文,送入大模型生成回复,更新缓存,并异步清理过期会话与资源。
流程说明:
- 1. 用户发起对话请求,携带SessionID、用户输入文本
- 2. 网关层解析SessionID,读取Redis会话状态,校验会话是否存在、是否被风控冻结
- 3. 执行会话过载检测:全局会话数、用户并发数、服务器资源阈值校验
- 4. 执行超长Prompt 拦截:计算当前输入Token,单条 + 全局上下文总和校验
- 5. 执行敏感内容熔断检测:关键词→语义模型→上下文关联三层风控
- 6. 检测无异常,拼接系统提示词 + 历史上下文 + 当前提问
- 7. 计算拼接后总Token,判断是否临近上下文窗口阈值
- 8. 若超标触发上下文自动裁剪,精简历史消息并更新会话状态
- 9. 把合规且Token达标的完整上下文送入大模型推理
- 10. 获取模型回复,追加到会话历史消息列表
- 11. 重新统计总Token、更新会话最后交互时间、刷新Redis会话缓存
- 12. 定时任务异步扫描过期会话、清理过载资源、归档冷数据、风控日志落库
九、应用实践
以下是一个大模型会话状态管理与上下文风控系统示例,实现会话生命周期管理、超长Prompt拦截、敏感内容熔断、上下文自动裁剪和过载保护等功能,通过调用本地模型API进行真实推理。
实现的测试用例:
- 测试1:正常对话
- 测试2:调用真实模型生成春天的短文
- 测试3:超长文本拦截
- 测试4:敏感内容熔断
import time import json import requests from typing import List, Dict import tiktoken # ===================== 1. 基础配置 ===================== # 模型上下文窗口上限 MAX_CONTEXT_TOKEN = 8192 # 裁剪预警阈值 80% TOKEN_WARNING_RATIO = 0.8 # 单条Prompt最大拦截Token SINGLE_PROMPT_MAX_TOKEN = 1000 # 会话闲置过期时间 秒 SESSION_EXPIRE_SECONDS = 7200 # 本地模型API地址 LOCAL_MODEL_API = "http://192.168.3.6:8000/v1/chat/completions" # 初始化tokenizer tokenizer = tiktoken.get_encoding("cl100k_base") # 敏感词基础库 SENSITIVE_WORDS = {"违规词1", "违规词2", "敏感诱导", "涉政内容"} # ===================== 2. 数据结构定义 ===================== class SessionState: def __init__(self, session_id: str, user_id: str): self.session_id = session_id self.user_id = user_id self.status = "active" # active idle expire ban self.create_time = time.time() self.last_interact_time = time.time() self.messages: List[Dict[str, str]] = [] self.total_token = 0 self.risk_flag = False self.overload_flag = False # 内存会话存储 模拟Redis session_cache: Dict[str, SessionState] = {} # ===================== 3. 基础工具函数 ===================== def count_token(text: str) -> int: """文本转Token统计""" return len(tokenizer.encode(text)) def calc_messages_total_token(messages: List[Dict[str, str]]) -> int: """计算历史消息总Token""" total = 0 for msg in messages: total += count_token(msg.get("content", "")) return total def print_step(step_num: int, title: str, content: str = "", status: str = "info"): """打印流程步骤""" icons = {"info": "[*]", "success": "[OK]", "warning": "[!]", "error": "[X]", "process": "[~]"} icon = icons.get(status, "[*]") print(f"\n{'='*60}") print(f"{icon} 步骤 {step_num}: {title}") print(f"{'='*60}") if content: print(content) def print_divider(title: str): """打印分隔线""" print(f"\n{'─'*60}") print(f"[>] {title}") print(f"{'─'*60}") # ===================== 4. 模型调用函数 ===================== def call_local_model(messages: List[Dict[str, str]], user_input: str) -> Dict: """调用本地大模型API""" print_step(6, "调用本地大模型", status="process") # 构建请求体 prompt = user_input if messages and len(messages) > 1: # 如果有历史消息,构建上下文 context = "" for msg in messages[-5:]: # 只取最近5轮 if msg["role"] == "user": context += f"用户: {msg['content']}\n" elif msg["role"] == "assistant": context += f"助手: {msg['content']}\n" prompt = f"{context}用户: {user_input}\n助手:" payload = { "prompt": prompt, "stream": False, "delta_mode": True, "temperature": 0.7, "max_tokens": 512 } print(f"[->] 请求地址: {LOCAL_MODEL_API}") print(f"[->] 请求体:") print(json.dumps(payload, ensure_ascii=False, indent=2)) try: start_time = time.time() response = requests.post( LOCAL_MODEL_API, json=payload, headers={"Content-Type": "application/json"}, timeout=120 ) latency = round(time.time() - start_time, 3) print(f"\n[<-] 响应状态码: {response.status_code}") print(f"[TIME] 响应延迟: {latency}s") if response.status_code == 200: result = response.json() print(f"[<-] 响应内容:") print(json.dumps(result, ensure_ascii=False, indent=2)[:500] + "..." if len(json.dumps(result)) > 500 else json.dumps(result, ensure_ascii=False, indent=2)) # 提取生成的文本 generated_text = "" if "choices" in result and len(result["choices"]) > 0: choice = result["choices"][0] if "text" in choice: generated_text = choice["text"] elif "delta" in choice and "content" in choice["delta"]: generated_text = choice["delta"]["content"] elif "message" in choice and "content" in choice["message"]: generated_text = choice["message"]["content"] return { "success": True, "content": generated_text, "latency": latency, "raw_response": result } else: print(f"❌ 请求失败: {response.text[:200]}") return { "success": False, "error": f"HTTP {response.status_code}: {response.text[:200]}", "latency": latency } except requests.exceptions.ConnectionError as e: print(f"❌ 连接失败: {str(e)}") return {"success": False, "error": f"连接失败: 请检查模型服务是否已启动 ({LOCAL_MODEL_API})"} except requests.exceptions.Timeout as e: print(f"❌ 请求超时: {str(e)}") return {"success": False, "error": "请求超时"} except Exception as e: print(f"❌ 异常: {str(e)}") return {"success": False, "error": str(e)} # ===================== 5. 超长Prompt拦截 ===================== def check_long_prompt(user_input: str) -> (bool, str, int): """返回是否通过,提示信息,token数""" token_num = count_token(user_input) print(f"[TXT] 输入文本Token数: {token_num}") print(f"[TXT] 最大允许Token数: {SINGLE_PROMPT_MAX_TOKEN}") if token_num > SINGLE_PROMPT_MAX_TOKEN: return False, f"输入内容过长,当前Token:{token_num},最大允许{SINGLE_PROMPT_MAX_TOKEN},请精简后重试", token_num return True, "校验通过", token_num # ===================== 6. 敏感内容熔断检测 ===================== def check_sensitive_content(text: str) -> (bool, str): print(f"[CHK] 检测敏感词库: {SENSITIVE_WORDS}") for word in SENSITIVE_WORDS: if word in text: return False, f"内容包含敏感信息[{word}],已触发会话风控熔断" return True, "内容合规" # ===================== 7. 上下文自动裁剪 ===================== def auto_cut_context(session: SessionState): """时间顺序淘汰法 裁剪最早对话""" warning_token = int(MAX_CONTEXT_TOKEN * TOKEN_WARNING_RATIO) print(f"[!] 上下文Token预警阈值: {warning_token} ({TOKEN_WARNING_RATIO*100}%)") print(f"[TXT] 当前会话Token: {session.total_token}") cut_count = 0 while session.total_token > warning_token: # 保留系统提示词,删除最早一轮问答 if len(session.messages) >= 3: removed = session.messages[1:3] del session.messages[1:3] cut_count += 1 print(f"[CUT] 裁剪第{cut_count}轮历史对话: {removed[0]['content'][:30]}...") session.total_token = calc_messages_total_token(session.messages) else: break if cut_count > 0: print(f"[OK] 共裁剪 {cut_count} 轮对话,当前Token: {session.total_token}") else: print(f"[OK] 无需裁剪,当前Token: {session.total_token}") # ===================== 8. 会话过载简单校验 ===================== def check_session_overload(session: SessionState) -> (bool, str): # 模拟全局最大在线会话数限制 current_sessions = len(session_cache) print(f"[USER] 当前在线会话数: {current_sessions}/2000") if current_sessions > 2000: return False, "当前服务会话过载,请稍后再试" # 单会话Token过载 if session.total_token > MAX_CONTEXT_TOKEN * 0.9: print(f"[!] 单会话Token接近上限: {session.total_token}/{MAX_CONTEXT_TOKEN}") session.overload_flag = True auto_cut_context(session) return True, "过载校验通过" # ===================== 9. 会话消息交互入口 ===================== def llm_chat_interact(session_id: str, user_id: str, user_input: str, use_real_model: bool = False) -> str: print_divider(f"开始处理会话 [{session_id}] 用户 [{user_id}]") print(f"[IN] 用户输入: {user_input[:100]}{'...' if len(user_input) > 100 else ''}") # 1. 获取或创建会话 print_step(1, "会话状态管理") if session_id not in session_cache: print(f"[NEW] 创建新会话") session = SessionState(session_id, user_id) # 初始化系统提示词 session.messages.append({"role":"system", "content":"你是专业的大模型智能助手,回答专业严谨通俗易懂"}) session_cache[session_id] = session print(f"[OK] 会话创建成功,已添加系统提示词") else: session = session_cache[session_id] print(f"[LOAD] 复用已有会话") print(f"[STAT] 会话历史消息数: {len(session.messages)}") print(f"[STAT] 会话当前Token: {session.total_token}") session.last_interact_time = time.time() # 2. 超长Prompt拦截 print_step(2, "超长Prompt拦截检测") ok, msg, token_num = check_long_prompt(user_input) if not ok: print(f"❌ 拦截原因: {msg}") return msg print(f"✅ {msg}") # 3. 敏感内容熔断 print_step(3, "敏感内容熔断检测") ok, msg = check_sensitive_content(user_input) if not ok: print(f"❌ {msg}") session.risk_flag = True session.status = "ban" return msg print(f"✅ {msg}") # 4. 加入当前用户消息 print_step(4, "构建对话上下文") session.messages.append({"role":"user", "content":user_input}) session.total_token = calc_messages_total_token(session.messages) print(f"[TXT] 已添加用户消息,当前总Token: {session.total_token}") print(f"[NUM] 当前对话轮数: {(len(session.messages)-1)//2}") # 5. 过载检测+自动裁剪 print_step(5, "上下文过载检测与自动裁剪") ok, msg = check_session_overload(session) if not ok: print(f"❌ {msg}") return msg print(f"✅ {msg}") # 6. 调用大模型 if use_real_model: model_result = call_local_model(session.messages, user_input) if model_result["success"]: model_reply = model_result["content"] print_step(7, "模型响应处理", status="success") print(f"[LEN] 生成内容长度: {len(model_reply)} 字符") print(f"[TIME] 模型响应延迟: {model_result['latency']}s") else: print_step(7, "模型调用失败", status="error") model_reply = f"[模型调用失败: {model_result['error']}]" else: print_step(6, "模拟大模型响应", status="info") model_reply = f"【模拟响应】已正常响应你的提问,当前会话总Token:{session.total_token},上下文已自动维护。实际部署时请设置 use_real_model=True 调用真实模型。" print(f"[OUT] {model_reply}") # 7. 保存助手回复 session.messages.append({"role":"assistant", "content":model_reply}) session.total_token = calc_messages_total_token(session.messages) print_divider(f"会话处理完成") print(f"[STAT] 最终会话状态:") print(f" - 消息总数: {len(session.messages)}") print(f" - 总Token数: {session.total_token}") print(f" - 对话轮数: {(len(session.messages)-1)//2}") print(f" - 会话状态: {session.status}") return model_reply # ===================== 10. 测试运行 ===================== if __name__ == "__main__": print_divider("大模型会话状态管理与上下文风控系统测试") # 测试1: 正常会话交互(使用模拟响应) print("\n" + "="*60) print("测试1: 正常会话交互") print("="*60) res = llm_chat_interact("session_001", "user_001", "请详细讲解LLM会话状态管理与上下文风控", use_real_model=False) print(f"\n[OUT] 最终回复: {res}") # 测试2: 继续对话(使用真实模型) print("\n" + "="*60) print("测试2: 调用真实模型生成春天的短文") print("="*60) res2 = llm_chat_interact("session_001", "user_001", "写一首春天的短文", use_real_model=True) print(f"\n[OUT] 最终回复:\n{res2}") # 测试3: 超长文本拦截 print("\n" + "="*60) print("测试3: 超长文本拦截测试") print("="*60) long_text = "测试超长文本" * 1000 res3 = llm_chat_interact("session_002", "user_002", long_text, use_real_model=False) print(f"\n[OUT] 最终回复: {res3}") # 测试4: 敏感内容熔断 print("\n" + "="*60) print("测试4: 敏感内容熔断测试") print("="*60) res4 = llm_chat_interact("session_003", "user_003", "这句话包含违规词1需要被拦截", use_real_model=False) print(f"\n[OUT] 最终回复: {res4}") print_divider("所有测试完成")
输出结果:
─────────────────────────────────────────────────────────
[>] 大模型会话状态管理与上下文风控系统测试
─────────────────────────────────────────────────────────
============================================================
测试1: 正常会话交互
============================================================
─────────────────────────────────────────────────────────
[>] 开始处理会话 [session_001] 用户 [user_001]
─────────────────────────────────────────────────────────
[IN] 用户输入: 请详细讲解LLM会话状态管理与上下文风控
============================================================
[*] 步骤 1: 会话状态管理
============================================================
[NEW] 创建新会话
[OK] 会话创建成功,已添加系统提示词
============================================================
[*] 步骤 2: 超长Prompt拦截检测
============================================================
[TXT] 输入文本Token数: 21
[TXT] 最大允许Token数: 1000
✅ 校验通过
============================================================
[*] 步骤 3: 敏感内容熔断检测
============================================================
[CHK] 检测敏感词库: {'敏感诱导', '违规词1', '涉政内容', '违规词2'}
✅ 内容合规
============================================================
[*] 步骤 4: 构建对话上下文
============================================================
[TXT] 已添加用户消息,当前总Token: 52
[NUM] 当前对话轮数: 0
============================================================
[*] 步骤 5: 上下文过载检测与自动裁剪
============================================================
[USER] 当前在线会话数: 1/2000
✅ 过载校验通过
============================================================
[*] 步骤 6: 模拟大模型响应
============================================================
[OUT] 【模拟响应】已正常响应你的提问,当前会话总Token:52,上下文已自动维护。实际部署时请设置 use_real_model=True 调用真实模型。
─────────────────────────────────────────────────────────
[>] 会话处理完成
─────────────────────────────────────────────────────────
[STAT] 最终会话状态:
- 消息总数: 3
- 总Token数: 112
- 对话轮数: 1
- 会话状态: active
[OUT] 最终回复: 【模拟响应】已正常响应你的提问,当前会话总Token:52,上下文已自动维护。实际部署时请设置 use_real_model=True 调用真实模型。
============================================================
测试2: 调用真实模型生成春天的短文
============================================================
─────────────────────────────────────────────────────────
[>] 开始处理会话 [session_001] 用户 [user_001]
─────────────────────────────────────────────────────────
[IN] 用户输入: 写一首春天的短文
============================================================
[*] 步骤 1: 会话状态管理
============================================================
[LOAD] 复用已有会话
[STAT] 会话历史消息数: 3
[STAT] 会话当前Token: 112
============================================================
[*] 步骤 2: 超长Prompt拦截检测
============================================================
[TXT] 输入文本Token数: 11
[TXT] 最大允许Token数: 1000
✅ 校验通过
============================================================
[*] 步骤 3: 敏感内容熔断检测
============================================================
[CHK] 检测敏感词库: {'敏感诱导', '违规词1', '涉政内容', '违规词2'}
✅ 内容合规
============================================================
[*] 步骤 4: 构建对话上下文
============================================================
[TXT] 已添加用户消息,当前总Token: 123
[NUM] 当前对话轮数: 1
============================================================
[*] 步骤 5: 上下文过载检测与自动裁剪
============================================================
[USER] 当前在线会话数: 1/2000
✅ 过载校验通过
============================================================
[~] 步骤 6: 调用本地大模型
============================================================
[->] 请求地址: http://192.168.3.6:8000/v1/chat/completions
[->] 请求体:
{
"prompt": "用户: 请详细讲解LLM会话状态管理与上下文风控\n助手: 【模拟响应】已正常响应你的提问,当前会话总Token:52,上下文已自动维护。实际部署时请设置 use_real_model=True 调用真实模型。\n用户: 写一首春天的短文\n用户: 写一首春天的短文\n助手:",
"stream": false,
"delta_mode": true,
"temperature": 0.7,
"max_tokens": 512
}
[<-] 响应状态码: 200
[TIME] 响应延迟: 3.81s
[<-] 响应内容:
{
"id": "chatcmpl-local",
"object": "text_completion",
"model": "ZhipuAI/chatglm2-6b",
"choices": [
{
"text": "春天,是四季轮回的起点,大地上万物复苏,生机勃勃。这是一个充满希望与活力的季节,让我们一起迎接春天的到来吧!\n\n春风拂面,轻轻地拂过我们的脸庞。带来了新的气息,带来了愉悦的心情。春雨纷纷扬扬,敲响大地的琴弦,为春天注入了生机。绿色的植物开始生长,嫩嫩的叶芽从枝头伸出,一片崭新的世界正在慢慢展开。\n\n春天是一个特别的季节,既有生机勃发的喜悦,也有万物复苏的沉默。我们迎来了希望的春天,也迎来了挑战的春天。愿我们能够勇敢地面对挑战,迎接未来的繁荣与和平。\n\n愿春天永远充满我们的心灵,愿我们永远",
"index": 0,
"finish_reason": "stop"
}
]
}...
============================================================
[OK] 步骤 7: 模型响应处理
============================================================
[LEN] 生成内容长度: 246 字符
[TIME] 模型响应延迟: 3.81s
─────────────────────────────────────────────────────────
[>] 会话处理完成
─────────────────────────────────────────────────────────
[STAT] 最终会话状态:
- 消息总数: 5
- 总Token数: 450
- 对话轮数: 2
- 会话状态: active
[OUT] 最终回复:
春天,是四季轮回的起点,大地上万物复苏,生机勃勃。这是一个充满希望与活力的季节,让我们一起迎接春天的到来吧!
春风拂面,轻轻地拂过我们的脸庞。带来了新的气息,带来了愉悦的心情。春雨纷纷扬扬,敲响大地的琴弦,为春天注入了生机。绿色的植物开始生长,嫩嫩的叶芽从枝头伸出,一片崭新的世界正在慢慢展开。
春天是一个特别的季节,既有生机勃发的喜悦,也有万物复苏的沉默。我们迎来了希望的春天,也迎来了挑战的春天。愿我们能够勇敢地面对挑战,迎接未来的繁荣与和平。
愿春天永远充满我们的心灵,愿我们永远
============================================================
测试3: 超长文本拦截测试
============================================================
─────────────────────────────────────────────────────────
[>] 开始处理会话 [session_002] 用户 [user_002]
─────────────────────────────────────────────────────────
[IN] 用户输入: 测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长文本测试超长...
============================================================
[*] 步骤 1: 会话状态管理
============================================================
[NEW] 创建新会话
[OK] 会话创建成功,已添加系统提示词
============================================================
[*] 步骤 2: 超长Prompt拦截检测
============================================================
[TXT] 输入文本Token数: 5000
[TXT] 最大允许Token数: 1000
❌ 拦截原因: 输入内容过长,当前Token:5000,最大允许1000,请精简后重试
[OUT] 最终回复: 输入内容过长,当前Token:5000,最大允许1000,请精简后重试
============================================================
测试4: 敏感内容熔断测试
============================================================
─────────────────────────────────────────────────────────
[>] 开始处理会话 [session_003] 用户 [user_003]
─────────────────────────────────────────────────────────
[IN] 用户输入: 这句话包含违规词1需要被拦截
============================================================
[*] 步骤 1: 会话状态管理
============================================================
[NEW] 创建新会话
[OK] 会话创建成功,已添加系统提示词
============================================================
[*] 步骤 2: 超长Prompt拦截检测
============================================================
[TXT] 输入文本Token数: 19
[TXT] 最大允许Token数: 1000
✅ 校验通过
============================================================
[*] 步骤 3: 敏感内容熔断检测
============================================================
[CHK] 检测敏感词库: {'敏感诱导', '违规词1', '涉政内容', '违规词2'}
❌ 内容包含敏感信息[违规词1],已触发会话风控熔断
[OUT] 最终回复: 内容包含敏感信息[违规词1],已触发会话风控熔断
─────────────────────────────────────────────────────────
[>] 所有测试完成
─────────────────────────────────────────────────────────
十、总结
总的来说,其实大模型本身并没有长期记忆,全靠应用层维护会话状态和历史上下文,这也是做会话管理的根本逻辑。日常开发里很容易忽略Token机制、上下文窗口限制,导致多轮对话越聊越长,不仅占用大量显存、拉高算力成本,还会出现模型逻辑错乱、响应超时等问题,而过载管控、自动裁剪正好从源头解决了资源浪费和服务稳定性问题。另外超长Prompt前置拦截、敏感内容多层熔断,不只是优化体验,更是大模型应用合规落地的刚需,能规避监管风险和恶意请求冲击。
我们实践先吃透Token计算、上下文窗口这些基础知识点,再跟着流程理解每一层风控的执行逻辑,避免一上来就啃复杂算法。可以先测试超长文本、敏感词、会话溢出的不同场景,再逐步扩展 Redis会话持久化、语义智能裁剪等扩展功能,由浅入深实操落地,才能更深入的理解这套方法的执行逻辑。