1. 从一次线上事故说起为什么上下文工程比提示词工程更值得投入去年冬天我负责的一个客服类 Agent 上线第三天就出了状况。用户投诉说同一个问题问到第五轮Agent 就开始失忆前面确认过的订单号、退款金额全都不认了。我第一反应是模型能力不行换了更大的模型问题依旧。后来把每一轮的 prompt 打出来逐字比对才发现真正的原因对话历史越堆越长我用的那套朴素拼接方案把早期关键信息挤到了上下文窗口的边缘模型对边缘 token 的注意力本来就弱再加上中间夹杂了大量无用的工具调用返回关键信息等于被淹没了。这件事让我彻底转变了思路。提示词工程Prompt Engineering解决的是怎么问上下文工程Context Engineering解决的是给模型看什么、看多少、按什么顺序看。前者是话术后者是信息架构。一个 Agent 能不能稳定工作八成取决于后者。这篇内容我想把过去一年多踩过的坑、试过的方案完整梳理一遍核心围绕四件事Token 到底怎么被消耗的、上下文压缩有哪些真正可用的手段、分层记忆该怎么设计、以及整套系统怎么落地不翻车。适合正在做 Agent 开发、被上下文长度和成本折磨过的同学也适合刚入门想搞清楚Agent 记忆到底是怎么回事的朋友。文中涉及的数字和阈值都是我在实际项目里调出来的经验值不是教科书标准答案你可以根据自己的场景微调。先说一个反直觉的结论大部分 Agent 的上下文问题不是窗口不够大而是信息组织得太烂。把窗口从 8K 扩到 128K成本涨了十几倍效果可能只提升一点点因为模型在长上下文里的有效注意力是稀疏的。与其无脑堆长度不如把工程做扎实。2. Token 消耗的真实账本钱到底花在哪了2.1 一次 Agent 调用里Token 都流向了哪里很多人算成本只算用户输入 模型输出这在 Chat 场景够用但在 Agent 场景会严重低估。一个典型的带工具调用的 Agent 轮次Token 消耗至少包含这几块消耗项说明典型占比系统提示词角色设定、规则、输出格式约束5%~15%工具定义每个工具的 name、description、参数 schema10%~30%对话历史之前所有轮次的 user/assistant 消息20%~50%工具调用结果检索内容、API 返回、文件片段20%~60%当前用户输入本轮问题1%~5%模型输出回复或工具调用参数5%~15%我第一次做成本核算时被工具定义这一项吓了一跳。一个中等复杂度的 Agent 挂了 12 个工具每个工具的 JSON Schema 平均 200 token光工具定义就吃掉 2400 token而且每一轮都要重新传一遍。如果一轮对话平均 8 次模型调用那就是 19200 token 纯粹花在告诉模型它有哪些工具上。提示工具定义是隐形成本大户。工具数量超过 8 个时强烈建议做工具的动态筛选或分组加载而不是全量塞进系统提示词。2.2 上下文窗口、计费窗口、有效注意力窗口是三回事新手最容易混淆这三个概念。我用一个类比解释上下文窗口桌子有多大能摆多少张纸。计费窗口不管你摆多少按你实际摆上去的纸收费。有效注意力窗口模型真正能看清的其实只有桌子中间那一小块边上的纸它扫一眼就过去了。实测下来即便模型标称支持 128K当上下文超过 32K 之后对中间位置信息的召回率会明显下降。业界常说的lost in the middle就是这个现象。所以我的经验法则是关键信息尽量放在上下文的开头或结尾中间部分只放可容忍丢失的内容。2.3 一个可复用的 Token 预算分配模板与其事后惊讶账单不如事前做预算。我现在的项目都会先定一个单轮 Token 预算然后按比例切分。以单轮 8000 token 预算为例系统提示词 工具定义固定 1500 token 上限超了就精简工具描述长期记忆召回800 token只召回最相关的 3~5 条近期对话历史3000 token保留最近 N 轮工具调用结果2000 token超长结果先摘要再入上下文当前输入 输出预留700 token这个模板的好处是任何一块超支你都能立刻定位。我见过太多项目是哪里长了砍哪里结果把最关键的对话历史砍了反而更糟。预算分配的本质是给每一类信息设定优先级和上限让压缩有章可循。2.4 用 tiktoken 做精确计量别靠字数估算中文一个字大约 0.6~1.5 个 token波动极大靠字数估算误差能到 50%。我现在的做法是统一用tiktoken做精确计数封装成一个工具函数在每次拼接上下文前先算一遍。import tiktoken enc tiktoken.get_encoding(cl100k_base) def count_tokens(text: str) - int: return len(enc.encode(text)) def count_messages_tokens(messages: list) - int: total 0 for m in messages: total count_tokens(m.get(content, )) total 4 # 每条消息的角色和分隔符开销 return total 2 # 整体格式开销注意不同模型的编码器不一样cl100k_base适用于多数主流模型但换模型时一定要重新校准。我曾经因为换了模型没换编码器预算算出来偏小 20%导致线上频繁触发截断。3. 上下文压缩不是简单截断而是有损信息的智能取舍3.1 为什么直接截断最早的消息是最差方案最朴素的压缩就是保留最近 N 轮把老的丢掉。这个方案的问题在于最早的消息往往包含任务目标、用户身份、关键约束。你把它们丢了Agent 就不知道自己在干嘛了。我做过一个对比实验同一个多轮任务方案 A 是滑动窗口截断方案 B 是摘要 保留关键实体。结果方案 A 在第五轮之后任务完成率掉到 40%方案 B 还能维持 85% 以上。差距全在早期关键信息有没有被保住。3.2 摘要压缩什么时候摘要摘要成什么摘要不是把历史复述一遍而是抽取对后续决策有用的信息。我现在的摘要 prompt 大致是这样约束的请将以下对话压缩为结构化摘要只保留 1. 用户的核心目标与已确认的事实订单号、金额、时间等 2. 已执行的操作及其结果 3. 尚未解决的问题 不要保留寒暄、重复确认、无关的工具返回。 输出格式 - 目标 - 已确认事实 - 已完成操作 - 待办关键在于结构化。自由文本摘要每次格式都不一样模型读起来费劲结构化摘要稳定、可解析、可增量更新。触发时机也很重要。我的经验是不要每轮都摘要那样既费钱又容易丢信息。触发条件设成两个一是历史 token 超过预算的 70%二是对话轮次达到某个阈值比如 6 轮。满足任一才触发一次摘要把摘要结果替换掉被压缩的那段历史。3.3 工具结果的压缩这里才是省钱大头前面说过工具调用结果能占 20%~60%这是压缩收益最高的地方。几个实操手段检索结果只留 Top-K 片段向量检索返回 10 条别全塞进去按相关性取前 3 条每条截断到 300 字。API 返回做字段裁剪一个订单接口返回 50 个字段Agent 可能只需要 5 个。在工具层就裁掉别让模型看。长文档先分块摘要再召回不要整篇塞先离线切成块、每块生成摘要检索时召回摘要需要细节再二次拉取原文。注意工具结果压缩一定要在工具层做而不是在拼接上下文时做。前者是源头治理后者是末端补救前者省的是真金白银。3.4 语义压缩与去重把重复的话合并掉多轮对话里经常出现用户反复确认同一件事或者 Agent 重复调用同一个工具。我加了一个轻量的去重层对最近 N 条消息做语义相似度计算相似度超过阈值的合并成一条。这个操作能砍掉 10%~20% 的冗余 token而且几乎不损失信息。实现上不需要上重型模型用一个小型 embedding 模型算余弦相似度就够了。阈值我一般设在 0.92太低会误合并太高没效果。3.5 压缩的边界哪些信息绝对不能压有几类信息我从不压缩宁可超预算也要保留用户明确给出的约束和禁止项不要给我打电话这类已经确认的关键标识符订单号、身份证后四位等当前任务的原始目标描述安全相关的规则这些一旦丢失Agent 可能做出完全错误的行为代价远大于省下的那点 token。4. 分层记忆设计让 Agent 像人一样记住该记的4.1 三层记忆模型工作记忆、情景记忆、语义记忆人的记忆是分层的Agent 也该如此。我现在的设计分三层层级对应概念存储内容生命周期访问方式工作记忆短期当前对话上下文单次会话直接拼接情景记忆中期历史会话摘要、事件数天到数月按时间/相关性召回语义记忆长期用户画像、偏好、知识长期向量检索工作记忆就是当前上下文窗口里的内容前面讲的压缩都是针对它。情景记忆是上次我们聊到哪了语义记忆是这个用户是谁、喜欢什么。4.2 工作记忆上下文窗口的精细化管理工作记忆的管理核心是动态组装。每一轮调用前我按这个顺序拼系统提示词固定语义记忆召回用户画像按需情景记忆召回相关历史会话摘要结构化对话摘要当前会话的压缩历史最近 N 轮原始对话当前用户输入这个顺序不是随便定的。越靠前的内容模型注意力越稳定所以把最重要的系统规则和用户画像放前面把可容忍丢失的近期对话放中间偏后。4.3 情景记忆会话摘要的存储与召回每次会话结束我会生成一份会话摘要存进数据库字段包括会话 ID、时间、主题、关键结论、涉及实体。下次用户再来先按用户 ID 拉取最近若干条摘要再用当前问题做相关性排序取 Top-3 注入上下文。这里有个坑摘要的粒度要适中。太粗整个会话一句话丢信息太细每轮一条又变成变相的全量历史。我的做法是会话级摘要 关键事件级摘要两级会话级给全局事件级给细节。4.4 语义记忆用户画像的构建与更新语义记忆解决的是个性化。我维护一个用户画像对象包含偏好、禁忌、常用信息等。更新策略是增量式每轮对话后用一个轻量模型判断这轮有没有产生值得长期记住的信息有就抽取成键值对更新画像。{ user_id: u_123, preferences: {language: 中文, reply_style: 简洁}, facts: {常用收货地址: 已确认, 会员等级: 黄金}, taboos: [不要电话联系] }画像不能无限膨胀我设了上限比如 50 个键值对超了就按最近使用时间 重要性淘汰。4.5 三层记忆之间的流转规则三层不是孤立的要有流转机制工作记忆 → 情景记忆会话结束时摘要归档情景记忆 → 语义记忆多次出现的稳定信息升级为画像语义记忆 → 工作记忆每轮按需召回注入这个流转设计让 Agent 有了越用越懂你的能力而不是每次都从零开始。5. 落地实战一套可复现的上下文工程管线5.1 整体架构与数据流把前面的东西串起来一条完整的管线是这样的用户输入 → 计算当前 token 预算 → 召回语义记忆用户画像 → 召回情景记忆相关历史摘要 → 加载当前会话结构化摘要 → 拼接最近 N 轮原始对话 → 检查总 token超预算则触发压缩 → 调用模型 → 处理工具调用结果先裁剪再入上下文 → 会话结束触发摘要归档与画像更新5.2 关键代码上下文组装器def build_context(user_input, session, user_profile, budget8000): parts [] parts.append(system_prompt) # 固定 parts.append(render_profile(user_profile)) # 语义记忆 parts.append(recall_episodic(session.user_id, user_input)) # 情景记忆 parts.append(session.structured_summary) # 会话摘要 parts.append(render_recent_turns(session, n4)) # 近期对话 parts.append(user_input) ctx \n.join(filter(None, parts)) if count_tokens(ctx) budget: ctx compress(ctx, budget) # 触发压缩 return ctx5.3 压缩触发与降级的优先级超预算时的降级顺序我固定为先砍工具结果 → 再压缩早期对话 → 再减少召回条数 → 最后才动系统提示词。系统提示词是最后防线绝不轻易动。5.4 监控指标怎么知道上下文工程做得好不好上线后我盯这几个指标单轮平均 token 消耗看成本趋势压缩触发频率太高说明预算太紧或信息太冗余关键信息召回率用测试集验证看有没有丢关键信息任务完成率最终效果指标这几个指标一起看才能判断是省了钱但变笨了还是又省钱又聪明。6. 踩过的坑与调优心得6.1 摘要丢关键信息的排查过程有次用户投诉 Agent 忘了订单号。我把摘要日志打出来一看摘要 prompt 里我写了只保留核心信息结果模型把订单号当成了细节给删了。修复方法是在摘要 prompt 里显式列出必须保留的字段类型而不是笼统说核心信息。这个坑告诉我给模型的压缩指令必须具体到字段级别。6.2 记忆召回的污染问题情景记忆召回时如果只按向量相似度取 Top-K很容易召回语义相似但实际无关的历史。比如用户问退款召回了一堆退货的历史。我的解法是相似度 时间衰减 用户显式标记三者加权而不是纯向量。6.3 成本与效果的平衡点怎么找我做过一轮 A/B预算从 4000 提到 8000任务完成率从 72% 提到 89%成本翻倍再从 8000 提到 16000完成率只到 91%成本又翻倍。边际收益在 8000 附近就明显递减了。所以别盲目堆预算找到自己场景的拐点最重要。6.4 几个容易被忽略的细节工具描述里的示例参数会显著增加 token能删就删时间戳、UUID 这类信息对模型决策帮助有限能省则省多语言场景下中文 token 效率通常比英文低预算要留余量压缩后的摘要要定期回测模型换了摘要质量可能变化7. 关于分层记忆我最后想说的几句实在话做 Agent 上下文工程这一年多我最大的体会是这不是一个靠堆模型能力能解决的问题而是一个信息架构问题。你把信息组织好了小模型也能跑得很稳组织不好再大的窗口也救不了。分层记忆的价值不在于记得多而在于记得对。工作记忆管当下情景记忆管来龙去脉语义记忆管这个人是谁。三层各司其职Agent 才像个有记忆的助手而不是每次重启的机器人。如果你刚开始做我的建议是先把 Token 预算和压缩管线搭起来这是投入产出比最高的部分分层记忆可以后加但架构上要预留位置别等系统跑起来了再重构那时候改动成本会高很多。至于具体的阈值和比例别照抄我的拿你自己的数据跑几轮 A/B找到属于你场景的那个拐点那才是真正有用的东西。
企业数字化 ERP 产品动态
相关推荐
WebMCP 声明式 API 终极指南:用 <form> 零 JS 把网页表单变成 AI 可调用工具 WebMCP 声明式 API 终极指南:用 零 JS 把网页表单变成 AI 可调用工具【免费下载链接】webmcp 🤖 WebMCP 项目地址: https://gitcode.com/gh_mirrors/webm/webmcp
WebMCP 声明式 API 让你无需写一行 JavaScript,只需给现有的 <form&… · 2026/9/25 2:41:06
百考通AI实操指南:毕业设计从“肝”到“干”的高效路径 每年三四月份,各大高校的实验室和宿舍里总会准时上演同一出戏:论文查重红字满天飞、代码跑不出结果、开题报告还没动笔、PPT答辩日期已经逼近。我见过太多学生把毕业设计活活完成了一场“肝”的竞赛——熬夜刷夜赶进度、复制粘贴攒章节、对着空白文档发呆… · 2026/9/25 2:41:00
Visual Syslog日志存储与轮转:按大小/日期自动旋转日志文件的实用技巧清单 Visual Syslog日志存储与轮转:按大小/日期自动旋转日志文件的实用技巧清单 【免费下载链接】visualsyslog Syslog Server for Windows with a graphical user interface 项目地址: https://gitcode.com/gh_mirrors/vi/visualsyslog
Visual Syslog 是一款免费… · 2026/9/25 2:40:54
波场链上监控与交易自动化:从区块轮询到TRC20信号捕获 简介:面向Java开发者和区块链技术学习者,这套资料提供一套基于TRON波场链的监控与交易实现方案。方案覆盖HD钱包生成、TRX余额查询、TRC20代币余额查询、TRX与TRC20转账、TRX冻结换取TRON Power(TP)、交易与转账信息查询、区块信息… · 2026/9/25 3:07:21
Pomander PHP 部署实战:任务配置、多机并行与回滚避坑指南 简介:Pomander是一款面向PHP开发者的应用部署工具,适合需要频繁迭代、多环境发布的敏捷团队与协作项目,用于简化代码从开发到生产环境的推送流程。资源包共38个文件,以26个PHP源码文件为核心,辅以yml、yaml等环境与持续… · 2026/9/25 3:07:21
H5跳转微信小程序的三大方案:Scheme、URL Link与开放标签实战指南 1. 项目概述:为什么H5跳转微信指定页面这件事,比你想象中更难也更重要“外部H5跳转微信指定页面”——这短短十个字,背后是无数前端工程师、小程序开发者、运营同学在深夜改需求时咬牙切齿的战场。我做过6个年均DAU超500万的微信生态项目&… · 2026/9/25 3:07:15
Xray 共享工作区与基于能力的 RPC 系统设计:从 2018 年 4 月 9 日周报看协作编辑的底层实现 开发工具 【免费下载链接】xray An experimental next-generation Electron-based text editor 项目地址: https://gitcode.com/gh_mirrors/xray/xray 点击查看 免费下载 Xray 在 2018 年 4 月 9 日的更新周报中记录了共享工作区(Shared Workspaces&… · 2026/9/25 3:07:03
零广告靠社媒:独立站卖数字材料月入数万美元的运营拆解 1. 项目拆解:卖“材料”的独立站到底是一门什么生意1.1 “材料”是什么,为什么能卖出高溢价先说说“材料”这个引号。很多人看到“卖材料”第一反应是卖钢筋水泥,或者是卖布料皮革,但做独立站的人听到这个词,脑子里想的… · 2026/9/25 3:07:03
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37