从零打造 AI Agent:第一天,我学到了什么

一个后端开发者的 Agent 学习笔记,Day 1。


为什么开始学 Agent?

我每天用 Claude Code 写代码,它帮我读文件、写代码、跑命令------一个对话窗口完成整套开发流程。这让我很好奇:它背后的原理到底是什么?

拆开来看其实不复杂:Claude Code 本质就是 LLM + 读写文件的工具 + 执行命令的工具。LLM 负责思考和规划,工具负责干活,两者组合起来就是一个能独立完成任务的智能体。

这个"组合"就是 Agent。

所以我决定从零开始,用 LangChain 框架亲手搭建一个 Agent。今天是第一天,这篇文章记录我学到的所有东西。


一、Agent 到底是什么?

直接调用大模型 API 有几个硬伤:

  • 记不住:每次对话都是全新的,LLM 不记得你们上次聊了什么(无状态)
  • 不会动手:它只能告诉你"怎么做",没法亲自去读文件、调 API、跑命令
  • 不知道内部知识:公司内部的文档、代码库,预训练数据里没有
  • 不知道最新信息:训练数据有截止日期,今天的新闻它不知道

Agent 就是给 LLM 装上各种"外挂",补上这些短板:

ini 复制代码
Agent = LLM + Memory + Tool + RAG + MCP + Skills
能力短板 Agent 的解决方案
记不住上下文 Memory 模块(数据库 / Redis)
没法动手操作 Tool Use(调用 API、读写文件、执行命令)
不懂内部知识 RAG(检索增强生成)
拿不到最新信息 MCP / Tool(外部工具协议)
搞不定复杂任务 Skills(技能编排)

Agent 的工作流程

markdown 复制代码
用户丢来一个复杂任务
    │
    ▼
LLM 规划推理:这任务需要什么?
    │
    ├──► 需要记忆? → 查 Memory
    ├──► 需要动手? → 调用 Tool(可能多个、可能多轮)
    ├──► 需要查内部文档? → RAG 检索
    │
    ▼
把以上所有信息组装进上下文 → LLM 生成最终回复

核心思想一句话:LLM 是大脑,工具是手脚,记忆是海马体。组合起来才是一个完整的人。


二、LangChain:统一的大模型调用框架

LangChain 比 OpenAI 公司还早诞生。它的核心价值就一个:用同一套接口调用不同厂商的模型

最简调用:5 行代码

javascript 复制代码
import { ChatOpenAI } from "@langchain/openai";

const model = new ChatOpenAI({
    modelName: "deepseek-v4-flash",
    apiKey: process.env.DEEPSEEK_API_KEY,
    configuration: {
        baseURL: "https://api.deepseek.com/v1", // 兼容 OpenAI 接口
    },
});

const response = await model.invoke("你觉得什么水果好吃?");
console.log(response.content);

DeepSeek 提供了 OpenAI 兼容的 API,所以用 @langchain/openai 就能直接调。换成通义千问、月之暗面,改一下 baseURLapiKey 就行,代码完全不用动。


三、核心重点:Tool 工具机制

这是今天最有收获的部分。Agent 能"干活",全靠 Tool。

3.1 Tool 的两个组成部分

在 LangChain 中定义一个 Tool,需要两样东西:

ini 复制代码
Tool = 异步处理函数(干活) + 描述对象(告诉 LLM 什么时候用它)

以读文件工具为例:

javascript 复制代码
const readFileTool = tool(
    // 第一部分:干活函数
    async ({ filePath }) => {
        const content = await fs.readFile(filePath, "utf8");
        console.log(`[工具调用] 读取 ${filePath},共 ${content.length} 字节`);
        return content;
    },
    // 第二部分:描述对象
    {
        name: "read_file",
        description: `读取文件内容。当用户要求查看代码、分析文件时调用。`,
        schema: z.object({
            filePath: z.string().describe("要读取的文件路径"),
        }),
    }
);

这里有一个很精妙的设计:LLM 并不会真的执行你的函数代码。它只是在推理时"决定"要调用这个工具,然后停下来,把工具名和参数返回给你。你在外部执行完,再把结果传回去。

这个过程中三个关键字段各司其职:

  • name:LLM 用它来指认"我要调这个工具"
  • description:告诉 LLM 什么场景下该用这个工具------描述越详细,LLM 判断越准
  • schema(Zod 校验):约束 LLM 必须传什么参数、参数是什么类型

3.2 Tool 调用的完整循环

matlab 复制代码
第 1 轮:LLM 推理
  → "用户要我读 tool.mjs,我得调 read_file 工具"
  → 返回 tool_calls: [{name: "read_file", arguments: {filePath: "tool.mjs"}}]
  → 注意:LLM 此时不生成文本内容!

执行工具(外部)
  → fs.readFile("tool.mjs") → 返回文件内容

第 2 轮:LLM 再次推理
  → "拿到文件内容了,我来分析一下..."
  → 生成文本回复给用户

这个循环可能有多轮------比如"先读文件分析,再写分析结果到新文件",就需要两轮工具调用。

3.3 Agent 主循环代码

javascript 复制代码
// 注册工具
const modelWithTools = model.bindTools([readFileTool, writeFileTool]);

// Agent 主循环
while (true) {
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    // 没有 tool_calls → 任务完成,输出回复
    if (!response.tool_calls?.length) {
        console.log(response.content);
        break;
    }

    // 有 tool_calls → 并行执行所有工具
    const toolMessages = await Promise.all(
        response.tool_calls.map(async (tc) => {
            const tool = toolList.find(t => t.name === tc.name);
            const result = await tool.invoke(tc.args);
            return new ToolMessage({
                content: result,
                tool_call_id: tc.id, // 通过 id 关联,LLM 知道谁的结果
            });
        })
    );
    messages.push(...toolMessages);
    // 回到循环开头,让 LLM 基于结果继续推理
}

四、性能关键:Promise.all 并行执行

4.1 为什么需要 Promise

LLM 调用和 Tool 执行都是异步操作(网络请求、文件读写)。JavaScript 通过 Promise 管理异步。

Promise 有三种状态,且不可逆

scss 复制代码
Pending ──resolve()──► Fulfilled(成功)
Pending ──reject()───► Rejected(失败)

async/await 是语法糖,让异步代码写起来像同步:

javascript 复制代码
async function getWeather() {
    return new Promise((resolve) => {
        setTimeout(() => resolve({ temp: 38 }), 2000);
    });
}
const data = await getWeather(); // 等 2 秒,拿到 { temp: 38 }

4.2 串行 vs 并行

javascript 复制代码
// ❌ 串行:等天气(2s) → 再等推文(0.5s) → 总耗时 2.5s
const weather = await getWeather();
const tweets = await getTweets();

// ✅ 并行:同时发起 → 等最慢的那个(2s) → 总耗时 2s
const [weather, tweets] = await Promise.all([
    getWeather(),
    getTweets(),
]);

4.3 在 Agent 中的落地

LLM 一次可能返回多个互不依赖的 tool_calls。比如用户问"帮我读一下这三个文件",LLM 会一次性返回 3 个 read_file 调用。这时候用 Promise.all 并行执行,耗时 = 最慢的那个文件,而不是三个文件加起来。

判断标准很简单:工具之间没有数据依赖 → 并行;后一个依赖前一个的输出 → 串行。

这就是高性能 Agent 的关键优化点。


五、回头看 Claude Code

学完这一天,我终于理解了 Claude Code 的底层模型:

ini 复制代码
Claude Code = LLM + fs(文件读写)+ cli(命令执行)

当我对它说"创建一个 React Todo 项目",它的 Planning 大概是:

  1. 调 cli → npm create vite@latest
  2. 调 fs → 写入 App.jsx 代码
  3. 调 cli → npm run dev

每一步都是 LLM 决定调哪个工具,外部执行完后把结果传回去,LLM 再决定下一步。

我自己在写的 Agent 也是这个模式------LLM + Tool 列表 + 循环推理。只是我的 Tool 还只有读写文件,后面还可以加 HTTP 请求、数据库查询、发邮件......扩展空间无限。


六、总结

今天从零开始,搞清楚了四件事:

  1. Agent 为什么存在------补 LLM 的能力短板(记忆、动手、知识、时效)
  2. LangChain 怎么用 ------统一接口调模型,bindTools 注册工具
  3. Tool 机制是核心------LLM 决定用什么工具,外部执行,结果返回,循环往复
  4. Promise.all 是性能关键------互不依赖的工具调用必须并行

知识地图

javascript 复制代码
Day 1 已覆盖 ✅
├── 理论基础:Agent 定义、工作流程
├── LangChain:LLM 调用、Tool 定义/注册/调用循环
└── JS 异步:Promise 三态 → async/await → Promise.all 并行

待学习 ⬜
├── Memory --- 让 Agent 记住历史对话
├── RAG --- 检索内部知识库
├── MCP --- 标准化工具协议
├── Skills --- 复杂任务编排
├── LangGraph --- 多智能体协作
└── NestJS --- Agent 产品化部署

最后

第一天下来最大的感受:Agent 概念不复杂,复杂的是工程落地。

把 LLM + Tool + Memory 组合起来,原理上就几十行代码。但要做到生产可用------工具的错误处理、并行调度的最优策略、多轮对话的状态管理、安全权限控制------每一样都是硬仗。

不过这就是 "Harness Engineering" 的意义:把 AI 能力驯服,装进产品里,创造真实的商业价值。

Day 1 结束,明天继续。


日期:2026-07-06

相关推荐
阿里云云原生2 小时前
不改代码也能监控 AI Agent?揭秘 OBI 如何在内核层精准解析 GenAI 语义流量
云原生·agent
MicrosoftReactor2 小时前
技术速递|Token 经济学:智能体 AI 时代的新 FinOps
人工智能·ai·agent·token·finops
SelectDB3 小时前
Apache Doris 在 AgentLogsBench 中领先,支撑 Agent 可观测性生产负载
运维·数据库·agent
倾颜3 小时前
给 AI Chat 加上长期记忆:模型提取 + 程序把关 + 规则召回
llm·agent·next.js
陳陈陳4 小时前
🤖 Agent开发完全指南:从LLM到智能体的蜕变之旅
langchain·llm·agent
槑有老呆5 小时前
从零打造你的第一个 AI Agent:LLM 不够用?给它装上"外挂"
agent
倾颜5 小时前
AI Mind 的多会话短期记忆容器:如何隔离多个聊天上下文
langchain·agent·next.js
阿拉斯攀登5 小时前
Prompt 工程与答案生成优化
prompt·agent·memory·知识库·向量数据库·rag
Briwisdom5 小时前
Agent 帮我写 CUDA(续):当 Self-Attention 遇上 Causal Mask 和 Cross-Attention
agent·算子开发·flash attention