LLM 学习笔记 Day 4:Agent

一、LLM 的边界:为什么它不能直接完成复杂任务?

一个场景

用户说:"帮我生成一份 Java 简历。"

如果直接丢给 LLM,它会生成一份"看起来不错"的简历------但很可能是凭空捏造的。LLM 没有用户的真实经历,不知道目标岗位的具体要求,也无法调用外部工具去搜索、匹配、排版。

真正需要的执行流程

复制代码
用户输入
 → 理解意图
 → 收集 JD(需要用户上传或描述)
 → 解析 JD(提取技术要求)
 → 收集简历(需要用户提供)
 → 解析简历(提取技能、经历)
 → 匹配排序(精确对比 JD 和简历)
 → 重写优化
 → 生成 PDF

LLM 能完成其中的"理解意图""解析 JD""重写优化"------这些属于语言理解与生成

但它做不了:

  • 获取外部信息(搜索、读文件)
  • 精确计算(打分排序)
  • 执行动作(调用 API、生成 PDF)
  • 多步循环(根据中间结果调整策略)

LLM vs Agent 本质区别

LLM Agent
只能"回答" 可以"行动"
被动的,单次生成 主动的,循环执行
不知道的只能编 不知道的可以去查
输出文本 调用工具 + 输出文本

Agent = LLM + 规划能力 + 工具调用 + 记忆 + 反思

LLM 是一个"思考器官",Agent 是一个"完整的执行者"。


二、 Tool(工具)?

Tool 的准确定义

Tool 是 LLM 不具备的能力的外部扩展。 它让 Agent 能够"做事情",而不只是"说事情"。

为什么 LLM 需要 Tool?

  • 精确计算:LLM 擅长语言概率,不擅长数学规则
  • 实时信息:LLM 的知识有截止日期
  • 执行操作:LLM 不能调 API、读写文件、操作数据库

Tool ≠ 函数

"Tool 就是函数"------这个理解不完整。

判断标准:Tool 是一个可以被调用来完成具体任务的能力单元,有明确的输入输出。

三、Function Calling:为什么比 ReAct 稳定?

以前的做法(ReAct)

让 LLM 在输出文本中嵌入特殊标记:

复制代码
Action: Calculator
Action Input: 123 * 456

然后用代码解析文本 ,提取出工具名和参数。

问题

  • 格式不稳定:多一个空格或换行就可能解析失败
  • 依赖正则匹配,复杂场景容易出错

Function Calling 的做法

LLM 直接输出结构化 JSON

json 复制代码
{
  "name": "calculator",
  "parameters": {
    "expression": "123 * 456"
  }
}

为什么更稳定?

  • 结构化输出:JSON 格式确定,不会因文本差异解析失败
  • Schema 约束:可以预定义参数类型、必填项,LLM 被训练去遵守这些约束
  • 训练有素:现代 LLM 在训练阶段已学过 Function Calling

四、Tool Calling 全过程------Agent 的核心循环

所有 Agent 的通用骨架

复制代码
用户输入
 → ① LLM 分析:需要调用什么工具?
 → ② 决定调用 Tool
 → ③ 执行 Tool → 得到 Observation(观察结果)
 → ④ Observation 返回给 LLM
 → ⑤ LLM 判断:任务完成了吗?还需要再调工具吗?
 → ⑥ 如需要,回到②;如完成,生成最终回答

Observation 是什么?为什么一定要回传 LLM?

Observation = Tool 执行后返回的原始结果。 比如:

  • 计算器 Tool → "56088"
  • 检索 Tool → ["简历段落1", "简历段落2"]

为什么不能直接返回给用户?

用户问"我的简历匹配吗?" → Agent 调检索 Tool 拿到一堆文本片段 → 如果直接返回,用户看到的是碎片数据,不是答案。

正确做法: Observation 回传给 LLM → LLM 阅读并理解 → 生成自然语言回答:

"您的简历在 Java 方面匹配度很高,但在微服务经验上有所欠缺......"

Observation 必须回传 LLM 的三个原因:

  1. LLM 是唯一的"理解者"和"表达者"
  2. LLM 需要判断任务是否完成
  3. LLM 需要整合多步 Observation 生成完整答案