写在前面:
复杂的Agent系统往往需要多个专业Agent协作完成一个任务。但问题来了:当一个用户请求到达时,应该由哪个Agent来处理?是让一个“主管Agent”做路由分发,还是让Agent们自己决定谁能处理?后者正是责任链模式的核心思想——将请求沿着一条“链”传递,直到某个节点有能力处理它。
这种模式天然适合Agent编排场景:多个Agent各司其职,互不干扰,还能灵活扩展。今天这篇文章,我会用最通俗的例子讲清楚责任链模式,再结合Agent系统的实际代码,展示如何用它构建灵活、可扩展的多Agent协作框架。
一、什么是责任链模式?
责任链模式(Chain of Responsibility)是一种行为设计模式,它允许将请求沿着处理者链传递,直到有一个处理者能够处理该请求为止。每个处理者都有机会处理请求,也可以选择将请求传递给下一个处理者。
核心要点:
解耦请求发送者和接收者
多个对象都有机会处理请求
处理者可以动态组成链
二、生活中的例子
例子1:公司报销审批
员工提交报销单 → 组长审批(500元以内权限)→ 经理审批(500-5000元)→ 总监审批(5000元以上)。每一级都有处理权限,无法处理就往上“甩锅”。
例子2:客服工单流转
用户提交问题 → 机器人客服 → 人工客服 → 技术专家。机器人处理不了就转人工,人工处理不了就升级。
例子3:技术面试
应届生面试 → 技术面(基础)→ 项目面(深入)→ HR面(薪资)。每一轮都有不同的考察侧重点,上一轮通过才进入下一轮。
这些例子的共同点:请求沿着一条预先定义的路径传递,直到找到能处理它的对象。
三、在Agent系统中的应用
3.1 场景描述
假设我们构建一个智能客服Agent系统,需要处理三类用户请求:
基础问答:如“你们公司的地址在哪?” → 由FAQ Agent处理
技术问题:如“如何配置API密钥?” → 由技术文档Agent处理
投诉建议:如“我要投诉客服” → 由人工转接Agent处理
传统做法:写一个巨大的if-else路由,判断关键词后调用不同Agent。问题:新增一种请求类型就要改代码,Agent之间耦合严重。
责任链模式解法:将每个Agent封装成一个处理器,按优先级串联成链,请求依次经过每个Agent,直到某个Agent声明“我能处理”。
3.2 代码实现(Java版)
// 1. 定义处理器抽象类 public abstract class AgentHandler { protected AgentHandler next; public void setNext(AgentHandler next) { this.next = next; } // 处理请求,如果不能处理则传递给下一个 public void handle(Request request) { if (canHandle(request)) { doHandle(request); } else if (next != null) { next.handle(request); } else { // 没有处理器能处理 System.out.println("没有Agent能处理该请求"); } } protected abstract boolean canHandle(Request request); protected abstract void doHandle(Request request); } // 2. 具体处理器:FAQ Agent public class FaqAgent extends AgentHandler { @Override protected boolean canHandle(Request request) { return request.getCategory() == Category.FAQ || request.getQuestion().contains("地址") || request.getQuestion().contains("电话"); } @Override protected void doHandle(Request request) { System.out.println("FAQ Agent 回答: " + answerFromKnowledgeBase(request)); } } // 3. 技术文档Agent public class TechDocAgent extends AgentHandler { @Override protected boolean canHandle(Request request) { return request.getQuestion().contains("API") || request.getQuestion().contains("配置"); } @Override protected void doHandle(Request request) { // 调用RAG检索技术文档 String answer = ragService.search(request.getQuestion()); System.out.println("技术文档Agent 回答: " + answer); } } // 4. 人工转接Agent public class HumanAgent extends AgentHandler { @Override protected boolean canHandle(Request request) { // 投诉类请求或前两个Agent都处理不了时,转到人工 return request.getCategory() == Category.COMPLAINT; } @Override protected void doHandle(Request request) { System.out.println("转接人工客服,工单已创建"); // 调用工单系统API } } // 5. 构建责任链 public class AgentChain { public static AgentHandler buildChain() { FaqAgent faq = new FaqAgent(); TechDocAgent tech = new TechDocAgent(); HumanAgent human = new HumanAgent(); faq.setNext(tech); tech.setNext(human); return faq; // 返回链头 } } // 6. 使用 public class Client { public static void main(String[] args) { AgentHandler chain = AgentChain.buildChain(); Request req1 = new Request("你们公司在哪?", Category.FAQ); chain.handle(req1); // FAQ Agent 回答 Request req2 = new Request("API怎么配置?", Category.TECH); chain.handle(req2); // 技术文档Agent 回答 Request req3 = new Request("我要投诉!", Category.COMPLAINT); chain.handle(req3); // 转接人工 } }3.3 责任链模式在Agent编排中的优势
3.4 进阶:支持并行+动态权重
实际Agent系统中,有时候需要多个Agent“投票”决定由谁处理,或者根据置信度分数选择最合适的节点。可以扩展责任链:
public class WeightedAgentHandler extends AgentHandler { private double confidenceThreshold; @Override protected boolean canHandle(Request request) { double score = calculateConfidence(request); return score >= confidenceThreshold; } private double calculateConfidence(Request request) { // 每个Agent根据自己的逻辑计算处理该请求的置信度 // FAQ Agent:关键词匹配度 // 技术Agent:向量相似度 return similarity; } } // 链遍历时收集所有能处理的Agent,选置信度最高的执行这种变体在多Agent协作框架(如AutoGen、CrewAI)中很常见:每个Agent声明自己的能力(Skills),调度器根据请求匹配最合适的Agent。
3.5 流程图:责任链驱动的Agent编排
四、总结
责任链模式在Agent编排中堪称“天然适配”——它将请求路由的职责分散到各个Agent节点,让每个Agent自己决定是否“接单”。相比中心化的路由分发,责任链模式带来了更好的扩展性、解耦性和动态性。
在Java生态中,Spring WebFlux的WebFilter、Servlet的FilterChain都是责任链模式的经典应用。而在AI Agent领域,无论是任务规划、工具调用、还是多Agent协作,责任链都能发挥巨大价值。
下次当你需要构建一个多Agent系统时,不妨先从责任链开始——它简单、可靠、易于理解,且足以应对大部分场景。
❓思考题:在你的多Agent系统中,如果多个Agent都声称“我能处理”同一个请求,你如何裁决?是给每个Agent打分选最高分,还是让第一个响应的优先?或者你用过其他编排模式(如黑板模式、发布-订阅)?欢迎分享你的实践。