当前位置: 首页
AI教程
LangChain.js+ReAct循环实战:从零实现AI编程助手

LangChain.js+ReAct循环实战:从零实现AI编程助手

热心网友 时间:2026-05-28
转载

Claude Code 凭借精准的代码理解与生成能力,已成为开发者提升效率的得力工具。但究其本质,它依然是大模型结合工具调用,在代码场景下实现的智能交互。好消息是,借助 LangChain.js,我们可以完全复现这一核心能力。

在之前的文章中,我们已经系统掌握了 LangChain.js 的基础知识:从接入大模型、调用与流式输出,到消息体系的应用,再到自定义 Tool 的开发与闭环实现。这些技术积累,正是我们打造专属代码助手的坚实基石。

本文将基于 LangChain.js,整合大模型能力与自定义工具链,手把手教你构建一个简易版的 Claude Code。我们将实现从本地文件读写、代码落地,到执行命令的全流程能力,让大模型真正成为一个能读、能写、能执行的智能编程伙伴。

一、核心能力拆解

Claude Code 的强大之处,在于它能理解代码上下文并执行具体操作。我们可以将其核心能力抽象为三个基础工具,对应代码中的三大模块:

工具 功能定位 技术实现
read_file 代码理解与语法分析 fs.readFile 读取项目文件
write_file 代码自动生成与文件写入 fs.writeFile + 自动目录创建
execute_command 环境交互与运行验证 child_process.spawn 支持前台与后台模式

这三个工具构成了代码助手的最小能力闭环:读(感知上下文)→ 写(生成代码)→ 执行(验证运行结果)。

二、核心代码解析:工具实现细节

2.1 文件读取工具

const readFileTool = tool(async ({ filePath }) => {
  try {
    const content = await fs.readFile(filePath, 'utf-8');
    return `文件内容:\n${content}`;
  } catch (error) {
    return `读取文件失败: ${error.message}`;
  }
}, {
  name: 'read_file',
  description: '使用此工具来读取指定文件的内容...',
  schema: z.object({
    filePath: z.string().describe('需要读取的文件路径'),
  }),
});

设计上需要关注以下几个要点:

  • 路径兼容:支持相对路径或绝对路径,以适应不同的项目结构。
  • 错误透传:将文件不存在、权限不足等错误信息清晰地反馈给模型,让它能自主决策是重试还是调整策略。
  • UTF-8 默认编码:覆盖绝大多数代码文件场景,避免编码问题带来干扰。

这样一来,当用户提出“帮我分析一下 src/utils/helper.js 的潜在问题”时,模型就能自主调用此工具获取代码上下文,而无需用户手动粘贴代码。

2.2 文件写入工具

const writeFileTool = tool(async ({ filePath, content }) => {
  try {
    const dir = path.dirname(filePath);
    await fs.mkdir(dir, { recursive: true }); // 关键:自动创建目录
    await fs.writeFile(filePath, content, 'utf-8');
    return `文件写入成功: ${filePath}`;
  } catch (error) {
    return `文件写入工具调用失败: ${error.message}`;
  }
}, {
  name: 'write_file',
  description: '向指定路径写入文件内容,并自动创建所需的目录',
  schema: z.object({
    filePath: z.string().describe('文件路径'),
    content: z.string().describe('需要写入的文件内容'),
  }),
});

这里的核心设计是 recursive: true 参数,它能自动创建目录链。这正是 Claude Code 体验流畅的关键所在——用户只需说“创建一个 React 组件 components/UserProfile/index.tsx”,工具会自动处理好 components/UserProfile/ 目录的创建,无需用户分步操作。

2.3 命令执行工具 —— 环境交互的“双脚”

这是三个工具中最复杂的一个,需要支持交互式命令(如 npm install)和常驻服务(如 npm run dev):

const executeCommandTool = tool(async ({ command, workingDirectory, background = false }) => {
  const [cmd, ...args] = command.split(' ');
  const child = spawn(cmd, args, {
    cwd: workingDirectory || process.cwd(),
    stdio: background ? 'pipe' : 'inherit', // 前台交互 或 后台静默
    shell: true,
    detached: background, // 关键:后台运行解耦
  });

  if (background) {
    child.unref(); // 允许父进程退出而子进程继续运行
    return `命令已在后台启动: ${command}`;
  }
  // ... 前台模式等待完成
}, {
  name: 'execute_command',
  schema: z.object({
    command: z.string(),
    workingDirectory: z.string().optional(), // 项目隔离
    background: z.boolean().optional(), // 服务启动模式
  }),
});

其双模式设计解析如下:

模式 适用场景 技术特征
前台模式 (background: false) npm installgit status stdio: 'inherit' 实时展示输出,用户体验如同在终端直接执行
后台模式 (background: true) npm run dev、启动数据库服务 detached: true + unref() 实现服务常驻,不阻塞对话流程

workingDirectory 参数至关重要。在多项目场景下,通过它直接指定工作目录,可以避免使用 cd 命令带来的副作用和路径混乱。例如:

// 正确:直接指定目录
executeCommandTool.invoke({ command: "npm run build", workingDirectory: "./my-project" })

// 避免:依赖 cd 的不可靠方式
executeCommandTool.invoke({ command: "cd my-project && npm run build" })

为什么 cd 命令不可靠?

原因在于平台兼容性。cd my-project && npm run build 这种写法强依赖 Shell 语法,不同平台支持度不一。

操作系统平台 命令分隔符 潜在问题
Linux/macOS && 正常执行
Windows CMD && 支持,但行为略有差异
Windows PowerShell ; 或换行 && 在旧版本可能不兼容

更隐蔽的是路径分隔符问题:

// Unix
cd ./my-project && npm start
// Windows(可能失败)
cd .\my-project && npm start // 反斜杠
// 或
cd my-project && npm start // 驱动器根目录问题

workingDirectory 参数由 Node.js 的 path 模块统一处理,能自动适配不同平台。

另一个问题是路径包含空格时,cd 命令容易解析错误:

// 危险:路径带空格导致命令被截断
executeCommandTool.invoke({ command: "cd ./my project && npm start" })
// 实际执行:cd ./my ("project" 被当作新命令)
// 报错:/bin/sh: line 0: cd: too many arguments
// 即使加引号也复杂
executeCommandTool.invoke({ command: "cd "./my project" && npm start" })
// 需要处理嵌套引号、转义,容易出错

最关键的是,相对路径的基准会混乱。cd 改变的是进程级的工作目录,而 spawncwd 选项只影响子进程。在 background: true 模式下使用 cd,很容易导致目录上下文丢失。

三、Agent 核心引擎

工具准备就绪后,我们需要构建 Agent 的大脑——让大模型能够理解需求、决策使用哪个工具、执行动作、观察结果,并循环这一过程直至任务完成。本节将实现一个支持流式输出和多轮工具调用的交互式 Agent。

3.1 架构设计:ReAct 循环

ReAct(Reasoning + Acting,推理+行动)是 Agent 设计的经典范式。它模拟人类解决问题的思维过程:不是一次性给出答案,而是通过“思考→行动→观察”的循环逐步推进。

与传统 LLM 调用的区别显而易见:

交互模式 交互方式 核心特点
标准 LLM 一问一答 依赖预训练知识,无法获取实时信息
ReAct Agent 多轮工具调用 通过工具与外部世界交互,动态获取信息

3.2 模型初始化与工具绑定

核心模块 功能作用
ChatOpenAI 大模型接口,支持工具调用(兼容 OpenAI 格式)
InMemoryChatMessageHistory 内存级对话历史,维护多轮上下文
JsonOutputToolsParser 解析模型输出的工具调用 JSON 数据
HumanMessage/SystemMessage/ToolMessage 构建标准化的消息体系

选择 InMemoryChatMessageHistory 的原因很简单:作为简易版实现,内存存储足以演示核心逻辑。

const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.API_KEY,
  configuration: {
    baseURL: process.env.BASE_URL, // 兼容第三方 API(如 DeepSeek、豆包)
  },
});
const tools = [readFileTool, writeFileTool, executeCommandTool];
const modelWithTools = model.bindTools(tools);

bindTools 这一步至关重要,它将工具的定义信息(名称、描述、参数模式)注入模型上下文,让模型知道:有哪些工具可用、在什么场景下使用、以及参数应该如何填写。

3.3 核心循环:runAgentWithTools 实现

这是整个 Agent 的心脏,实现了 ReAct 循环:

async function runAgentWithTools(prompt, maxIterations = 30) {
  // 1. 记录用户输入
  await history.addMessage(new HumanMessage(prompt));
  let toolParser = new JsonOutputToolsParser();

  // 2. 多轮迭代,直到任务完成或达到上限
  for (let i = 0; i < maxIterations; i++) {
    let messages = await history.getMessages();
    console.log(`⏳ 正在等待 AI 思考...`);

    // 3. 流式调用模型
    let fullResponse = null;
    let hasStartedOutput = false;
    const stream = await modelWithTools.stream(messages);

    // 4. 实时处理流式响应
    for await (const chunk of stream) {
      // 累积完整响应(用于后续工具调用判断)
      if (!fullResponse) {
        fullResponse = chunk;
      } else {
        fullResponse = fullResponse.concat(chunk);
      }

      // 尝试解析工具调用(流式过程中可能不完整,用 try-catch 保护)
      let parsedTools = null;
      try {
        parsedTools = await toolParser.parseResult([{ message: fullResponse }]);
      } catch (error) {
        // 解析失败说明工具调用尚未完整,继续等待
      }

      // 5. 实时流式输出内容
      let outputContent = '';
      // 情况 A:普通文本回复
      if (chunk.content) {
        outputContent = chunk.content;
      }
      // 情况 B:工具调用中的代码生成(如 write_file 的内容字段)
      else if (parsedTools && parsedTools.length > 0) {
        for (const toolCallChunk of parsedTools) {
          if (toolCallChunk.type === 'write_file' && toolCallChunk.args.content) {
            outputContent += toolCallChunk.args.content;
          }
        }
      }

      // 6. 实时打印到终端
      if (outputContent && outputContent.trim() !== '') {
        if (!hasStartedOutput) {
          console.log(`\n✨ AI 回复:\n`);
          hasStartedOutput = true;
        }
        process.stdout.write(outputContent);
      }
    }

    // 7. 保存完整响应到历史
    const response = fullResponse;
    await history.addMessage(response);

    // 8. 判断是否需要工具调用
    if (!response.tool_calls || response.tool_calls.length === 0) {
      if (hasStartedOutput) console.log('\n');
      return response.content; // 无需工具,直接返回
    }
    if (hasStartedOutput) console.log('\n');

    // 9. 执行工具调用闭环
    for (const toolCall of response.tool_calls) {
      const foundTool = tools.find(t => t.name === toolCall.name);
      if (foundTool) {
        console.log(`[工具调用] ${toolCall.name}(${JSON.stringify(toolCall.args)})`);
        // 执行工具
        const toolResult = await foundTool.invoke(toolCall.args);

        // 10. 将工具结果反馈给模型(关键步骤!)
        await history.addMessage(new ToolMessage({
          content: toolResult,
          tool_call_id: toolCall.id, // 必须匹配,让模型知道对应哪个调用
        }));
      }
    }
    // 11. 循环继续:模型收到工具结果后,决定下一步行动
  }
  return '达到最大迭代次数';
}

整个循环流程可以概括为:用户输入 → 模型思考 → 判断是否需要调用工具 → 是则执行工具并反馈结果 → 模型基于结果再次思考 → 循环直至任务完成或达到迭代上限。

3.4 流式输出的工程细节

为什么要做流式处理?体验差异非常明显。

使用场景 体验差异
非流式模式 等待 10 秒后才一次性看到结果,用户可能以为程序卡死或无响应
流式模式 立即看到“正在分析...”、“发现依赖问题...”,能清晰感知响应进度与状态

代码中处理了两种输出源:一是模型的自然语言回复(用于解释思路或询问确认),二是 write_file 工具调用中的代码内容。特别优化的一点是代码生成的实时预览:当模型调用 write_file 生成数百行代码时,用户能立即看到内容,而不是等待整个文件写入完成。

3.5 工具调用闭环:为什么 ToolMessage 至关重要

这是最容易被忽视但最核心的机制:

await history.addMessage(new ToolMessage({
  content: toolResult, // 工具执行结果(成功/失败/输出)
  tool_call_id: toolCall.id, // 必须匹配模型的 tool_call.id
}));

闭环逻辑是这样的:模型发出指令(如“读取 package.json”),系统执行工具并得到结果,然后将结果包装成 ToolMessage 并关联对应的 tool_call_id 反馈给模型。模型“观察”到这个结果后,才能基于新信息决策下一步(如“建议升级依赖”或“执行更新命令”)。

如果缺少 ToolMessage,模型就会遗忘自己已经调用了工具,很可能陷入“重复调用同一工具”或“幻觉执行结果”的死循环。

3.6 交互层:命令行对话界面

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
let history = new InMemoryChatMessageHistory();
let systemMessage = new SystemMessage(`你是一个经验丰富的程序员,善于使用工具完成任务。工具:1. read_file: 读取文件2. write_file: 写入文件3. execute_command: 执行系统命令,支持指定工作目录`);

async function interactiveChat() {
  await history.addMessage(systemMessage);
  console.log('\n=== AI 编程助手 ===');
  console.log('输入 "exit" 或 "quit" 退出\n');

  while (true) {
    const userInput = await new Promise((resolve) => {
      rl.question('用户: ', resolve);
    });

    if (userInput.toLowerCase() === 'exit' || userInput.toLowerCase() === 'quit') {
      console.log('\n再见!');
      rl.close();
      break;
    }
    if (userInput.trim() === '') continue;

    try {
      await runAgentWithTools(userInput);
    } catch (error) {
      console.error(`\n❌ 错误: ${error.message}\n`);
    }
  }
}
interactiveChat().catch(console.error);

设计上需要注意:在对话开始时注入持久的 SystemMessage 来定义 AI 角色和工具说明;实现循环对话以支持连续多轮交互,并自动累积历史记录;同时提供 exit/quit 命令和 Ctrl+C 的安全退出方式。

四、实战演示:完整工作流

来看一个真实的对话流程,展示三大工具如何协同工作。

场景:创建并运行一个 Express 服务

用户输入:“帮我创建一个简单的 Express 服务器,监听 3000 端口,并启动它。”

模型执行流程将是:首先调用 write_file 创建项目目录和 package.jsonapp.js 等文件;然后调用 execute_command 执行 npm init -ynpm install express;最后再次调用 execute_command,以 background: true 模式启动 node app.js 服务。

最终,模型会返回类似这样的信息:“Express 服务器已创建并在后台启动,运行在 http://localhost:3000。你可以使用 curl http://localhost:3000 进行测试。”

五、总结

至此,我们基于 LangChain.js 完整复刻了 Claude Code 的核心能力闭环。回顾整个实现过程,关键突破点在于三个工具的精巧设计和 ReAct 循环的稳健实现。

核心模块 解决的问题 技术亮点
read_file 代码上下文感知与分析 错误透传,让模型自主决策重试策略
write_file 代码自动化生成与落地 recursive: true 实现目录链自动创建
execute_command 环境交互与运行验证 双模式设计(前台/后台)+ 工作目录隔离
runAgentWithTools 多轮工具调用闭环 流式输出 + ToolMessage 反馈机制

这个简易版 Claude Code 的真正价值,不在于单个工具的能力,而在于让大模型成为了工作流的智能编排者:用户意图 → 模型决策 → 工具执行 → 结果观察 → 再决策 → ... → 任务完成。每一次循环迭代,都是模型对当前状态的重新评估和策略调整。ReAct 范式的引入,让 AI 从“回答问题”进化到了“解决问题”。

流式体验带来的用户价值也不容小觑。对于代码生成这类长耗时任务,流式输出不仅提升了感知性能,更重要的是建立了信任——用户能实时看到 AI 的思考过程和代码构建进度,而不是面对一个黑盒等待。

当然,当前实现只是一个最小可用版本(MVP)。在生产级场景中,还需要考虑以下增强方向:

优化方向 当前局限 优化方案
上下文长度 大文件读取会撑爆 Token 实现 read_file 的分块读取 + 智能摘要
安全管控 无命令白名单,可执行任意操作 增加危险命令拦截 + 用户确认机制
状态持久化 进程退出即丢失对话历史 接入 Redis/数据库实现跨会话记忆
多模态扩展 仅支持文本交互 增加图片输入(UI 设计稿转代码)
协作能力 单 Agent 串行执行 多 Agent 协作(生成 Agent + 审查 Agent)

写在最后

Claude Code 的流行,证明了“大模型 + 工具调用 + 代码场景”这一范式的巨大潜力。通过 LangChain.js,我们无需依赖闭源产品,就能构建出完全符合自身工作流和习惯的专属助手。

更重要的是,这个过程让我们深入理解了 AI 应用开发的本质:它不是要替代开发者,而是将重复性、机械性的操作自动化,从而让人类能够更专注于那些需要创造性、策略性思考的决策环节。

来源:https://juejin.cn/post/7617410783702777899

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
开源AI桌面助理智能体YouClaw-Chat2DB打造轻量级个人助手

开源AI桌面助理智能体YouClaw-Chat2DB打造轻量级个人助手

YouClaw是什么 在AI工具层出不穷的今天,一款名为YouClaw的桌面智能体悄然进入了视野。它由Chat2DB团队开发,于2026年3月正式推出,定位非常清晰:一个轻量级、开源的个人AI助理。最大的亮点在于其“开箱即用”的特性——无需折腾复杂的环境配置,也无需编写任何代码。用户只需下载应用,扫

时间:2026-05-28 14:29
WPS AI智能创作指南:AI写课件的未来与实践

WPS AI智能创作指南:AI写课件的未来与实践

提升办公效率的AI课件生成,如何利用WPS AI实现文档智能创作? 在快节奏的现代职场中,时间总是不够用,尤其是制作课件这类需要整合信息、设计排版的繁琐工作,常常让人感到分身乏术。有没有一种方法,能让我们从重复劳动中解放出来,把精力聚焦在更有价值的创意和思考上?答案是肯定的,而关键就在于善用AI工具

时间:2026-05-28 14:29
BrokerSpot外汇交易平台深度评测与使用指南

BrokerSpot外汇交易平台深度评测与使用指南

BrokerSpot是什么 在竞争激烈的房地产经纪行业,如何高效获取精准客户是每位从业者面临的核心挑战。有没有一种智能解决方案,能够真正利用科技力量破解这一难题?BrokerSpot的出现,为这个问题提供了全新的思路。 简而言之,BrokerSpot是一款专为房地产经纪人设计的AI智能获客与管理平台

时间:2026-05-28 14:28
AI工具助你高效撰写商业计划书应对快节奏创业挑战

AI工具助你高效撰写商业计划书应对快节奏创业挑战

适合需求: 在当今瞬息万变的商业环境中,撰写一份高质量的商业计划书已成为企业发展的核心需求。无论是寻求融资的初创公司、规划战略的成熟企业,还是独立创业者,一份逻辑清晰、数据扎实、专业度高的商业计划书,都是吸引投资、指导内部运营、明确市场方向的必备工具。然而,将这份“战略蓝图”转化为具有说服力的文档,

时间:2026-05-28 14:28
WPS AI写作工具高效应用指南:提升创作效率的实用技巧

WPS AI写作工具高效应用指南:提升创作效率的实用技巧

适合需求: 在信息过载的当下,高效产出优质文本已成为一项核心技能。无论是职场人士撰写商业计划与述职报告,学生完成学术论文与课程作业,还是内容创作者、自媒体运营者需要持续输出,普遍面临“提笔难”的困境。灵感碎片化、逻辑组织耗神、表达效率低下,如同引擎空转,消耗大量心力却进展缓慢。 因此,借助专业的智能

时间:2026-05-28 14:27
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程