ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

自研多智能体编排框架MAF:L1-L5安全分级与工程落地实践

自研多智能体编排框架MAF:L1-L5安全分级与工程落地实践 上周整理团队AI项目矩阵时翻到一份《通用型AI智能体L1-L5分级安全框架白皮书》。那段时间正好被多个开源智能体框架的选型搞得焦头烂额一边是LangChain这类重生态的编排库一边是Coze这类托管平台还有各种RAG中间件、记忆服务、工具网关。项目越做越觉得真正卡住生产环境的不是某个模型能力不够强而是当多个Agent需要分工协作、共享上下文、互相调用工具时缺乏一套统一的“调度和管控底座”。这也是我后来决定自己动手维护一个名为MAF的智能体框架的初衷。这个框架不是什么颠覆性发明更准确的定位是“面向生产环境的轻量级多智能体编排框架”代码量大头不在Agent推理本身而在任务路由、状态收敛、工具鉴权和分级安全控制。这篇文章我会把MAF的核心设计思路、编排机制、L1-L5安全分级怎么落地、以及最容易翻车的几个场景完整拆开来讲。无论是准备自研Agent框架的技术负责人还是刚接触多智能体编排的同学应该都能从中找到可以直接抄作业的部分。1. 为什么在多智能体场景下我最终选择了自研MAF1.1 单一Agent的瓶颈能力再强也扛不住横向拆解先说一个很现实的问题很多团队一开始的Agent项目只有一个模型实例所有任务都塞进同一个Prompt。初期原型跑得欢但一旦进入生产缺陷立刻暴露。最典型的是三类问题上下文窗口冲突让一个Agent同时管理用户会话、检索数据库、生成报告即使模型支持很长的上下文几轮工具调用下来也会出现指令遗忘或者把上一轮检索到的数据误用到这一轮的生成里。工具权限边界模糊所有工具挂在同一个Agent下面意味着一个写SQL的工具和一个发邮件的工具拥有同等调用权。结果就是Agent偶尔会做出“越权”的动作——你让它查订单量它顺手把订单明细导出并发送了。失败恢复成本高一个Agent执行链路中如果某个环节出错整个任务要么重跑要么返回一堆无意义的部分结果。没有子任务级别的隔离就没有子任务级别的重试。这些问题的本质是“推理实体”和“执行单元”没有做职责拆分。MAF的思路很直接把Agent当作可注册、可调度的计算节点每个节点有自己的职责边界、工具白名单和状态生命周期框架层面统一处理任务分发、上下文隔离和结果聚合。1.2 与主流框架对比MAF到底节省了什么成本做选型的时候不是没考虑过直接用现成框架。我以实际工程视角做了个简单对照对比维度通用编排框架如LangChain/LangGraph类托管式平台如Coze类MAF自研定位架构自由度高但编排逻辑复杂时理解成本高低受平台约束高编排逻辑可视化自控工具接入依赖生态适配器跨系统需二次开发受平台内置连接器限制统一工具协议HTTP/CLI/SDK均可接入安全策略需要自行组合组件无内置分级体系平台级策略定制困难内置L1-L5分级安全模型策略可编程可观测性依赖第三方链路追踪平台内监控数据出不来内置执行轨迹录制与回放生产级部署可部署但需大量加固开箱即用但绑定容器化部署核心依赖极少选择自研不是觉得开源框架不好而是我需要的“策略可控性”和“执行可观测性”很难在通用框架里同时满足。特别是L1-L5分级安全框架这套东西如果建立在第三方抽象之上每次安全策略升级都要跟着上游版本走风险不可控。2. MAF的核心抽象四个对象关系拆解2.1 Agent不是“一个人”而是“一个可执行上下文”MAF里每个Agent本质上是一个封闭的执行环境内部包含四个东西模型配置哪个模型、什么温度、什么System Prompt、工具白名单、状态存储、失败策略。对外只暴露三个接口接收消息、返回结果、报告状态。这种设计的关键好处是上下文隔离。Agent A的System Prompt、工具调用历史、中间变量永远不会泄漏给Agent B除非通过框架的专用消息通道显式传递。这从根上解决了多Agent互相“串话”的问题。Agent的实现代码如下所示from maf import Agent, ToolSpec agent Agent( nameorder_analyzer, model{provider: openai, name: gpt-4o, temperature: 0.2}, system_prompt你是订单数据分析助手只负责查询和分析订单数据。, tools[ ToolSpec(namequery_orders, permission_level3), ToolSpec(nameexport_report, permission_level2), ], state_storeredis://localhost:6379/0, max_iterations6, )permission_level就是L1-L5安全分级在工具层的贯穿点后面第4节会详细展开。2.2 消息不是“一句话”而是“带路由信息的信封”在MAF里Agent之间不直接对话全部通过框架的消息总线传递。消息结构包含5个字段{ message_id: msg_20250321_0001, source: router, target: order_analyzer, task_type: analysis_task, payload: {date_range: 2025-03-01~2025-03-20}, metadata: { trace_id: trace_8f3a2b, max_hops: 5, timeout_ms: 30000 } }task_type字段是路由的核心依据每个Agent注册时声明自己能处理的task_type列表路由表基于声明而非模型推理。这意味着任务分发是确定性行为不依赖模型“猜该发给谁”。trace_id则是整个执行链路可追踪的基础。2.3 Tool规范一切可执行能力都是HTTP资源每个Tool在框架内部被描述为一个标准HTTP调用。不管底层是Python函数、Shell脚本还是外部API统一包装成tools: - name: query_orders endpoint: http://tool-gateway:8080/query_orders method: POST timeout_ms: 15000 permission_level: 3 input_schema: date_range: string category: optional_string output_schema: order_count: integer total_amount: float rate_limit: calls_per_minute: 30这个设计的收益很实在Tool的调用权限、频控、超时会话全部集中在Tool Gateway层控制。Agent模型永远接触不到真实的数据库地址或API密钥它只能看到“有一个叫query_orders的东西可以查订单”——具体的凭据管理、网络策略、资源访问全部由Gateway代理完成。2.4 Policy模块安全策略的“法律层”MAF里有一个常驻的Policy Engine负责在消息投递前、工具调用前、结果返回前三个节点做策略校验。校验规则用声明式配置编写例如policy: - rule: order_analyzer_tools_limit action: allow condition: agent: order_analyzer tool_whitelist: [query_orders, export_report] effect: enforce_tool_whitelist - rule: block_pii_exfiltration action: deny condition: data_contains: [email, phone, id_card] tool_invokes_network: true effect: block_and_alertPolicy Engine的决策不进入模型推理上下文完全在框架内核执行。这意味着Agent无论如何诱导都无法绕过已经加载到内核的策略决策。这也是我坚持把Policy放在框架核心而不是放在Agent Prompt里的根本原因——Prompt会被模型“重新理解”而内核代码不会。3. MAF的编排机制从任务分解到结果收敛3.1 三种基础编排队形MAF内置三种任务编排原语所有复杂剧本都由它们组合而成。顺序流水线Pipeline任务按声明顺序依次经过Agent链每个Agent的输出是下一个Agent的输入。适合信息提取、净化、格式化这类线性流程。星型路由器Router一个Router节点收到任务后根据任务类型分发到不同叶子Agent叶子结果汇总回Router。适合分类分诊、并行检索场景。令牌环Token Ring多个Agent按环形拓扑传递同一个任务令牌每个节点只能修改任务令牌中的指定字段。适合多角色协作编辑、多方决策场景。有一次做跨部门汇报数据聚合我用了Router三路Pipeline的组合。一个路由Agent把请求拆成销售、供应链、客户成功三条Pipeline每路各自完成取数、清洗、摘要三步最后统一汇入一个汇总Agent。整体耗时从旧的“单Agent串行跑全流程”的3分20秒降到了55秒而正确率还高了不少——因为每个子任务都在自己的上下文里执行没有互相污染。3.2 任务状态机与收敛策略多Agent框架最怕的就是“跑飞”A让B做事B又让A帮忙两边互等任务永远不结束。MAF每个任务实例都有严格状态机PENDING → RUNNING → WAITING_AGENT → WAITING_TOOL → COMPLETED或FAILED。框架推动状态流转时不依赖模型自觉而是靠三个硬性收敛参数task: max_hops: 6 # 任务最多经过6个Agent防止踢皮球式循环 max_iterations: 12 # 单个Agent最多执行12轮工具调用 global_timeout_s: 120 # 全局硬超时超时直接判FAILED并触发补偿同时引入Human-in-the-Loop机制当同一任务的两个Agent产出结论冲突或置信度低于阈值时任务自动进入WAITING_USER状态等待人工仲裁。仲裁结果会写入案例库作为后续类似冲突的参考先例——这是MAF收敛能力提升的重要数据资产。3.3 上下文共享不能没有也不能全给多Agent协作必须解决上下文共享问题但共享粒度直接决定安全边界。MAF采用三级共享模型全局上下文任务级不可变元数据如任务ID、发起时间、数据使用许可声明。所有Agent只读。共享工作区一个KV Store允许Agent写入指定key但每个key有独立的可见性配置。Agent A可以只看到自己写入的key和显式授权的key。私有记忆Agent自身状态库其他Agent不可见。这个三级模型相当于把“聊天记录可见范围”的权限思维移植到了Agent协作场景。实际效果是编排脚本里可以明确写“Agent B只能看到Agent A写入的summary_前缀key”B的上下文里就物理上不会出现A的其他内部数据。4. L1-L5分级安全框架在MAF里的实际落地4.1 分级不是为了限制而是为了让Agent“知道自己几斤几两”L1-L5分级安全框架的核心思想是不同复杂度和自治程度的Agent必须被赋予不同级别的权限并接受对应的审计强度。打个比方一名实习生和一位VP能审批的金额上限和使用公司印章的权限一定不同。AI Agent虽然不会恶意但它会“误用”——没有分级一个只该读报表的Agent拿着全部数据库权限迟早惹祸。MAF实现的分级如下级别定位权限特征审计强度L1单次工具调用只能调用白名单内无副作用工具如查询类API每次调用记录入参出参L2限定任务流程可调用有状态工具但禁止跨域访问记录完整工具调用链L3数据敏感操作可处理PII/敏感数据强制脱敏后输出全链路数据血缘追踪L4跨系统协作可调用变更类工具写库、发消息需二次授权操作前审批变更后审计L5长期自治可在沙箱内自主决策并执行多步变更具备熔断能力实时行为监控定期压力复评4.2 L1-L2工具白名单与副作用控制L1的实现最轻在Tool Gateway层面维护一张白名单表未注册的Endpoint直接拒绝。副作用检查靠idempotent标记白名单内所有POST工具必须声明幂等键Gateway对相同幂等键的重复请求直接返回第一次的结果。L2在L1基础上增加“任务级工具上下文”。比如一个L2 Agent处理“查询订单并计算环比”它在一个连贯任务中使用了多个工具框架会把所有工具调用串成有向无环图。如果Agent想“跳过某一步骤直接执行后面的工具”框架会评估依赖链是否完整不完整则挂起任务等待补充——这防止了Agent在部分数据未获取的情况下做出基于残缺信息的行动。4.3 L3脱敏与数据血缘L3是很多做数据业务的团队必须跨过的门槛。MAF在L3主要做了三件事自动识别基于正则小型NER模型对工具返回值做PII扫描命中即标记字段级敏感标签。强制脱敏如果目标Agent的权限级别低于L3敏感字段在投递前自动替换为掩码。即使上游Agent是L4也不能把未脱敏数据直接丢给L2下游。血缘记录每个敏感字段从哪个工具返回、经过哪个Agent、最终被写入哪个目标系统全部记录在案。这直接支撑了安全审计和数据合规。这条链路里有个看起来简单但实际很坑的细节脱敏必须做在“Agent上下文投递前”而不是“工具返回后”。因为工具返回后数据还在框架内存里Agent发起下一轮推理时依旧可能间接接触到原始值。MAF在L3强制用“脱敏后的消息体”重建Agent的上下文轮次原始值只保留在内存审计区等待清理。4.4 L4变更类操作的二次授权当Agent要执行写操作、发送消息、删除资源这类变更动作时MAF会触发授权令牌机制。Agent发出变更请求后工具不会立即执行而是生成一个授权任务推送给策略审核人员或审批接口。只有拿到有效授权令牌变更请求才会被Tool Gateway接受。这里我用了一个很管用的配置按操作“影响范围”设置审批阈值。影响范围小于阈值的比如只更新一条自己创建的状态记录Agent可以自主完成影响范围超过阈值的比如批量发送通知、全量更新配置必须人工点击审批。这样既避免Agent行使权力又不让审批流程拖垮效率。4.5 L5自治沙箱与熔断回路到了L5级别Agent被允许在较长周期内自主规划并执行一系列操作。这里最忌惮的是“单一假设持续错误”——Agent一开始理解错了目标后面所有步骤都会顺着错的方向狂奔。我自己的经验是L5必须满足三个前置条件沙箱隔离Agent只能在隔离环境内执行操作外部系统通过网关代理访问任何异常流量可被网关切断。定期快照与回滚每次变更步骤执行前自动快照状态支持一键回滚到最后成功快照。熔断回路实时监控成功率、拒识率、工具错误率。任何一个指标连续N次超过阈值主动降级为L4——需要人工确认才能继续执行变更。有一次自动化营销Agent在沙箱里跑着跑着因为目标用户画像数据源临时返回了异常格式导致连续生成的几条推送文案都指向了错误人群。放在L4第二次异常就会触发人工确认但L5沙箱里因为有熔断回路第八次异常自动触发了降级把没发出去的文案全部扣留在网关。复盘时发现如果没这套机制最后十几条推送会全部发错对象那才是真正的灾难。5. MAF落地实录从零搭一个最小多智能体系统5.1 环境准备与依赖清单MAF整体采用“内核扩展”架构核心运行时依赖极少。以下是我们在测试环境搭的最小集群组件配置说明Python运行时3.11MAF内核基于asyncio对版本有要求Redis6.2状态存储与消息总线兼容Redis ClusterPostgreSQL14审计日志与执行轨迹持久化容器运行时Docker 24Gateway与Agent节点容器化模型服务OpenAI兼容接口可对接任意OpenAI兼容服务安装MAF内核只需要一条命令pip install maf-core5.2 最小三Agent系统配置我搭了一个“查询-分析-报告”的三Agent最小系统。先定义Agent注册文件agents: - name: data_fetcher level: L1 tools: [query_orders, query_users] model: {name: gpt-4o-mini, temperature: 0} system_prompt: 你只负责调用工具获取原始数据不做任何分析。 - name: analyst level: L3 tools: [calc_kpi, trend_analysis] model: {name: gpt-4o, temperature: 0.1} system_prompt: 你负责分析数据并输出结构化结论不得请求任何非白名单工具。 needs: [summary_prefix_data] - name: reporter level: L2 tools: [generate_markdown, send_to_channel] model: {name: gpt-4o-mini, temperature: 0.4} system_prompt: 你负责把分析结论整理为报告并推送。注意needs字段——analyst声明自己需要读取data_fetcher写到共享工作区里的summary_前缀数据框架在路由时自动注入这部分数据而不是把data_fetcher的全部上下文拷贝过去。这就是前面说的“按需共享”的配置体现。创建编排脚本from maf import Pipeline, Task pipeline Pipeline( namedaily_report_pipeline, steps[data_fetcher, analyst, reporter], ) task Task( task_typereport, payload{date_range: 2025-03-20}, ) result await pipeline.run(task) print(result.status, result.summary)跑通这个最小系统只要半小时。但重点不在于“能跑”而是验证三个关键行为查询Agent是否严格按声明只执行L1工具分析Agent是否只接收到声明需要的共享数据报告Agent对L4级别的发送动作是否触发了授权令牌这里我配置成send_to_channel的权限LEVEL4Pipeline直接跑会挂起等待审批故意留着做链路验证。5.3 28天压测后的三个关键发现系统跑了28天处理了大约2600个真实业务请求我总结出三个值得记录的现象状态存储延时会拖慢Agent节奏一开始状态存储放在PostgreSQL单库Agent每次迭代都要写状态在并发请求较高时锁等待明显。后来把状态存储全量切换到RedisPostgreSQL只承担审计日志整体P95延迟降低了约40%。共享工作区需要配置TTL开始共享key没有过期时间导致陈旧数据被下游Agent误用。后来统一加上了与任务生命周期绑定的TTL任务结束自动清理。Prompt里声明权限不如框架里声明权限早期我试图让Agent“根据System Prompt约定不使用某工具”结果压测中多次出现Agent在复杂任务中“忘记”约定并请求了禁止工具。自从权限声明改为框架级配置文件后这个问题消失了——因为Tool Gateway直接拒绝了未授权工具的调用请求表现层再怎么“忘事”也无所谓。6. 翻车场景复盘多Agent编排最容易踩的四个坑6.1 两个Agent互相“踢皮球”导致任务死循环现象编排了一个“讨论型”任务Agent A和Agent B对同一个问题各执一词互相把任务令牌推给对方直到达到max_hops上限才被强制终止。整个过程浪费了8次模型调用和约40秒时间。排查打开执行轨迹后发现这两个Agent的职责定义有重叠——A的System Prompt里写着“你可以把无法处理的事情交给B”B的Prompt里也写了“你可以把需要复核的事情交回给A”。结果就是任何任务只要有一点模糊两边就互相推。修复两个层面同时下手。框架层面严格限制max_hops并增加“同一Agent被重复触发次数限制”超过2次直接上报而不是继续转发。业务层面重新划分职责边界明确哪类任务A必须自行完成、哪类任务B不允许回抛。6.2 Agent在推理中产生了“工具幻觉”调用了不存在的工具现象某个Agent在回答“上月GMV”时模型自己编造了一个叫get_gmv_last_month的工具调用而且“看起来”成功了——因为Tool Gateway对未注册Endpoint返回了一个404 ToolNotFound错误但模型把这个错误解析成“工具不存在我告诉你结果吧”的常规错误没上报给编排层。排查追踪日志显示Gateway返回的404 ToolNotFound被Agent当作“该工具不可用”的正常分支于是模型直接生成了编造结果并继续后续步骤。修复在Tool Gateway协议里增加“未注册工具”专属错误码ERR711并规定任何Agent收到该错误码必须终止当前任务链并上报不允许自行“合理推断”。同时给所有工具响应增加了schema校验编造结果无法通过output_schema约束条件时也会触发失败。6.3 全局上下文里塞入了无关数据导致Agent被“带偏”现象一个数据分析Agent在某次任务中生成了带强烈倾向性的结论后续所有结论都顺着这个倾向走。排查发现是因为共享工作区里残留了另一个任务的营销文案数据该Agent在检索共享key时命中了这些文案把它们当成了分析依据的一部分。修复两处修改。共享工作区key全部增加“任务ID前缀”做软隔离检索时强制过滤非当前任务ID的key。同时对所有Agent接收到的共享数据做来源标记模型上下文里明确区分“这是任务数据”和“这是可能的参考信息”避免把偶然检索到的数据当作事实输入。6.4 高并发下事件顺序错乱消息“后发先至”现象50并发压测时Router把任务分发给三个Agent要求结果统一汇总。但汇总Agent收到的结果顺序错乱——一个本该先完成的预处理结果反而在最终结果到达之后才返回导致汇总脚本把中间态当成了终态输出。排查事件总线采用了Redis List做队列但分发时用了并发消费出队顺序不保证与提交顺序一致。任务虽然带message_id汇总Agent却按到达顺序而不是按sequence处理。修复消息增加sequence_no字段每个分支任务的序号在Router创建时确定。汇总Agent按sequence_no聚合缺失时等待乱序时重新排序。后续又在Tool Gateway层增加了“乱序消息缓冲区”保证进入Agent上下文的序列永远是有序的。最后说两句实际的MAF这套框架走到今天踩过的坑远不止上面四个但我最深的体会是多智能体编排框架真正的护城河不是模型能力而是管控能力。模型迭代很快今天GPT-4能干的活明天可能一个更小的模型也能干但“一个Agent在什么条件下被允许调用什么工具、它的上下文里能出现什么数据、它的每一个决策如何被审计”这些规则一旦确定下来是不随模型版本变化而失效的。如果你打算在自己的团队里做类似的框架我的建议是先别追求功能大而全把L1-L5分级安全框架里的“L1-L3”先跑得极其扎实——工具白名单、数据脱敏、执行轨迹录制这三件事做到位系统就已经能扛住大部分线上需求了。L4和L5的审批流、熔断回路可以等业务复杂度真到了那一步再逐步加上去否则一开始就是一堆杀鸡用牛刀的策略堆积反而拖累研发进度。框架的代码我已经在内部仓库维护了大半年目前支撑着团队里七八个Agent应用的日常运行。上面这套设计思路和技术选型如果你也想动手复刻一版最值得投入时间的部分是第4节的安全分级和第3节的任务收敛机制——架构可以先糙但这两个地方绝对不能糙。
返回列表