系列文章第 4 篇 · AI Agent 六大主流架构拆解
本篇拆解 Router,解决一个入口、多个专长的分发问题,并把它落到油菜种植技术咨询这一典型多领域场景上。
什么是 Router
核心思想一句话:前置一个路由器,先把输入按意图/领域分类,再分发给对应的领域子 Agent,各自处理后再以统一格式返回。
一个最小运行单元:
1
2
3
4
5
6
7
| 用户问题
↓
Router 路由器:判定领域
↓
领域子 Agent A / B / C
↓
汇聚输出
|
示例背景:油菜种植技术咨询
油菜种植涉及多个专业领域:栽培(播期、密度、灌溉)、植保(菌核病、蚜虫等病虫害防治)、土肥(施肥方案、硼肥等)。农户或农技人员问一个问题,往往只对应其中一个领域。
如果用一个通用 Agent 回答所有问题,会面临三个麻烦:
- 提示词臃肿:必须把栽培、植保、土肥三套知识、三套工具都塞进同一份 system prompt,互相干扰。
- 工具冲突:一个通用 Agent 可能同时拿到栽培工具和植保工具,在不确定领域时乱调用。
- 效果天花板低:每个领域都有专业术语与最佳实践,通用 Agent 很难在每个方向上都做深。
Router 的做法是:对外只暴露一个问答入口,对内按问题领域分发给专门的栽培 Agent、植保 Agent、土肥 Agent。 每个子 Agent 只配自己领域的提示词和工具,Router 则只做一件事——判定这个问题属于哪个领域。
架构与运行机制

运行机制三要素:
- 统一入口:用户只面对一个入口,不需要提前选择领域。
- Router 路由器:根据输入语义判定领域/意图,返回路由结果(领域 + 理由)。
- 领域子 Agent + 结果汇聚:被命中的子 Agent 用专属提示词和工具处理问题,未命中时走兜底策略(通用 Agent 或追问澄清),最后统一格式返回给用户。
关键设计点:
- Router 只做分类,不做业务逻辑:它不应该自己生成最终答案,只决定交给哪个子 Agent。
- 子 Agent 之间尽量解耦:每个子 Agent 的系统提示、工具集、输出格式只关心自己的领域,降低相互干扰。
- 路由判定的准确率是瓶颈:一旦分错,后续子 Agent 再强也救不回来。因此 Router 的 prompt 要给出清晰的领域定义与示例,必要时加兜底或二次确认。
- 输出格式最好统一:各子 Agent 返回的格式应一致(例如都用「结论 + 依据」),否则前端拼接体验差。
基于 LangChain 的代码演示
定义三个领域工具
用 @tool + Pydantic args_schema 定义三个互不重迭的领域查询工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| from langchain.tools import tool
from pydantic import BaseModel, Field
CULTIVATION_DB = {
"播种期": "长江中下游直播油菜适宜播种期为 9 月下旬至 10 月中旬,移栽油菜可提前 7–10 天。",
"种植密度": "直播每亩留苗 2.0–2.5 万株,移栽每亩 0.6–0.8 万株。",
"灌溉": "蕾薹期与花期是需水关键期,保持田间持水量 70% 左右。",
}
PEST_DB = {
"菌核病": "油菜菌核病防治:花期用 50% 腐霉利可湿性粉剂 1000–1500 倍液喷雾,连防 2–3 次。",
"蚜虫": "蚜虫可用 10% 吡虫啉可湿性粉剂 2000 倍液或 25% 噻虫嗪水分散粒剂 5000 倍液防治。",
"菜青虫": "菜青虫可用苏云金杆菌(Bt)或氯虫苯甲酰胺防治。",
}
FERTILIZER_DB = {
"基肥": "每亩施腐熟有机肥 1000–1500 kg + 复合肥(N-P₂O₅-K₂O 15-15-15)30–40 kg。",
"追肥": "蕾薹期亩追尿素 5–8 kg,初花期喷施 0.2% 硼砂溶液防花而不实。",
"硼肥": "缺硼土壤在苗期和初花期各喷一次 0.2% 硼砂溶液。",
}
class CultivationInput(BaseModel):
keyword: str = Field(description="栽培关键词,如 '播种期'、'种植密度'、'灌溉'")
class PestInput(BaseModel):
keyword: str = Field(description="病虫害关键词,如 '菌核病'、'蚜虫'、'菜青虫'")
class FertilizerInput(BaseModel):
keyword: str = Field(description="施肥关键词,如 '基肥'、'追肥'、'硼肥'")
@tool(name_or_callable="query_cultivation_tech", args_schema=CultivationInput)
def query_cultivation_tech(keyword: str) -> str:
"""查询油菜栽培技术要点。"""
if keyword in CULTIVATION_DB:
return f"栽培技术:{keyword} — {CULTIVATION_DB[keyword]}"
return f"未找到 '{keyword}' 的栽培技术,请尝试:{list(CULTIVATION_DB.keys())}"
@tool(name_or_callable="query_pest_control", args_schema=PestInput)
def query_pest_control(keyword: str) -> str:
"""查询油菜病虫害防治方案。"""
if keyword in PEST_DB:
return f"病虫害防治:{keyword} — {PEST_DB[keyword]}"
return f"未找到 '{keyword}' 的防治方案,请尝试:{list(PEST_DB.keys())}"
@tool(name_or_callable="query_fertilizer_plan", args_schema=FertilizerInput)
def query_fertilizer_plan(keyword: str) -> str:
"""查询油菜施肥方案。"""
if keyword in FERTILIZER_DB:
return f"施肥方案:{keyword} — {FERTILIZER_DB[keyword]}"
return f"未找到 '{keyword}' 的施肥方案,请尝试:{list(FERTILIZER_DB.keys())}"
|
领域子 Agent 挂载工具
三个子 Agent 各挂一个领域工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| from langchain.agents import create_agent
llm = ChatOllama(model="qwen3.5:9b", temperature=0)
cultivation_agent = create_agent(
model=llm,
tools=[query_cultivation_tech],
system_prompt="你是油菜栽培技术专家。用户问栽培/农事/播种/密度/灌溉等问题,调用 query_cultivation_tech 查询后给出简明建议。",
)
pest_agent = create_agent(
model=llm,
tools=[query_pest_control],
system_prompt="你是油菜植保专家。用户问病虫害识别与防治,调用 query_pest_control 查询后给出防治建议。",
)
fertilizer_agent = create_agent(
model=llm,
tools=[query_fertilizer_plan],
system_prompt="你是油菜土肥专家。用户问施肥方案/肥料/追肥/硼肥,调用 query_fertilizer_plan 查询后给出建议。",
)
|
构建 Router + 三个领域子 Agent
Router 本身也是一个 Agent,只负责输出结构化的路由决策:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| from langchain.agents.structured_output import ToolStrategy
from langchain_ollama import ChatOllama
from pydantic import BaseModel, Field
from typing import Literal
class RouteDecision(BaseModel):
"""路由决策结果。"""
route: Literal["栽培", "植保", "土肥", "其他"] = Field(
description="问题所属领域:栽培(播种/密度/灌溉等农事)、植保(病虫害防治)、土肥(施肥方案);与三者均无关时填 '其他'"
)
reason: str = Field(description="一句话说明判定理由")
ROUTER_PROMPT = (
"你是油菜种植技术咨询的领域路由器。"
"判断用户问题属于栽培、植保、土肥中的哪一个领域,无法归类时选 '其他'。"
"只做分类,不要回答用户的问题本身。"
)
router = create_agent(
model=llm,
tools=[],
system_prompt=ROUTER_PROMPT,
response_format=ToolStrategy(RouteDecision),
)
AGENTS = {
"栽培": cultivation_agent,
"植保": pest_agent,
"土肥": fertilizer_agent,
}
|
定义问答入口函数
1
2
3
4
5
6
7
8
9
10
11
12
| def route_and_answer(question: str) -> str:
result = router.invoke({"messages": [{"role": "user", "content": question}]})
decision: RouteDecision = result["structured_response"]
if decision.route not in AGENTS:
return f"无法识别问题领域(识别为:{decision.route}),请补充描述或换个说法。理由:{decision.reason}"
answer = AGENTS[decision.route].invoke({
"messages": [{"role": "user", "content": question}]
})["messages"][-1].content
return f"【路由到:{decision.route}】依据:{decision.reason}\n\n{answer}"
|
函数返回路由决策结果及对应领域子 Agent 的回答。
运行:多领域问题自动分发
1
2
3
4
| if __name__ == "__main__":
print(route_and_answer("油菜播种期"))
print(route_and_answer("油菜菌核病怎么防治"))
print(route_and_answer("油菜施肥方案"))
|
执行输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| 【路由到:栽培】依据:播种期属于油菜种植农事操作中的播种管理范畴
关于油菜播种期的建议:
**长江中下游地区:**
- **直播油菜**:适宜在 **9月下旬至10月中旬** 进行播种
- **移栽油菜**:可提前 **7–10天**(约9月中下旬)完成移栽
**注意事项:**
- 播种期应结合当地气候条件灵活调整,避免过早或过晚影响产量
- 直播油菜需确保土壤墒情适宜,移栽油菜则需预留缓苗时间
如需了解其他栽培技术要点(如种植密度、灌溉管理等),欢迎继续提问!
【路由到:植保】依据:油菜菌核病属于病虫害防治范畴
油菜菌核病是油菜生产中的常见病害,主要危害花器和茎秆,严重时会导致“烂腰”和减产。以下是综合防治建议:
### 一、化学防治(关键时期)
- **最佳时机**:**花期**是防治的关键窗口期,此时病菌孢子活跃,易侵染。
- **推荐药剂**:50% 腐霉利可湿性粉剂 1000–1500 倍液喷雾。
- **施药次数**:连防 2–3 次,间隔 7–10 天一次。
- **注意事项**:喷药时注意均匀覆盖花部,避免重喷漏喷。
### 二、农业防治(基础措施)
- **合理轮作**:与非十字花科作物(如玉米、小麦等)轮作,减少土壤中病菌积累。
- **清除病残体**:收获后及时清理田间病株残体,集中销毁,降低菌源。
- **合理密植**:避免种植过密,保持田间通风透光,降低湿度。
- **排水降湿**:雨季注意排水,避免田间积水,减少高湿环境利于发病的条件。
### 三、其他建议
- 若病情较重,可结合使用其他杀菌剂(如多菌灵、咪鲜胺等)轮换使用,延缓抗药性产生。
- 选用抗病品种也是预防病害的重要措施。
通过“农业防治 + 化学防治”相结合,可有效控制油菜菌核病的发生与蔓延。
【路由到:土肥】依据:问题涉及油菜施肥方案,属于土肥领域
油菜基肥施肥建议如下:
- **有机肥**:每亩施用腐熟有机肥 1000–1500 kg;
- **复合肥**:每亩施用 N-P₂O₅-K₂O 比例为 15-15-15 的复合肥 30–40 kg。
如果您还想了解追肥、硼肥或其他施肥阶段的方案,请随时告诉我!
|
优缺点
优点
- 一个入口,多个专长:产品对外统一,对内可挂载任意多个垂直 Agent,扩展性强。
- 提示词与工具解耦:每个子 Agent 只需承载一个领域的知识,避免提示臃肿和工具冲突。
- 效果上限更高:子 Agent 可以为单一职责深度优化(提示词、工具、示例)。
- 可独立迭代:新增领域只需新增一个子 Agent + 一条路由规则,不影响已有领域。
缺点
- 路由准确率是瓶颈:一旦分错,后续回答必然跑偏;模糊问题或跨领域问题尤其容易误判。
- 子 Agent 之间默认不通信:一个复杂问题可能需要栽培 + 植保 + 土肥联合回答,Router 只做单选,需要更高层编排(这就是 Multi-Agent 要解决的问题)。
- 领域切分是隐性成本:哪些领域独立、边界在哪、是否允许重叠,需要人工设计与持续维护。
- 输出格式需治理:子 Agent 返回格式不一致时,前端拼接体验差。