Skip to content

Prompt 与上下文工程 · 知识点

Prompt 是上下文里的一块指令。真正决定效果的是:窗口里放什么、按什么顺序、何时压缩、何时检索、何时交给工具


0. 总图

一次 LLM 调用 = 把 有限的上下文窗口 填满,然后让模型预测下一步。

窗口里通常有这些块(按常见 messages 结构):

  1. System / Developer:角色、硬约束、输出协议、安全边界
  2. Few-shot 示例:教格式和边界 case,不是教知识
  3. 业务上下文:用户画像、当前任务状态、权限、今天的日期
  4. 检索结果 / 记忆:RAG 片段、长期记忆、会话摘要
  5. 工具结果:函数返回、MCP 输出、代码执行日志
  6. 用户当前问题
  7. (可选)思考/草稿区:CoT、scratchpad、hidden thinking

上下文工程要解决的就是:

  • 这些块 谁进窗口、谁不进
  • 顺序怎么排(模型对位置敏感)
  • 超长了怎么 压缩 / 裁剪 / 外置(RAG/工具)
  • 怎么保证输出 可解析、可复现、可评测

1. Prompt 工程(仍要会,但是「组件」不是全部)

重点 1.1 Prompt 的标准零件

一个能上线的 prompt,建议固定包含:

零件作用示例
角色限定能力边界和口吻「你是客服助手,只能基于知识库回答」
任务一句话说清楚要干什么避免模型自己发明目标
硬约束不能做什么、必须做什么不编造、不承诺、不输出隐私
输入说明变量从哪来、缺省怎么处理{doc} 为空时明确拒绝回答
输出协议JSON / Markdown / 指定字段给 schema 和正反例
示例few-shot覆盖正常 + 边界 + 拒绝
上下文槽位动态注入的文档、历史、工具结果用 XML/标签包起来,防污染

推荐结构(Claude 系常用 XML,OpenAI 系常用 Markdown 标题,本质一样:分隔符 + 命名空间):

text
<role>…</role>
<rules>…</rules>
<output_format>…</output_format>
<examples>…</examples>
<context>…</context>
<user_query>…</user_query>

为什么要用分隔符:降低「用户输入冒充系统指令」的概率,也方便模型区分「资料」和「问题」。

1.2 常见策略(会点名、会取舍)

Zero / One / Few-shot

  • Zero-shot:任务简单、格式不严时用
  • Few-shot:格式敏感、边界多、领域口径要统一时用
  • 示例要 短、像真实流量、含失败样本(例如「知识库没有就说不知道」)
  • 示例过多会占窗口、还可能过拟合示例风格

思维链 CoT

  • 适合:数学、多步判断、需要可追溯理由
  • 不适合:延迟敏感、答案必须极短、或会把推理暴露给用户(可改成内部思考 + 对外只给结论)
  • 需要推理时可以让模型先想,对外接口只返回结构化结论,推理写入日志。

ReAct / 先规划再执行

  • 本质是「思考 → 选工具 → 观察 → 再思考」
  • 详细放在 03-Agent与工具调用,这里只需知道:Agent 的 prompt 是状态机说明书

结构化输出

优先顺序(从稳到不稳):

  1. 官方 JSON Schema / 工具调用(Function Calling)—— 最稳
  2. 明确 schema + 校验 + 失败重试
  3. 「请输出 JSON」纯自然语言 —— 最不稳,只能做 demo

落地时一定要有:解析失败 → 把错误信息回灌再生成一次(repair loop)→ 仍失败则降级

角色 / 风格 / 安全

  • 角色能提升稳定性,但不能当权限系统。权限必须在应用层做。
  • 安全约束写在 system 里,且用户输入永远当 数据 不当 指令

1.3 解码参数(常被当成 prompt 问题)

参数影响应用建议
temperature随机性抽取/分类/JSON 用 0–0.2;写作 0.7+
top_p核采样一般和 temperature 只调一个
max_tokens长度上限结构化输出设够但不要过大,防跑飞
stop截断防模型把示例后面的内容续出来
seed(若有)可复现评测时固定

常见误判:输出不稳定不一定是 prompt 写坏了,也可能是 temperature 太高,或每次检索结果不同。

1.4 Prompt 调试方法(体现工程能力)

不要只说「我再改改 prompt」。一套可讲的流程:

  1. 固定评测集(20–50 条真实 query,含边界)
  2. 一次只改一个变量(角色 / 示例 / 约束 / 顺序)
  3. 看失败类型:拒答过多、幻觉、格式错、口径漂
  4. 用「失败样本 → 加规则或加 few-shot」迭代
  5. 回归:改 A 不能把 B 弄坏(prompt 也有回归测试)

2. 上下文工程(本模块重点,拉开差距的地方)

重点 2.1 核心约束:窗口是稀缺资源

要能讲清楚这几个词:

  • Token:模型的计费和长度单位,中文大约 1 字 ≈ 1.5–2 token(粗估即可)
  • Context window:一次能看见的最大 token 数
  • 有效上下文 ≠ 标称窗口:越长,中间信息越容易丢(Lost in the Middle)
  • KV Cache:前缀不变时可复用计算;所以 稳定的 system 前缀 对延迟和成本很重要(Prompt Cache)

重点 2.2 Lost in the Middle

现象:模型对 开头和结尾 更敏感,中间的文档/历史容易被忽略。

工程对策:

  • 最重要的指令放 system 头部,当前问题放最后
  • RAG 结果不要无脑按相似度堆 20 段,做 rerank 后只留 top-k
  • 长文档:结论/相关段落前置,或先摘要再答
  • 多文档时加标题、来源、相关性分数,让模型知道权重

重点 2.3 上下文装填策略(必会画)

从「贵且满」到「便宜且外置」:

text
全量塞进窗口
  → 滑动窗口(只留近 N 轮)
  → 摘要压缩(旧对话变成 summary)
  → 分层记忆(工作记忆 / 会话摘要 / 长期记忆)
  → RAG 按需检索
  → 工具按需查询(DB、搜索、代码)

怎么放:

  • 必须每次都看到的硬规则 → system
  • 当前任务状态 → 工作记忆(短、结构化)
  • 可能相关的知识 → RAG,不默认全塞
  • 实时/权威/可计算的数据 → 工具,不写进 prompt 装懂
  • 很久以前的偏好 → 长期记忆,检索后注入

2.4 对话记忆的三种形态

类型存什么怎么用风险
短期(滑动窗口)最近若干轮原文实现简单一长就爆窗、成本高
会话摘要压缩后的事实与决策中长会话标配摘要丢失细节、错误会累积
长期记忆用户偏好、实体、结论跨会话检索注入写错记忆会污染所有后续回答

实践组合(可直接当标准答案):

  1. 保留最近 K 轮原文
  2. 更早的内容做成 滚动摘要(只记事实、决策、未决问题)
  3. 关键实体进长期记忆(需确认机制,避免把幻觉写进记忆)
  4. 每轮回答前:摘要 + 近 K 轮 + 本轮检索/工具结果 + 当前问题

2.5 压缩(Compaction)怎么做才不像丢信息

常见手法:

  • 抽取式:保留关键句、决策、数字、承诺(保真,更适合客服/法律)
  • 生成式摘要:更短,但可能编造,必须约束「只根据原文」
  • 结构化状态:把对话压成 JSON 状态机(订单状态、已选套餐)—— 业务系统最稳
  • 按主题分桶:技术支持里「已尝试步骤 / 环境信息 / 未解决问题」分开存

压缩原则:

  • 数字、ID、结论、用户明确偏好 不可丢
  • 客套话、重复确认、失败的探索路径 可丢或极压缩
  • 摘要要带时间/轮次,避免过期信息当现状

2.6 工具结果也是上下文(很多人漏这一块)

Agent 场景下,真正把窗口打爆的往往不是用户话,而是:

  • 网页全文
  • 代码文件
  • 检索 10 段原文
  • 连续 8 次工具日志

对策:

  • 工具返回先 截断 / 摘要 / 抽字段
  • 只把「对下一步有用的观察」写回消息
  • 原始大结果落磁盘或对象存储,上下文里放指针
  • 多步 Agent 要做 observation compaction

2.7 Prompt Caching(前缀缓存)

思想:把 很少变的大段(系统提示、工具定义、知识库静态说明)放在消息最前面且保持字节级稳定,让服务端复用 KV。

注意:

  • 中间插一句「今天是 x 号」可能导致整段缓存失效(看厂商实现)
  • 动态内容后置:日期、用户名、本轮检索结果放后面
  • 这是成本和延迟优化,也会倒逼你把 prompt 设计成「稳定前缀 + 动态后缀」

3. 和相邻模块的边界

问题用 Prompt/上下文用 RAG用微调用 Agent/工具
口吻、格式、拒答策略通常不值得
私有知识、会更新的文档少部分可塞知识易过期,慎用查 DB/API 也可以
要算、要查实时数据不要让模型算钱/库存文档检索不够
固定分类体系、极稳口径few-shot 可解样本很多、要极稳可考虑
多步任务、要操作外部系统单次 prompt 不够只提供信息

金句:能检索就不要塞进 prompt;能调用工具就不要让模型瞎编数字;能用 schema 就不要靠「请你输出 JSON」。


4. 安全(本模块要会的那部分)

详细在 07-评测可观测与安全,这里掌握 3 点即可:

  1. Prompt Injection:用户/文档里藏「忽略之前指令」。对策:分隔符、检索文档当数据、工具权限白名单、关键操作二次确认。
  2. 间接注入:RAG 抓到的网页/PDF 里带恶意指令,比用户直接注入更隐蔽。
  3. 泄露:系统提示、内部工具、其他用户数据不要回显。日志里脱敏。

不要把安全只写在 prompt 里。Prompt 是软约束,鉴权、允许列表、服务端校验 才是硬约束。


5. 工程化(应用岗加分)

上线级 prompt 不是一段字符串,而是一套资产:

  • 模板化:Jinja / 消息数组模板,变量显式声明
  • 版本号prompt_id + version,请求日志能复盘
  • 环境隔离:dev / staging / prod 可回滚
  • 评测集:每次改 prompt 跑回归(准确率、拒答率、schema 合法率、延迟、token)
  • 在线监控:空回复、解析失败、用户点踩、超时
  • A/B:只对一部分流量放新版本

可观测要记:完整 messages(脱敏后)、模型参数、检索片段 ID、解析是否成功。没有这些,线上坏了你无法复现。


6. 你要能现场画的两张图

图 1:单次问答装填

text
[稳定 System + 工具定义]  ← 可缓存前缀
[Few-shot]
[会话摘要]
[近 K 轮]
[本轮 RAG / 工具观察]
[当前用户问题]            ← 放最后

图 2:超长对话生命周期

text
每轮:
  若 token < 阈值 → 原文拼接
  若超阈值 → 旧轮次抽成摘要,保留近 K 轮
  若摘要也膨胀 → 摘要再压缩,重要状态写入结构化 memory
  知识类问题 → 走 RAG,不把全书塞进历史

7. 准备到什么程度算够(自检)

能不看稿讲 3 分钟:

  1. Prompt 零件有哪些,为什么要分隔符
  2. 什么是上下文工程,和「写提示词」有何不同
  3. Lost in the Middle 是什么、你怎么排顺序
  4. 对话爆窗的三层处理:滑动窗口 / 摘要 / RAG+记忆
  5. 结构化输出怎么做才稳
  6. 什么知识放 prompt、什么放 RAG、什么放工具
  7. 改 prompt 如何评测,而不是凭感觉

能现场手改:

  • 把一段散文 prompt 改成带 schema 的模板
  • 给一个「答非所问 / 幻觉 / JSON 偶尔坏」的 case 做诊断

8. 建议复习顺序

  1. 消息角色(system/user/assistant/tool)和 token 窗口
  2. Prompt 零件 + 结构化输出 + few-shot
  3. Lost in the Middle、顺序、截断
  4. 记忆:滑动窗口、摘要、长期记忆
  5. 工具结果压缩、Prompt Cache
  6. 注入攻击与「文档当数据」
  7. Prompt 版本与评测

本目录配合:02-RAG(检索当上下文)、03-Agent(工具观察当上下文)、07-评测与安全(怎么证明变好了)。


了解

思维链(Chain of Thought, CoT)

让模型先写出中间推理步骤,再给结论,而不是直接蹦答案。经典触发:「请一步步思考」;也可以在 few-shot 里示范带推理的例子。

  1. 解决什么 — 多步算术、规则判断、要可追溯理由。中间 token 当草稿纸,比一口出答案稳。
  2. 两种写法 — Zero-shot:只加「逐步思考」。Few-shot:示例里带完整推理。ToT / 自洽(多次采样投票)是加强版,更贵。
  3. RAG 里怎么用 — 证据已经在上下文里、还要跨多段综合时可以 CoT。不能用 CoT 补知识:库里没有的事实,想再多也是编。
  4. 上线注意 — 更慢、更费 token;推理可能泄露策略。对内 think、对外只给 answer + citations。延迟敏感、短答案、纯检索题不要开。

更细的「何时用/不用」看 01-Prompt与上下文工程/面试题.md B3。


相关代码示例