LangChain 多工具协作:一个 Agent 不够用时怎么办
个人主页 for_ever_love__ 欢迎各位大佬莅临其他栏目: 大模型开发从0到1 其他栏目: iOS项目总结大全 其他栏目: 我想学python了 其他栏目: iOS UI 文章目录LangChain 多工具协作一个 Agent 不够用时怎么办一、先理解问题根源工具越多越不准二、解法一工具分组 路由先试这个2.1 用 RunnableBranch 做路由2.2 更省的做法用关键词/规则先兜一层三、解法二多 Agent 分工Supervisor 模式3.1 手写 Supervisor3.2 官方的 langgraph-supervisor四、两种方案怎么选五、多 Agent 的三个坑5.1 消息爆炸5.2 无限来回5.3 子 Agent 抢活六、小结LangChain 多工具协作一个 Agent 不够用时怎么办给一个 Agent 挂十几个工具很快就会发现它开始乱选该查天气的去查了数据库该下单的去搜了网页。这篇讲两种解法——工具分组路由和多 Agent 分工以及什么时候该用哪个。一、先理解问题根源工具越多越不准这不是玄学有三个实际原因schema 占用上下文每个工具的名称、描述、参数都要送进 prompt20 个工具能吃掉几千 token挤压真正的任务信息选择空间变大模型要在 20 个选项里挑一个描述稍微有点重叠比如search_doc和search_wiki就会选错注意力稀释长 schema 列表里排在中间的工具容易被忽略。经验阈值单个 Agent 的工具数控制在 10 个以内超过就要拆分。二、解法一工具分组 路由先试这个思路不把所有工具都给一个 Agent而是先判断任务类型再把对应的一组工具注入进去。用户提问 ↓ 路由一次轻量 LLM 调用只做分类 ↓ ┌────────┬────────┬────────┐ 订单组 物流组 售后组 (3工具) (2工具) (4工具) ↓ 对应 Agent 执行2.1 用 RunnableBranch 做路由fromlangchain_core.runnablesimportRunnableBranch,RunnableLambdafromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.output_parsersimportStrOutputParser route_promptChatPromptTemplate.from_template( 判断下面的用户问题属于哪一类只输出一个词order / logistics / service / other 问题{question} )routerroute_prompt|llm|StrOutputParser()defbuild_agent(category:str):tool_map{order:[search_order,list_orders,cancel_order],logistics:[query_logistics,change_address],service:[create_ticket,refund,send_email],}toolstool_map.get(category,[])ifnottools:returnNonereturncreate_react_agent(llm,tools)defhandle(question:str):categoryrouter.invoke({question:question}).strip()agentbuild_agent(category)ifagentisNone:returngeneral_chain.invoke(question)returnagent.invoke({messages:[(user,question)]})路由本身只是一次极轻的 LLM 调用输出一个词代价远小于给 20 个工具让模型慢慢挑。2.2 更省的做法用关键词/规则先兜一层能不调 LLM 就别调importre RULES[(r物流|快递|发货|签收|单号,logistics),(r退款|退货|投诉|发票,service),(r订单|下单|购买|支付,order),]defcheap_route(question:str):forpattern,catinRULES:ifre.search(pattern,question):returncatreturnNonedefhandle(question:str):catcheap_route(question)orrouter.invoke({question:question}).strip()...规则命中率高的话能省掉大部分路由调用。规则没命中再降级到 LLM 分类。这是典型的快慢结合。三、解法二多 Agent 分工Supervisor 模式当任务真的复杂到需要多个角色各自推理、再汇总时才上多 Agent。典型结构┌────────────┐ │ supervisor │ ← 负责分派和汇总 └──────┬─────┘ ┌──────────┼──────────┐ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │research │ │ code │ │ writer │ │ Agent │ │ Agent │ │ Agent │ └─────────┘ └─────────┘ └─────────┘supervisor不干活只判断下一步交给谁和是不是可以结束了子 Agent各自有专门的工具和 prompt只负责自己那一摊。3.1 手写 SupervisorfromtypingimportLiteralfrompydanticimportBaseModelfromlanggraph.graphimportStateGraph,MessagesState,START,ENDfromlanggraph.prebuiltimportcreate_react_agentfromlanggraph.typesimportCommand# --- 子 Agent ---research_agentcreate_react_agent(llm,[web_search,read_page],prompt你负责搜集资料只做检索不写结论。)code_agentcreate_react_agent(llm,[run_python,read_file],prompt你负责写代码并运行验证只做计算不写文章。)# --- Supervisor 的决策 schema ---classRoute(BaseModel):next:Literal[research,coder,FINISH]supervisor_llmllm.with_structured_output(Route)defsupervisor(state:MessagesState):respsupervisor_llm.invoke([(system,你是团队主管。根据对话进展决定下一步交给谁。research需要查资料coder需要算数据FINISH信息够了可以结束。),*state[messages],])return{next:resp.next}defcall_research(state:MessagesState):resultresearch_agent.invoke({messages:state[messages]})return{messages:result[messages][-1:]}defcall_coder(state:MessagesState):resultcode_agent.invoke({messages:state[messages]})return{messages:result[messages][-1:]}# --- 组装图 ---graphStateGraph(MessagesState)graph.add_node(supervisor,supervisor)graph.add_node(research,call_research)graph.add_node(coder,call_coder)graph.add_edge(START,supervisor)graph.add_conditional_edges(supervisor,lambdas:s[next],{research:research,coder:coder,FINISH:END,})graph.add_edge(research,supervisor)graph.add_edge(coder,supervisor)teamgraph.compile()要点子 Agent 的返回只取最后一条消息塞回主 state否则主对话会被子 Agent 的中间过程撑爆supervisor 用with_structured_output保证输出可控每个子 Agent 的 prompt 要明确边界“只做检索不写结论”否则它们会互相抢活。3.2 官方的 langgraph-supervisor不想手写可以用官方包pipinstalllanggraph-supervisorfromlanggraph_supervisorimportcreate_supervisor workflowcreate_supervisor([research_agent,code_agent,writer_agent],modelllm,prompt你是一个三人团队的主管合理分派任务最后汇总成一个完整报告。,)appworkflow.compile()它帮你处理了消息传递、路由、终止条件这些样板代码。但建议先手写一遍理解原理再用官方包不然出了问题不知道怎么调。四、两种方案怎么选维度工具分组路由多 Agent 分工复杂度低高LLM 调用次数少1 次路由 1 个 Agent多每轮 supervisor 子 Agent延迟低高适用场景任务一次就能归到某一类任务需要多角色接力调试难度低高决策依据任务是否需要接力。“帮我查一下这个订单的物流” → 一类工具搞定 →分组路由“调研一下竞品写份分析报告” → 要先检索、再分析、再写作 →多 Agent。能用分组路由解决的别上多 Agent。多 Agent 的成本是数倍增长的而且调试非常折磨人。五、多 Agent 的三个坑5.1 消息爆炸子 Agent 跑 5 步就有 10 条消息全塞回主 state几轮下来上下文就满了。解法只回传结论。defcall_research(state:MessagesState):resultresearch_agent.invoke({messages:state[messages]})# 只取最终那条 AI 消息并重标记来源finalresult[messages][-1]return{messages:[AIMessage(contentf[调研结果]{final.content},nameresearch)]}用name字段标记来源supervisor 能分得清是谁说的。5.2 无限来回supervisor 可能让 research 和 coder 反复横跳。解法限制轮数。classState(MessagesState):rounds:intdefsupervisor(state:State):ifstate.get(rounds,0)6:return{next:FINISH}...return{next:resp.next,rounds:state.get(rounds,0)1}5.3 子 Agent 抢活没有明确边界时research 也会写结论writer 又去检索一遍。解法prompt 里写死不做什么比写要做什么更重要你是资料检索员。 只做使用搜索工具收集信息返回原文要点。 不做不要分析、不要下结论、不要撰写报告、不要调用其他角色的工具。六、小结工具超过10 个就要拆否则模型选择准确率明显下降先试工具分组路由一次轻量分类 → 注入对应工具组代价小效果好路由可以规则优先、LLM 兜底省调用多 Agent 只在任务需要多角色接力时才上Supervisor 模式子 Agent 只回传结论用name标记来源、限制轮数、prompt 里写死不做什么官方langgraph-supervisor能省样板代码但建议先手写一遍理解原理。下一篇讲 LangGraph 的 State 设计——多节点之间怎么安全共享数据。