🤖 搞懂 AI Agent:从聊天到干活的 5 个关键环节

0 阅读10分钟

🤖 搞懂 AI Agent:从聊天到干活的 5 个关键环节

摘要:2025 年,AI Agent 已经从概念走向落地。从 Cursor 到 Claude Code,从飞书 CLI 到各种自动化工具,Agent 正在重塑我们与软件交互的方式。本文从 LLM → Tool → Agent Loop → Memory → 架构模式 层层递进,用可运行的代码带你建立完整的 Agent 认知体系。


📌 前言

你有没有想过一个问题:

同样是调用 LLM API,为什么 ChatGPT 只能跟你聊天,而 Claude Code 能直接帮你写代码、读文件、执行命令?

答案就两个字:Agent。

Agent(智能体)不是一个新的模型,而是一套让 LLM「长出手脚」的系统设计。理解 Agent,是 2025 年每个开发者都必须补上的一课。

本文不会堆砌概念,而是用可运行的代码带你走完 Agent 的完整链路。


🎯 本文适合谁

  • 🧑‍💻 使用过 LLM API,但不太理解 Agent 原理的开发者
  • 🔧 想自己动手实现一个 Agent 的工程师
  • 🤔 对 Function Calling、Tool Use 一知半解的 AI 爱好者
  • 📚 想系统建立 Agent 认知体系的学习者

一、什么是 Agent?

一句话定义

Agent = LLM + Tools + Memory + Planning
组件角色通俗理解
LLM大脑负责思考和推理
Tools手脚负责执行具体操作
Memory记忆记住上下文和历史经验
Planning规划分解复杂任务,制定执行计划

传统软件是「你告诉它做什么,它就做什么」——流程固定、路径确定。而 Agent 是「你告诉它目标,它自己想办法完成」——动态规划、自主决策。

Agent 与普通 AI 对话的区别

维度普通 AI 对话Agent
能力边界只能生成文本能读文件、调 API、操作浏览器、写代码
决策方式单次问答多步推理、动态调整
工具使用按需调用各种工具
记忆仅当前对话短期 + 长期记忆

一个 Agent 有多强?取决于三个要素:

  • 🧠 用了什么大脑(LLM)— 决定推理上限
  • 🔧 装了什么工具(Tools)— 决定行动能力
  • 📋 拿到了什么信息(Context/Memory)— 决定决策质量

有图有真相

屏幕截图 2026-07-06 230608.png

二、LLM — Agent 的大脑

LLM(大语言模型)是 Agent 的核心推理引擎。它负责理解任务、规划步骤、生成响应

⚠️ 关键认知:LLM 只负责推理和生成,它没有「手」,无法直接操作外部世界。真正的行动能力来自 Tool。

推理过程的可见性

现代 LLM 提供了 reasoning_content(思维链),让我们能看到模型的推理过程:

const result = await client.chat.completions.create({
    model: "your-model-name",  // 替换为你使用的支持 Function Calling 的模型
    reasoning_effort: 'high',  // 开启深度推理
    messages: [
        { role: 'system', content: '你是一个足球领域的专家。' },
        { role: 'user', content: 'c罗是哪个国家的足球运动员?' },
        { role: 'assistant', content: 'c罗是葡萄牙的足球运动员。' },
        { role: 'user', content: '内马尔呢?' }
    ]
});

// 查看推理过程
console.log('思考过程:', result.choices[0].message.reasoning_content);
// 输出:模型会分析上下文,识别"内马尔呢?"是在问国籍...

// 最终答案
console.log('最终答案:', result.choices[0].message.content);
// 输出:内马尔是巴西的足球运动员。

💡 reasoning_effort 控制推理深度。设为 'high' 时,模型会花更多时间「思考」,适合复杂任务。代价是更慢、更贵。

多轮对话的本质

多轮对话不是模型「记住了」之前的对话,而是你每次请求都把完整的 messages 数组发过去。模型通过上下文理解来「假装」有记忆:

messages: [
    { role: 'user', content: 'c罗是哪个国家的?' },
    { role: 'assistant', content: '葡萄牙。' },
    { role: 'user', content: '内马尔呢?' }  // 模型通过上下文推断"内马尔呢"=问国籍
]

这个机制是 Agent 记忆系统的基础——对话历史本身就是一种「短期记忆」。


三、Tool — Agent 的手脚

LLM 再强,也只是一个「大脑」。它能推理,但不能:

  • 📈 查询实时股价
  • 📁 读写本地文件
  • 🌐 浏览网页
  • 💻 执行代码

Tool(工具)就是给 Agent 装上「手脚」。 没有 Tool,Agent 只能「纸上谈兵」。

Function Calling 完整流程

这是 Agent 最核心的机制,一次完整的 Tool 调用需要 2 次 LLM 交互

用户提问:"青岛啤酒的收盘价是多少?" │ ▼ 第 1 次 LLM 调用 LLM 推理:需要调用 get_closing_price 工具 返回:tool_call(函数名 + 参数) │ ▼ 代码执行 Tool 调用 get_closing_price("青岛啤酒") 返回结果:"67.92" │ ▼ 第 2 次 LLM 调用 将 tool 结果交给 LLM LLM 生成最终答案:"青岛啤酒今日收盘价为 67.92 元。"

💡 为什么是 2 次调用? 因为 LLM 本身不执行函数。第 1 次是「决策」(告诉你要调哪个函数),第 2 次是「总结」(拿到结果后生成自然语言回答)。

代码实现

第一步:定义 Tool Schema(告诉 LLM 有哪些工具可用)

const tools = [
    {
        type: 'function',
        function: {
            name: 'get_closing_price',
            description: '获取指定股票的收盘价',  // 这段描述是 LLM 理解工具的关键!
            parameters: {
                type: 'object',
                properties: {
                    name: {
                        type: 'string',
                        description: '股票名称'  // LLM 通过这个描述提取参数
                    }
                },
                required: ['name']
            }
        }
    }
];

⚠️ 核心要点description 写得好不好,直接决定 LLM 能否准确调用工具。这是 Prompt Engineering 在 Agent 场景的直接应用。

第二步:定义 Tool 的实际执行函数

// ⚠️ 演示数据,生产环境请替换为真实 API 调用
function get_closing_price(name) {
    if (name === '青岛啤酒') return '67.92';
    if (name === '贵州茅台') return '1488.21';
    return '未找到股票';
}

第三步:完整的 Agent Loop(第 1 次 → 执行 → 第 2 次)

async function agentLoop(userQuestion) {
    let messages = [
        { role: 'user', content: userQuestion }
    ];

    try {
        // ===== 第 1 次 LLM 调用 =====
        const firstResponse = await client.chat.completions.create({
            model: process.env.LLM_MODEL,
            messages,
            tools,
            tool_choice: 'auto'  // 让 LLM 自主决定是否调用工具
        });

        const message = firstResponse.choices[0].message;

        // LLM 决定调用工具
        if (message.tool_calls) {
            messages.push(message);  // 把 LLM 的"决策"加入对话历史

            // ===== 执行 Tool =====
            for (const toolCall of message.tool_calls) {
                const functionName = toolCall.function.name;
                const args = JSON.parse(toolCall.function.arguments);

                let result;
                if (functionName === 'get_closing_price') {
                    result = get_closing_price(args.name);
                }

                // 把 Tool 结果以 tool role 追加到消息列表
                messages.push({
                    role: 'tool',
                    tool_call_id: toolCall.id,
                    content: result
                });
            }

            // ===== 第 2 次 LLM 调用 =====
            const secondResponse = await client.chat.completions.create({
                model: process.env.LLM_MODEL,
                messages,  // 包含原始问题 + LLM 决策 + Tool 结果
                tools,
            });

            return secondResponse.choices[0].message.content;
        }

        return message.content;  // LLM 认为不需要调用工具,直接返回
    } catch (error) {
        console.error('Agent 执行出错:', error.message);
        return `抱歉,处理你的请求时出错了:${error.message}`;
    }
}

// 使用
const answer = await agentLoop('青岛啤酒的收盘价是多少?');
console.log(answer);
// 输出:青岛啤酒今日收盘价为 67.92 元。

💬 聊聊:你在实际项目中使用 Function Calling 遇到过什么坑?工具调用失败你是怎么处理的?评论区聊聊你的经验 👇


四、Agent Loop — Agent 的「心跳」

理解了 Tool 调用后,我们来看更大的图景:Agent Loop

Agent 的运行不是一次性的,而是一个持续的循环:

感知 (Perceive)
  接收用户输入、环境状态、Tool 返回结果
    │
    ▼
推理 (Reason)
  LLM 分析当前状态,决定下一步行动
    │
    ▼
行动 (Act)
  调用 Tool / 生成回复 / 修改状态
    │
    ▼
观察 (Observe)
  获取行动结果,更新上下文
    │
    ▼
是否完成?── 否 ──→ 回到"感知"
    │
    是
    ▼
  返回最终结果

与传统软件的核心区别:

传统软件Agent
控制流if-else 固定分支,开发者预设所有路径LLM 在每一步动态决策
可处理场景只能处理预设情况可以处理开发者未预见的情况

这就是为什么 Agent 能处理开放式任务——它不需要你穷举所有可能,而是「见招拆招」。


五、Memory — Agent 的记忆

一个没有记忆的 Agent,每次对话都是「失忆」重新开始。记忆系统让 Agent 能积累经验、保持上下文。

三层记忆架构

1. 短期记忆:对话上下文

就是 messages 数组。Agent 的每一轮对话都依赖这个数组来理解上下文。

let messages = [
    { role: 'system', content: '你是一个股票分析师。' },
    { role: 'user', content: '茅台怎么样?' },
    { role: 'assistant', content: '贵州茅台今日收盘价 1488.21 元...' },
    { role: 'user', content: '那青岛啤酒呢?' }  // 通过上下文理解"那"指代股票
];

局限性:上下文窗口有限(通常 8K~128K tokens),太长的对话会被截断。

2. 长期记忆:向量数据库 / RAG

将历史信息存入向量数据库(如 ChromaDB、Pinecone),需要时通过语义检索召回:

用户提问 → Embedding → 向量检索 → 找到相关历史 → 作为 context 注入 prompt → LLM 回答

这就是 RAG(Retrieval-Augmented Generation)——检索增强生成。

一个最小化的 RAG 流程如下:

// 1. 将历史文档向量化并存入数据库
import { ChromaClient } from 'chromadb';
const collection = await chromaClient.createCollection({ name: 'agent_memory' });

await collection.add({
    ids: ['doc_1'],
    documents: ['贵州茅台 2024 年 Q3 营收 388 亿,同比增长 15%...'],
    // embedding 由 ChromaDB 自动生成
});

// 2. 用户提问时,检索最相关的历史记忆
const results = await collection.query({
    queryTexts: ['茅台最近的营收情况如何?'],
    nResults: 3  // 取 top 3 最相关的文档
});

// 3. 将检索结果注入 prompt,增强 LLM 的回答
const context = results.documents[0].join('\n');
messages.unshift({
    role: 'system',
    content: `参考以下历史信息回答问题:\n${context}`
});

💡 这就是 Claude Code、Cursor 等工具能「记住」整个项目上下文的核心原理。

3. 工作记忆:当前任务状态

Agent 在执行复杂任务时,需要跟踪中间状态:

const taskState = {
    goal: '帮我分析茅台的财务状况',
    completedSteps: ['获取股价', '获取市盈率'],
    currentStep: '分析营收趋势',
    pendingSteps: ['生成报告'],
    intermediateData: { pe: 28.5, revenue: '...' }
};

💬 你的经验:你是如何管理 Agent 的长期记忆的?用向量数据库还是其他方案?欢迎分享你的实践 👇


六、经典 Agent 架构模式

在 Agent 工程实践中,有两种被广泛验证的架构模式:

ReAct(Reasoning + Acting)

最经典的 Agent 模式。核心思想:交替进行推理和行动

Thought: 我需要查询茅台的股价
Action: get_stock_price("贵州茅台")
Observation: 1488.21Thought: 股价拿到了,用户可能还想知道涨跌幅...
Action: get_change_rate("贵州茅台")
Observation: +2.3%
Thought: 信息足够了,可以生成回答
Answer: 贵州茅台今日收盘价 1488.21 元,涨幅 2.3%...

每一步都有 Thought(推理)→ Action(行动)→ Observation(观察),循环往复。

Plan-and-Execute

适合复杂任务:先规划,再执行

用户:帮我写一份竞品分析报告

Step 1 (Plan): 分解任务
  - 1.1 确定竞品列表
  - 1.2 收集各竞品数据
  - 1.3 对比分析
  - 1.4 生成报告

Step 2 (Execute): 逐步执行每个子任务
  - 执行 1.1 → 完成
  - 执行 1.2 → 完成
  - ...

两种模式对比

维度ReActPlan-and-Execute
适用场景简单到中等任务复杂、多步骤任务
决策方式边做边想先想后做
灵活性高(随时调整)中(计划可能需要修订)
可预测性

🐛 实战踩坑:在一次项目中,我用 ReAct 模式让 Agent 爬取网页数据。Agent 执行到第 3 步时 Tool 返回了一个超长的 HTML(约 200KB),远超模型的上下文窗口,导致下一轮 API 调用直接报错 context_length_exceeded。最终解决方案是:在 Tool 返回结果前做一层预处理截断——对超过 4000 字符的返回结果只保留摘要,并附上"完整数据已缓存,如需细节请明确指定"。这个教训是:Agent 的 Tool 设计不仅要关注"能不能调通",更要考虑返回数据的大小和格式是否在 LLM 的消化范围内。

💬 你的选择:ReAct(边做边想)和 Plan-and-Execute(先想后做),你在实际项目中更倾向哪种模式?为什么?


七、实战:完整的 Agent 代码

把前面所有概念串起来,这是一个最小但完整的 Agent 实现。

环境准备

开始之前,确保你的环境满足以下条件:

# 1. Node.js 版本要求 ≥ 18
node -v

# 2. 初始化项目并安装依赖
npm init -y
npm install openai dotenv
# 3. 创建 .env 文件,配置以下变量
# .env
LLM_API_KEY=your-api-key-here
LLM_API_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o

💡 说明:本文使用 OpenAI 兼容的 API 格式,你可以替换为任何支持 Function Calling 的模型(GPT-4o、Claude、DeepSeek 等),只需修改 LLM_API_BASE_URLLLM_MODEL 即可。

初始化 + 定义 Tools

import { OpenAI } from 'openai';
import dotenv from 'dotenv';
dotenv.config();

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

// 定义 Tool Schema
const tools = [
    {
        type: 'function',
        function: {
            name: 'get_closing_price',
            description: '获取指定股票的收盘价',
            parameters: {
                type: 'object',
                properties: {
                    name: { type: 'string', description: '股票名称' }
                },
                required: ['name']
            }
        }
    }
];

// Tool 的实际执行函数
// ⚠️ 演示数据,生产环境请替换为真实 API 调用
const toolFunctions = {
    get_closing_price(name) {
        const prices = {
            '青岛啤酒': '67.92',
            '贵州茅台': '1488.21',
            '宁德时代': '218.50'
        };
        return prices[name] || `未找到 ${name} 的股价数据`;
    }
};

Agent Loop 核心逻辑

async function agent(userQuestion) {
    console.log(`\n用户: ${userQuestion}\n`);

    let messages = [
        { role: 'system', content: '你是一个专业的股票分析师,善于用简洁的语言回答用户关于股票的问题。' },
        { role: 'user', content: userQuestion }
    ];

    try {
        // Agent Loop:最多循环 5 次,防止无限循环
        for (let i = 0; i < 5; i++) {
            const response = await client.chat.completions.create({
                model: process.env.LLM_MODEL,
                messages,
                tools,
                tool_choice: 'auto'
            });

            const message = response.choices[0].message;
            messages.push(message);

            // LLM 不需要调用工具,直接返回答案
            if (!message.tool_calls) {
                console.log(`Agent: ${message.content}`);
                return message.content;
            }

            // LLM 决定调用工具 → 执行 → 结果回传
            console.log(`[调用工具] ${message.tool_calls.map(tc => tc.function.name).join(', ')}`);

            for (const toolCall of message.tool_calls) {
                const fn = toolFunctions[toolCall.function.name];
                if (!fn) {
                    console.warn(`未知工具: ${toolCall.function.name}`);
                    continue;
                }
                const args = JSON.parse(toolCall.function.arguments);
                // 通用参数提取:不假设参数名一定是 name
                const argValue = args.name || args.symbol || args.query || Object.values(args)[0];
                const result = fn(argValue);

                console.log(`  → ${toolCall.function.name}("${argValue}") = ${result}`);

                messages.push({
                    role: 'tool',
                    tool_call_id: toolCall.id,
                    content: result
                });
            }
        }

        return '达到最大循环次数,请尝试简化你的问题。';
    } catch (error) {
        console.error('Agent 执行异常:', error.message);
        return `抱歉,Agent 运行出错:${error.message}。请检查网络连接和 API 配置。`;
    }
}

运行效果

await agent('青岛啤酒的收盘价是多少?');
await agent('贵州茅台和宁德时代,哪个更贵?');
用户: 青岛啤酒的收盘价是多少?
[调用工具] get_closing_price
  → get_closing_price("青岛啤酒") = 67.92
Agent: 青岛啤酒今日收盘价为 67.92 元。

用户: 贵州茅台和宁德时代,哪个更贵?
[调用工具] get_closing_price, get_closing_price
  → get_closing_price("贵州茅台") = 1488.21
  → get_closing_price("宁德时代") = 218.50
Agent: 贵州茅台收盘价 1488.21 元,宁德时代收盘价 218.50 元,贵州茅台更贵。

💡 注意第二个问题:LLM 自主决定同时调用两次工具来并行获取数据。这就是 Agent 的「智能」——它能根据问题动态决定工具调用策略,而不是呆板地一次只调一个。


💡 核心总结

黄金公式

Agent = LLM(推理) + Tools(行动) + Memory(记忆) + Planning(规划)

各组件的关系

用户输入
  │
  ▼
┌─── Agent ──────────────────────┐
│                                │
│  LLM (大脑) ◄──► Memory (记忆) │
│      │               ▲         │
│      │          Planning (规划) │
│      ▼                         │
│  Tools (手脚)                  │
│                                │
└────────────────────────────────┘
  │
  ▼
最终输出

学习路径建议

阶段内容目标
🟢 入门LLM API 调用、多轮对话、Function Calling能调用 LLM API,理解 Tool 机制
🟡 进阶Agent Loop、ReAct 模式、Tool 设计能手写一个简单的 Agent
🔴 深入Memory 系统、RAG、Multi-Agent 协作掌握生产级 Agent 框架(LangChain / LlamaIndex / AutoGen)

🔗 参考资料


💬 交流讨论

本文从 LLM API 调用出发,到完整的 Agent Loop 实现,用可运行的代码串起了 Agent 的核心概念。如果你对某个环节还有疑问,或者想了解 Multi-Agent、RAG 等进阶话题,欢迎在评论区留言!

下一篇预告:《手把手带你接入 MCP Server,让 Agent 能力暴增 10 倍》 🔥


觉得有用?点个赞 👍 收藏 ⭐ 关注 👆,不错过后续 Agent 实战系列!