AI Agent 入门实战:用 Langchain 手写一个简易版 Claude Code

1 阅读6分钟

不是直接调大模型接口,而是给它装上 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:要调用的工具列表,包含 idnamearguments
  • 多个工具通过 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 分三步:

步骤工具说明
1write_fileVite 创建项目,写入文件
2LLM 编程能力生成组件代码(需要编程能力比较强的模型)
3cli_command项目运行起来,调用 CLI 命令工具

八、总结

组件解决的问题
LLM思考、规划、推理
Memory记住历史对话和上下文
Tool读写文件、执行命令、访问网页
RAG获取私有文档和最新信息
MCP标准化对接第三方工具
Skills固化复杂任务为可复用技能

Agent 其实并不复杂:

  • LLM 本身就可以思考、规划
  • 给它用 Tool 扩展能力,它就能自己做事情
  • 用 Memory 管理记忆,它就可以记住你要它记住的东西
  • 用 RAG 查询内部知识来获取知识

这样一个知道内部知识、能思考、规划,能够帮你做事情的扩展后的 LLM,就是一个 Agent。