卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
秋招投递表
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
秋招投递表
代码随想录 (opens new window)
  • 本栏必读

    • 卡码大模型专栏介绍
  • 大模型面经

  • 大模型动态

  • Claude深度解读

  • 入门认知

  • Prompt与调用基础

    • 大模型怎么接入真实应用
    • Prompt Engineering:结构化Prompt设计
    • Few-shot、CoT与自我反思
    • 结构化输出:JSON Schema怎么约束
    • 上下文窗口与Context Engineering
      • 简要回答
      • 详细回答
      • 知识拓展
    • 同步、异步、流式输出怎么选
    • Function Calling详解:大模型怎么调用工具
  • RAG检索增强

  • Agent智能体

  • 微调认知

  • 部署与工程化

  • 多模态入门

  • Transformer原理

  • 手撕Transformer

  • 模型家族与Llama架构

# 上下文窗口有多大?Context Engineering入门

KamaClaude

上一篇《大模型结构化输出》讲的是怎么管住模型的输出:用JSON Schema定义结构,用校验和重试接住异常。

但模型输出之前,还有一个更容易被忽略的问题:这次到底给模型看什么?

面试官继续问:“模型支持200K、1M上下文,是不是把历史对话、知识库文档、工具结果全塞进去就行?”

很多录友会回答:“窗口够大就能记得更多,满了再做摘要。”

这句话不能说完全错,但没有回答面试官真正关心的工程问题。

上下文窗口只是容量上限。真正决定效果的,是有限的Token里放了什么、删了什么、按什么顺序放,以及每一轮怎么更新。

这就是Context Engineering,上下文工程。

# 简要回答

  • 上下文窗口:模型生成本轮答案时能够参考的Token总预算,通常由系统指令、工具定义、Few-shot示例、历史消息、检索数据、本轮问题和输出共同占用。
  • 窗口大小:由具体模型和接口决定。当前主流模型从数十万到约100万Token都有,但“标称能装下”不等于“每个位置的信息都能稳定用好”。
  • Context Engineering:不是继续雕一句Prompt,而是持续选择、组织、压缩和更新模型本轮真正需要的信息。
  • 常见手段:相关信息检索、去噪与排序、滑动窗口、关键信息摘要、外部记忆、旧工具结果清理、任务隔离。

一句话:Prompt Engineering关心“指令怎么写”,Context Engineering关心“模型此刻看见什么”。

# 详细回答

# 上下文窗口不是输入框大小,是一整笔Token预算

先把最容易混淆的概念说清楚。

上下文窗口不是只计算用户这次输入了多少字。模型调用时进入上下文的内容,都可能占位置:

  • System Prompt和业务规则;
  • 工具名称、参数Schema和说明;
  • Few-shot示例;
  • 多轮对话历史;
  • RAG召回的文档;
  • 工具执行结果;
  • 用户本轮问题;
  • 模型为本轮生成的输出。

可以先记住一个简化公式:

输入Token + 本轮输出Token ≤ 上下文窗口
1

部分推理模型还会消耗推理Token,具体是否计入窗口、怎么计费,要看厂商接口定义,不能自己猜。

上下文窗口中系统规则工具定义历史检索和本轮问题共同占用输入预算并需为输出预留空间

这条预算关系最容易踩的坑,是把窗口全部留给输入。

假设一个模型窗口是200K,你已经塞了198K输入,又要求它最多输出8K,当然可能超限。即使接口没有直接报错,框架也可能从前面截断历史消息。被截掉的如果正好是关键规则,模型接下来就会像“突然失忆”一样。

所以生产环境不会把窗口吃到100%。通常要提前给输出、工具返回和后续轮次留缓冲区,在调用前做Token估算,而不是等API报错。

窗口上限是硬边界,预留空间是工程纪律。

# 200K、1M到底有多大?

Token不是汉字数,也不是字符数。

同一句话换一种语言、换一个分词器,Token数量都可能变化。代码、JSON、长URL、表格和自然语言的切分方式也不一样。所以“1个Token固定等于几个汉字”只能拿来粗估,不能拿来做线上限流。

截至2026年7月,一些主流API已经提供约100万Token的上下文窗口,也仍有模型是200K。比如OpenAI当前模型页列出了约1.05M窗口,Anthropic文档同时列出了1M和200K模型,Gemini官方文档也说明多款模型支持1M或更大的长上下文。具体选型时必须查当前模型文档:

  • OpenAI模型列表 (opens new window)
  • Claude上下文窗口说明 (opens new window)
  • Gemini长上下文说明 (opens new window)

但录友别只盯着数字。

标称上下文回答的是“最多能送进去多少”,不是“送进去以后能不能找准、用好、还付得起”。

一个100万Token的窗口,不等于100万Token的完美记忆。它更像一张非常大的工作台:材料确实都摆得下,但无关文件、过期结论和几百页日志混在一起,真正要用的那张纸反而更难找。

# 为什么信息越多,模型反而可能答得更差?

很多人默认:相关信息不确定,那就多塞一点,总不会有坏处。

坏处很直接。

第一,信号被噪声稀释。十段材料里只有一段能回答问题,模型要先从九段干扰里找到它。

第二,信息会冲突。旧规则说退款期限是7天,新规则改成15天,两版同时放进去,模型可能选错。

第三,关键内容的位置会变化。对话越长,最早的约束会被挤到长上下文中间。

研究里有一个很典型的现象叫Lost in the Middle (opens new window):同样的关键信息,只改变它在长上下文中的位置,模型表现就可能明显变化;信息放在开头或结尾时往往更容易被利用,埋在中间时更容易丢失。

全部材料直接进入上下文会因噪声位置和规则冲突降低有效信号密度而筛选排序能保留高信号信息

这不是说中间的信息一定读不到,也不是所有模型退化程度都一样。真正应该得到的工程结论是:不要把“窗口装得下”当成“模型一定用得到”。

Anthropic把随着上下文增长而出现的召回、聚焦能力下降称为context rot。无论叫上下文腐化、注意力稀释还是上下文污染,落到系统里都是同一件事:你给的Token越来越多,但每个Token带来的边际价值越来越低。

# Context Engineering和Prompt Engineering有什么区别?

《Prompt Engineering不是“写提示词”》里,我们强调了角色、任务、约束和输出格式;《Few-shot、CoT与自我反思》又讲了怎么用示例、推理步骤和复核机制改变生成过程。它们都属于Prompt Engineering,重点是怎么表达指令、怎么引导生成。

Context Engineering的范围更大,它要管整次推理能看到的所有状态:

System规则 + 用户请求 + Few-shot示例 + 对话历史
+ RAG文档 + 工具定义 + 工具结果 + 任务状态 + 外部记忆
1
2

比如一个客服系统,Prompt写得很清楚:“必须根据最新订单状态回答,不得编造。”

可你拼进上下文的是昨天的物流记录,那Prompt再漂亮也没用。又或者你把最近50轮闲聊、30条召回文档和完整数据库结果全塞进去,模型可能连“最新订单状态”在哪都找不准。

所以Context Engineering不是“高级Prompt技巧”,而是围绕上下文做一条动态数据链路。

Anthropic关于Context Engineering的文章 (opens new window)给了一个很实用的定义:在模型推理时,持续策划和维护一组最优Token。换成大白话就是:用尽可能少的高信号信息,让模型更可能做对当前任务。

# 一次上下文编排,到底做了什么?

一套基本的上下文编排链路可以拆成五步:

  1. 检索:从历史消息、知识库、业务数据库和工具中找到候选信息;
  2. 筛选:去掉和当前任务无关、重复、过期或不可信的内容;
  3. 排序:按相关性、时效性、指令优先级重新组织;
  4. 压缩:长内容保留结论、证据、精确ID和未完成事项,删掉过程噪声;
  5. 组装:给输出留出预算,再按稳定结构送给模型。

上下文工程把系统规则会话历史外部记忆工具和请求依次经过检索筛选排序压缩与预算组装后交给模型

注意,这五步不是只在会话开始时做一次。用户每追问一轮、Agent每调用一次工具,候选信息都变了,上下文也应该重新编排。

一个极简的伪代码可以这样写:

def build_context(request, session):
    candidates = retrieve(
        query=request.question,
        sources=[session.memory, session.history, business_db]
    )

    selected = filter_stale_and_duplicate(candidates)
    ranked = rank_by_relevance_and_recency(selected, request.question)
    evidence = fit_token_budget(ranked, budget=60_000)

    return [
        system_rules,
        session.state_summary,
        *evidence,
        request.question,
    ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

这里最重要的不是函数名,而是顺序:先从信息全集里找候选,再做取舍,最后按预算组装。 不是先把所有东西塞进去,超了再从头随便砍。

# 滑动窗口:只保留最近几轮,够不够?

滑动窗口是最简单的上下文管理办法:只保留最近N轮消息,旧消息自动移出。

它适合短期依赖强的场景。比如普通客服闲聊,用户当前一句“那什么时候到”主要依赖前两轮的订单话题,不需要把半年前的聊天全带上。

但滑动窗口也很粗暴。

关键约束不一定出现在最近几轮。用户第一轮说“我对花生过敏”,聊了20轮后才问“这个套餐能不能吃”。如果只截最后5轮,这条信息就丢了。

所以成熟一点的做法不是单独使用滑动窗口,而是分层:

  • 最近几轮保留原文,保证局部对话自然;
  • 早期历史压成状态摘要,保留目标、约束、决定和未完成事项;
  • 精确事实放进外部存储,需要时再检索;
  • 大段原始日志和旧工具结果移出工作上下文,但保留可追溯地址。

最近对话解决连贯性,摘要解决持续状态,外部记忆解决长期事实。

# 摘要压缩不是“把前文缩短一点”

上下文快满时,把早期对话总结后开启一个更干净的窗口,这叫Compaction,上下文压缩。

听起来很简单,真正难的是:摘要是有损的。

一段排错记录压缩后,“我们试过A方案但因为连接池泄漏失败”可能只剩“尝试过A方案”。下一轮模型没看到失败原因,又把A方案重做一遍。

所以面向长任务的摘要,至少要保住这些信息:

  • 当前目标和验收条件;
  • 已确认的事实与证据来源;
  • 已做决定,以及为什么这么决定;
  • 失败尝试和失败原因;
  • 精确的文件名、订单号、错误码、参数值;
  • 仍未解决的问题和下一步动作。

摘要适合保留“状态”,不适合替代所有“原始证据”。合同原文、代码文件、数据库记录仍应放在外部可检索存储里,需要时重新取回。

# 长对话怎么跑下去?靠的是分层记忆

一个能持续运行的会话,通常不会只维护一份不断增长的messages数组。

它会把信息分成三层:

  • 工作上下文:当前任务马上要用,直接送给模型;
  • 状态摘要:跨轮次必须保持的目标、约束、进度和决定;
  • 外部记忆:完整历史、文档、日志和结构化事实,需要时检索。

长对话通过工作上下文状态摘要和外部记忆三层结构让必要信息在后续轮次重新回到模型窗口

每一轮结束后,系统要判断新信息去哪:当前就要用的留在窗口,长期有效的写入状态或记忆,纯过程噪声只保留日志地址。下一轮再围绕新问题取回必要部分。

这才是“记忆管理”。不是让模型永远背着全部历史,而是让信息在合适的时候重新进入工作上下文。 关于短期记忆、长期记忆和RAG的边界,可以接着看《Agent的记忆》。

# 工具调用为什么特别容易污染上下文?

Agent一旦开始调用工具,上下文膨胀会非常快。

查一次数据库可能返回几千行,跑一次测试可能打印几万字日志,打开网页还会带回导航、脚注和无关区域。工具每调用一次,结果继续追加;下一轮模型又要重新读。

工程上要控制三件事:

  • 工具定义按需加载:当前任务用不到的工具,不要把完整Schema全塞进去;
  • 工具输出先加工:分页、过滤、只返回必要字段,错误日志保留关键堆栈和定位信息;
  • 旧结果及时清理:结论已经写入状态后,原始大结果移出工作窗口,通过ID或文件路径保留追溯能力。

缓存也救不了这个问题。Prompt Cache可以降低重复输入的计算或费用,但缓存里的Token通常仍占上下文窗口。便宜地塞满,还是塞满。 这部分的计算和缓存复用过程,可以看《Claude Code为什么快?Prompt Cache一篇讲明白》。

# 怎么判断上下文工程做得好不好?

不要只看“有没有超窗口”。至少同时看四组指标:

  • 效果:回答准确率、引用命中率、任务完成率、约束遵守率;
  • 上下文质量:召回信息是否相关,关键事实是否被保留,过期信息是否混入;
  • 资源:每轮输入Token、输出Token、缓存命中、调用成本;
  • 体验:首字延迟、总耗时、长会话后性能是否退化。

最有价值的测试不是用一个短问题跑一次,而是专门构造长会话:把关键规则放在开头、中间和结尾,加入相似但错误的旧数据,再看模型是否仍能找到正确证据。

如果你的“优化”只是把输入从20K缩到10K,但准确率也掉了,那不叫优化,只叫删内容。

上下文工程优化的是单位Token的信息价值,不是单纯追求Token越少越好。

# 知识拓展

Q1:上下文窗口越大,模型能力就越强吗?

不一定。窗口大小只说明容量,还要看模型能否在不同位置稳定召回信息、长输入的延迟与成本,以及冲突信息下的判断能力。选模型要用自己的长上下文数据测,不要只比较参数表。

Q2:RAG和Context Engineering是什么关系?

RAG是上下文工程的一种重要手段,负责从外部知识库找相关材料。但Context Engineering还要管理系统规则、消息历史、工具定义、工具结果、任务状态、排序、压缩和预算。RAG解决“找什么”,上下文工程还要解决“怎么放、放多少、什么时候更新”。

Q3:滑动窗口和摘要压缩怎么选?

最近几轮足以回答当前问题,用滑动窗口最简单;任务跨很多轮,早期决定以后还会用,就要加结构化摘要;精确原文以后可能复查,再配外部存储。真实系统通常是三者组合,不是三选一。

Q4:为什么换一个更大窗口的模型,问题还在?

因为原问题可能不是容量不足,而是上下文里有噪声、冲突、过期数据或关键证据排序太靠后。换大窗口只是把垃圾桶换大了,没有提高信息密度。

Q5:面试中怎么回答“你们怎么做上下文管理”?

不要只说“超过长度就截断”。要说清楚上下文由哪些部分组成,怎么预留输出预算,历史消息怎么滑动和摘要,RAG结果怎么筛选排序,工具大结果怎么清理,长期事实存在哪里,以及你用什么长会话评测验证没有丢关键约束。

上下文窗口再大,也是有限的工作台。

真正的工程能力,不是把它堆满,而是让模型每一轮都只看到最该看的东西。

Last Updated: 7/17/2026, 3:04:53 PM

← 结构化输出:JSON Schema怎么约束 同步、异步、流式输出怎么选 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪