一文搞懂AI Agent核心概念:从LLM、Tools到记忆体,手把手带你实现一个能查股价的智能体

为什么现在的AI不仅能聊天,还能帮你写代码、查股价、操作浏览器?背后全靠 Agent(大脑+手脚+记忆) 这三大支柱。本文将用最通俗的语言 + 可运行的 Node.js 代码,带你一次性搞懂 LLM、Tool、Data/Context 的铁三角关系,并亲手实现一个能多轮对话、自动查股票收盘价的完整 Agent。


1. 引言:AI 正在从"聊天"走向"干活"

2025 年以来,AI 领域最火的关键词已经不是"大模型"本身,而是 Agent(智能体) 。你会发现,Cursor、Claude Code、豆包、WorkBuddy 这些产品,不再只是你问我答,它们能 读文件、搜网络、写代码、操作浏览器、甚至控制你的电脑------这一切的核心,就是 Agent。

作为一名开发者,如果你还不理解 Agent、LLM、Tool 之间的关系,很快就会被时代甩开。今天,我就用最直白的语言和可运行的 Node.js 代码,带你一次性理清这些概念,并亲手造一个能查股票收盘价的 Agent。


2. Agent:能"干活"的 AI

Agent 是什么?

简单说,Agent = 大脑(LLM) + 手脚(Tools) + 记忆与知识(Data/Context)

它不再满足于"回答问题",而是 主动规划、调用工具、执行任务,最后把结果反馈给你。

例如:

  • 你问:"青岛啤酒今天的收盘价是多少?"
    普通 LLM 只能根据训练数据瞎猜(可能还是过时的)。
    但 Agent 会识别出"需要查实时数据",于是调用股票价格查询工具,拿到结果后再组织成自然语言回答你。
  • 你问:"帮我写一个 Python 脚本,爬取某网站标题。"
    Agent 会调用代码执行工具,甚至直接操作你的 IDE。

Agent 有多强,取决于三个因素:

  1. 大脑(LLM) :推理能力强不强,能不能理解复杂指令。
  2. 手脚(Tools) :接入了多少外部能力(数据库、API、浏览器、文件系统)。
  3. 记忆与知识(Data/Context) :能拿到多少历史对话、系统指令和外部检索数据。

现在最值钱的岗位就是 Agent 工程师,他们负责把各种工具"装"给 LLM,并设计好上下文记忆机制,让 AI 真正落地到业务中,降本增效。


3. LLM:Agent 的"大脑"

LLM(大语言模型)是 Agent 的核心推理引擎。

它负责 理解你的意图、拆解任务、决定调用哪个工具、组织最终回复

但 LLM 本身 只有推理和生成文本的能力 ,它无法主动去查数据库、发 HTTP 请求、操作文件系统------这些"行动"全靠 工具(Tool) 来完成。

举个例子:

  • 你问:"青岛啤酒股价多少?"
  • LLM 推理:用户想要实时股价 → 我需要调用 get_closing_price 这个工具 → 参数是"青岛啤酒"。
  • LLM 生成一个 工具调用请求(而不是直接回答),交给外部执行。
  • 外部拿到结果后,再回传给 LLM,LLM 再组织成"青岛啤酒收盘价 67.92 元"返回给你。

整个流程就像:大脑发出指令 → 手脚去执行 → 大脑再汇报结果


4. Tool:让 AI 长出"手脚"

Tool 就是 LLM 能够调用的外部函数或 API。

通过 Tool,LLM 可以查询数据库、发送邮件、控制浏览器、读写文件......没有 Tool,LLM 就是纸上谈兵

OpenAI 和各大模型厂商都提供了标准的 Tool 定义接口(Function Calling),让开发者可以轻松地为 LLM 注册工具。

下面我们先看如何声明一个工具

go 复制代码
// index.mjs 中的工具声明部分
const tools = [
    {
        type: "function",
        function: {
            name: "get_closing_price",
            description: "获取指定股票的收盘价",
            parameters: {
                type: "object",
                properties: {
                    name: {
                        type: "string",
                        description: "股票名称,如'青岛啤酒'、'贵州茅台'"
                    }
                },
                required: ["name"]
            }
        }
    }
];

关键点解析:

  • type: "function":固定写法,表示这是一个函数工具。
  • function.name:工具名称,LLM 在调用时会引用它。
  • function.description极其重要!清晰描述工具功能,LLM 靠它判断何时调用。
  • function.parameters:定义参数结构(JSON Schema),告诉 LLM 需要哪些参数、类型是什么。
  • required:必填参数列表。

注意: 这里只是"声明"了工具,真正的执行逻辑是 get_closing_price 函数。LLM 不会直接执行它,而是返回一个工具调用请求,由我们的代码去执行。


5. 数据与上下文(Data & Context):Agent 的"记忆"与"知识库"

如果说 LLM 是大脑、Tools 是手脚,那么数据和上下文(Data & Context)就是 Agent 的血液和记忆体。一个没有上下文记忆的 Agent,每次对话都是"失忆"的;一个没有外部数据的 Agent,只能用训练集里的陈旧知识"胡编乱造"。

在实战中,"上下文"主要由以下三大块构成:

5.1 对话上下文(Messages / 短期记忆)

这就是你在笔记中提到的 messages 多轮对话列表。它承载着当前会话的所有历史信息,让 LLM 能够"记得"我们刚才说了什么。

为什么它至关重要?

如果没有将历史对话传回给 LLM,当你问"那茅台呢?"时,LLM 根本不知道你在延续关于"股票收盘价"的话题。它会孤立地回答问题,甚至反问"你指茅台的什么?"

代码对应:

main.mjs 中,正是通过不断累加 messages 数组来实现多轮上下文理解的。我们把历史问答都放进去,LLM 就能明白"那茅台呢?" = "查一下贵州茅台的收盘价"。

5.2 系统提示词(System Prompt / 指令上下文)

这也是数据上下文中极其重要的一环。它就像给 Agent 设定的"人设"和"工作守则",在每一次推理时都会被置入上下文。

举例:

main.mjs 中,system 角色扮演的是"足球专家"。如果将系统提示改为:

css 复制代码
{ role: 'system', content: '你是股票交易助手,所有回答必须附带数据来源,且必须使用工具查询,禁止瞎猜。' }

那么在整个对话生命周期中,Agent 都会被这个指令上下文约束,确保它不会胡编乱造股价。

5.3 外部知识库与长期数据(RAG / 长期记忆)

这是现代 Agent 落地企业场景的杀手锏。因为 LLM 的训练数据是有截止日期的(比如截止 2024 年初),它不知道公司内部的财报、私有协议或实时政策。

"数据"如何补全 Agent 的能力?

当用户问"我们公司 Q3 的报销制度是什么?"时,通用 LLM 根本不知道。这时 Agent 会:

  1. 检索(Retrieve) :先去向量数据库或企业知识库中,检索出相关的 PDF 或 Word 文档内容(这就是外部 Data)。
  2. 注入(Augment) :把这些查到的文本内容,拼接到当前的 messages 上下文中(比如伪装成 systemuser 消息)。
  3. 生成(Generate) :LLM 基于这些新注入的数据来生成答案。

"拿到了什么信息"决定了 Agent 的能力。 如果 Agent 拿到了实时联网搜索的"信息",它就能回答最新新闻;如果拿到了企业数据库的"信息",它就能做商业智能分析。


🔥 升级版架构图:Agent 的四维拼图

结合新增的"数据与上下文",我们来更新一下核心逻辑图:

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         AI Agent(智能体)                      │
│                                                                 │
│  ┌──────────────┐    ┌──────────────┐   ┌───────────────────┐ │
│  │ 1. 大脑 (LLM) │◄──►│ 2. 手脚(Tool)│   │ 3. 记忆与知识(Data│ │
│  │  推理 & 规划   │    │ 操作外部世界  │   │    & Context)     │ │
│  └──────────────┘    └──────────────┘   └───────────────────┘ │
│          │                  ▲                      ▲           │
│          └──────────────────┼──────────────────────┘           │
│                             │                                  │
│              ┌──────────────┴──────────────┐                   │
│              │   ① 短期记忆(Messages)      │                   │
│              │   ② 指令约束(System Prompt) │                   │
│              │   ③ 长期知识(RAG/数据库)   │                   │
│              └─────────────────────────────┘                   │
└─────────────────────────────────────────────────────────────────┘

6. 实战:从零搭建一个完整的股票查询 Agent

有了前面的理论,我们终于进入实战。这一次,我们不只打印 tool_calls,而是完整跑通"声明工具 → LLM请求调用 → 本地执行 → 结果回传 → 生成最终答案"的全链路

6.1 项目结构 & 客户端初始化

less 复制代码
.
├── client.mjs       // 初始化 OpenAI 兼容客户端
├── index.mjs        // 🌟 完整 Agent 逻辑(工具声明 + 往返调用)
└── main.mjs         // 展示 reasoning_effort 深度推理

client.mjs(客户端封装):

arduino 复制代码
import { OpenAI } from "openai";
import dotenv from 'dotenv';

dotenv.config();

const client = new OpenAI({
    apiKey: process.env.DEEPSEEK_API_KEY,
    baseURL: process.env.DEEPSEEK_API_BASE_URL,
});

export default client;

6.2 完整 Agent 代码(index.mjs)

下面这段代码是精华所在,我加上了详细注释,帮你理解每一步在做什么:

javascript 复制代码
import client from "./client.mjs";

// ---------- 第一步:声明工具(告诉 LLM 它有这个能力) ----------
const tools = [
    {
        type: "function",
        function: {
            name: "get_closing_price",
            description: "获取指定股票的收盘价",
            parameters: {
                type: "object",
                properties: {
                    name: {
                        type: "string",
                        description: "股票名称,如'青岛啤酒'、'贵州茅台'"
                    }
                },
                required: ["name"]
            }
        }
    }
];

// ---------- 第二步:真正干活的函数(模拟查数据库/API) ----------
function get_closing_price(name) {
    if (name === '青岛啤酒') return "67.92 元";
    if (name === '贵州茅台') return "1488.21 元";
    return "未找到该股票数据";
}

// ---------- 第三步:发送消息(携带 tools 声明) ----------
const send_message = async (messages) => {
    return await client.chat.completions.create({
        model: 'deepseek-v4-flash', // 替换成你的模型
        messages,
        tools,
        tool_choice: 'auto'
    });
};

// ---------- 第四步:主流程(处理工具调用往返) ----------
const main = async () => {
    // 初始化对话上下文(记忆从这里开始)
    let messages = [
        { role: 'user', content: "青岛啤酒的收盘价是多少?" }
    ];

    // 4.1 第一次请求 LLM
    let response = await send_message(messages);
    let assistantMessage = response.choices[0].message;

    // 4.2 检查 LLM 是否要求调用工具
    if (assistantMessage.tool_calls) {
        console.log("🧠 LLM 决定调用工具:", assistantMessage.tool_calls[0].function.name);

        // 解析参数
        const toolCall = assistantMessage.tool_calls[0];
        const args = JSON.parse(toolCall.function.arguments);
        const stockName = args.name;

        // 4.3 执行本地工具函数(这一步就是 Agent 的"手脚"在动)
        const result = get_closing_price(stockName);
        console.log(`⚙️ 执行工具: get_closing_price("${stockName}") -> ${result}`);

        // 4.4 把 LLM 的调用请求和工具结果,都追加到上下文(Messages)里
        messages.push(assistantMessage); // 加入 LLM 的请求调用记录
        messages.push({
            role: 'tool',                // 工具回传的角色
            tool_call_id: toolCall.id,   // 关联本次调用 ID
            content: result              // 工具执行结果
        });

        // 4.5 第二次请求 LLM:把工具结果带回去,让它生成最终答案
        response = await send_message(messages);
        assistantMessage = response.choices[0].message;
    }

    // 4.6 输出最终答案
    console.log("🤖 Agent 最终回答:", assistantMessage.content);
};

main();

运行结果示例:

css 复制代码
🧠 LLM 决定调用工具: get_closing_price
⚙️ 执行工具: get_closing_price("青岛啤酒") -> 67.92 元
🤖 Agent 最终回答: 青岛啤酒的收盘价为 67.92 元。

6.3 验证"上下文记忆"的重要性

如果我们接着问"那茅台呢?",只需要把 messages 改成:

ini 复制代码
let messages = [
    { role: 'user', content: "青岛啤酒的收盘价是多少?" },
    { role: 'assistant', content: "青岛啤酒的收盘价为 67.92 元。" }, // 记住上一轮
    { role: 'user', content: "那茅台呢?" }
];

因为上下文里有"收盘价"这三个字,LLM 就能准确推断出"茅台"指的是"查询贵州茅台的收盘价",并再次调用 get_closing_price("贵州茅台")如果没有这个记忆上下文,LLM 就会一脸懵。


7. 推理能力与 reasoning_effort API

除了工具调用,LLM 的 推理过程(Reasoning) 也至关重要。

尤其是处理复杂问题时,我们不仅想要最终答案,还想看到它"思考"的步骤,便于调试和信任。

DeepSeek 提供了 reasoning_effort 参数,可以控制模型的推理深度。

我们在 main.mjs 中演示:

php 复制代码
import client from './client.mjs';

const main = async () => {
    const result = await client.chat.completions.create({
        model: 'deepseek-v4-flash',
        reasoning_effort: 'high',  // 开启深度推理模式
        messages: [
            { role: 'system', content: '你是一个足球领域的专家,请尽量帮我回答与足球相关的问题' },
            { role: 'user', content: 'c罗是哪个国家的足球运动员?' },
            { role: 'assistant', content: 'c罗是葡萄牙的足球运动员' },
            { role: 'user', content: '内马尔呢?' }
        ]
    });

    console.log('🧠 思考过程:');
    console.log(result.choices[0].message.reasoning_content); // 推理链
    console.log('\n📢 最终答案:');
    console.log(result.choices[0].message.content);
};

main();

运行后,你会看到类似输出:

erlang 复制代码
🧠 思考过程:
好的,用户问完C罗之后,接着问了内马尔。看来他可能是在了解不同知名足球运动员的国籍,或者是在对比不同球员的背景。
嗯,从之前的对话看,用户对足球领域有兴趣,但问题比较基础,可能是个刚开始关注足球的新球迷,或者只是想快速获取一些基本信息。
他的深层需求可能不仅仅是知道内马尔是哪个国家的,而是想了解内马尔的基本情况,比如他是否和C罗是同一时代的对手,或者他的技术特点是什么。
...

📢 最终答案:
内马尔是巴西的足球运动员。他目前效力于沙特阿拉伯的利雅得新月俱乐部,也是巴西国家队的核心球员。

reasoning_content 字段 展示了模型的思维链,对于调试 prompt、理解模型决策非常有帮助。

reasoning_effort 可选 low / medium / high,越高推理越深入,但也更耗时、更贵。


8. 普通对话(无工具)示例

如果你的需求只是简单问答,不需要调用外部工具,那么直接用基础的 completion 即可:

javascript 复制代码
import client from './client.mjs';

export async function getCompletion(prompt) {
    const response = await client.chat.completions.create({
        model: process.env.DEEPSEEK_MODEL,
        messages: [ { role: 'user', content: prompt } ]
    });
    return response.choices[0].message.content;
}

这是最简模式,适合简单问答。但一旦涉及到实时数据或操作,就必须引入我们前面讲的 Tools 和 Context。


9. 总结:一张图看懂 Agent 核心架构

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                         AI Agent(智能体)                      │
│                                                                 │
│  ┌──────────────┐    ┌──────────────┐   ┌───────────────────┐ │
│  │ 1. 大脑 (LLM) │◄──►│ 2. 手脚(Tool)│   │ 3. 记忆与知识(Data│ │
│  │  推理 & 规划   │    │ 操作外部世界  │   │    & Context)     │ │
│  └──────────────┘    └──────────────┘   └───────────────────┘ │
│          │                  ▲                      ▲           │
│          └──────────────────┼──────────────────────┘           │
│                             │                                  │
│              ┌──────────────┴──────────────┐                   │
│              │ ① 短期记忆(Messages)        │                   │
│              │ ② 指令约束(System Prompt)   │                   │
│              │ ③ 长期知识(RAG/数据库)      │                   │
│              └─────────────────────────────┘                   │
└─────────────────────────────────────────────────────────────────┘
  • LLM 负责"想"------推理、拆解任务、决定用什么工具。
  • Tools 负责"做"------执行具体操作,获取数据或改变状态。
  • Data/Context 负责"记"------保持多轮对话的连贯性,提供系统指令和外部知识。

而你作为开发者,最重要的工作就是:

  1. 为 LLM 精心设计 工具描述(description 和 parameters),让 LLM 能精准选用。
  2. 编写工具的真实实现(调用数据库、第三方 API 等)。
  3. 维护好 messages 上下文数组,让 Agent 拥有"记忆"。
  4. 处理多轮工具调用的往返流程(执行 → 回传 → 再生成)。

10. 下一步:进阶玩法

当你掌握了基础,可以尝试:

  • 多工具协同:一个 Agent 同时具备查股价、查天气、发邮件的能力。
  • ReAct 模式:让 LLM 进行"推理-行动-观察"的循环,自主完成复杂任务。
  • 本地工具:比如操作文件系统、控制浏览器(Puppeteer)、执行 Shell 命令。
  • RAG 接入:把企业私有文档向量化,注入到上下文里,打造专属行业专家。

现在,市场对 Agent 工程师的需求井喷,因为企业真正需要的是"能干活"的 AI,而不是只会聊天的玩具。希望这篇文章帮你迈出了扎实的第一步。

快去动手敲一遍代码吧,亲手感受一下 LLM 如何通过 Tools + Context 焕发新生!

相关推荐
沉默王二1 小时前
老板:“请说出一个录用你的理由。”我脱口而出:“每个月 AI 支出都超过我的生活费了!”老板愣了一下,随即哈哈大笑:“好吧,你被录用了。”
人工智能·ai编程·claude
Artech2 小时前
[MAF预定义的AIContextProvider-02]AgentSkillsProvider——将Agent Skills引入MAF
ai·c#·agent·agent skills·maf
乘风gg3 小时前
OpenClaw 爆火,但”飞书"赢麻了!!!
前端·ai编程·claude
冬奇Lab14 小时前
Agent 系列(21):Harness 测试工程——45 个测试怎么设计,以及它发现了什么 bug
人工智能·llm·agent
袋鱼不重17 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
量子位18 小时前
刚刚,Fable-5之下,智谱开源的GLM-5.2拿下AI编程第一!
ai编程
量子位18 小时前
SpaceX一分现金没花收购Cursor,马斯克吞下AI编程工具第一名
ai编程
程序员黑豆18 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
孟健18 小时前
我装了 Hermes Desktop,但最后还是回到 Telegram
ai编程