第2章 什么是AI-Agent
来源:https://ai-agent-guide.xiaofuge.cn/chapters/ch02-what-is-agent.html 所属:第一篇-Agent基础
从 ChatBot 到 Agent,AI 应用的范式跃迁
2.1 一个问题引入
如果我问你:ChatGPT 是 AI Agent 吗?
答案是:不是。ChatGPT 是一个出色的 ChatBot(聊天机器人),它能理解你的问题并生成回答。但它不会主动帮你查航班、订外卖、写代码到文件里。
而 AI Agent 可以。
这个区别看似微小,实则是 AI 应用的一次范式跃迁。ChatBot 时代的 AI 是一个"顾问"——你问它答,答案再好也需要你自己去执行。Agent 时代的 AI 是一个"员工"——你交代目标,它自己规划步骤、调用工具、交付结果。从"给你建议"到"替你完成",中间隔着的是与真实世界交互的能力。理解这条分界线,是理解整本书的钥匙。
"ChatBot 回答问题,Agent 解决问题。"
2.2 ChatBot vs Agent:核心区别
我们先通过一个动画来看两者的区别。同样的任务:"帮我查一下明天北京的天气"
注意两者的本质差异不在"回答得好不好",而在闭环是否完整。ChatBot 的闭环止步于"生成文本"——它能告诉你该去查天气,但查的动作要你来做。Agent 的闭环延伸到了"改变外部状态"——它真的调用了天气 API、拿到了数据、甚至可以进一步帮你设提醒。这个"感知→决策→行动→观察"的循环,就是 Agent 区别于一切对话式 AI 的根本特征。
ChatBot
用户:明天北京天气怎么样?
ChatBot:我无法实时查询天气,但你可以...
用户:那帮我订个提醒?
ChatBot:抱歉,我没有这个能力。
→ 只能对话,不能行动
Agent
用户:明天北京天气怎么样?
Agent:[思考] 需要调用天气API
Agent:[工具调用] weather_api("北京", "2026-07-02")
Agent:[观察] 明天北京晴,28°C
→ 明天北京晴,最高28°C。需要我设个提醒吗?
看到了吗?ChatBot 只能"说",Agent 能"做"。这个"做"的能力,来自于 Agent 独有的四个核心模块。
2.3 AI Agent 的四大核心模块
一个完整的 AI Agent 由四个核心模块组成,缺一不可: 🧠 Agent 四模块
1. LLM(大脑) 负责理解、推理、决策。是 Agent 的"智力引擎"。
2. 记忆(Memory) 短期记忆(对话上下文)+ 长期记忆(向量数据库)。
3. 规划(Planning) 将复杂任务拆解为子任务,制定执行计划。
4. 工具(Tools) 调用外部 API、数据库、代码执行器等,实现"行动"。
2.4 Agent 是怎么工作的?
我们来看 Agent 完成一个任务的完整流程。点击"下一步"逐步查看:
1
感知(Perceive)
用户输入"帮我分析一下最近的房价趋势",Agent 通过 LLM 理解用户意图。
← 1 / 5 → 重播
2.5 Agent 的核心闭环
上面的五个步骤可以抽象为一个经典闭环:感知 → 决策 → 行动 → 反馈。这个闭环是所有 Agent 的基础运行模式。
这个闭环并非凭空而来,它源自控制论中的 OODA 循环(Observe-Orient-Decide-Act)。关键在于**"反馈回到感知"这条虚线**——它让 Agent 从"一次性执行"变成"持续修正"。没有这条回边,Agent 就是一个单向流水线,遇到意外就会卡死;有了它,Agent 能在每次行动后观察结果、调整下一步,从而具备容错和自适应能力。这正是 Agent 能处理开放性任务的原因。
这个闭环不断循环,让 Agent 能够处理多步骤、多轮交互的复杂任务。后续章节讲的 ReAct 模式、反思机制,都是在这个闭环基础上的演进。
2.6 Agent vs ChatBot vs Copilot
面试中经常被问到这三者的区别,我们用一张表总结:
三者代表了 AI 应用自主性的三个层级。ChatBot 是被动应答,Copilot 是人机协作(AI 给建议、人来执行),Agent 是自主执行(AI 定计划、AI 去落地)。越往后,AI 的自主性越强、人的参与度越低,但对系统的可靠性和安全性要求也越高。理解这个光谱,能帮你在面试中精准定位产品形态。 | 维度 | ChatBot | Copilot | Agent | | --- | --- | --- | --- | | 核心能力 | 对话回答 | 辅助完成 | 自主完成 | | 自主性 | 无 | 低(需人引导) | 高(自主规划) | | 工具使用 | ✗ | 有限 | ✓ 完整 | | 记忆能力 | 短期 | 短期 | 短期+长期 | | 典型产品 | ChatGPT | GitHub Copilot | Devin, AutoGPT | ## 2.7 从用户输入到输出的完整链路
面试最高频的问题之一:整个 Agent 从用户发出消息到完成任务,中间经历了哪些步骤? 很多面试官会要求你从接收消息开始,一步一步讲清楚每一步做了什么、为什么需要、哪些模块负责。本节把这条链路彻底拆透。
"能画出完整链路图,面试基本稳了。"
🔗 完整 8 步链路
一条完整的 Agent 执行链路,从用户输入到最终输出,包含 8 个核心步骤:
注意:Step 5 → Step 2 的回边表示 Agent 在执行调度后,可能发现需要重新理解意图(比如工具返回了新信息),进入迭代循环。这正是 Agent 与 ChatBot 的核心差异——Agent 不是一条直线,而是可以循环迭代的。 📌 每一步详细说明
Step 1: 用户输入接收 做什么:接收用户的原始消息(文本、图片、语音等),进行预处理(格式化、清洗噪声)。为什么需要:这是 Agent 与外部世界的接口,所有后续步骤都基于此输入。负责模块:输入处理模块 + 消息队列。
Step 2: 意图识别 做什么:理解用户想做什么——是简单问答?是代码修改?还是复杂的多步任务?为什么需要:不同的意图决定不同的执行路径。负责模块:LLM(语义理解)+ 规则引擎(关键词匹配)。
Step 3: 任务分类 做什么:判断任务类型和复杂度等级(简单问答 / 代码解释 / 代码修改 / 复杂开发)。为什么需要:复杂度决定是否需要拆解,类型决定调用哪些工具。负责模块:分类器(LLM 推理或规则引擎)。
Step 4: 任务拆解 做什么:将复杂任务分解为有序的子任务序列,并确定依赖关系和执行顺序。为什么需要:LLM 单次调用无法完成复杂目标,必须拆成可执行的小步骤。负责模块:规划模块(Planning)——详见 2.3 节。
Step 5: 执行调度 做什么:决定先做什么后做什么,何时调用模型推理、何时调用外部工具。为什么需要:资源有限,执行顺序影响效率和结果质量。负责模块:调度器(Scheduler)——详见 2.9 节。
Step 6: 工具调用 做什么:通过 Function Calling / MCP 协议调用外部工具(搜索引擎、数据库、代码执行器、API 等)。为什么需要:LLM 本身无法查天气、执行代码、读写文件,必须借助工具。负责模块:工具模块(Tools)+ Function Calling 接口。
Step 7: 结果整合 做什么:收集各子步骤的输出(模型推理结果 + 工具返回数据),整合为逻辑连贯的完整答案。为什么需要:多步执行的结果是碎片化的,必须缝合才能形成有意义的回复。负责模块:LLM(结果合成)+ 记忆模块(中间结果缓存)。
Step 8: 输出返回 做什么:格式化最终结果(文本、表格、代码块、图表等),返回给用户。同时将本次交互存入记忆。为什么需要:用户体验取决于输出质量;记忆存入为下次交互提供上下文。负责模块:格式化引擎 + 记忆写入模块。
来看一段模拟完整链路执行的代码:
Python TypeScript Go Java
# 模拟 Agent 完整执行链路
class AgentChain:
def __init__(self):
self.llm = LLMEngine() # Step 2/5/7 的核心引擎
self.memory = MemoryStore() # 记忆模块
self.tools = ToolRegistry() # Step 6 的工具集
self.classifier = TaskClassifier() # Step 3 分类器
self.planner = TaskPlanner() # Step 4 规划器
def run(self, user_input):
# Step 1: 用户输入接收
raw_msg = InputHandler.receive(user_input)
print(f"[Step1] 收到原始消息: {raw_msg}")
# Step 2: 意图识别
intent = self.llm.identify_intent(raw_msg)
print(f"[Step2] 意图识别结果: {intent}") # e.g. "数据分析"
# Step 3: 任务分类
task_type, complexity = self.classifier.classify(intent)
print(f"[Step3] 任务类型={task_type}, 复杂度={complexity}")
# Step 4: 任务拆解(仅复杂任务)
if complexity == "complex":
sub_tasks = self.planner.decompose(raw_msg, intent)
print(f"[Step4] 拆解为 {len(sub_tasks)} 个子任务")
else:
sub_tasks = [raw_msg] # 简单任务无需拆解
print(f"[Step4] 简单任务,无需拆解")
# Step 5: 执行调度
schedule = self.llm.schedule(sub_tasks, self.tools.available_tools())
print(f"[Step5] 调度计划: {schedule}")
results = []
for task in schedule:
# Step 6: 工具调用(需要时)
if task.need_tool:
tool_result = self.tools.call(task.tool_name, task.tool_args)
print(f"[Step6] 工具 {task.tool_name} 返回: {tool_result}")
results.append(tool_result)
else:
# 纯模型推理
model_result = self.llm.reason(task.prompt)
print(f"[Step5→推理] 模型推理结果: {model_result}")
results.append(model_result)
# Step 7: 结果整合
final_answer = self.llm.synthesize(results, original_intent=intent)
print(f"[Step7] 整合完成: {final_answer}")
# Step 8: 输出返回
formatted = OutputFormatter.format(final_answer)
self.memory.save_interaction(raw_msg, intent, formatted)
print(f"[Step8] 输出返回给用户")
return formatted
# 执行示例
agent = AgentChain()
result = agent.run("帮我分析最近北京房价趋势")
# [Step1] 收到原始消息: 帮我分析最近北京房价趋势
# [Step2] 意图识别结果: 数据分析
# [Step3] 任务类型=complex, 复杂度=complex
# [Step4] 拆解为 3 个子任务
# [Step5] 调度计划: [search_housing_data → analyze_trend → generate_report]
# [Step6] 工具 search_api 返回: {...房价数据...}
# [Step5→推理] 模型推理结果: 一线城市环比下降2%
# [Step7] 整合完成: 北京房价分析报告
# [Step8] 输出返回给用户
// 模拟 Agent 完整执行链路
class AgentChain {
private llm = new LLMEngine(); // Step 2/5/7 的核心引擎
private memory = new MemoryStore(); // 记忆模块
private tools = new ToolRegistry(); // Step 6 的工具集
private classifier = new TaskClassifier(); // Step 3 分类器
private planner = new TaskPlanner(); // Step 4 规划器
run(userInput: string): string {
// Step 1: 用户输入接收
const rawMsg = InputHandler.receive(userInput);
console.log(`[Step1] 收到原始消息: ${rawMsg}`);
// Step 2: 意图识别
const intent = this.llm.identifyIntent(rawMsg);
console.log(`[Step2] 意图识别结果: ${intent}`);
// Step 3: 任务分类
const { taskType, complexity } = this.classifier.classify(intent);
console.log(`[Step3] 任务类型=${taskType}, 复杂度=${complexity}`);
// Step 4: 任务拆解(仅复杂任务)
let subTasks: string[];
if (complexity === 'complex') {
subTasks = this.planner.decompose(rawMsg, intent);
console.log(`[Step4] 拆解为 ${subTasks.length} 个子任务`);
} else {
subTasks = [rawMsg];
console.log('[Step4] 简单任务,无需拆解');
}
// Step 5: 执行调度
const schedule = this.llm.schedule(subTasks, this.tools.availableTools());
console.log(`[Step5] 调度计划: ${schedule}`);
const results: any[] = [];
for (const task of schedule) {
// Step 6: 工具调用(需要时)
if (task.needTool) {
const toolResult = this.tools.call(task.toolName, task.toolArgs);
console.log(`[Step6] 工具 ${task.toolName} 返回: ${toolResult}`);
results.push(toolResult);
} else {
// 纯模型推理
const modelResult = this.llm.reason(task.prompt);
console.log(`[Step5→推理] 模型推理结果: ${modelResult}`);
results.push(modelResult);
}
}
// Step 7: 结果整合
const finalAnswer = this.llm.synthesize(results, intent);
console.log(`[Step7] 整合完成: ${finalAnswer}`);
// Step 8: 输出返回
const formatted = OutputFormatter.format(finalAnswer);
this.memory.saveInteraction(rawMsg, intent, formatted);
console.log('[Step8] 输出返回给用户');
return formatted;
}
}
// 执行示例
const agent = new AgentChain();
const result = agent.run('帮我分析最近北京房价趋势');
// 模拟 Agent 完整执行链路
package main
import "fmt"
// AgentChain Agent 执行链路
type AgentChain struct {
llm *LLMEngine
memory *MemoryStore
tools *ToolRegistry
classifier *TaskClassifier
planner *TaskPlanner
}
func NewAgentChain() *AgentChain {
return &AgentChain{
llm: NewLLMEngine(),
memory: NewMemoryStore(),
tools: NewToolRegistry(),
classifier: NewTaskClassifier(),
planner: NewTaskPlanner(),
}
}
func (a *AgentChain) Run(userInput string) string {
// Step 1: 用户输入接收
rawMsg := InputHandlerReceive(userInput)
fmt.Printf("[Step1] 收到原始消息: %s\n", rawMsg)
// Step 2: 意图识别
intent := a.llm.IdentifyIntent(rawMsg)
fmt.Printf("[Step2] 意图识别结果: %v\n", intent)
// Step 3: 任务分类
taskType, complexity := a.classifier.Classify(intent)
fmt.Printf("[Step3] 任务类型=%s, 复杂度=%s\n", taskType, complexity)
// Step 4: 任务拆解
var subTasks []string
if complexity == "complex" {
subTasks = a.planner.Decompose(rawMsg, intent)
fmt.Printf("[Step4] 拆解为 %d 个子任务\n", len(subTasks))
} else {
subTasks = []string{rawMsg}
fmt.Println("[Step4] 简单任务,无需拆解")
}
// Step 5: 执行调度
schedule := a.llm.Schedule(subTasks, a.tools.AvailableTools())
fmt.Printf("[Step5] 调度计划: %v\n", schedule)
var results []interface{}
for _, task := range schedule {
// Step 6: 工具调用
if task.NeedTool {
toolResult := a.tools.Call(task.ToolName, task.ToolArgs)
fmt.Printf("[Step6] 工具 %s 返回: %v\n", task.ToolName, toolResult)
results = append(results, toolResult)
} else {
modelResult := a.llm.Reason(task.Prompt)
fmt.Printf("[Step5→推理] 模型推理结果: %v\n", modelResult)
results = append(results, modelResult)
}
}
// Step 7: 结果整合
finalAnswer := a.llm.Synthesize(results, intent)
fmt.Printf("[Step7] 整合完成: %s\n", finalAnswer)
// Step 8: 输出返回
formatted := OutputFormatterFormat(finalAnswer)
a.memory.SaveInteraction(rawMsg, intent, formatted)
fmt.Println("[Step8] 输出返回给用户")
return formatted
}
func main() {
agent := NewAgentChain()
result := agent.Run("帮我分析最近北京房价趋势")
fmt.Println(result)
}
// 模拟 Agent 完整执行链路
public class AgentChain {
private LLMEngine llm = new LLMEngine(); // Step 2/5/7 的核心引擎
private MemoryStore memory = new MemoryStore(); // 记忆模块
private ToolRegistry tools = new ToolRegistry(); // Step 6 的工具集
private TaskClassifier classifier = new TaskClassifier(); // Step 3 分类器
private TaskPlanner planner = new TaskPlanner(); // Step 4 规划器
public String run(String userInput) {
// Step 1: 用户输入接收
String rawMsg = InputHandler.receive(userInput);
System.out.println("[Step1] 收到原始消息: " + rawMsg);
// Step 2: 意图识别
Intent intent = llm.identifyIntent(rawMsg);
System.out.println("[Step2] 意图识别结果: " + intent);
// Step 3: 任务分类
ClassifyResult result = classifier.classify(intent);
System.out.printf("[Step3] 任务类型=%s, 复杂度=%s%n", result.taskType, result.complexity);
// Step 4: 任务拆解
List subTasks;
if ("complex".equals(result.complexity)) {
subTasks = planner.decompose(rawMsg, intent);
System.out.printf("[Step4] 拆解为 %d 个子任务%n", subTasks.size());
} else {
subTasks = List.of(rawMsg);
System.out.println("[Step4] 简单任务,无需拆解");
}
// Step 5: 执行调度
List schedule = llm.schedule(subTasks, tools.availableTools());
System.out.println("[Step5] 调度计划: " + schedule);
List results = new ArrayList<>();
for (Task task : schedule) {
// Step 6: 工具调用
if (task.needTool) {
Object toolResult = tools.call(task.toolName, task.toolArgs);
System.out.printf("[Step6] 工具 %s 返回: %s%n", task.toolName, toolResult);
results.add(toolResult);
} else {
// 纯模型推理
Object modelResult = llm.reason(task.prompt);
System.out.printf("[Step5→推理] 模型推理结果: %s%n", modelResult);
results.add(modelResult);
}
}
// Step 7: 结果整合
String finalAnswer = llm.synthesize(results, intent);
System.out.println("[Step7] 整合完成: " + finalAnswer);
// Step 8: 输出返回
String formatted = OutputFormatter.format(finalAnswer);
memory.saveInteraction(rawMsg, intent, formatted);
System.out.println("[Step8] 输出返回给用户");
return formatted;
}
public static void main(String[] args) {
AgentChain agent = new AgentChain();
String result = agent.run("帮我分析最近北京房价趋势");
}
}
代码中每一步都打印了日志,你可以清楚地看到一条消息从进入 Agent 到变成最终输出,走过了哪些节点。面试时,能讲出这 8 步并解释每步的作用,就是满分回答。
2.8 意图识别与任务分类
Step 2(意图识别)和 Step 3(任务分类)是整条链路的分叉点——Agent 能否走上正确的执行路径,取决于这两步做得好不好。面试中经常追问:Agent 怎么理解用户意图?怎么判断任务复杂度?
🎯 三种意图识别方法
意图识别的三种方法对比 | 方法 | 原理 | 优点 | 缺点 | 适用场景 | | --- | --- | --- | --- | --- | | 关键词匹配 | 匹配预设关键词,如"天气"→查询意图 | 速度快,成本低 | 粗粒度,误判率高 | 简单指令型交互 | | 语义理解 | 通过 LLM 深层理解用户表达的真实意图 | 精准,能理解隐含意图 | 成本高,延迟大 | 复杂多意图场景 | | 模式识别 | 基于历史对话模式匹配相似意图 | 利用经验,越用越准 | 依赖数据量,新意图难识别 | 高频重复场景 | 实际工程中,三者通常组合使用:先用关键词匹配快速筛选常见意图,命中后直接走快速路径;没命中则交给 LLM 做语义理解;长期积累的模式数据用于优化匹配规则。这就是分层意图识别策略。
Python TypeScript Go Java
# 分层意图识别:关键词 → 语义 → 模式
def identify_intent(user_input, context):
# 第一层:关键词匹配(快路径)
keyword_intent = match_keywords(user_input)
if keyword_intent and keyword_intent.confidence > 0.9:
return keyword_intent # 高置信度,直接返回
# 第二层:语义理解(慢路径)
semantic_intent = llm_understand_intent(user_input, context)
if semantic_intent.confidence > 0.7:
# 记录新模式,丰富规则库
pattern_db.record(user_input, semantic_intent)
return semantic_intent
# 第三层:模式识别(兜底)
pattern_intent = match_patterns(user_input, pattern_db)
return pattern_intent or semantic_intent
# 示例
print(identify_intent("明天天气咋样", []))
# → Intent(type="查询", sub_type="天气", confidence=0.95) # 关键词命中
print(identify_intent("我项目里这段代码跑不通,帮我看看", []))
# → Intent(type="代码修改", confidence=0.85) # 语义理解命中
// 分层意图识别:关键词 → 语义 → 模式
function identifyIntent(userInput: string, context: Context[]): Intent {
// 第一层:关键词匹配(快路径)
const keywordIntent = matchKeywords(userInput);
if (keywordIntent && keywordIntent.confidence > 0.9) {
return keywordIntent; // 高置信度,直接返回
}
// 第二层:语义理解(慢路径)
const semanticIntent = llmUnderstandIntent(userInput, context);
if (semanticIntent.confidence > 0.7) {
// 记录新模式,丰富规则库
patternDB.record(userInput, semanticIntent);
return semanticIntent;
}
// 第三层:模式识别(兜底)
const patternIntent = matchPatterns(userInput, patternDB);
return patternIntent || semanticIntent;
}
// 示例
console.log(identifyIntent('明天天气咋样', []));
// → Intent(type="查询", subType="天气", confidence=0.95) // 关键词命中
console.log(identifyIntent('我项目里这段代码跑不通,帮我看看', []));
// → Intent(type="代码修改", confidence=0.85) // 语义理解命中
// 分层意图识别:关键词 → 语义 → 模式
package main
// Intent 意图
type Intent struct {
Type string
SubType string
Confidence float64
}
func identifyIntent(userInput string, context []Context) Intent {
// 第一层:关键词匹配(快路径)
keywordIntent := matchKeywords(userInput)
if keywordIntent.Confidence > 0.9 {
return keywordIntent // 高置信度,直接返回
}
// 第二层:语义理解(慢路径)
semanticIntent := llmUnderstandIntent(userInput, context)
if semanticIntent.Confidence > 0.7 {
// 记录新模式,丰富规则库
patternDB.Record(userInput, semanticIntent)
return semanticIntent
}
// 第三层:模式识别(兜底)
patternIntent := matchPatterns(userInput, patternDB)
if patternIntent.Confidence > 0 {
return patternIntent
}
return semanticIntent
}
// 分层意图识别:关键词 → 语义 → 模式
public class IntentIdentifier {
public Intent identifyIntent(String userInput, List context) {
// 第一层:关键词匹配(快路径)
Intent keywordIntent = matchKeywords(userInput);
if (keywordIntent != null && keywordIntent.getConfidence() > 0.9) {
return keywordIntent; // 高置信度,直接返回
}
// 第二层:语义理解(慢路径)
Intent semanticIntent = llmUnderstandIntent(userInput, context);
if (semanticIntent.getConfidence() > 0.7) {
// 记录新模式,丰富规则库
patternDB.record(userInput, semanticIntent);
return semanticIntent;
}
// 第三层:模式识别(兜底)
Intent patternIntent = matchPatterns(userInput, patternDB);
return patternIntent != null ? patternIntent : semanticIntent;
}
}
📊 任务分类矩阵
意图识别之后,Agent 需要对任务进行分类,决定执行策略。不同的任务类型对应不同的处理路径:
任务分类矩阵:类型 → 策略 → 路径 | 任务类型 | 典型输入 | 执行策略 | 链路路径 | 复杂度 | | --- | --- | --- | --- | --- | | 简单问答 | "Python 的 list 怎么排序?" | 直接回答 | Step 1→2→3→5→7→8 | 低 | | 代码解释 | "这段代码在做什么?" | 分析 + 输出说明 | Step 1→2→3→5→7→8 | 中 | | 代码修改 | "把这段代码改成异步版本" | 理解+定位+修改 | Step 1→2→3→4→5→6→7→8 | 中高 | | 复杂开发 | "帮我搭建一个 REST API 项目" | Step 1→2→3→4→5→6→7→8(多轮循环) | 高 | 关键观察:简单问答可以跳过 Step 4(任务拆解)和 Step 6(工具调用),直接走快速路径。而复杂开发任务必须走完全部 8 步,且 Step 5→2 的迭代循环可能执行多轮。
🔀 分类决策流程图
Python TypeScript Go Java
# 任务分类器:判断复杂度并选择执行路径
class TaskClassifier:
# 关键词 → 复杂度的映射规则
COMPLEXITY_RULES = {
"简单问答": {
"keywords": ["是什么", "怎么用", "区别", "概念"],
"path": "direct_answer",
"complexity": "low"
},
"代码解释": {
"keywords": ["这段代码", "什么意思", "解释一下"],
"path": "analyze_explain",
"complexity": "medium"
},
"代码修改": {
"keywords": ["修改", "改成", "优化", "修复", "重构"],
"path": "locate_modify",
"complexity": "medium_high"
},
"复杂开发": {
"keywords": ["搭建", "实现", "开发", "创建项目", "从零开始"],
"path": "decompose_execute",
"complexity": "high"
}
}
def classify(self, intent):
# 规则匹配 + LLM 兜底
for task_type, rule in self.COMPLEXITY_RULES.items():
if any(kw in intent.raw_input for kw in rule["keywords"]):
return task_type, rule["complexity"], rule["path"]
# 规则未命中,交给 LLM 判断
llm_result = self.llm_classify(intent)
return llm_result.type, llm_result.complexity, llm_result.path
# 示例
classifier = TaskClassifier()
print(classifier.classify(Intent(raw_input="Python list 怎么排序?")))
# → ("简单问答", "low", "direct_answer")
print(classifier.classify(Intent(raw_input="帮我搭建一个 REST API")))
# → ("复杂开发", "high", "decompose_execute")
// 任务分类器:判断复杂度并选择执行路径
const COMPLEXITY_RULES: Record = {
'简单问答': {
keywords: ['是什么', '怎么用', '区别', '概念'],
path: 'direct_answer',
complexity: 'low'
},
'代码解释': {
keywords: ['这段代码', '什么意思', '解释一下'],
path: 'analyze_explain',
complexity: 'medium'
},
'代码修改': {
keywords: ['修改', '改成', '优化', '修复', '重构'],
path: 'locate_modify',
complexity: 'medium_high'
},
'复杂开发': {
keywords: ['搭建', '实现', '开发', '创建项目', '从零开始'],
path: 'decompose_execute',
complexity: 'high'
}
};
function classify(intent: Intent): ClassifyResult {
// 规则匹配
for (const [taskType, rule] of Object.entries(COMPLEXITY_RULES)) {
if (rule.keywords.some(kw => intent.rawInput.includes(kw))) {
return { taskType, complexity: rule.complexity, path: rule.path };
}
}
// 规则未命中,交给 LLM 判断
return llmClassify(intent);
}
// 示例
console.log(classify({ rawInput: 'Python list 怎么排序?' }));
// → { taskType: '简单问答', complexity: 'low', path: 'direct_answer' }
console.log(classify({ rawInput: '帮我搭建一个 REST API' }));
// → { taskType: '复杂开发', complexity: 'high', path: 'decompose_execute' }
// 任务分类器:判断复杂度并选择执行路径
package main
// ComplexityRule 复杂度规则
type ComplexityRule struct {
Keywords []string
Path string
Complexity string
}
// TaskClassifier 任务分类器
type TaskClassifier struct {
rules map[string]ComplexityRule
}
func NewTaskClassifier() *TaskClassifier {
return &TaskClassifier{
rules: map[string]ComplexityRule{
"简单问答": {Keywords: []string{"是什么", "怎么用", "区别", "��念"}, Path: "direct_answer", Complexity: "low"},
"代码解释": {Keywords: []string{"这段代码", "什么意思", "解释一下"}, Path: "analyze_explain", Complexity: "medium"},
"代码修改": {Keywords: []string{"修改", "改成", "优化", "修复", "重构"}, Path: "locate_modify", Complexity: "medium_high"},
"复杂开发": {Keywords: []string{"搭建", "实现", "开发", "创建项目", "从零开始"}, Path: "decompose_execute", Complexity: "high"},
},
}
}
func (c *TaskClassifier) Classify(intent Intent) (taskType, complexity, path string) {
// 规则匹配
for name, rule := range c.rules {
for _, kw := range rule.Keywords {
if strings.Contains(intent.RawInput, kw) {
return name, rule.Complexity, rule.Path
}
}
}
// 规则未命中,交给 LLM 判断
return llmClassify(intent)
}
// 任务分类器:判断复杂度并选择执行路径
import java.util.*;
public class TaskClassifier {
private static final Map COMPLEXITY_RULES = new HashMap<>();
static {
COMPLEXITY_RULES.put("简单问答", new ComplexityRule(
Arrays.asList("是什么", "怎么用", "区别", "概念"), "direct_answer", "low"));
COMPLEXITY_RULES.put("代码解释", new ComplexityRule(
Arrays.asList("这段代码", "什么意思", "解释一下"), "analyze_explain", "medium"));
COMPLEXITY_RULES.put("代码修改", new ComplexityRule(
Arrays.asList("修改", "改成", "优化", "修复", "重构"), "locate_modify", "medium_high"));
COMPLEXITY_RULES.put("复杂开发", new ComplexityRule(
Arrays.asList("搭建", "实现", "开发", "创建项目", "从零开始"), "decompose_execute", "high"));
}
public ClassifyResult classify(Intent intent) {
// 规则匹配
for (Map.Entry entry : COMPLEXITY_RULES.entrySet()) {
String taskType = entry.getKey();
ComplexityRule rule = entry.getValue();
for (String kw : rule.keywords) {
if (intent.getRawInput().contains(kw)) {
return new ClassifyResult(taskType, rule.complexity, rule.path);
}
}
}
// 规则未命中,交给 LLM 判断
return llmClassify(intent);
}
static class ComplexityRule {
List keywords;
String path;
String complexity;
ComplexityRule(List keywords, String path, String complexity) {
this.keywords = keywords;
this.path = path;
this.complexity = complexity;
}
}
}
2.9 执行调度决策
Agent 拿到子任务列表后,下一步是执行调度——决定先做什么后做什么,什么时候该调用模型(推理/理解/生成文本),什么时候该调用工具(搜索/计算/文件操作)。这是 1.7 链路中 Step 5 的核心逻辑。
"调度器的质量,决定了 Agent 是'聪明地做事'还是'笨拙地乱撞'。"
🌳 调度决策树
调度决策的核心逻辑可以用一棵决策树描述: ⚡ 模型 vs 工具:何时调用谁?
调用模型(LLM)
- 理解用户意图和上下文
- 逻辑推理和因果分析
- 生成文本、代码、创意内容
- 结果整合与格式化
- 判断下一步做什么
调用工具(Tools)
- 搜索实时信息(天气、新闻)
- 执行代码(运行、测试)
- 读写文件(磁盘操作)
- 调用外部 API(支付、数据库)
- 数学计算(高精度运算)
一个关键原则:模型擅长"思考",工具擅长"行动"。调度器的核心职责就是判断当前子任务属于哪一类,把任务分给最合适的执行者。
Python TypeScript Go Java
# 调度器实现:根据任务特征分配执行路径
class Scheduler:
def __init__(self, llm, tools):
self.llm = llm
self.tools = tools
def dispatch(self, sub_task):
"""根据子任务特征,决定调用模型还是工具"""
# 判断1:是否需要外部数据?
if sub_task.requires_external_data:
# 搜索、数据库查询、API调用 → 工具
tool_name = self._select_tool(sub_task)
result = self.tools.call(tool_name, sub_task.params)
print(f"[调度] 工具执行: {tool_name} → {result}")
return result
# 判断2:是否需要逻辑推理?
if sub_task.requires_reasoning:
# 分析、推理、决策 → 模型
result = self.llm.reason(sub_task.prompt)
print(f"[调度] 模型推理: {sub_task.prompt} → {result}")
return result
# 判断3:是否需要格式化输出?
if sub_task.requires_formatting:
result = self.llm.format(sub_task.raw_output)
print(f"[调度] 模型格式化 → {result}")
return result
# 判断4:是否需要验证结果?
if sub_task.requires_verification:
# 交叉验证:先工具获取事实,再模型判断一致性
tool_result = self.tools.call("verify", sub_task.params)
model_result = self.llm.reason(
f"验证以下结果是否合理: {tool_result}"
)
print(f"[调度] 交叉验证 → 工具:{tool_result}, 模型:{model_result}")
return model_result
# 默认:模型处理
return self.llm.reason(sub_task.prompt)
def _select_tool(self, sub_task):
"""根据任务类型选择最合适的工具"""
tool_map = {
"search": "search_api",
"database": "db_query",
"code_execution": "code_runner",
"file_operation": "file_handler",
"calculation": "calculator"
}
return tool_map.get(sub_task.tool_type, "general_tool")
# 执行示例
scheduler = Scheduler(LLMEngine(), ToolRegistry())
# 搜索类任务 → 调用工具
scheduler.dispatch(SubTask(type="search", requires_external_data=True))
# [调度] 工具执行: search_api → {"北京房价": ...}
# 推理类任务 → 调用模型
scheduler.dispatch(SubTask(type="analyze", requires_reasoning=True))
# [调度] 模型推理: 分析房价趋势 → 一线城市环比下降2%
# 验证类任务 → 工具+模型
scheduler.dispatch(SubTask(type="verify", requires_verification=True))
# [调度] 交叉验证 → 工具:数据查询结果, 模型:验证通过
// 调度器实现:根据任务特征分配执行路径
class Scheduler {
constructor(private llm: LLMEngine, private tools: ToolRegistry) {}
dispatch(subTask: SubTask): any {
// 判断1:是否需要外部数据?
if (subTask.requiresExternalData) {
const toolName = this.selectTool(subTask);
const result = this.tools.call(toolName, subTask.params);
console.log(`[调度] 工具执行: ${toolName} → ${result}`);
return result;
}
// 判断2:是否需要逻辑推理?
if (subTask.requiresReasoning) {
const result = this.llm.reason(subTask.prompt);
console.log(`[调度] 模型推理: ${subTask.prompt} → ${result}`);
return result;
}
// 判断3:是否需要格式化输出?
if (subTask.requiresFormatting) {
const result = this.llm.format(subTask.rawOutput);
console.log(`[调度] 模型格式化 → ${result}`);
return result;
}
// 判断4:是否需要验证结果?
if (subTask.requiresVerification) {
const toolResult = this.tools.call('verify', subTask.params);
const modelResult = this.llm.reason(`验证以下结果是否合理: ${toolResult}`);
console.log(`[调度] 交叉验证 → 工具:${toolResult}, 模型:${modelResult}`);
return modelResult;
}
// 默认:模型处理
return this.llm.reason(subTask.prompt);
}
private selectTool(subTask: SubTask): string {
const toolMap: Record = {
search: 'search_api',
database: 'db_query',
code_execution: 'code_runner',
file_operation: 'file_handler',
calculation: 'calculator'
};
return toolMap[subTask.toolType] || 'general_tool';
}
}
// 调度器实现:根据任务特征分配执行路径
package main
// Scheduler 调度器
type Scheduler struct {
llm *LLMEngine
tools *ToolRegistry
}
func (s *Scheduler) Dispatch(subTask *SubTask) interface{} {
// 判断1:是否需要外部数据?
if subTask.RequiresExternalData {
toolName := s.selectTool(subTask)
result := s.tools.Call(toolName, subTask.Params)
fmt.Printf("[调度] 工具执行: %s → %v\n", toolName, result)
return result
}
// 判断2:是否需要逻辑推理?
if subTask.RequiresReasoning {
result := s.llm.Reason(subTask.Prompt)
fmt.Printf("[调度] 模型推理: %s → %v\n", subTask.Prompt, result)
return result
}
// 判断3:是否需要格式化输出?
if subTask.RequiresFormatting {
result := s.llm.Format(subTask.RawOutput)
fmt.Printf("[调度] 模型格式化 → %v\n", result)
return result
}
// 判断4:是否需要验证结果?
if subTask.RequiresVerification {
toolResult := s.tools.Call("verify", subTask.Params)
modelResult := s.llm.Reason(fmt.Sprintf("验证以下结果是否合理: %v", toolResult))
fmt.Printf("[调度] 交叉验证 → 工具:%v, 模型:%v\n", toolResult, modelResult)
return modelResult
}
// 默认:模型处理
return s.llm.Reason(subTask.Prompt)
}
func (s *Scheduler) selectTool(subTask *SubTask) string {
toolMap := map[string]string{
"search": "search_api",
"database": "db_query",
"code_execution": "code_runner",
"file_operation": "file_handler",
"calculation": "calculator",
}
if name, ok := toolMap[subTask.ToolType]; ok {
return name
}
return "general_tool"
}
// 调度器实现:根据任务特征分配执行路径
public class Scheduler {
private final LLMEngine llm;
private final ToolRegistry tools;
public Scheduler(LLMEngine llm, ToolRegistry tools) {
this.llm = llm;
this.tools = tools;
}
public Object dispatch(SubTask subTask) {
// 判断1:是否需要外部数据?
if (subTask.requiresExternalData) {
String toolName = selectTool(subTask);
Object result = tools.call(toolName, subTask.params);
System.out.printf("[调度] 工具执行: %s → %s%n", toolName, result);
return result;
}
// 判断2:是否需要逻辑推理?
if (subTask.requiresReasoning) {
Object result = llm.reason(subTask.prompt);
System.out.printf("[调度] 模型推理: %s → %s%n", subTask.prompt, result);
return result;
}
// 判断3:是否需要格式化输出?
if (subTask.requiresFormatting) {
Object result = llm.format(subTask.rawOutput);
System.out.printf("[调度] 模型格式化 → %s%n", result);
return result;
}
// 判断4:是否需要验证结果?
if (subTask.requiresVerification) {
Object toolResult = tools.call("verify", subTask.params);
Object modelResult = llm.reason("验证以下结果是否合理: " + toolResult);
System.out.printf("[调度] 交叉验证 → 工具:%s, 模型:%s%n", toolResult, modelResult);
return modelResult;
}
// 默认:模型处理
return llm.reason(subTask.prompt);
}
private String selectTool(SubTask subTask) {
return switch (subTask.toolType) {
case "search" -> "search_api";
case "database" -> "db_query";
case "code_execution" -> "code_runner";
case "file_operation" -> "file_handler";
case "calculation" -> "calculator";
default -> "general_tool";
};
}
}
调度器的核心价值在于避免无谓的调用:如果用户只是问"Python 怎么排序",不需要调用搜索工具,模型直接回答即可;如果用户问"北京明天天气",模型无法知道实时数据,必须调用工具。调度器就是在做这个判断。 📋 八股总结 — 面试高频考点
Q1: 什么是 AI Agent?它和 ChatBot 的本质区别是什么?
AI Agent 是一种能够感知环境、自主规划、使用工具、采取行动来完成目标的 AI 系统。
本质区别在于:自主性。ChatBot 只能被动回答���题(输入→输出),Agent 能主动拆解任务、调用工具、多步执行(感知→规划→行动→反馈)。ChatBot 是"嘴",Agent 是"手+脑"。
Q2: AI Agent 的四大核心模块是什么?分别有什么作用?
① LLM(大脑):理解意图、推理决策、生成回答
② 记忆(Memory):短期记忆保存对话上下文,长期记忆通过向量库存储经验
③ 规划(Planning):将复杂目标拆解为可执行的子任务序列
④ 工具(Tools):调用外部 API、代码执行器、数据库等,实现"行动"能力
四者协同构成 Agent 的完整能力闭环。缺了 LLM 没有智力,缺了记忆没有连贯性,缺了规划只能做简单任务,缺了工具无法与外部世界交互。
Q3: Agent 的"感知-决策-行动-反馈"闭环是什么意思?
这是 Agent 运行的基本范式:
感知:接收用户输入或环境变化
决策:LLM 推理分析,决定下一步做什么
行动:调用工具执行具体操作
反馈:观察行动结果,更新状态,决定是否继续循环
这个闭环可以多轮循环,使 Agent 能处理需要多个步骤才能完成的复杂任务。ReAct 模式(第5章)就是这个闭环的经典实现。
Q4: Agent、ChatBot、Copilot 三者的区别?面试怎么答?
ChatBot:被动对话,只能回答,不能行动。如 ChatGPT。
Copilot:辅助人类完成工作,人在主导,AI 是工具。如 GitHub Copilot。
Agent:自主完成目标,AI 主导,人可监督。能独立规划、决策、执行。
关键区别在于自主性程度:ChatBot 无自主性,Copilot 低自主性(人主导),Agent 高自主性(AI 主导)。
Q5: 为什么说 2025-2026 年是 Agent 元年?技术条件发生了什么变化?
几个关键条件同时成熟:
① LLM 能力跃升:GPT-4o、Claude 3.5、Gemini 2.0 推理能力大幅提升,足以支撑复杂规划
② Function Calling 标准化:OpenAI 等原生支持工具调用,不再需要 hack
③ MCP 协议:工具调用标准化,跨框架复用成为可能
④ 框架成熟:LangGraph、CrewAI、Google ADK、Spring AI 等生产级框架涌现
⑤ 成本下降:模型调用成本大幅降低,多轮 Agent 调用经济可行
Q6: 从用户输入到 Agent 输出,完整链路包含哪些步骤?每步的作用是什么?
完整 8 步链路:
① 用户输入接收:接收原始消息,预处理清洗
② 意图识别:理解用户想做什么(问答/修改/开发),决定执行路径
③ 任务分类:判断任务类型和复杂度,决定是否需要拆解
④ 任务拆解:将复杂任务分解为子任务序列(仅复杂任务需要)
⑤ 执行调度:决定何时调用模型、何时调用工具,安排执行顺序
⑥ 工具调用:通过 Function Calling/MCP 调用外部工具获取数据或执行操作
⑦ 结果整合:收集各步骤输出,缝合为完整答案
⑧ 输出返回:格式化结果返回用户,同时存入记忆
关键:Step 5→2 的回边表示迭代循环,Agent 不是单程直线,而是可以循环调整的。
Q7: Agent 如何判断一个任务是简单问答还是需要多步执行?判断依据是什么?
通过意图识别 + 任务分类两步判断:
意图识别有三种方法:关键词匹配(快但粗糙)、语义理解(精准但成本高)、模式识别(利用历史经验)。实际工程中三者组合使用,形成分层识别策略。
任务分类依据四个维度:
① 是否需要外部数据?(需要 → 至少涉及工具调用)
② 是否需要多步操作?(需要 → 必须任务拆解)
③ 输入的复杂度?(单句问答 → 简单,长文+多要求 → 复杂)
④ 是否有依赖关系?(步骤间有先后依赖 → 复杂调度)
简单问答:跳过拆解和工具调用,直接回答。复杂任务:走完 8 步链路,可能多轮迭代。
Q8: Agent 的调度器如何决定"调用模型"还是"调用工具"?
调度决策的核心原则:模型擅长思考,工具擅长行动。
决策树的四个判断节点:
① 需要外部数据?→ 调用工具(搜索/数据库/API)
② 需要逻辑推理?→ 调用模型(理解/分析/生成)
③ 需要格式化输出?→ 调用模型(润色/排版)
④ 需要验证结果?→ 工具+模型交叉验证(工具获取事实,模型判断一致性)
实际工程中,调度器还考虑成本和延迟:简单意图先用关键词快速路由(低成本),复杂意图才走完整 LLM 推理链路(高成本但精准)。