基于Node + LangChain + 火山引擎大模型,从零实现带记忆的命令行 AI 聊天机器人

前言

火山引擎大模型完全兼容 OpenAI 接口协议,无需大幅改代码即可快速替换适配。本文带你从零实现一个 命令行交互式、支持多轮记忆、异常容错、高低版本 Node 兼容 的 AI 聊天机器人,适合新手入门 LangChain 链式调用、大模型私有化/国产模型适配。

最终实现效果

  • ✅ 命令行实时交互式聊天

  • ✅ 完整多轮对话记忆(上下文关联)

  • ✅ 兼容 Node.js 16/18/20 全版本

  • ✅ 超时保护、全局异常捕获、优雅退出

  • ✅ 适配火山引擎 OpenAI 兼容接口

  • ✅ 无进程残留、交互体验流畅

一、技术栈介绍

1. LangChain:大模型应用开发框架,快速实现提示词模板、对话记忆、链式调用

2. 火山引擎方舟大模型:字节跳动官方大模型服务,兼容 OpenAI 接口,国内访问稳定

3. Node.js:服务端运行环境,实现命令行交互与接口请求

4. dotenv:环境变量管理,保护密钥安全

二、环境准备

2.1 版本要求

Node.js ≥ 16(推荐 18+ LTS,规避流兼容问题)

2.2 安装依赖

新建项目,安装核心依赖:

npm install @langchain/openai @langchain/core dotenv
# Node < 18 额外安装流兼容补丁
npm install web-streams-polyfill

“@langchain/openai”: “^1.5.3”,
“@langchain/core”: “^1.2.1”,
“dotenv”: “^17.4.2”

2.3 火山引擎密钥准备

前往【火山引擎方舟平台】控制台,获取三个核心参数:

  • VOLC_API_KEY:API 访问密钥

  • VOLC_MODEL:模型接入点 ID

  • VOLC_BASE_URL:接口基础地址

2.4 配置环境变量 .env

项目根目录新建 .env 文件,写入配置:

# 火山引擎大模型配置
VOLC_API_KEY=你的火山引擎API密钥
VOLC_MODEL=你的模型接入点ID
VOLC_BASE_URL=https://ark.cn-beijing.volces.com/api/v3

三、完整可运行源码(index.js)

代码已做全版本兼容、异常优化、逻辑重构,可直接复制运行:

// -------------------------- 全局环境兼容修复 --------------------------
// 修复新版Node crypto懒加载问题(LangChain 强依赖)
if (!globalThis.crypto) {
  globalThis.crypto = require('crypto')
}
if (!globalThis.crypto.webcrypto) {
  globalThis.crypto.webcrypto = globalThis.crypto
}

// 低版本Node(<18) 兼容Web Streams API
const nodeMajor = parseInt(process.versions.node.split('.')[0])
if (nodeMajor < 18 && typeof globalThis.ReadableStream === 'undefined') {
  try {
    const polyfill = require('web-streams-polyfill')
    globalThis.ReadableStream = polyfill.ReadableStream
    globalThis.WritableStream = polyfill.WritableStream
    globalThis.TransformStream = polyfill.TransformStream
  } catch (err) {
    console.error('❌ 检测到Node<18,请执行:npm i web-streams-polyfill')
    process.exit(1)
  }
}

// -------------------------- 全局异常守护 & 优雅退出 --------------------------
// 捕获同步异常
process.on('uncaughtException', error => {
  console.error('\n❌ 程序异常:', error.message)
  process.exit(1)
})

// 捕获异步Promise异常
process.on('unhandledRejection', (reason) => {
  console.error('\n❌ 请求异常:', reason.message)
})

// Ctrl+C 优雅退出
process.on('SIGINT', () => {
  console.log('\n\n👋 退出AI聊天程序,再见!')
  process.exit(0)
})

// -------------------------- 加载项目依赖 --------------------------
require('dotenv').config()
const { ChatOpenAI } = require('@langchain/openai')
const { ChatPromptTemplate, MessagesPlaceholder } = require('@langchain/core/prompts')
const { RunnableWithMessageHistory } = require('@langchain/core/runnables')
const { InMemoryChatMessageHistory } = require('@langchain/core/chat_history')
const readline = require('readline')

// -------------------------- 初始化火山引擎大模型 --------------------------
const llm = new ChatOpenAI({
  apiKey: process.env.VOLC_API_KEY,
  model: process.env.VOLC_MODEL,
  temperature: 0.7, // 随机性 0-1,越高越灵活
  configuration: {
    baseURL: process.env.VOLC_BASE_URL
  }
})

// -------------------------- 构建提示词模板 --------------------------
// 结构:系统设定 + 历史对话占位 + 用户当前输入
const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个简洁、专业、聪明的AI助手,回答通俗易懂'],
  new MessagesPlaceholder('history'),
  ['user', '{input}']
])

// -------------------------- 初始化对话记忆 --------------------------
// 内存存储对话历史,程序重启后清空
const chatMemory = new InMemoryChatMessageHistory()

// -------------------------- 构建带记忆的对话链 --------------------------
const baseChain = prompt.pipe(llm)
const chatChain = new RunnableWithMessageHistory({
  runnable: baseChain,
  getMessageHistory: () => chatMemory,
  inputMessagesKey: 'input',
  historyMessagesKey: 'history'
})

// -------------------------- 创建命令行交互实例 --------------------------
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

console.log('🚀 火山引擎AI聊天机器人启动成功!输入 exit 退出\n')

// -------------------------- 超时工具函数(防止请求卡死) --------------------------
function timeout(ms, promise) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error(`请求超时(${ms / 1000}秒),请重试`))
    }, ms)

    promise.then(
      val => {
        clearTimeout(timer)
        resolve(val)
      },
      err => {
        clearTimeout(timer)
        reject(err)
      }
    )
  })
}

// -------------------------- 递归实现多轮对话 --------------------------
async function startChat() {
  rl.question('你:', async (input) => {
    // 退出逻辑
    if (input.trim() === 'exit') {
      rl.close()
      process.exit(0)
    }

    try {
      // 加载状态提示
      process.stdout.write('AI:思考中...\r')
      // 调用大模型,30秒超时保护
      const res = await timeout(30000, chatChain.invoke(
        { input: input },
        { configurable: { sessionId: 'volc-single-session' } }
      ))
      // 打印回复
      console.log(`AI:${res.content}\n`)
    } catch (err) {
      console.log(`\n❌ 对话失败:${err.message}\n`)
    }

    // 递归继续对话
    startChat()
  })
}

// 启动对话
startChat()

四、核心原理深度解析

4.1 国产大模型适配原理

火山引擎方舟大模型 100% 兼容 OpenAI v1 接口协议,因此可以直接使用 @langchain/openai包接入,无需安装专属 SDK。仅需替换:

  • baseURL 为火山引擎接口地址

  • apiKey 为火山引擎密钥

  • model 为火山引擎模型端点

4.2 LangChain 对话记忆实现

核心依赖两个类实现多轮上下文记忆

  1. InMemoryChatMessageHistory:内存级对话存储,自动保存用户、AI 历史消息

  2. RunnableWithMessageHistory:为对话链自动注入历史消息,无需手动拼接上下文

模板中 MessagesPlaceholder('history') 会自动填充过往对话,实现连贯聊天。

4.3 兼容性修复关键点

原生 LangChain 在低版本 Node 会报错,本文已全部修复:

  • crypto 报错:新版 Node 懒加载 crypto,手动注入 webcrypto 适配 LangChain 依赖

  • ReadableStream 未定义:Node18+ 原生支持 Web Streams,低版本自动加载 polyfill

4.4 容错机制

  • 30 秒请求超时,避免网络卡死

  • 全局捕获同步/异步异常,程序不崩溃

  • Ctrl+C、exit 命令双优雅退出方案

五、运行测试

1. 确保 .env 配置正确

2. 执行运行命令:

node index.js

3. 交互效果:

🚀 火山引擎AI聊天机器人启动成功!输入 exit 退出

你:你好,介绍一下自己
AI:我是基于火山引擎大模型开发的AI助手,能够为你提供问答、解答问题、日常交流等服务。

你:帮我简单解释一下LangChain
AI:LangChain是一款大模型应用开发框架,主要用于快速搭建基于大语言模型的应用,支持对话记忆、链式调用、工具调用等能力,大幅降低AI应用开发门槛。

你:exit

👋 退出AI聊天程序,再见!

六、常见踩坑问题解决方案

问题1:ReadableStream is not defined

原因:Node.js 版本低于 18,无原生 Web Streams 支持

解决:执行 npm i web-streams-polyfill

问题2:crypto.webcrypto 未定义

原因:新版 Node 惰性加载 crypto 模块

解决:代码中手动注入 webcrypto 兼容代码

问题3:大模型请求 401/403 失败

原因:密钥错误、模型端点未开通、余额不足

解决:核对 .env 配置,检查火山引擎控制台模型权限与余额

七、扩展升级方向

当前为内存版对话机器人,可继续升级:

  1. 持久化记忆:替换内存存储为 Redis/数据库,重启不丢失对话

  2. 流式输出:实现打字机实时回复效果

  3. 工具调用:接入搜索、计算器、代码执行工具

  4. 多会话隔离:支持多用户独立对话记忆

  5. Web 界面:对接前端,做成网页聊天机器人

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐