YAOTU INSIGHTS

提示词工程、上下文工程与Agent框架的联合应用实践

提示词工程、上下文工程与Agent框架的联合应用实践
年初接了一个偏门需求把几家分支机构的知识库、工单系统、产品手册全塞给大模型做一套既能回答问题、又能主动查数据、还能触发后续流程的「分析型助理」。一开始我以为就是个普通的RAG项目真正做起来才发现单靠提示词堆料完全不够上下文怎么喂、喂多长、模型什么时候该调用哪个工具、多轮对话里哪些历史要保留这些问题搅在一起逼着我从提示词工程、上下文工程和agent框架三个层面同步下手。这篇文章不聊理论就讲这套联合应用的落地过程包括三个层面各自解决什么问题、我在关键环节的取舍依据、以及实测踩过的坑。想搭一套复杂智能体、或者正在把RAG往生产级推进的朋友可以对照着少走点弯路。1. 三层能力边界提示词、上下文与agent框架的定位划分动手之前我先逼着自己把三个概念理干净。很多人把提示词工程、上下文工程、agent框架混为一谈真到协作时职责不清楚系统一复杂就乱套。1.1 核心定位的差异化拆解我的理解是提示词工程解决的是「模型的行为规范」问题。包括角色设定、输出格式约束、任务分解策略、答案风格引导。它的作用范围是从用户输入到模型输出这一层映射关系。一个人问「帮我看看上周销量」提示词决定的不是上周销量数据从哪来而是模型用什么语气、什么结构、什么维度来呈现答案。上下文工程解决的是「模型的信息边界」问题。模型本身是离线训练的它的知识截止在训练那一刻。上下文工程负责把当前任务真正需要的私有数据、实时数据、历史对话摘要以合理的方式拼装到模型的输入窗口里。它的关键词是筛选、压缩、编排、更新。没有它提示词写得再好模型也只能凭想象回答。agent框架解决的是「模型的执行链路」问题。一个任务往往不是一次问答就能结束的需要模型判断需不需要查数据库、查完之后要不要再追问、是不是要调一个外部API、失败之后怎么重试。agent框架负责把这些步骤组织成循环规划、执行、观察、再规划。这三个层面是层层依赖的关系agent框架一个循环里包含了很多次模型调用每一次调用之前都要由上下文工程组装信息而组装完信息之后的模型行为由提示词来做规范和约束。1.2 三个层面如果没有配合会出什么问题我在项目早期做了个对比测试。同一套业务问题分别用三种方案实现方案A只用提示词工程。把角色、格式限制写得很详细但知识库里新增的产品资料根本没进入上下文。实测10个问题里有4个模型给出了貌似合理、实际完全是编造的操作建议。原因很直接模型根本没看过这些资料再强的格式约束也改变不了它的知识底子。方案B提示词加上下文工程但不引入agent框架。对于「XX型号打印机WIFI连不上怎么办」这类直接检索型问题效果确实不错。但问题是用户不会一直问简单东西当问题变成「对比一下办公区两台设备最近两个月的故障率分析一下要不要统一换新」时光靠一次检索一次生成完全搞不定需要拆成多轮检索、甚至要动态调用统计工具才能算出来。没有agent的调度能力这类复合任务基本歇菜。方案C三个层面都上。问题进来之后先由上下文工程做意图识别和关键词预处理agent根据意图决定执行路径涉及数据分析时调用代码解释器涉及文档查询时切换检索策略每一轮工具返回的结果都重新拼接进上下文最终由统一的提示词模板约束输出标准。结论很清楚提示词管嘴巴上下文管食材agent管动作。三者缺一复杂任务就露出明显的短板。2. 提示词工程的关键实施细节提示词工程看起来门槛不高反正就是写一段话让模型照着做。但做到生产级需要花精力打磨的地方远比想象多。下面是我觉得最值得抠的三个方向。2.1 角色与任务的显式分层我见过太多提示词把角色设定和能力描述混成一团模型容易抓不住重点。我的做法是拆成三层写。第一层是角色声明一句话定义模型是什么比如「你是设备运维助理工程师负责解读设备数据与操作手册」。这一层决定模型的回答基调和专业程度。第二层是职责边界明确说明模型在什么情况下做什么、不做什么。比如「只依据提供的资料回答问题资料中找不到相关内容时明确说明不得编造操作步骤」。这一层是防幻觉的第一道闸门。第三层才是任务指令针对当前具体问题给出的操作要求。这个分层写法的价值在于模型对「你是谁」和「你能做什么」的权重是不同的。把职责边界放在角色声明后面可以让模型的自我认知约束前置比只在结尾加一句「如果不知道就说不知道」管用得多。2.2 few-shot示例的选样策略有一次我为了做产品对比功能在提示词里放了两组示例一组是价格对比一组是参数对比。实测下来模型回答产品参数类问题时结构明显偏向示例的格式但数据引用经常错位金额和数量混为一谈。后来把示例换成一组真实的「带数据引用」的对比分析后问题基本消失。这说明示例选择的关联度极其重要。示例不是随便找两个差不多的就行的它必须覆盖当前任务的真实数据形态。如果示例里的数据格式都带着单位、引文编号、表格结构模型就会模仿那个形态去组织输出。选择示例时我通常坚持三条原则示例和真实问题的领域强相关最好是同一类子任务示例里必须包含标准的结构化要素比如「依据资料[x]的说明该参数正常范围是...」示例的覆盖顺序要跟常见问题类型匹配用户最常问的类型放最前面2.3 结构化输出与运行时校验生产级提示词输出不能停留在「看起来不错」的程度必须让下游程序能稳定解析。我建了一套输出契约在提示词里直接约束返回JSON格式包含固定的字段并且说明每个字段的值域。实测最影响解析稳定性的不是格式措辞而是模型偶尔会在JSON里塞多余的解释性文字或者把字段名微调变形。我在提示词里加了「只输出JSON对象不要输出任何解释性内容」同时在下游加了一层解析容错先正则提取JSON区块再尝试解析解析失败才进入重试逻辑而不是直接返回错误。这一套下来几百次测试的输出可解析率大概从88%提到了接近98%。剩下的2%靠agent循环里的重试兜底具体见后面agent部分。3. 上下文工程把信息精准投喂到模型的「工作台」上下文工程是我这次项目里花时间最多、也是收获最大的一块。它不像提示词那样可以通过肉眼快速迭代因为它牵涉到数据流、窗口占用和动态更新出了问题排查也比较绕。3.1 检索增强不是简单拼接先重构信息再进上下文最初我图省事知识库文档直接按固定长度切块用户提问时拿问题原文去做相似度检索然后把命中的几个块原样拼进上下文。结果模型经常答非所问检索到的一个块是关于安装步骤的中间段标题信息不在块里模型就不知道这段话在说哪个产品。后来我对信息重构做了以下几件事第一块切分从固定长度改成按语义边界切。一级标题、二级标题这样的章节结构作为切分主轴块内保留上下文连通性块与块之间允许部分重叠。第二构建块摘要。每个块除了正文内容还生成一个50字以内的摘要包含产品型号、章节主题、核心结论。检索时把摘要和正文一起做相似度计算只拿正文进模型上下文。这样既保证检索精度又减少无关噪声占用窗口。第三答案拼接时带上来源标记。在每块正文前面加「【资料1】产品手册-型号X-章节3.2」模型回答问题时就会带着编号引用。这招是后续做溯源验证的关键也是用户信任感的来源。3.2 上下文预算管理窗口不是用来装的是用来算的这是上下文工程里最核心的意识转变。模型上下文窗口是有限的但真实业务资料是无限的不可能全塞进去。上下文预算就是给每一次模型调用计算出「最佳投喂量」。我的固定套路是系统提示词固定占用约1200 token含角色、职责边界、few-shot示例历史对话摘要压缩到600 token以内查询任务相关的检索块最多取4块每块控制在300 token上下总量约1200 token预留约400 token给工具调用返回结果整体目标是把单次调用的输入稳定控制在3500到4000 token之间即使模型上下文窗口有128K也只启用它的零头。很多人以为窗口大就能多塞实际上输入过长会显著增加延迟、成本和出现注意力分散的风险模型反而更容易被中段噪声带跑。把信息裁剪到刚好够用是我做过的最有效的质量提升手段。3.3 多轮对话中的记忆分层多轮对话最容易翻车的点在于把每一轮的历史原文全塞进去窗口快速膨胀然后模型被早期错误信息带偏。或者反过来一句历史都不带用户说「它那个问题解决了吗」模型完全不知道「它」指谁。我这个项目里用了两层记忆短期记忆最近3轮对话的原文摘要按角色交替保存每轮不超过100 token。用于处理直接指代和基本承接。长期记忆每一轮结束之后由模型从当前对话中抽取结构化事实存入一个独立列表。比如设备型号、故障现象、最后结论、遗留事项。下一次对话把这份事实表放进上下文模型就有了「真正记住的东西」。实际测试下来长期记忆抽取带来的体验提升非常明显。用户问「上次说的那个噪音问题后来排查到哪一步了」模型能准确接住而不是只能复述聊天历史。注意长期记忆必须做「过期清理」。我在结构化的同时给每项记忆打上生成时间戳超过7天的自动丢弃避免旧信息污染新决策。尤其是设备状态类信息时效性极强。4. agent框架让模型从「回答问题」进入「完成任务」如果说上下文工程解决的是「喂什么」agent框架解决的就是「干什么」。一个复杂任务要拆成几步、每一步用什么工具、中间结果如何判断合法性这是agent框架的职责。4.1 任务分解与工具调用的循环设计我先用最简单的方式跑通闭环问题进来后丢给模型模型输出一份「行动计划」包含若干步骤每个步骤对应一个工具调用或一次检索操作。然后由程序逐条执行计划把执行结果反馈给模型模型根据结果决定是继续下一步还是直接收敛答案。具体到代码层面核心循环大概长这样用户输入 → 上下文组装 → 模型推理 → 工具调用指令解析 ↑ ↓ └──── 结果反馈并入上下文 ← 工具执行并返回结果这个循环最关键的地方在于模型每次收到的输入必须包含两个部分当前目标、以及上一步工具返回的真实结果。回流的信息不经过筛选直接进下一个推理轮次保证模型能基于真实数据决策而不是靠记忆补完。遇到工具执行失败时我让模型看到报错信息并自行判断重试还是换路径。比如一次数据查询因为参数格式问题失败模型会在下一步计划里修正参数重新调用而不是简单把错误抛给用户。4.2 防止「无限空转」最大轮次与终止条件agent框架最大的工程隐患是循环失控。模型会陷入一种情况反复调同一个工具调完说不行再调再不行最后在兜圈子里耗尽时间和预算。我设置了三个终止条件最大轮次限制单次任务最多执行6个工具调用超出直接降级为「基于现有信息给出最终回答」收敛判定连续两轮工具结果没有产生新的有效信息强制结束答案确认模型认为自己已经完成目标时输出终态标记这三个条件里收敛判定最省成本。我记录了每一轮工具结果的摘要哈希如果本轮结果摘要和上一轮相同就判定没有新信息直接终止循环。实测至少砍掉了三成无意义轮次。4.3 单一agent还是多agent分工一开始我的设计是「一个大代理包打天下」什么任务都往里塞。结果问题多了之后提示词里的任务说明越来越长面对不同类型请求时模型行为开始「人格分裂」有时候像运维专家有时候像数据分析师切换不够稳定。我把架构改成「主agent 子agent」的分层模式。主agent负责意图识别和任务拆分判断请求属于「文档问答」「数据分析」「工单操作」三种类型中的哪一种然后把子任务分发给对应的子agent。每个子agent保留自己独立的系统提示词、工具集和上下文模板。改完之后整体稳定性提升很明显。原因也不复杂每个子agent的提示词足够聚焦上下文工程也更有针对性——文档问答走RAG检索数据分析走工具调用。相比之下单一agent的上下文窗口鱼龙混杂很容易互相干扰。个人经验除非任务类型极其单一否则不要把所有能力捆绑进一个agent里。面对复合场景分层设计带来的维护成本远小于单agent混沌状态下的调试成本。5. 联合实战一个跨文档分析场景的完整拆解讲完三个层面的方法论我用一个实际场景把它们串起来看看一次完整的任务是怎么在联合体系里流转的。这个场景是我们内部系统里的高频请求我用它做了大量回归测试。场景用户提了一个问题——「帮我分析一下办公区A区和B区最近三个月的设备报修趋势主要看哪些型号的问题在增加。如果B区某个型号的报修量占比超过30%帮我拉一份该型号的维护建议摘要并按月生成一张趋势说明表。」这个问题如果交给普通RAG基本只能部分回答而且很可能答错。因为这里既有数据查询又有条件判断还要查询文档生成摘要建议是一个典型的复合任务。流程大致如下第一步主agent收到问题后解析出关键要素时间范围最近3个月、对象A区/B区、指标报修趋势、型号占比、条件阈值30%、输出动作建议摘要和趋势表。第二步主agent将任务拆成三个阶段数据查询阶段、条件判断阶段、文档查询与汇总阶段并在上下文中写入任务状态标记。第三步数据分析子agent执行第一步调用数据查询工具。工具返回近三个月报修明细按型号聚合。模型读取所有返回内容识别出B区确有某型号的报修占比达到34.7%超过阈值于是触发第三步。第四步文档问答子agent以该型号为关键词做检索把资料切块过一遍增强流程找到操作手册中的维护建议部分提取并压缩成摘要。第五步结果回流到主agent由它统一按预设的表格模板生成最终答案。表格列包含月份、报修总数、某型号报修量、占比趋势回答段落里带出摘要建议并附检索到的资料编号。整个任务一共消耗了5轮模型调用、2次工具调用总耗时约11秒。而同一问题如果由人来手动查三个系统再整理正常需要20分钟以上。这套流程能跑通的关键就是三个层面的职责配合agent决定先查数再查文档上下文工程保证数据查询结果和文档块精准入槽提示词则统一了每个阶段的输出格式让程序能解析「触发条件」和「汇总结构」。6. 踩过的坑与排查实录联合应用的系统调试难度不是三个模块难度的简单相加。我整理几个实际工程里最高频的问题基本覆盖了大部分优化需求。6.1 模型的「幻觉来源」常被误判一开始我认为幻觉是提示词没写够导致的。后来追踪了一批幻觉样本发现接近六成的问题根因在上下文工程检索阶段没找到正确内容或者找到的内容块本身就不含答案信息。模型面对「没有可用信息」的输入本能地开始编造哪怕是提示词里写了「不知道就说不知道」。排查方法很简单给每次模型调用加日志记录输入上下文包含哪些资料块、模型输出引用了哪些编号。校验引用编号是不是真的存在于本次上下文里。这组日志跑了两周基本能定位出幻觉出现在检索层还是生成层再针对性修复。6.2 上下文压缩导致的信息丢失压缩历史对话时我踩过一次大坑。当时用了一个比较激进的摘要策略把一轮长对话压成一句话。结果到下一轮模型完全丢掉了关键参数细节比如设备型号被摘要成了「那台设备」后续工具调用传参时直接报错。后来我调整了压缩策略摘要只压缩「过程性对话」关键结构化要素单独建字段保存比如设备型号、时间范围、数值阈值这些不参与摘要压缩以原样进入下一轮上下文。这个改动之后跨轮次任务的成功率大幅提升。6.3 工具调用时的格式抖动模型在决定调用工具时偶尔会输出不符合预期的参数结构。尤其是添加字段之后旧分支里的模型仍然按旧字段名传参造成解析失败。我的对策是一端双保险一方面在提示词的工具说明里强调字段名精确匹配另一方面在代码里给每个工具加参数校正层。校正逻辑是如果发现字段名不匹配尝试做一次别名映射比如「machine_type」映射到「device_type」。映射失败才真的报错。6.4 多agent之间的上下文串扰分层agent上线后出现了一个隐蔽问题数据子agent的推理风格会「传染」给文档问答子agent。排查后发现是共享了底层基础模板系统提示词里的风格描述互相影响。处理办法是把每个子agent的提示词完全独立包括风格词、约束词、示例全部各自维护一份。同时增加每次调用的「身份前缀」比如在系统消息里强调「你是文档问答助理」和「你是数据分析助理」从输入层就把身份区分开。7. 工具选型与工程落地经验最后聊几句工具层面的实战心得。这一套架构的落地我强烈建议先确定编排层再选模型而不是反过来。编排层的选型我试过用代码直接写循环逻辑也试过更成熟的agent框架。直接用代码写的优势是可控性最强每个循环节点都可以加日志、断点、人为干预但缺点是工具多了之后维护成本飙升。成熟框架的缺点是封装较黑盒出问题时排查链路比较长。我的最终选择是轻量框架 核心循环自研的组合框架提供工具调用与模型接口的基础能力核心的终止判定、上下文预算、任务状态管理等关键逻辑全部收在自己代码里。这样既保留了灵活性又不会重复造轮子。模型选型方面效果差异最大的不是推理能力上限而是指令跟随稳定性。同样的提示词模板有些模型在工具调用格式上频繁抖动有些就非常稳定。有条件的话先用一周的线上问题集做A/B测试再定别只看单条prompt的对齐效果。检索方面不要把「向量检索」当成唯一答案。很多业务场景里关键词检索 过滤条件的效果不比向量差而且响应更快。我的项目里最终用的是向量关键词混合检索按得分加权合并实测在设备型号、工单编号这类精确匹配场景下准确率明显优于纯向量方案。最后再分享一个后来养成但非常受益的习惯给每个版本的系统建立「回归问题集」。这个集合覆盖了五种常见任务类型、二十条经典问题外加十条容易触发幻觉的刁钻问题。每次修改提示词、调整上下文策略、升级模型都先跑一遍问题集再对比输出差异。这套体系看起来笨重却是保证联合应用系统长期稳定迭代最扎实的办法。很多偶发问题在新增功能后悄然出现没有回归集的兜底上线后真的会措手不及。