多代理
你将学会: 先判断该不该拆;用 Skills(不换执行者)解决「领域知识太多」。
前置: 阶段 1~2。不要一上来就上多代理。
先问: 单代理是不是工具太多选错、是不是两块知识不该同时进上下文、是不是要并行?都不是就别拆。
| 模式 | 换执行者 | 先学 |
|---|---|---|
| Skills | 否,按需加载提示词 | 本课 |
| Subagents | 是,当工具调,上下文隔离 | 仓库加深 |
| Handoffs | 是,改状态切换阶段 | 仓库加深 |
| Router | 分类后分发 | 仓库加深 |
完整代码:Skills
from dotenv import load_dotenv
load_dotenv()
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
model = init_chat_model(
"deepseek:deepseek-chat",
temperature=0.5,
max_tokens=2500,
timeout=300,
max_retries=6,
)
SKILLS = {
"write_sql": "你是 SQL 专家。先写表假设,再给 SELECT,默认 LIMIT 10,并解释。",
"review_contract": "你是合同审查。列出金额/期限/违约,标风险,最后一句建议。",
}
@tool
def load_skill(skill_name: str) -> str:
"""加载技能正文。可用:write_sql、review_contract。"""
skill = SKILLS.get(skill_name)
print(f" [load_skill] {skill_name}", flush=True)
return skill or f"没有技能 {skill_name}"
agent = create_agent(
model=model,
tools=[load_skill],
system_prompt=(
"专业任务必须先 load_skill 再作答。"
"可用:write_sql、review_contract。"
),
)
r = agent.invoke({
"messages": [{"role": "user", "content": "写个查询:每个用户的订单数。"}]
})
print("调用 =>", [tc["name"] for m in r["messages"] if m.type == "ai" for tc in m.tool_calls])
print("回答 =>", r["messages"][-1].text[:300])
应看到 [load_skill] write_sql。这还是一个 agent,只是提示词按需灌入。
真的换执行者:子代理当工具
Skills 不够用时(两块知识不该同时进上下文、要隔离失败),把另一个 agent 包成工具。子代理每次都是全新上下文,主代理只拿到返回文本。
from dotenv import load_dotenv
load_dotenv()
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
model = init_chat_model(
"deepseek:deepseek-chat",
temperature=0.5,
max_tokens=2500,
timeout=300,
max_retries=6,
)
def search_docs(query: str) -> str:
"""搜索内部文档。"""
return f"关于「{query}」的文档结论:用 create_agent 即可,不必先画 LangGraph。"
research_agent = create_agent(
model=model,
tools=[search_docs],
system_prompt="你是调研专家。必须调用 search_docs,只用一句话给结论。",
)
@tool("research", description="调研一个主题并返回结论")
def call_research_agent(query: str) -> str:
result = research_agent.invoke({"messages": [{"role": "user", "content": query}]})
return result["messages"][-1].text
main_agent = create_agent(
model=model,
tools=[call_research_agent],
system_prompt="调研类问题必须调用 research 工具,不要自己编资料。",
)
result = main_agent.invoke({
"messages": [{"role": "user", "content": "调研:LangChain 里多代理怎么编排?"}]
})
print("主代理调用 =>", [
tc["name"] for m in result["messages"] if m.type == "ai" for tc in m.tool_calls
])
print("最终回复 =>", result["messages"][-1].text[:200])
应看到主代理调用 research。Handoffs(改状态切换阶段)和 Router(先分类再分发)见仓库,本课不要求手写。
练习
- 再问一句合同条款,确认加载的是
review_contract。 - 跑通上面的子代理脚本,口述:Skills 和 Subagents 谁换了执行者、谁隔离了上下文。
本章验收
- 能说出三种「值得拆」的信号
- 能独立写出
load_skill并跑通 - 能解释:子代理为什么「当工具调用」而不是再开一个聊天窗口
对照仓库:04-多代理/ 下 Handoffs / Router / Subagents 与四篇 Build 教程。
下一课:LangGraph
JavaWeb
Spring
MyBatis
linux
消息队列
JavaSE
工具
片段
AI
搜索
dy