想象你是一家大型软件公司的CEO。公司里有研发部、设计部、市场部、客服部,每个部门都有自己的办公室、文件柜和门禁权限。市场部不会闯进研发部翻代码,客服部改不了设计部的产品蓝图;部门之间要协作,得走正式邮件或工单流程。这套“各管各的、协作走流程”的制度,让上百人的公司运转得井井有条。 如果把一个部门想象成一个 AI Agent(智能体),把部门里的办公室和文件柜想象成 Agent 的上下文空间——也就是它工作时看到的对话历史、数据片段、工具返回结果——那么上面的画面,就是一个生产级多Agent系统的日常。要是所有 Agent 共用一个上下文空间,就像所有部门共用一个文件柜:拿错文件、误改数据、职责混乱只是时间问题。 这篇文章会像给公司设计办公制度一样,带你设计多Agent系统的上下文分区:怎样给每个 Agent 分独立办公室(分区)、怎样定文件权限(隔离)、怎样规范跨部门邮件(消息协议)、怎样设门禁(边界控制)、怎样做保洁(防污染)、怎样整理档案室(防膨胀)。读完你就会理解:会分区的系统才可控,这是 Context Engineering 的第一课。
学好上下文分区与隔离机制,你就能构建出真正可控的多Agent系统——不串扰、不越权、不膨胀。这是从“Demo能跑”走向“生产可用”的关键跃迁,也是 Context Engineering 岗位最核心的竞争力。
可视化演示
展示多Agent系统的上下文分区结构、通信边界与消息协议、以及私有状态与共享状态的隔离机制。
本节配有交互动效(进入视口后自动加载,约 3KB)。
上下文分区结构 每个Agent拥有独立上下文空间,避免信息串扰 共享区存放公共信息,Agent通过受控接口访问 Agent_i ∩ Agent_j = Shared 分区隔离保证系统可控性,防止上下文污染
上下文分区设计
想象一家公司:市场部、研发部、客服部各自拥有独立办公室,每个办公室里都有专属文件柜。市场部不会趴在研发部的桌上翻看代码方案,客服部也不会修改市场部的活动排期。这就是“分区”的直觉——空间上互相独立,职责上各管一摊。多Agent系统要构建的,正是这种物理意义上的“隔间”。
在AI领域,每个Agent(智能体)都是一个独立的“部门员工”。它工作时需要“看”的对话历史、检索到的资料、工具调用结果,合在一起被称为它的上下文空间(Context)。如果多个Agent共用同一个上下文,就像所有部门挤在一个大办公室乱翻文件——信息串扰只是时间问题。所以第一步,就是给每个Agent分配一片独立、互不重叠的上下文分区。
工程上,每个Agent维护自己的上下文缓冲(通常是一个按时间排序的消息列表)。系统的总上下文不设“中央大池子”,而是拆成若干个私有分区,外加一个可选的共享分区。私有不共享,共享要受控——这两条原则一起保证了模型的每个输入窗口只装载当前职责范围内的高相关信息,推理才不会“走神”。
这套设计与公司工位制度如出一辙:每位员工有专属工位,外人进不来,自己的桌面自己打理。分区越清晰,每个人的“工作桌面”越干净,系统整体的可控性也越强。
- C_total(总上下文)整个多Agent系统在任意时刻需要维护的全部上下文数据,它的上限受模型窗口约束。
- ⊕(互斥并集)把多个分区拼在一起,重点是分区之间没有重叠,任何一条上下文只属于一个分区。
- C_i^private(私有分区)第 i 个 Agent 专属的上下文区域,只有它自己能读写,是最小隔离单元。
- C_shared(共享分区)所有 Agent 按权限共享的区域,相当于公司公告栏,写入和读取都受到约束。
状态隔离机制
办公室分好了,接下来是“文件归属”问题。员工抽屉里的是私人便签,走廊里的是公共公告栏,财务部保险柜里的工资数据谁也不能乱碰。一个系统里哪些数据该私有、哪些该共享、哪些该被严密保护,就是状态隔离机制要回答的问题。
状态(State)指 Agent 在运行过程中产生和依赖的数据:任务进度、已收集的信息、中间决策结果。多Agent系统里最朴素的误解是“把数据全共享给所有人”——这会让系统迅速失控。正确的做法是建立访问控制:每个Agent默认只拥有自己产生的私有状态,只有别人真正需要时,才通过授权方式暴露一部分。
工程上常用访问控制矩阵来刻画这种关系:矩阵的行是Agent,列是状态条目,元素为1表示“该Agent有权读取这条状态”。系统运行时,每次读取前都查询矩阵,命中1才放行。私有状态不写入共享区;共享区只容纳明确的、经过清洗的数据,写入者是谁、写入者有哪些权限,全部留痕。这样一来,“谁的东西谁做主,借别人的要看授权”就成了可执行代码。
就像私人抽屉和公共柜的界限一旦清晰,员工就不会拿错东西。多Agent系统也一样:私有与共享的边界越明确,协作不越权,数据不漂移。
- M_ij(权限矩阵元素)第 i 行对应 Agent i,第 j 列对应状态 j,这个格子的值决定了访问权。
- 取 1 或取 0(二值化判定)1 允许访问,0 禁止访问。把复杂的权限策略简化为布尔判断,便于系统高速执行。
- 访问条件(can access 判定)“可访问”由系统策略决定,比如该Agent是否在状态拥有者授权的白名单中。
消息协议设计
有了独立办公室和文件柜,员工之间怎么协作?答案是走公司邮件系统,而不是冲到对方办公室翻桌面。邮件有固定格式——发件人、收件人、主题、正文、时间——收件人一看就知道这封信要自己做什么。多Agent系统里,这套“公司邮件”就是消息协议(Message Protocol)。
设计消息协议的核心任务,是定义一条消息到底长什么样、包含哪些字段、字段用什么语义。没有协议的系统,Agent之间协作就像口头传话,信息在传递中失真、丢失、被误解。而协议一旦成型,所有Agent都遵守同一个“写信格式”,系统的可理解性和可维护性立刻提升。
一个最小可用的消息协议包含五个字段:sender(谁发的)、receiver(发给谁)、type(属于哪类事件,比如请求、回复、通知)、payload(携带的任务内容)、ts(时间戳)。sender 和 receiver 解决“寻址”问题,type 让接收方快速决定调用哪个处理分支,payload 是消息的正文,ts 则用于处理乱序到达和事后追溯。字段越规范,协作链路越清晰。
就像公司邮件的发件人、抄送、主题、附件、日期缺一不可,Agent之间的每次交互都因协议而可追踪、可路由、可扩展。协议越规范,系统出问题时越容易回溯:是哪封信、哪个环节传错了话。
- S(发送方)标明消息从哪里发出,对应发送 Agent 的唯一 ID,是所有路由和溯源的起点。
- R(接收方)标明消息送往哪个 Agent。支持单播(一个接收者)或广播(多个接收者按类型订阅)。
- T 与 P(类型与内容)type 决定消息的语义类别,payload 装载真正的任务内容,二者配合让接收方高效分派处理。
- ts(时间戳)记录消息产生的时间,用于乱序恢复、延迟统计和日志审计。
通信边界控制
办公室分区后,员工能不能去别的部门串门?当然可以,但要走流程:填访客登记、联系对接人、在公共会客室见面。直接闯进去翻东西是被禁止的。这种“串门制度”对应到多Agent系统,就是通信边界控制(Communication Boundary)。
通信边界不是抽象口号,而是系统在消息必经之路上设置的检查点。设计边界时的核心矛盾是:既要保证Agent不能直接读写彼此的私有上下文,又要让必要的协作通过受控通道正常发生。边界划得太松,私有数据会泄漏;划得太紧,协作链路会瘫痪。
工程上区分两种边界:显式边界是代码里明确写出的检查逻辑,例如消息必须经过网关校验、共享区读取前必须查询权限表;隐式边界是设计层面的约定,例如约定Agent A 绝不构造发给 Agent B 的管理命令。无论哪种,最终都归结为一个门禁函数 Gate:输入双方身份,由策略函数计算后返回放行或拒绝。任何一个请求在穿越边界时都必须经过这道门。
门禁的本质是“方便协作但不放行越权”。每个Agent清楚自己能去哪里、不能去哪里,整座“公司大楼”才能既开放又安全。
- Gate(a,b)(门禁函数)评估“从 Agent a 发起的请求能否到达 Agent b”的函数,返回值为放行或拒绝。
- Policy(a,b)=1(策略命中)系统的授权策略给出1,说明 a 对 b 的操作是被允许的,门禁放行。
- allow / deny(双值输出)门禁只有两种决定,不存在“半放行”。如需更细粒度,则由上层协议拆分为多条策略。
污染防护策略
食品车间有一条铁律:生食和熟食必须分线处理,交叉污染是重大事故。办公室里也一样,如果市场部把客户闲聊记录随手扔进研发部的需求文档,整个项目立刻乱套。多Agent系统的上下文,同样害怕这种“串味”。
上下文污染(Context Pollution)指无关、错误或过时的信息混入某Agent的上下文,导致模型产生错误判断或行为偏移。常见的污染源有三类:不设防的共享区写入、消息中携带的冗余噪音、过期状态未清理。防护的第一步是识别污染源——任何进入Agent上下文的文本,都该先回答一个问题:“这条信息跟当前任务相关吗?”
工程上可以用“纯净度”指标来量化污染程度:分子是当前任务相关的上下文片段数,分母是片段总数,比值越接近1越纯净。执行层面布置三道防线:入口过滤(写入前检查内容相关性)、定期清理(定时剔除过期或无关片段)、隔离墙(高风险数据不进任何Agent的即时上下文,只允许在受限查询时临时读取)。这三道防线配合,能把污染概率压到极低。
就像厨房里生熟分开、随手擦台面,多Agent系统的上下文也需要持续保洁。干净的上下文带来稳定的推理结果,而稳定的推理结果,才支撑得起可预测的系统行为。
- Purity(C)(上下文纯净度)衡量一个Agent的上下文中“有用信息”的密度,是污染程度的反向指标。
- N_relevant(相关片段数)与当前任务目标直接相关的上下文片段数量,是分子。
- N_total(总片段数)当前上下文中所有片段的数量,包括相关片段和噪音,是分母。
- 取值范围 [0,1]纯净度不会超过1,也不会小于0。低于某个阈值(如0.6)时,系统应触发清理或压缩流程。
膨胀控制技巧
公司档案室如果只进不出,几年后连过道都堆满文件柜,想找一份合同得翻三天。所以正规公司都有文件处理制度:旧合同扫描归档、废纸销毁、办公桌只放正在使用的文件。AI系统也一样,上下文不控制,就会膨胀到模型无法处理。
上下文膨胀(Context Bloat)是长生命周期Agent的常见病:对话轮次一多,完整历史记录把有限的上下文窗口撑满,token成本(也就是按字数计费的计算成本)飙升,模型还被海量噪音干扰得找不着重点。膨胀控制的本质,是给上下文做“空间管理”,让有限窗口里始终装载最高价值的信息。
最通用的手段是摘要压缩(Summarize):让LLM把早期对话提炼成一段概要,与近期完整消息合并成新上下文,信息量损失可控而体积大幅缩减。第二种思路是滑动窗口(Sliding Window):只保留最近K条消息的完整原文,更早的整段丢弃。更精细的系统会把已完结任务的上下文归档到外部存储(比如向量数据库),需要时再按语义检索回来,实现“内存虽小,外存无限”。
档案室定期整理,员工找资料才快。上下文定期压缩、滑动、归档,Agent的“工作记忆”才始终轻盈而准确。记住一句话:会遗忘的系统,才是健康的系统。
- C_old(旧上下文)超过设定轮次或时间的历史记录,完整保留会让token成本持续上涨。
- Summarize(摘要函数)由LLM执行压缩,把冗长历史提炼为要点式概要,保留骨架信息。
- C_recent(近期上下文)最近若干轮对话或任务的完整内容,保证近期信息的准确性和即时可得性。
- ∪(新并集)摘要块与近期块合并成新的上下文分区,旧内容不再占用完整窗口。
AI 应用场景
电商客服多Agent路由系统
阶段:多Agent编排与上下文管理
解决的问题:传统单Agent客服系统把售前、售后、物流所有信息塞进同一个上下文,用户问一句物流,模型却要翻完整个购物聊天记录,既慢又容易答非所问。分区后,每个客服Agent只看自己职责范围内的上下文,订单状态通过共享区受控读取。
具体案例:某电商平台部署“订单咨询”“售后处理”“物流跟踪”三个Agent,各自拥有独立上下文分区。用户提问先由路由器判别意图,分发给对应Agent;物流Agent需要订单号时,通过共享上下文读取订单状态的授权字段,而不是拷贝客服的全部对话。系统上线后,人工介入率下降40%。
多Agent代码评审流水线
阶段:多Agent协作与消息协议设计
解决的问题:代码评审需要三个视角——代码规范、安全隐患、性能瓶颈。若由一个Agent同时看待三个维度,上下文相互干扰,意见变得模糊。按视角分区后,每个评审Agent只关注自己的检查项,通过消息协议把结论汇总给主Agent。
具体案例:一家SaaS公司的CI流水线接入“规范评审Agent”“安全评审Agent”“性能评审Agent”。每个Agent收到同一个diff(代码变更),但各自的上下文只包含对应领域的检查规则和过往案例。评审结束后,三个Agent通过消息队列把结构化结论发给主Agent统一生成报告。结果精确率从68%提升到92%。
企业知识库多部门助手
阶段:上下文隔离与共享设计
解决的问题:企业为HR、财务、行政各建一个智能助手时,如果共用同一个知识库上下文,HR会看到财务数据,财务可能读到员工薪酬信息。采用分区+共享方案后,各部门助手有私有上下文,公司制度类文档放在共享区并做权限分级。
具体案例:某集团用该方法搭建内部助手矩阵:HR助手和财务助手共享“考勤制度”“报销流程”等公开文档,但各自的员工问询记录、审批历史作为私有状态互不可见。敏感字段(如薪酬)被隔离墙挡住,只有经授权的Agent在特定查询场景下可临时读取。审计时,每次越权尝试都有完整的消息日志。
Python 演示
# -*- coding: utf-8 -*-"""多Agent上下文分区与隔离机制演示""" class ContextPartition: """上下文分区管理器:每个Agent独立分区,共享区受控访问""" def __init__(self): self.agents_map = {} # agent_id -> 私有上下文记录 self.shared_pool = {} # 共享上下文(key -> value) self.msg_queue = [] # 消息队列 def register_agent(self, agent_id, allowed_shared=None): agent_info = { 'private_context': [], 'allowed_shared': set(allowed_shared or []) } self.agents_map[agent_id] = agent_info print("[注册] %s 已获得独立上下文分区" % agent_id) def write_private(self, agent_id, content): if agent_id not in self.agents_map: raise ValueError("Agent未注册") self.agents_map[agent_id]['private_context'].append(content) def read_private(self, agent_id): return list(self.agents_map[agent_id]['private_context']) def publish_shared(self, agent_id, key, content): self.shared_pool[key] = content self.msg_queue.append({'from': agent_id, 'type': 'publish', 'key': key}) def read_shared(self, agent_id, key): if key not in self.agents_map[agent_id]['allowed_shared']: self.msg_queue.append({'from': agent_id, 'type': 'denied', 'key': key}) return None return self.shared_pool.get(key) def send_msg(self, sender, receiver, payload): if sender not in self.agents_map or receiver not in self.agents_map: raise ValueError("消息两端必须已注册") msg = {'from': sender, 'to': receiver, 'type': 'msg', 'payload': payload} self.msg_queue.append(msg) def drain_queue(self): queue, self.msg_queue = self.msg_queue, [] return queue def compact_context(self, agent_id, keep_last=2): agent_info = self.agents_map[agent_id] ctx = agent_info['private_context'] if len(ctx) > keep_last: archive_size = len(ctx) - keep_last agent_info['private_context'] = ctx[-keep_last:] print("[压缩] Agent %s 已归档 %d 条旧上下文" % (agent_id, archive_size)) def demo(): system = ContextPartition() system.register_agent("客服", allowed_shared=["订单"]) system.register_agent("售后", allowed_shared=["订单"]) system.register_agent("物流", allowed_shared=["订单"]) system.write_private("客服", "张先生反馈商品破损") system.write_private("客服", "张先生希望补发新品") system.publish_shared("客服", "订单", {"order": "PO-001", "user": "张先生"}) order = system.read_shared("售后", "订单") print("[售后] 共享订单:", order) blocked = system.read_shared("物流", "工资单") print("[物流] 越权读取:", blocked) system.send_msg("客服", "售后", "请安排补发") for msg in system.drain_queue(): target = msg.get("to", "共享区") detail = msg.get("key", msg.get("payload", "")) print("[消息] %s -> %s | %s | %s" % (msg["from"], target, msg["type"], detail)) for i in range(5): system.write_private("物流", "物流节点 %d 更新" % i) system.compact_context("物流") print("[物流] 压缩后剩余上下文:", len(system.read_private("物流"))) if __name__ == "__main__": demo()
self.agents_map[agent_id] = agent_info每个Agent注册时获得独立的上下文分区记录,这是“独立办公室”的落地。'allowed_shared': set(allowed_shared or [])记录该Agent被授权访问的共享数据key白名单,如同办公室门禁卡上登记的权限。self.agents_map[agent_id]['private_context'].append(content)私有上下文只能由所属Agent自己追加写入,别人没有入口。if key not in self.agents_map[agent_id]['allowed_shared']:读取共享区前必须校验白名单,越权访问会被拒绝并记入消息队列。self.msg_queue.append(msg)所有跨Agent通信(发布、越权、发消息)统一进入消息队列,不直接触碰对方上下文。queue, self.msg_queue = self.msg_queue, []消费消息队列时原子替换,既拿到全部消息又避免并发重复读取。agent_info['private_context'] = ctx[-keep_last:]压缩时只保留最近 keep_last 条,旧内容整体归档,完成“档案室整理”。
常见误区
误区为了让Agent之间信息互通,我把所有上下文放到一个大池子里,每个Agent都能看到所有信息。这样实现最简单,协作也方便,为何要搞得那么复杂?
正解共用上下文会导致三宗罪——信息串扰、token浪费、职责边界模糊。就像所有部门共用一个文件柜:你拿错我的、我改错你的,出了问题无从追责。正确做法是每个Agent一个独立分区,信息共享走受控的共享区或消息协议。
为何常见:小规模Demo中单上下文确实能跑通,Agent数量少、任务简单时问题不明显,让人误以为放大规模也不会出问题。
误区既然是协作系统,共享的信息越多,Agent之间的配合应该越默契。所以我尽量把所有数据都放进共享区,谁需要谁自己取。
正解共享区信息过多会让读取方被无关信息干扰(污染),写入权限也难以收敛。应遵循“最小共享原则”:只共享必要的任务状态和结论,原始数据留在生产者的私有分区。就像公司公告栏只贴制度通知,不会把所有部门内部文档都贴上去。
为何常见:直觉上“信息多=协同好”,忽略了LLM对无关信息高度敏感,以及权限管理随共享范围扩大而指数级变复杂。
误区我给别的Agent发消息时,把这个Agent的完整对话历史都附带上,这样对方就能完全理解我的处境,回答更准确。
正解这会导致双重灾难:一是消息体积膨胀,token成本急剧上升;二是无关历史作为噪音污染接收方上下文。消息协议只应携带精简的任务信息(payload),对方需要更多背景时,通过共享区或发起查询来获取。
为何常见:单人使用LLM时“给足上下文”确实有效,开发者把单Agent习惯直接平移到了多Agent场景,忽略了消息是要被另一个Agent解析的系统数据。
误区既然要隔离,那就让每个Agent完全看不到别人,只通过消息联系,这样最安全。共享区也不要了,全都由主Agent转发。
正解过度隔离会破坏系统效能,所有交互都经主Agent转发会形成瓶颈和单点故障。合理的设计是“分区私有 + 消息通信 + 受控共享”三者的结合:私有数据严格隔离,协作数据走协议,公共数据放在带权限的共享区。隔离的目的是可控,不是封闭。
为何常见:把“隔离”理解成“隔绝”,忽略了多Agent系统存在的意义就是协作。安全与效率之间的平衡,才是隔离设计的真正难点。
面试题
Q1. 多Agent系统中,上下文分区的主要目的是?
- A.降低存储空间开销
- B.避免Agent之间串扰← 正确答案
- C.加快模型推理速度
- D.简化网络配置方案
答案:B。分区隔离的核心目标是避免信息串扰和职责混乱。就像公司给每个部门独立办公室,目的是让各部门专注自己的工作,而不是为了省空间或加速。B正确,A、C、D是可能附带的好处而非主要目的。
Q2. 在状态隔离设计中,“共享状态”最适合的比喻是?
- A.员工的私人保险柜
- B.公司门口的公告栏← 正确答案
- C.个人办公笔记本
- D.部门内部档案柜
答案:B。共享状态的特点是“多个人可按权限读取、写入需受控”——这正是公告栏的属性。私人保险柜和笔记本对应私有状态,部门档案柜虽然可多人访问但有严格权限,更接近受控共享,但公告栏的“公开且按规则发布”特性最贴切。
Q3. 消息协议五元组中,payload 字段的核心作用是什么?
- A.判定消息的类型
- B.指明接收方地址
- C.携带任务详细内容← 正确答案
- D.记录发送的时间
答案:C。payload 就是信件的正文,装载消息真正要传达的任务内容。type 负责分类、receiver 负责寻址、ts 负责时序,都与正文无关。C正确。A对应type,B对应receiver,D对应ts。
Q4. 以下哪些属于预防上下文污染的有效手段?
- A.按职责隔离上下文分区← 正确答案
- B.共享区写入前清洗校验← 正确答案
- C.限制共享区写入权限← 正确答案
- D.把数据复制给所有Agent
答案:ABC。按职责分区让Agent只看相关数据,写入前清洗校验能拦截垃圾内容,限制共享区写入权限能防止越权污染——这三者都是防污染防线。D恰恰是污染的主要来源之一,把数据无条件复制给所有Agent必然引入大量无关噪音。
Q5. 上下文膨胀控制中“压缩策略”的核心思路是?
- A.删除所有历史消息
- B.旧内容摘要保留近期完整← 正确答案
- C.把上下文移到共享区
- D.扩大上下文窗口尺寸
答案:B。压缩策略的精髓是“旧内容提炼成摘要,近期信息保留完整”,既保留知识骨架又控制体积。A粗暴删除会损失关键信息,C只是转移问题,D治标不治本——窗口再大也有穷尽时。
Q6. 设计Agent通信边界时,以下做法正确的有哪些?
- A.禁止Agent之间互访私有上下文← 正确答案
- B.通信须经消息协议通道← 正确答案
- C.共享上下文做权限分级← 正确答案
- D.允许任意读取私有状态
答案:ABC。私有上下文互不可见是隔离的底线,通信必须走协议通道才可追踪,共享区权限分级才能控制敏感数据——ABC都是正确边界设计。D直接打破私有状态隔离,会造成数据泄漏与职责混乱。
Q7. 当一个Agent需要另一个Agent的中间处理结果时,最合理的做法是?
- A.直接读取对方私有上下文
- B.通过消息协议请求结果← 正确答案
- C.复制对方全部上下文
- D.合并两个Agent为一个
答案:B。通过消息协议发起请求,让对方以消息形式返回结论,既获得信息又不破坏隔离。A和C都越过了私有上下文边界,D则破坏了职责分工,都是错误做法。
Q8. 关于上下文生命周期管理,以下哪种说法是正确的?
- A.上下文创建后永久保留
- B.任务完成及时清理归档← 正确答案
- C.生命周期只对共享区有效
- D.私有上下文不需管理
答案:B。上下文应随任务生命周期推进而清理和归档,这是防污染和防膨胀的共同要求。A永久保留必然导致膨胀,C和D都错误——共享区和私有区都有生命周期,私有上下文同样需要定期整理。
Q9. 多Agent消息协议中“路由寻址”要解决的根本问题是?
- A.消息格式的编码规则
- B.消息找到正确的接收Agent← 正确答案
- C.消息内容的加密方式
- D.消息生成的具体逻辑
答案:B。路由寻址就是“这封信该送到哪间办公室”,靠sender和receiver字段完成。A是协议格式问题,C是安全传输问题,D是内容生成问题,都不属于寻址范畴。
Q10. 以下哪些策略能有效控制多Agent系统的上下文膨胀?
- A.定期对旧内容做摘要压缩← 正确答案
- B.滑动窗口保留最近消息← 正确答案
- C.完结任务归档到外部存储← 正确答案
- D.每次请求重复完整历史
答案:ABC。摘要压缩在体积和质量间取平衡,滑动窗口限制即时窗口大小,外部归档实现“内存有限、外存无限”。ABC都是经典的膨胀控制手段。D恰恰是膨胀的根源,每次请求都携带完整历史会让token成本无限增长。