2026/11/2 6:31:53

Agent 17. Agent 的上下文工程怎么设计?

Agent 17. Agent 的上下文工程怎么设计? 17. Agent 的上下文工程怎么设计面试官你做 Agent 时上下文工程是怎么设计的‍♂️我就是把 System Prompt、历史对话和用户问题一起发给模型信息越全模型回答得越准。面试官信息越全越准几十个工具定义、上百轮历史和一堆检索结果全塞进去模型还能知道当前要做什么吗‍♂️我那就等快超过上下文窗口时把前面的对话压缩成摘要。面试官上下文工程不等于记忆压缩。用户刚改的要求、当前执行到哪一步、工具返回的事实这些内容从哪里来哪些必须放按什么顺序放你还没说。‍♂️我那我给每类内容划一块 Token 预算再按相关性取 Top K拼进 Prompt 里。面试官只看相关性也不够。网页里如果藏着一句「忽略之前的要求」你会不会把它当成高相关指令旧 Memory 和用户刚说的话冲突时听谁的上下文工程难就难在这些冲突怎么处理。这道题考的是 Agent 能不能在每一步开始前拿到一份「可信、相关、够用」的工作现场Prompt 拼接只是其中一个环节。-简要回答我会把 Agent 的上下文工程设计成一个运行时装配流程而不是把所有信息长期堆在一个 Prompt 里。每次模型调用前先根据当前子任务从指令、用户需求、结构化任务状态、短期对话、长期 Memory、工具定义与结果、RAG 证据中挑选本轮需要的内容再完成优先级排序、来源隔离和 Token 分配。其中System、Developer 和 User 指令负责告诉模型「要做什么、不能做什么」任务状态里的目标、约束、To-Do、当前步骤和已完成结果负责告诉模型「现在做到哪了」Memory、RAG 和工具结果则补充「完成这一步需要知道什么」。旧记忆和外部资料都不能覆盖更高优先级指令网页、文档和工具返回值也必须按数据处理不能混成新的命令。工程上我会先预留输出空间再给各类上下文设预算和不可丢失项。超出预算时优先去重、裁剪低相关证据和无关工具最后才压缩旧历史。同时把执行后的状态增量写回外部状态库让下一轮重新按当前步骤装配而不是让模型只靠聊天记录记住一切。-详细解析上下文不是聊天记录-而是-agent-的工作台先想一个很直观的场景。你让一个同事继续昨天没做完的需求桌上放着公司制度、原始需求、昨天的聊天记录、项目进度表、搜索资料和工具手册。如果这些东西全混成一摞纸他可能花半天都找不到「现在该干什么」。Agent 也是一样。模型的上下文窗口只是一个有限的工作台不是仓库。材料再多如果当前步骤需要的内容没有摆对位置过期资料没有拿走不可信内容也没有单独标出来效果照样会变差。所以上下文工程解决的是一个动态问题 在这一次模型调用里应该让模型看到什么以及怎么让它看。一份可用的上下文-由哪些部分组成第一层是 指令 。System 指令规定 Agent 的身份、总体边界和安全规则Developer 指令放应用侧的流程、业务约束和输出协议User 指令表达用户这一次明确要完成的事。不同模型接口的具体角色名称可能不同但设计原则一样高优先级规则不能被低优先级内容覆盖。第二层是 任务状态 。这部分经常被忽略却最影响多步任务能否连续执行。它不应该只是一段「之前聊了什么」的摘要而应该明确记录核心目标、成功标准、硬约束、当前步骤、待办项、已完成项、待确认问题和关键产物引用。这样模型进入新一轮时不用从几十轮对话里猜进度。第三层是 对话与 Memory 。最近几轮对话保留当前语境长期 Memory 提供跨会话的稳定信息比如用户偏好、已确认配置和历史决策。但 Memory 只是候选背景不是永远正确的事实。用户刚刚修改了技术栈旧 Memory 里原来的技术栈就应该失效不能因为存得更久反而拥有更高优先级。第四层是 外部观察 包括工具定义、工具执行结果和 RAG 检索证据。工具定义告诉模型当前能做哪些动作工具结果告诉模型动作产生了什么RAG 证据则提供回答或决策所需的外部知识。这些内容通常很长而且质量参差不齐更需要按当前步骤动态选择。把这几层放在一起可以看到一个关键区别指令决定行为边界任务状态决定执行位置Memory 补充过去RAG 和工具结果补充外部事实。它们都进入上下文但职责并不相同。先选再拼-不要把所有东西一股脑塞进去上下文装配的第一步不是摘要而是判断当前模型调用到底要完成哪个子任务。比如一个 Coding Agent 正在「运行测试并定位失败」此时需要的是用户的验收要求、当前 To-Do、刚修改的文件、测试命令和报错日志。两小时前查到的产品竞品资料即使和整个项目相关对当前步骤也没有用。反过来等 Agent 开始写发布说明时测试日志的完整堆栈就不必继续占着工作台。实际筛选时我会综合看四个维度与当前步骤的相关性、来源可信度、信息新鲜度以及缺失后的风险。像用户的硬约束、尚未完成的任务和刚发生的工具错误属于「漏掉就会把任务带偏」的内容应该优先保留重复检索结果、已经完成且不再影响后续的中间推理、当前不可用工具的完整定义则可以不注入。这里有一个容易踩的坑Top K 只能解决「相关不相关」解决不了「可信不可信」。一篇网页与问题高度相关不代表网页里的每句话都能当指令执行。因此检索打分之后还要做来源过滤、去重和版本判断涉及事实回答时还要保留证据来源方便模型引用和系统核验。排序不只是排版-而是在表达优先级内容选好了接下来才是怎么放。我一般会让稳定、权威的行为规则在前面随后放用户当前目标和结构化任务状态再放本轮需要的工具说明、RAG 证据与工具观察最后明确要求模型输出什么。具体顺序可以根据模型和任务通过评测调整但「规则、状态、数据」一定要分区不能混成一段没有边界的长文本。为什么要把任务状态单独放因为自然语言对话会把目标、闲聊、修改意见和中间结果交错在一起。模型虽然都能读到却未必能稳定判断哪一句还有效。把当前有效状态重新整理后模型拿到的是一张清晰的施工单而不是一段需要重新考古的群聊记录。固定前缀尽量保持稳定还有一个工程收益支持前缀缓存的模型服务更容易命中缓存。频繁变化的用户输入、任务状态和工具结果放在稳定内容之后可以减少重复计算。但缓存只是成本和延迟优化不能为了命中缓存牺牲指令正确性。to-do-为什么能让模型更聚焦To-Do 的价值并不是「列个清单看起来更有条理」而是把散落在历史对话里的进度变成模型每轮都能读取和更新的显式状态。一份实用的任务状态可以长这样core_intent: 修复登录接口偶发超时 success_criteria: 压测通过并且现有测试无回归 constraints: - 不修改对外 API todo: - id: T1 task: 定位慢查询 status: done evidence_ref: trace_102 - id: T2 task: 修改连接池配置 status: in_progress - id: T3 task: 执行回归测试 status: pending open_questions: - 生产环境连接数上限待确认每一步执行前Agent 只要看 in_progress 项就知道当前注意力该放在哪里执行后把结果、证据引用和状态变化写回去下一轮再读取新的快照。即使中间发生重试、切换模型或者恢复会话也能从结构化状态继续而不必让模型凭感觉回忆。不过To-Do 也不是生成一次就永远不动。如果用户新增需求或者工具结果证明原计划走不通Agent 要重新评估依赖关系并更新计划。否则一张过期的 To-Do 反而会把模型牢牢锚定在错误路径上。Token 预算要在装配前分不是超长后才截断上下文窗口再大也不能全部分给输入因为模型还需要空间输出答案、生成工具参数或写代码。所以预算的第一步是根据任务预留输出 Token 和安全余量剩下的容量才分给输入。输入预算可以按区域设上限但不要把比例写死。例如当前是事实问答RAG 证据可以多一些当前是工具执行任务状态和工具协议更重要当前是会话恢复已确认约束和关键产物引用不能缺。预算器应当随任务阶段调整而不是所有请求共用一个固定模板。如果仍然超长我会按「去掉重复内容 - 移除低相关工具和证据 - 用结构化状态替代冗长过程 - 压缩较旧历史」的顺序降载。用户硬约束、当前目标、安全规则和未完成状态属于不可随意丢失项。实在装不下时宁可分步检索或向用户确认也不要静默截掉关键要求。这也说明了它和记忆压缩的边界。记忆压缩研究的是长历史如何缩短上下文工程关心的是整个工作台怎么装配。压缩只是预算不够时的一种手段不能替代对工具、证据、状态和指令的选择。把上下文装配做成每一步都运行的闭环一个完整链路可以概括成确定当前步骤 - 读取最新指令和任务状态 - 按需召回 Memory、RAG 与工具 - 过滤冲突和低质量内容 - 分配 Token 并分区渲染 - 调用模型 - 把状态变化和证据引用写回。这里最重要的是「每一步都重新装配」。Agent 调完工具之后当前事实和下一步目标已经变化了。如果继续沿用上一轮完整 Prompt只在末尾追加一段工具结果上下文会越来越臃肿旧计划也可能持续干扰新决策。上线后怎么判断这套设计有没有用不能只看平均 Token 降了多少还要结合约束遵循率、关键事实召回率、工具选择正确率、任务完成率、引用忠实度和多轮续做成功率一起评估。再配合 Trace 记录每一轮到底注入了哪些内容出现 Badcase 时才能判断是没召回、排错顺序、状态过期还是模型本身执行错了。context-engineering-和-prompt-engineering-有什么区别这两个概念最容易混在一起。Prompt Engineering 主要在设计「怎么说」比如角色怎么描述、任务怎么拆、输出格式怎么约束、Few-shot 示例怎么写。它关注的是指令和模板本身是否清晰、稳定。Context Engineering 关注的是「这一轮让模型看到什么」。除了 Prompt还包括从哪里取任务状态、召回哪段 Memory、开放哪些工具、放哪些 RAG 证据、如何处理工具结果以及这些内容怎么排序、隔离和控制预算。它贯穿 Agent 的整个运行过程是动态的。Memory 则更像仓库负责跨时间保存和召回信息上下文是工作台只摆本轮需要的内容。记忆压缩是在仓库或工作台太拥挤时降低内容体积的一类方法。RAG 是给工作台找资料的机制也不等于上下文工程本身。一句话区分就是Prompt Engineering 把话写清楚Memory 把信息存下来RAG 把证据找回来Context Engineering 决定这一次到底把哪些东西摆到模型面前。-面试总结回答这道题不能只说「把历史对话拼进 Prompt」也不能一上来就聊滑动窗口和摘要。面试官想听的是你有没有把上下文当成 Agent 每一步都要动态装配的工作现场。比较完整的回答思路是先讲上下文的组成System、Developer、User 指令负责行为边界结构化任务状态负责目标、约束、To-Do 和当前进度近期对话与长期 Memory 补充历史工具定义、工具结果和 RAG 证据补充能力与外部事实。接着要说清楚工程设计围绕当前子任务做选择结合相关性、可信度、新鲜度和遗漏风险排序把指令与外部数据隔离避免检索内容反过来控制 Agent提前预留输出空间并动态分配 Token执行后把状态增量写回下一轮重新装配。最后把几个相近概念划清边界。Prompt Engineering 解决「怎么写指令」Memory 解决「信息怎么长期保存」记忆压缩解决「内容太长怎么缩」而 Context Engineering 解决的是「这一轮模型到底该看到什么」。能讲到这个层次面试官基本就能判断你做过的不只是聊天机器人而是能持续执行多步任务的 Agent。