1. 什么是 context-mode:先从一次失败的对话说起
去年我给一个电商团队做客服机器人优化,对方抱怨最多的就是:“模型时聪明时蠢,同一个问题换个问法就答非所问。”我上去一看,他们的 prompt 只有一句话:“你是一个客服,请回答用户问题。”
这大概是很多人玩 AI 应用的常态——你以为模型不行,其实是你根本没有给它足够的“上下文”。后来我把一套上下文管理策略交给他们,问题和 AI 发挥不稳定有关的大部分投诉都消失了。这套策略,就是我今天想聊的 context-mode。
context-mode,直译是“上下文模式”。它不是一个具体的算法,也不是某个框架的功能开关,而是一种组织 prompt、管理对话历史、动态切换响应策略的工作方式。你可以把它理解为:给大模型配一个导演,在对话开始前就安排好剧本,在对话过程中随时调整灯光和机位,最终让模型每一次输出都稳定落在你期望的轨道上。
我见过的 AI 应用,九成以上的翻车现场都不是模型笨,而是没有人告诉模型“你现在是谁、对面是谁、这次要达成的目标是什么、有哪些红线不能碰”。context-mode 就是把这些信息结构化地塞进每一次请求里,让模型始终在受控的上下文窗口内工作。
这篇文章我会从原理到实操,拆解 context-mode 的搭建方法,包含角色限定、记忆管理、意图切换、预算控制这几个核心环节,再用三个真实场景做完整演示。适合正在做 AI 应用开发、智能客服、内容生成工具,或者想系统化提升 prompt 效果的人参考。
2. context-mode 的核心逻辑:静态与动态的配合
2.1 为什么同一个模型,发挥时好时坏
先想一个生活中的例子。你问一个新来的实习生“帮我倒杯水”,他大概率会愣住,因为不知道用哪个杯子、接热水还是冷水、放你桌上还是会议室。但如果你说“王总,请用我桌上那个白色保温杯接一杯 60 度的温水,放我左手边”,他就能一次性把事办对。
大模型本质上也是这个“实习生”。它没有任何长期记忆,每次调用都是一次全新的开始。你上一次对话中提到的背景、偏好、要求,如果没有被放进这一次的输入里,它就会全部忘记。所谓“时好时坏”,绝大多数时候是因为不同轮次之间,信息的传递方式不一致。
context-mode 解决的就是这个问题。它把对话所需的背景信息从“碰运气”变成“按流程走”,每一次请求都包含一套完整的上下文包。类比一下:你不是在教实习生随机应变,而是每次都给他一份清晰的任务单。
2.2 context-mode 的两个层次:静态上下文与动态上下文
我习惯把 context-mode 拆成两层:静态上下文和动态上下文。
静态上下文是那些“不会随着对话变化”的部分,包括角色设定、产品背景、回答风格、禁忌规则、输出格式。它就像公司的入职手册,不管聊到什么话题,这些规矩始终有效。静态上下文应该在每一次请求中都原样携带,优先级最高。
动态上下文则是每一轮对话中不断变化的信息,包括用户刚刚提出的问题、已完成的对话历史、当前需要填写的槽位、最近查到的数据库结果。它像会议记录,每一轮都在更新,但不会全部塞进窗口。
好的 context-mode 设计,核心就是管理这两层信息的配比。静态层保证稳定性,动态层保证灵活性,两者配合,模型才能既守规矩又不死板。
我见过很多失败的 prompt,问题就是静态和动态混为一谈:把用户当前问题、历史记录、角色说明、参考范文全部糊在一起,结果模型既记不住角色,也抓不住重点。所以第一步,先把这两类信息在结构上分开。
2.3 context-mode 和普通 prompt 的本质区别
很多人觉得 context-mode 不就是把 prompt 写长一点吗?还真不是。
普通 prompt 是一段有时效性的指令,你写“你是一个文案专家”,只对这一次调用有效。context-mode 是一套可持续演进的上下文结构,它不只包含“你是谁”,还包含“你如何根据当前对话状态改变回应方式”,以及“什么样的信息该保留、什么样的该丢弃”。
用一个技术上的差异来说明:普通 prompt 是单层字符串,context-mode 通常是结构化对象,包含 system、history、user、tools 等多个槽位,每个槽位里有各自的优先级和生命周期。这也意味着,context-mode 通常需要一个调度器来组装每次请求的上下文,而不是在代码里拼字符串。
这引出一个关键结论:context-mode 不是一个写 prompt 的技巧,而是一个工程方案。它需要你在代码层面管理上下文的构建过程。
3. 手把手搭建一套 context-mode:从角色卡到动态策略
3.1 第一步:写一张可复用的角色卡
角色卡是 context-mode 的地基。它的作用是让模型在每轮对话开始前,就清楚自己的身份和边界。我推荐用五要素结构:角色、受众、任务、约束、输出格式。
一个我常用的角色卡模板:
[角色] 你是一位有十年经验的跨境电商客服主管, 擅长处理售前咨询、物流异常和售后纠纷。 [受众] 你在和一位可能不太懂技术的普通买家对话。 对方可能着急、有情绪,需要你的耐心和明确指引。 [任务] 根据后台订单信息,准确回答用户关于订单状态、 物流进度、退换货政策的提问。 [约束] 1. 只回答与订单、物流、售后相关的问题; 2. 不清楚的信息必须说明“需要核实”,严禁编造; 3. 语气温和专业,不使用感叹号和网络用语; 4. 涉及赔偿或补偿时,只提供标准政策,不额外承诺。 [输出格式] 统一按以下结构回复: - 问题确认:先用一句话复述用户的问题; - 处理方案:给出可执行的操作步骤; - 时间预期:说明什么时候会有结果; - 安抚话术:如果用户情绪激动,加一句共情表达。这段角色卡看起来简单,但每条信息都有明确用途。受众描述防止模型用技术黑话;约束第 2 条防幻觉;输出格式保证多轮回复的一致性。
实操建议是:这个角色卡不要写在代码里拼字符串,而应该放在配置文件或数据库里,方便运营同学直接修改。模型的表现要迭代,角色卡也要版本化管理。
3.2 第二步:设计带预算的动态记忆管理
动态上下文里最关键的是记忆管理。LLM 的上下文窗口是有上限的,即使是最新的模型,塞太多历史也会导致性能下降。所以不能让对话历史无限累积。
我常用“滚动窗口 + 摘要”的双层策略:
- 保留最近 6 轮对话的原始内容,让模型有完整的近期记忆;
- 更早的对话定期压缩成摘要,只留下关键信息:用户身份、已确认的需求、已给出的承诺、未完成事项。
这样做的好处是,模型既不会因为对话太长而遗忘前置信息,也不会因为信息过载而注意力分散。
预算控制也很关键。假设你的上下文窗口是 8000 token,我会这样分配:系统角色卡固定占 800 token,最新对话占 2000 token,历史摘要占 1000 token,工具返回结果占 2000 token,剩下 2200 token 留给模型生成。这个预算不是拍脑袋定的,是根据实际测试得到的经验值——角色卡太少会丢人设,历史摘要太少会丢关键承诺,输出空间太小会让回答变短。
3.3 第三步:用意图识别实现模式切换
context-mode 的精髓在于“模式”。不同场景下,模型的响应策略应该不同。
拿客服场景举例:用户在问物流,你应该用“查询模式”——模型需要查看订单接口,给出状态和时间预期;用户在表达不满,你应该用“安抚模式”——模型先共情,再提出补偿方案;用户只是闲聊,你应该用“拒绝模式”——礼貌说明自己只处理订单问题。
实现方式不复杂。在每次请求之前,先用规则或一个轻量分类器判断用户意图,然后动态选择对应的系统提示词。
用代码表达大概是这样的逻辑:
def build_context(user_input, session): intent = classify_intent(user_input) # 返回 "order_query" / "complaint" / "chitchat" system_template = { "order_query": ORDER_QUERY_SYSTEM, "complaint": COMPLAINT_SYSTEM, "chitchat": CHITCHAT_SYSTEM, }[intent] messages = [ {"role": "system", "content": system_template}, {"role": "system", "content": session.summary}, # 历史摘要 *session.recent_history, # 最近6轮原文 {"role": "user", "content": user_input}, ] return messages这里 KEY 点在于:切换的不是整个 prompt,而是 system 层级的“模式模板”。不同模板共享同一份历史摘要,但对角色、约束、输出格式的要求不同。
3.4 上下文预算怎么算:一个贴近实际的例子
这段演示一遍计算过程,方便你直接用。假设你用的是具有约 16K 上下文窗口的模型,目标是把输入控制在 13K 以内,留出余量。
各模块用量估算:
- 角色卡:800 token
- 固定业务规则(FAQ 片段、政策说明):1500 token
- 动态对话历史:最近 6 轮,每轮约 400 token,共 2400 token
- 历史摘要:约 800 token
- 外部数据(订单信息、商品详情):1000 token
- 预留输出空间:3000 token
- 总计:800 + 1500 + 2400 + 800 + 1000 + 3000 = 9500 token
在 13K 的预算内,合规且留有余量。如果某次外接数据返回特别长,比如订单列表有 20 条,就需要做截断或提取摘要,只保留最近 3 条的关键字段。
预算控制的意义不只是为了保证不超出窗口,还在于让模型把注意力花在最重要的信息上。动态上下文并非越多越好,有时候信息越少,模型回答越准。
4. 三个实操场景:客户服务、内容创作与代码辅助
4.1 场景一:智能客服的 context-mode 配置
把 context-mode 套到客服场景,我给它拆出三层:
第一层是固定的知识库上下文,包含退换货政策、物流时效说明、常见问题 FAQ。这部分每次请求都需要携带,适合放在角色卡之后作为静态上下文。
第二层是订单上下文。用户报出订单号后,系统调用订单接口,把订单状态、物流轨迹、商品信息塞进请求。这部分只在用户给出订单号时注入,避免浪费 token。
第三层是情绪上下文。如果用户连续发送短句、使用感叹号、或者包含“投诉”“退款”等敏感词,系统自动把情绪等级标记为“高”,并在角色卡附加一条安抚策略:“用户情绪激动时,先共情,再处理问题。”
实际测试中我发现一个有意思的现象:同样是“我的包裹怎么还没到”,在没有订单上下文时,模型会给出泛泛的物流解释;而注入具体物流信息后,模型会直接说“您的包裹已到达本市分拨中心,预计明天下午 6 点前送达,建议您晚上查看更新”,用户满意度提升非常明显。
这就印证了 context-mode 的一个核心原则:模型不需要所有信息,但关键信息一定要递送到。
4.2 场景二:内容创作助手的 context-mode 配置
内容创作类工具是 context-mode 最典型的受益场景。因为写作的主观性很强,用户最怕的就是“风格漂移”——上午让 AI 写专业报告,下午让它写幽默推文,结果两个都写得四不像。
我的解决方案是用“风格骨架”+“段落级约束”的组合:
风格骨架放在 system 层,约 500 token,定义了目标句式长度、用词偏好、语气温度、修辞手法上限。以小红书文案为例:短句多、每段不超过 3 行、口语化表达、允许使用网络流行语但不用生僻梗。
段落级约束放在 user 层,根据用户的具体指令动态变化。用户说“写一段产品种草文案”,系统会把“产品卖点速查表”“目标受众画像”“禁止出现的绝对化用词”这些信息注入提示词。
更重要的是历史参考上下文。我会在 system 层附上用户过去点赞最高的 3 篇文章作为风格锚点,模型会强烈模仿这种风格。实测结果:加入风格锚点后,生成文案的采纳率比不加入高约 40%——这个数字来自我自己的小范围用户测试,不一定有统计显著性,但趋势很明显。
这种配置方式的经验是:创作类 context-mode 的痛点不是信息不够,而是信息干扰。素材越多,模型越容易失控。所以每逢注入一段素材,都要问一句:如果去掉这段,输出质量会下降吗?不会,就删掉。
4.3 场景三:编程助手的 context-mode 配置
代码场景的 context-mode,核心要解决的是“代码库太大,无法全量塞进窗口”的问题。我的常用做法是检索增强拼接:
- 用户提问时,系统先对问题做关键词抽取;
- 在代码索引库里检索相关文件片段,每条截取 100-200 行;
- 把检索结果加上项目的编码规范、依赖说明,一起作为上下文注入。
关键点在编码规范的措辞上。比如“变量命名使用 camelCase”“错误处理必须包含日志输出”“禁止在业务代码中写 TODO”,这些规则写进 system 层后,模型的输出合规率会明显提高。
还有一个细节:代码上下文一定要标明“文件路径”和“语言类型”。模型对路径和语言非常敏感,上下文里如果写明“src/utils/format.ts (TypeScript)”,它在参考该代码答题时,会更准确地判断类型和导入方式。
编程助手的 context-mode 还有一个特殊技巧:把最近一次编译错误信息也注入上下文。模型看到真实报错之后,给出的修复建议比单纯描述问题要靠谱得多——这相当于给模型提供了“现场线索”,而不是让它盲猜。
5. 常见问题与排查技巧实录
5.1 问题速查表
我把做 context-mode 过程中最容易踩的坑整理成了下面这张表,每一项都是实际碰过的:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 模型记不住前面聊过的内容 | 历史摘要没有及时更新 | 检查摘要压缩逻辑,确认每轮结束后都刷新摘要 |
| 回答风格突然变化 | 模式切换时 system 模板不一致 | 确保切换 intent 后依然携带角色卡核心信息 |
| 上下文越界报错 | 外部数据注入太多 | 对外部数据做截断和字段过滤,预留足够的输出空间 |
| 模型过分听话但答非所问 | 角色卡太强压过任务指令 | 降低角色约束权重,任务指令放在 user 层 |
| 同一问题多次回答不一致 | 动态上下文含有噪声信息 | 精简历史片段,把无关闲聊排除在上下文之外 |
| 响应速度明显变慢 | 上下文过长导致 prefill 耗时高 | 缩短历史摘要,控制总输入 token 数 |
5.2 排查方法论:从现象到根因的 4 个检查点
遇到 context-mode 效果异常,我建议按以下顺序排查:
第一,检查每一层上下文是否真的被发送了。很多框架的缓存策略会导致 system 消息被合并或者截断,表面上你写了角色卡,实际上模型没看到。
第二,打印一份完整的 messages 列表逐条阅读。这个问题前面提过,但值得重复:不要在看日志时只盯 user 消息,system 消息才是影响最大的。
第三,检查摘要压缩策略是否触发了 bug。比如有的实现只在对话超过 10 轮时才生成摘要,但第 8-10 轮之间的信息已经在滚动窗口中被丢弃,造成信息断层。
第四,做“上下文消融实验”——依次删掉角色卡、历史摘要、外部数据,观察哪一层信息删除后对输出质量影响最大。这能帮你判断哪部分信息才是真正的关键上下文。
这套排查法在客服、写作、编程三个场景里都一样有效,核心思路是:把上下文视作一个黑盒,用“删减法”来确认信息的价值。
5.3 分享几个容易被忽略的细节
细节一:system 消息的顺序有讲究。把最重要的角色限定放在 system 的最前面,模型对靠前的位置有更好的注意力覆盖。业务规则放在后面,外部数据放最后。顺序乱套,效果会打折扣。
细节二:历史摘要不要用花哨的语言。摘要段落应该风格朴素、信息密集,例如“用户已确认两款产品,偏好蓝色款,预算 3000 元以内,等待物流报价中”。模型对这类“事实型摘要”的吸收效果远好于文学化的转述。
细节三:在 context-mode 中保留一条退出指令。当用户表示“不再需要帮助”或者连续输入“没事了”时,系统应该清理当前会话的模式标签,而不是继续沿用之前的角色限定。我见过不少机器人因为在用户结束意图后还维持“推销模式”,导致用户反复收到强迫感很强的回复,体验很差。
细节四:所有上下文的组装过程都要留日志。这不仅是调试需要,还能帮助你统计系统 token 消耗,为单位成本核算提供数据。
6. 写在最后:把 context-mode 当成产品来做
拆完这些场景,你会发现 context-mode 不是一个写完就固定的配置,而是一个需要持续迭代的系统。我会定期翻看对话日志,找出“模型输出质量下降”的片段,分析是上下文哪一部分导致的,然后调整角色卡措辞、修改摘要策略或更新意图分类规则。
最典型的一次优化经历:某客服项目最初把所有商品信息都塞进上下文,token 消耗高,回答还老跑偏。后来改成“用户问什么商品,才检索什么商品的信息”,把商品信息从静态上下文移到动态检索上下文,效果立刻提升,成本还下降了大半。
这也延伸出一个判断准则:上下文不是越多越好。在设计 context-mode 时,做减法比做加法更需要功力。凡是与当前任务无关的信息,不管看起来多重要,都应该被挡在上下文窗口之外。
实操中的另一种心得是:要学会借助工具辅助调试。用支持 token 可视化的工具检查输入,能直观看到哪些内容占用了过多预算,方便你做裁剪。我自己常用的组合是函数级拦截 + 日志分析,配合查看实际产出的回复效果来调参。
最后再提醒一句,context-mode 没有标准答案,任何场景的参数和模板都是靠实验试出来的。先跑通最小可用版本,再根据数据反馈逐步优化——这比一开始就追求完美配置要靠谱得多。你会在这个过程中慢慢摸到自己的节奏,找到最适合你业务的那些模式组合。