面试官问上下文工程?这份答案能扛追问
上个月帮一个朋友模拟面试,他做 RAG 做了半年,项目讲得头头是道。面试官最后轻飘飘问了一句:「你这个系统,一次调用里上下文是怎么分配的?」他卡了十几秒,最后挤出一句「就是把 prompt 写好一点」。
上下文工程(Context Engineering)这个词,2026 年已经从 Prompt Engineering 里被单独拎出来考。考的不是定义背诵,是你会不会算账——一次调用里,system prompt、工具定义、检索片段、历史对话各占多少 token,超预算了先砍谁。这篇给你一份能扛住追问的答案。
先看这题现在有多热。 招聘板 InterviewStack.io 统计了 5,590 条在招 AI Engineer 岗位,明确写出「context engineering」这个词的有 272 条,占 4.9%;而且按首次出现日期看,占比从 4 月的 2.5% 涨到了 9 月的 4.9%,半年翻了一倍。
但这里有个坑,面试时也值得说:4.9% 是「显性提到这个词」的下限,不是「多少团队在乎」的度量。招聘里写「build agents with tool calling and retrieval」的岗位占 56.5%,那些活干的就是上下文工程,只是没用这个词。所以真问题是:岗位描述里不写,面试官照样问。
数据来源:InterviewStack.io 博客《Context Engineering Interview Questions and Answers》(其自建招聘板统计,非全网样本;趋势受该站来源覆盖增长影响,引用需一并说明局限)。
一、面试题原文
你们现在还在调 prompt 吗?如果让你负责一个 Agent 系统的上下文管理,你会怎么设计?上下文超预算了怎么办?
二、考察点
这题看着像考概念,其实考三件事:
- 你能不能区分 Prompt Engineering 和 Context Engineering——分不清,说明你停留在「写咒语」阶段
- 你有没有「上下文是有限资源」的量化意识——会算 token 账的人,做的系统才可维护
- 你懂不懂位置偏见——东西塞进去了 ≠ 模型会看
三、分层参考答案
基础层:先纠正概念
一句话:Prompt Engineering 研究「这句话怎么写」,Context Engineering 研究「模型眼前应该出现哪些信息」。
| 维度 | Prompt Engineering | Context Engineering |
|---|---|---|
| 关注点 | 怎么写这句话 | 模型眼前应该有哪些信息 |
| 操作对象 | 一段提示词文本 | system + tools + 检索结果 + 历史 + 当前 query 的组合 |
| 变化频率 | 静态(写好就固定) | 动态(每一轮都在变) |
(微信不支持复杂表格,上表已精简。)
关键点:上下文是动态的。第 1 轮和第 50 轮,模型眼前的东西完全不一样。写死一段 system prompt 只是上下文工程的 10%。
原理层:把上下文当预算管
一次调用的上下文就五块,每块都吃 token:
- system prompt:角色与规则,通常占 10% 左右,短而稳定
- 工具定义:每个工具的 JSON schema,工具一多这块能吃掉 20% 以上
- 检索片段(RAG):从知识库召回的内容,通常是最大头
- 历史对话:随轮次线性增长,是超预算的第一嫌疑人
- 当前 query:用户这次的问题,占比小但优先级最高
超预算的裁剪顺序(面试直接说这个):先压历史(摘要在前、原文丢弃)→ 再降检索片段条数 → 最后才动 system 和 query。原因是 system 定义行为、query 是用户意图,砍这俩等于改需求。
实践层:位置也是信息
这是加分项,大部分候选人答不出来:模型对上下文开头和结尾的内容注意力最强,中间部分显著减弱。把关键信息放在中间 30%–70% 的位置,召回率会明显下降。
所以生产里的标准做法不是按相关度从高到低平铺,而是把最相关的放首尾,最弱的塞中间。
四、代码示例:预算分配 + 位置重排
纯离线可跑,不依赖 API Key。核心就是「算账」和「摆位置」:
def estimate_tokens(text):
"""离线 token 估算:中英文混合的经验近似。
英文约 4 字符/token,中文约 1.5 字符/token,按字符类别加权。
面试里先问一句「你用的什么 tokenizer」再给近似,比张口就报数稳。
"""
ascii_chars = sum(1 for c in text if ord(c) < 128)
cjk_chars = len(text) - ascii_chars
return int(ascii_chars / 4 + cjk_chars / 1.5)
def truncate_to_tokens(text, cap):
"""按估算 token 数裁剪文本:保留前 cap 个 token 对应的字符。
为什么不用 text[:n]:中英文每 token 的字符数差 6 倍,一刀切会切飞。
"""
if estimate_tokens(text) <= cap:
return text
kept, used = [], 0
for ch in text:
cost = 0.25 if ord(ch) < 128 else 1 / 1.5
if used + cost > cap:
break
kept.append(ch)
used += cost
return "".join(kept) + " …[已裁剪]"
def allocate_budget(system, tools, history, query, budget=8000):
"""按比例分配上下文预算,超限部分按优先级裁剪。"""
blocks = [
("system", system, 0.10),
("tools", tools, 0.20),
("history", history, 0.50),
("query", query, 0.20),
]
messages, report = [], []
for name, text, ratio in blocks:
cap = int(budget * ratio)
actual = estimate_tokens(text)
kept = truncate_to_tokens(text, cap)
messages.append({"role": name, "content": kept})
report.append(
{"block": name, "budget": cap, "actual": actual, "truncated": actual > cap}
)
return messages, report
def place_by_relevance(chunks):
"""对抗 Lost in the Middle:相关度最高的放首尾,最弱的塞中间。
chunks: [{"id": "c1", "score": 0.82}, ...],score 越高越相关。
"""
ordered = sorted(chunks, key=lambda c: c["score"], reverse=True)
result = [None] * len(ordered)
left, right = 0, len(ordered) - 1
for i, chunk in enumerate(ordered):
if i % 2 == 0:
result[left] = chunk
left += 1
else:
result[right] = chunk
right -= 1
return result
实跑输出(budget=2000,history 故意灌超长,全部本地实跑非编造):
=== 1. 离线 token 估算 ===
英文 72 字符 -> 约 18 tokens
中文 32 字符 -> 约 21 tokens
=== 2. 上下文预算分配(budget=2000,演示裁剪)===
system 预算 200 / 实际 14 未超限
tools 预算 400 / 实际 20 未超限
history 预算 1000 / 实际 1333 已裁剪
query 预算 400 / 实际 8 未超限
=== 3. 按相关度重排(首尾放最相关)===
重排后顺序(位置 -> 相关度):
位置 0(开头)-> c2 score=0.91
位置 1(中间)-> c3 score=0.67
位置 2(中间)-> c4 score=0.15
位置 3(中间)-> c1 score=0.42
位置 4(结尾)-> c5 score=0.78
注意 history 那行:实际 1333 超了 1000 的预算,被裁掉了。面试时把这个 report 画出来,比说十句「我们做了上下文优化」都管用。
五、追问与应答
追问 1:为什么不用最贵的那个模型、上下文窗口那么大?
答:窗口大不等于用得好。一是贵,长上下文按 token 计费,塞满 128K 每次调用都是真金白银;二是「大海捞针」研究表明长上下文中间位置的信息召回会掉。长上下文是能力,不是策略。
追问 2:历史压缩具体怎么做?
答:常见三档。① 滑动窗口:只保留最近 N 轮原文,更早的丢掉;② 滚动摘要:把旧对话让模型总结成一段,替换原文;③ 分层记忆:短期放上下文、长期进向量库按需检索。工程上一般是三档混用,短会话用窗口,长会话上摘要。
追问 3:怎么知道你的上下文策略生效了?
答:这是最关键的一问。要有可观测性:记录每次调用的各块 token 占比、裁剪命中率、以及最终任务完成率。没有这三个数,所谓「优化」都是玄学。可以补一句项目话术:我们上线上下文压缩后,同样任务的 token 成本降了约四成(数字需按你自己的项目填)。
追问 4:Context Engineering 是噱头吗?
答:可以这么答——名字是新词,事是老事。检索、摘要、缓存这些一直都在做,单独拎出来是因为 Agent 把「上下文组装」从一次性变成每轮动态决策,复杂度上了一个量级。承认这点反而显得你想过。
六、加分项与踩坑点
加分项(说这些):
- 「上下文是预算,不是垃圾桶」——一句话立住工程思维
- 主动提 Prompt Caching:system 和工具定义放前面且保持稳定,才能吃到缓存的折扣
- 主动提位置偏见和重排策略
- 提「策略要能被评估」,并说得出三个指标
踩坑点(别说):
- 把 Context Engineering 说成「就是写 system prompt」——直接暴露没做过 Agent
- 说「我们窗口无限所以不用管」——既贵又不可靠
- 只背定义不给数字——面试官会认为你没落地过
- 吹「解决了幻觉」——上下文工程降低噪声,不解决幻觉本身
七、小结
- 概念分清:Prompt Engineering 管「怎么写」,Context Engineering 管「放什么」,后者是动态的
- 上下文当预算管:system 10% / tools 20% / history 50% / query 20% 是起步配比,超限先砍历史
- 位置也是信息:最相关的放首尾,别平铺在中间
- 策略要可评估:token 占比、裁剪命中率、任务完成率,三个数缺一不可