详细说下什么是 context 里面的 shared context,另外讲讲常见的 session search 做法
沿着刚才那个“持续迭代电商项目”的例子讲。 昨天你让 Agent 做退款,讨论过“退款到账和库存恢复不是同一个状态”;今天开了新会话,让它继续写测试。 这时候有两个不同的需求: shared context:让新会话、其他参与任务的 Agent,都能拿到已经确认的退款规则,不必重新解释。 session search:当 Agent 不知道“为什么这么定,昨天讨论了哪些例外”时,能回到历史会话里找到原始讨论。 可以先记成一句话:前者侧重共享可复用的信息,后者侧重找回历史证据。它们能配合,但不是同一个东西。 一、shared context 到底共享什么 这个词不是一个所有框架都统一定义的标准术语。放在我们讨论的 Agent 上下文管理里,可以理解为:多个执行步骤、会话或 Agent 都能访问的一组公共背景和状态。 比如一个退款任务,可以有这些共享内容: 项目背景:订单、支付、库存分别由哪个模块负责。 已确认约束:只有指定的订单状态允许发起退款。 接口契约:金额单位、状态枚举、错误码。 任务状态:退款接口已完成,重复回调测试还没写。 关键决策:为什么退款状态和库存恢复状态分开管理,以及决策依据。 而某个 Agent 为排查问题读过的几十段日志、走过的错误路径、临时猜测,一般不适合全部变成 shared context。 这里有两条容易混淆的轴: 共享范围:谁能读到,当前任务、整个项目,还是某个用户的所有会话? 存活时间:只保留本次执行,还是跨会话长期保留? 所以 shared context 不一定是长期记忆。三个 Agent 在同一任务里共用的临时状态,也是共享上下文;某个用户的长期个人偏好,也不应该因此向所有 Agent、所有用户开放。 二、“共享存储”不等于“模型已经知道” 假设你把退款规则存进数据库,三个 Agent 都有读取权限。 这只能说明它们有机会获取规则,不代表规则已经进入它们当前的模型上下文。真正影响这次生成的,是这次调用实际传进去的信息。 通常可以这样做: 少量稳定且必需的信息,启动时直接注入。比如当前目标、必须遵守的业务约束、关键接口契约。 数量多、只在特定任务中相关的信息,按需检索。比如历史决策、某个模块的详细设计。 持续变化的信息,执行关键动作前重新读取。比如任务是否已经完成、接口版本是否变了。 因此,比较实用的结构是: 本轮上下文 = 必要的共享背景 + 当前任务状态 + 当前 Agent 的局部信息 + 按需检索到的证据。 这里的“+”是信息组成示意,不是要求把每部分全量拼进去。 如果用的是某些 Agent SDK,还要注意另一种含义:框架里的 context 对象可能只是应用传给工具的运行时对象,里面有数据库连接、用户身份等。它不一定自动发给模型,不能和模型可见上下文画等号。 三、多 Agent 怎么共享才不乱 继续举例: Agent A 写退款接口。 Agent B 写测试。 Agent C 做 review。 它们需要共同知道的是接口契约、业务规则和验收条件,而不是互相接收所有聊天记录。 一种简单可靠的设计是: 公共区域保存已确认的规则、契约和任务状态。 每个 Agent 保留自己的局部工作上下文。 Agent 完成阶段任务后,提交“结果、证据、未解决问题、对公共状态的修改建议”。 由协调者或确定的合并逻辑更新公共区域,必要时交给人确认。 比如 A 不能只提交“接口写完了”,而应该交代: 实现对应哪个代码版本。 遵循哪个契约版本。 哪些验证已经通过。 哪些边界条件还没覆盖。 否则 B 可能基于旧接口写测试,C 又基于另一个版本做 review,表面并行,实际互相返工。 共享状态最好有来源、更新时间、版本、确认状态。关键写入可以用版本检查,避免两个 Agent 同时覆盖彼此的改动。 尤其不要让模型的临时猜测直接升级成“全项目默认事实”。 一句话:共享经过整理的结论和可验证状态,隔离大量探索过程。 四、session search 常见怎么做 我这里把 session search 理解为“搜索历史会话”,既可以搜当前会话较早的内容,也可以跨会话搜索;不是特指某个产品的同名工具。 例如用户问: “上次为什么没选 Redis 做退款状态的权威存储?” 目标不是找一段包含 Redis 的文本,而是找到当时的方案讨论、最终决定及其理由。 常见实现可以分成几个层次。 第一种:关键词和全文检索 先用用户、项目、时间范围缩小搜索范围,再用关键词搜历史消息。 适合搜索错误码、函数名、工单号、明确出现过的技术名词。 比如搜 RefundCallback、ERR_REFUND_DUPLICATE,全文检索往往很直接,不必一上来就做向量库。 不足是表达变了容易漏:用户问“重复退款”,历史说的是“退款请求幂等”。 第二种:语义检索 把历史会话片段生成 embedding,按语义相似度召回。 “重复退款怎么防”可能召回“利用业务请求号实现幂等”的讨论。 但不能只依赖它。语义相近不代表证据准确,函数名、编号、否定条件、时间先后关系也容易被弱化。 第三种:混合检索 关键词检索和向量检索分别召回,再合并、去重、重排。 关键词负责精确实体,向量负责不同表述之间的语义关联。 这通常是一个值得考虑的升级方向,但不是任何小项目都必须上。历史不多、查询又以明确关键词为主时,全文检索可能已经够用。 第四种:分层检索 先搜会话标题、摘要、主题标签,定位可能相关的 session,再深入搜索这些 session 中的原始片段。 比如先定位“退款方案设计讨论”,再找其中关于 Redis 的部分。 它适合历史会话很多的情况。不过摘要可能漏掉细节,所以不要把摘要层当成唯一入口;必要时还要支持直接搜原始片段。 这些做法不是互斥关系,可以组合使用。 五、比选向量库更关键的是:怎么切、怎么读、怎么判定 首先,不建议把每条聊天消息都机械地当成独立检索单元。 比如原始对话: 用户:退款成功就立即恢复库存? Agent:可以。 用户:不对,已发货订单需要仓库确认退货。 Agent:明白,按订单履约状态区分。 只召回“可以”,答案就错了。 更合理的是按话题或若干相邻轮次切片,尽量保留问题、回答、纠正之间的关系。工具调用及其结果也应尽可能保留关联。 但也不要把一个很长的 session 整体做成单个检索单元,否则主题太杂,召回和阅读都不精确。 其次,搜索命中只是线索,不应直接等于答案。 可以设计两类工具,下面是示意接口,不是某个框架的固定 API: search_sessions(query project_id time_range) 返回会话编号、消息编号、时间、简短片段、匹配信息。 read_session(session_id anchor_message_id before after) 围绕命中消息读取前后文。 这样 Agent 能先定位,再核对,发现“后面还有一次纠正”时继续往后读,而不是一次把全部聊天历史塞进来。 第三,要区分“当时的讨论”和“现在的有效规则”。 历史里可能同时存在: 群友 8334提议。 被否决的方案。 用户最终确认的方案。 之后又修改过的决定。 不能简单按相似度最高取一条,也不能无脑认为最新消息就是最终事实。要结合发言者、确认状态、适用范围和是否被后续决定替代来判断。 回答“上次为什么这么选”时,应该还原当时的理由;回答“现在应该怎么实现”时,还得核对当前文档、代码和规则。 第四,权限必须在检索链路里处理。 按用户、租户、项目权限限定候选内容,读取原文时再校验。不能先把所有人的历史交给模型,再让它“自觉保密”。 历史文本也只是证据,不是当前指令。过去某条消息里写着“忽略规则”,不能因为被检索出来就重新生效。 六、这两个能力怎么接成一个工作流 仍然是“今天继续补退款测试”: 开始时,加载 shared context,拿到当前退款规则、接口契约和待办。 发现其中一条规则缺少理由,调用 session search,检索“已发货订单、退款、库存恢复”。 命中昨天的讨论后,读取前后文,确认最终结论及来源。 再核对当前代码是否仍然对应这条规则。 完成测试后,更新任务状态;如果有新的、已经确认的业务决策,再更新共享知识,并保留来源和版本。 注意,不是每次搜到聊天内容都要写入 shared context。否则历史猜测、废弃方案会不断污染公共知识。 如果你自己实现第一版,我建议先做: 原始会话存储,保留角色、时间、项目和消息关联。 一份简洁的项目共享说明和任务状态。 带权限过滤的全文搜索。 命中后读取前后文。 确认后才更新共享知识。 有了实际失败案例,再决定是否补语义检索、重排和自动记忆提取。不要一开始就把“上下文管理”做成复杂的记忆平台。 最后概括一下: shared context 解决“大家应该共同知道什么”。 session search 解决“需要时怎么找回过去说过什么”。 context engineering 解决“找到了这么多信息,这一步究竟给模型看哪些”。 参考:Anthropic 的 2025 年上下文工程文章讨论了按需检索、结构化笔记、压缩和子 Agent 上下文隔离。上面具体的存储字段与搜索接口是实现建议,不是它规定的标准。 https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents