不是直接调大模型接口,而是给它装上 Tool、Memory、RAG、MCP、Skills —— 它就能自己干活了
一、原生 LLM 的五个“做不到”
在聊 Agent 之前,我们先看一个核心问题:直接调用大模型接口,到底缺什么?
| 问题 | 说明 |
|---|---|
| ❌ 无记忆 | 你和它上周聊过的消息,它完全记不住。因为 LLM 天生是 stateless 的 |
| ❌ 不能行动 | 让它帮忙访问一个网页、做一些事情,它只能告诉你思路,需要我们自己做 |
| ❌ 知识局限 | 内部私有文档,LLM 不知道 —— 因为不在训练数据里 |
| ❌ 信息滞后 | 最新的世界新闻,已经不在训练数据中 |
| ❌ 无法操作外部系统 | 做 PPT、分析股市并自动买卖 —— 原生 LLM 做不到 |
而 Agent 就是围绕以上问题,给 LLM 加上:
text
Agent = LLM + Memory + Tool + RAG + MCP + Skills
这样一个知道内部知识、能思考、规划,能够帮你做事情的扩展后的 LLM,就是一个 Agent。
二、Agent 的完整工作流程
一张图看懂 Agent 如何响应你的请求:
text
用户以 Prompt 形式提出一个复杂任务
↓
LLM Planning / Reasoning
(规划 / 推理)
↓
┌───────┼───────┐
↓ ↓ ↓
Memory Tool RAG
(加载记忆)(调用工具)(查询知识)
↓
工具分步骤、调用多个工具
↓
RAG 查询出来的内容作为 Prompt Template
↓
Response
↓
用户(任务完成)
核心要点:
- LLM 本身就可以思考、规划
- 用 Tool 扩展能力,让它能自己做事
- 用 Memory 管理记忆,让它记住你要它记住的东西
- 用 RAG 查询内部知识,让它知道你不知道的
三、核心组件逐个拆解
1. Memory(记忆模块)
原生 LLM 是无状态的(stateless),每次对话都是全新的开始。
解决方案:
- 配合数据库持久化存储历史对话
- 配合前端存储(如 localStorage)保存用户上下文
- 配合 Redis 做短期记忆缓存
- LKM + 后端:通过后端服务管理会话状态
2. Tool(工具调用能力)
这是 Agent 最核心的能力 —— 让 LLM 能“动手”干活。
典型场景:
- 读取/写入文件(fs 模块)
- 执行命令行命令(CLI)
- 访问网页内容
- 调用第三方 API
手写一个简单版本的 Claude Code:
text
LLM + Tool(fs + cli)
3. RAG(检索增强生成)
解决 LLM “不知道” 的问题:
- 内部私有文档 → LLM 不知道 → RAG 模块查询后作为 Prompt 注入
- 最新世界新闻 → 不在训练数据中 → RAG 实时检索
4. MCP(Model Context Protocol)
第三方 Tool 的标准化协议,让 LLM 能以统一方式对接外部工具。
5. Skills(技能蒸馏)
将复杂任务固化为可复用的“技能”,比如:
- 做 PPT
- 分析股市并自动买卖
- 自动化任务(类似 Manus)
四、Agent 开发框架:Langchain
笔记中重点提到了 Langchain 生态:
| 框架 | 用途 |
|---|---|
| Langchain | 单智能体开发框架 |
| Langgraph | 多智能体开发框架 |
| 技术栈 | Node(Next.js)+ Langchain + Langgraph |
结合后端技术,开发 AI 全栈 Agent 产品,让 AI 技术通过 Harness Engineering 落地,实现 AI 技术的商业价值(FDE)。
五、实战:用 Langchain 构建一个文件读取 Agent
环境与依赖
javascript
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import { tool } from '@langchain/core/tools';
import {
HumanMessage,
SystemMessage,
ToolMessage,
AIMessage
} from '@langchain/core/messages';
import fs from 'node:fs/promises';
import { z } from 'zod'; // z 提供类型约束
模型初始化(兼容 DeepSeek)
javascript
const model = new ChatOpenAI({
modelName: 'deepseek-v4-flash',
apiKey: process.env.DEEPSEEK_API_KEY,
temperature: 0,
configuration: {
baseURL: 'https://api.deepseek.com/v1',
},
});
定义 Tool:读文件工具
javascript
const readFileTool = tool(
async ({ filePath }) => {
// 功能函数:实际读取文件
const content = await fs.readFile(filePath, 'utf-8');
// 时刻反馈 Agent 执行消息
// Agent 任务可能很复杂、很耗时,需要给用户反馈
// 用户太久没有看到反馈,可能会退出
console.log(`[工具调用] read_file(${filePath}) 成功读取 ${content.length} 字节`);
return content;
},
{
name: 'read_file',
description: '用此工具来读取文件内容,当用户要求读取文件、查看代码、分析文件内容时,调用此工具。输入文件路径(可以是相对路径或绝对路径)',
schema: z.object({
filePath: z.string().describe('要读取的文件路径'),
}),
}
);
const tools = [readFileTool];
关键设计要点:
description:详细描述功能、覆盖场景、参数需求schema:参数约束,Tool 与 LLM 要调用此工具,必须提供 schema 约定的参数tool_calls:要调用的工具列表,包含id、name、arguments- 多个工具通过
id关联,等会儿 tool 函数调用时对应
绑定工具 & 执行
javascript
// Langchain 提供了 LLM 和 Tools 注册的抽象
const modelWithTools = model.bindTools(tools);
const messages = [
new SystemMessage(
"你是一个代码助手,可以使用工具读取文件并解释代码。"
),
new HumanMessage('请读取 tool.mjs 文件内容并解释代码')
];
let response = await modelWithTools.invoke(messages);
// console.log(JSON.stringify(response));
messages.push(response);
// 如果 response 中有 tool_calls,需要执行对应的工具
// 并将结果作为 ToolMessage 返回给 LLM
多工具并发执行(Promise.all)
当 Agent 需要调用多个工具时,串行执行会严重影响效率。
html
<script>
// 封装成函数,调用时才创建 Promise、启动定时器
function getWeather() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ temp: 38, conditions: 'Sunny with Clouds' });
}, 2000);
});
}
function getTweets() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(['I like cake', 'BBQ is good too!']);
}, 500);
});
}
// ❌ 串行执行:总耗时 ≈ 2500ms
const main_serial = async () => {
console.time("serial");
const weatherData = await getWeather(); // 等 2000ms
const tweetsData = await getTweets(); // 再等 500ms
console.timeEnd("serial");
};
// ✅ 并行执行:总耗时 ≈ 2000ms
const main_parallel = async () => {
console.time("parallel");
// Promise.all 并行执行多个 Promise
// 等待所有 Promise 都完成,才返回结果
// 结果顺序与 Promise 顺序一致
const [weatherData, tweetsData] = await Promise.all([
getWeather(),
getTweets()
]);
console.timeEnd("parallel");
};
main_parallel();
</script>
Promise 核心知识点:
Promise.all静态方法并行执行多个 Promise- Promise 三种状态:
Pending(等待中)→Fulfilled(成功)或Rejected(失败) - 只能从 Pending → Fulfilled/Rejected 之一,且不能再变
await(ES8)最优雅的异步变同步语法
六、Agent 开发中的关键认知
1. Tool 调用的“自知之明”
LLM 有自知之明,当要调用 tool 的时候,不生成内容,停下来告诉用户。
这意味着:
- LLM 生成
tool_calls,而不是直接回答 - 系统执行工具,获取结果
- 将结果作为上下文再次交给 LLM 生成最终回答
2. 多工具调用的复杂性
- 任务复杂时,可能调用多个 tool,或每个 tool 调用多次
- 工具是异步的,LLM 哪个任务细节由哪个工具执行了,通过
id关联 - 结果需要历史会话才能组成完整的任务上下文
3. LLM 基于自然语言
LLM 理解用户的自然语言描述,将其转化为结构化的 tool 调用,这是 Agent 智能的核心。
七、Demo:创建一个 React + Vite TodoList
笔记中给出的完整 Agent 任务示例:
text
创建一个 React + Vite TodoList
要用到哪些 Tool?
这是一个编程任务,Planning 分三步:
| 步骤 | 工具 | 说明 |
|---|---|---|
| 1 | write_file | Vite 创建项目,写入文件 |
| 2 | LLM 编程能力 | 生成组件代码(需要编程能力比较强的模型) |
| 3 | cli_command | 项目运行起来,调用 CLI 命令工具 |
八、总结
| 组件 | 解决的问题 |
|---|---|
| LLM | 思考、规划、推理 |
| Memory | 记住历史对话和上下文 |
| Tool | 读写文件、执行命令、访问网页 |
| RAG | 获取私有文档和最新信息 |
| MCP | 标准化对接第三方工具 |
| Skills | 固化复杂任务为可复用技能 |
Agent 其实并不复杂:
- LLM 本身就可以思考、规划
- 给它用 Tool 扩展能力,它就能自己做事情
- 用 Memory 管理记忆,它就可以记住你要它记住的东西
- 用 RAG 查询内部知识来获取知识
这样一个知道内部知识、能思考、规划,能够帮你做事情的扩展后的 LLM,就是一个 Agent。