被微信群的AI机器人惊讶到了!我也手搓一个玩玩!

5,532 阅读9分钟

群里的AI机器人

大家好,我是石小石


今天在某群潜水,突然被一段对话吸引了。

很明显,这个【前端汤姆猫】是一个AI,我也来逗逗他

然而,我的弱智吧问题还没来得及问,可怜的机器人就被管理同学关进小黑屋了,不过瘾啊! 不过,作为一个程序员,对AI机器人的实现,我非常感兴趣

简单搜索后,我发现AI机器人的实现非常简单,那我也手搓一个玩玩吧。

机器人原理与实现技术方案

原理

如今,AI模型的发展已经非常成熟,我们很容易就能想到AI机器人的原理

  1. 用户在微信群中发送消息。
  2. 机器人监听到消息后,将其转发到 AI 模型进行处理。
  3. 模型返回生成的内容,机器人再发送回群聊。

刚好,前几天用了一个免费的AI大模型搭建了一个私有的聊天机器人。

文章链接:node+websoket极速构建一个私有ChatGPT!AI套壳居然如此简单!

文章中实现的效果展示

看来,现在我只需要把它改造改造,接入微信就行了!

技术方案

搭建一个基础的AI机器人,我们会用到下面两个东西

  • GPT 系列语言模型,负责生成智能回答。
  • Node.js:搭建服务端逻辑(java、python什么的都可)。

在之前的文章中,我也介绍过,AI大模型有很多,国产的如豆包文心一言通义千问kimi 等。考虑到免费、SDK调用简单等因素,本文我们使用Kimi的月之暗Moonshot模型。

如果需要将搭建的AI机器人接入微信,我们还需要使用Wechaty和qrcode-terminal。


Wechaty是一个开源的 Node.js 库,用于操作微信,提供登录、接收消息、发送消息等功能。它是我们实现微信AI机器人的核心,它的官网有非常详细的使用介绍

qrcode-terminal是一个非常简单的插件,它的作用是在终端打印二维码,用于扫描登录微信。

实现目标

通过以上技术栈,我们将从0到1搭建一个微信群 AI 聊天机器人,它具备以下功能:

  1. 基础功能:使用 Wechaty 登录微信并监听群聊消息,当群成员@机器人时触发智能回复。
  2. 智能化回复:通过上下文记忆提供连续对话,借助KImi月之暗模型进行回复。
  3. 个性化与趣味化:预设机器人角色(如“闷骚的程序员”),提升对话趣味性,并通过自定义触发词和消息过滤优化使用体验。

最终我们将实现一个既智能又人性化、具有实用性的微信 AI 机器人。

代码实现

准备开发环境

我们服务端使用nodejs,因此,首先确保安装 Node.js (推荐 v14 或更高版本)环境。

创建项目并初始化:

mkdir ai-chatbot && cd ai-chatbot
npm init -y

安装依赖:

npm install wechaty qrcode-terminal axios

登录微信

扫码登录是实现微信聊天机器人的第一步,我们需要通过wechaty qrcode-terminal两个插件在服务端实现微信登录,只有这样,我们才能实现调试开发。

通过wechaty,我们只需要6行代码,就可以 通过个人号 搭建一个 微信机器人功能 ,用来自动管理微信消息,它的核心代码如下

注:为避免官方封号,建议大家用小号!由于您自己操作导致的封号,本文概不负责!

import { Wechaty } from 'wechaty'

Wechaty.instance()
.on('scan',        qrcode  => console.log('扫码登录:' + qrcode))
.on('login',       user    => console.log('登录成功:' + user))
.on('message',     message => console.log('收到消息:' + message))
.on('friendship',  friendship => console.log('收到好友请求:' + friendship))
.on('room-invite', invitation => console.log('收到入群邀请:' + invitation))
.start()

我们在项目根目录创建index.js,写一个最基础的登录代码。

const { WechatyBuilder, ScanStatus, log } = require("wechaty");
const qrcodeTerminal = require("qrcode-terminal");

// 创建 Wechaty 实例
const bot = WechatyBuilder.build({ name: "chatanywhere-bot" });

// 处理扫码事件
bot.on("scan", (qrcode, status) => {
  if (status === ScanStatus.Waiting || status === ScanStatus.Timeout) {
    qrcodeTerminal.generate(qrcode, { small: true });
    console.log(
      `扫码链接:https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`
    );
  } else {
    log.info("扫码状态:", status);
  }
});

// 登录与登出事件
bot.on("login", (user) => console.log(`登录成功:${user.name()}`));
bot.on("logout", (user) => console.log(`已登出:${user.name()}`));

// 启动机器人
bot.start().catch((e) => console.error(e));

上面的代码实现了二维码生成、二维码扫描、扫码后登录状态的监控等功能,在控制台输入node index.js运行代码,我们就能看到一个微信二维码。

用微信扫描后,你就可以看到手机端的登录提示

实际上,这个二维码是一个用于登录微信网页版的二维码,但是,现在用网页登录不上了。

这意味着,想接入微信手机版或pad,你需要购买一个token或申请使用。为了便于演示核心,本文不会教你如何购买token和配置,请参考官方教程

监听群聊消息

扫码成功后,我们可以继续实现监听群聊消息的功能

// 监听消息事件
bot.on('message', async (msg) => {
  const talker = msg.talker(); // 消息发送者
  const text = msg.text(); // 消息内容
  const room = msg.room(); // 群聊信息

  if (room) {
    const topic = await room.topic(); // 获取群名称
    console.log(`[群聊: ${topic}] ${talker.name()}: ${text}`);
  } else {
    console.log(`[私聊] ${talker.name()}: ${text}`);
  }
});

引入 Kimi AI大模型

要让机器人智能回复,我们需要借助 Kimi的月之暗 模型。具体的使用方法参考我之前的文章:juejin.cn/post/744177…

import axios from 'axios';

const OpenAI = require("openai");

// 配置 Moonshot AI 客户端
const client = new OpenAI({
  apiKey: "你自己在kimi后台创建的API key",
  baseURL: "https://api.moonshot.cn/v1", // Moonshot API 的基础路径
});

async function getAIResponse(message) {
  try {
    const response = await client.chat.completions.create({
        model: "moonshot-v1-8k",
        messages: [
          { role: "user", content },
        ],
        temperature: 0.3, // 控制回答的随机性
      });
    // 3.获取 Kimi 的回答内容
    const reply = completion.choices[0]?.message?.content 
    // 4.将回答返回
    return reply;
  } catch (error) {
    console.error('AI Error:', error);
    return '抱歉,我的大脑短路了,请稍后再试!';
  }
}

上述代码中,我们定义了一个getAIResponse的方法,这个方法会根据message的参数值(其他用户的消息)调用Kimi的模型接口,返回AI回答。

智能回复群聊消息

现在,我们需要将AI回答通过Wechaty返回微信,并将返回结果发送到群聊。

bot.on('message', async (msg) => {
  const room = msg.room(); // 获取群聊
  const text = msg.text(); // 消息内容

  // 忽略自己的消息
  if (msg.self()) return;

  // 如果在群聊中,且 @ 了机器人
  if (room && text.includes(`@${bot.name()}`)) {
    const cleanText = text.replace(`@${bot.name()}`, '').trim(); // 去除 @ 内容
    const reply = await getAIResponse(cleanText); // 调用 GPT 接口
    await room.say(reply, msg.talker()); // 回复消息
  }
});

上述代码并不复杂,基本都是在调官方的api而已。

优化机器人

上下文记忆

为了让我们的AI机器人更加智能,我们需要保存最近几条消息,模拟连续对话。

const axios = require("axios");
const OpenAI = require("openai");

// 配置 Moonshot AI 客户端
const client = new OpenAI({
  apiKey: "你自己在kimi后台创建的API key", // 替换为你的API密钥
  baseURL: "https://api.moonshot.cn/v1", // Moonshot API 的基础路径
});

// 会话管理对象,存储每个用户的对话历史
const sessions = {};

async function getAIResponse(sessionId, message) {
  try {
    // 如果该会话还没有历史记录,初始化它
    if (!sessions[sessionId]) {
      sessions[sessionId] = [];
    }

    // 将用户消息添加到历史记录
    const userMessage = { role: "user", content: message };
    sessions[sessionId].push(userMessage);

    // 调用 Moonshot API 获取 AI 回复
    const response = await client.chat.completions.create({
      model: "moonshot-v1-8k", // 使用你选择的模型
      messages: sessions[sessionId], // 传递完整的对话历史
      temperature: 0.3, // 控制回答的随机性
    });

    // 获取 AI 回复内容
    const assistantMessage = response.choices[0]?.message?.content || "抱歉,我无法回答您的问题。";
    sessions[sessionId].push({ role: "assistant", content: assistantMessage }); // 记录 AI 回复

    // 返回 AI 回复
    return assistantMessage;
  } catch (error) {
    console.error("AI Error:", error);
    return "抱歉,我的大脑短路了,请稍后再试!";
  }
}

// 监听消息事件
bot.on('message', async (msg) => {
  const room = msg.room(); // 获取群聊
  const text = msg.text(); // 消息内容

  // 忽略自己的消息
  if (msg.self()) return;

  // 如果在群聊中,且 @ 了机器人
  if (room && text.includes(`@${bot.name()}`)) {
    const cleanText = text.replace(`@${bot.name()}`, '').trim(); // 去除 @ 内容
    const sessionId = msg.talker().id; // 使用 talker 的 ID 来唯一标识会话
    const reply = await getAIResponse(sessionId, cleanText); // 调用 AI 接口并获取回答
    await room.say(reply, msg.talker()); // 回复消息
  }
});

代码中的注释已经非常详细了,这里我就不过多赘述了!

定制化AI人设

为了让 AI 拥有预设性格,我们可以在每次回答问题时,传入一个固定的系统提示。

// ...

// 预设性格:程序员
const systemMessage = {
  role: "system",
  content:
    "你是一个闷骚的程序员,热爱开发!对别人的回复要充满对代码开发的激情!",
};

async function getAIResponse(sessionId, message) {
  try {
    // 如果该会话还没有历史记录,初始化它
    if (!sessions[sessionId]) {
      sessions[sessionId] = [];
    }

    // 在每个会话开始时加上系统消息来设定机器人的性格
    sessions[sessionId] = [systemMessage, ...sessions[sessionId]];

    // ...
  } catch (error) {
    // ...
  }
}

// 监听消息事件
bot.on('message', async (msg) => {
  // ...
});

当然,你的固定提示可以有很多,只需要将systemMessage变成一个数组即可。

更加精细化的操作,可以参考kimi的官方文档

自动加好友

bot.on('friendship', async (friendship) => {
  if (friendship.type() === 2) {
    await friendship.accept(); // 自动接受好友请求
  }
});

上面的代码是官方的demo写法,也没什么可说的

其他功能

除了上述的基本功能外,wechaty还提供了更多的微信操作功能,我们可以借助官方的示例,实现更多的功能。

大家可以根据需求自行添加代码。

完整代码

const { WechatyBuilder, ScanStatus, log } = require("wechaty");
const qrcodeTerminal = require("qrcode-terminal");
const axios = require("axios");
const OpenAI = require("openai")
  ;
// 创建机器人实例
const bot = WechatyBuilder.build({
  name: 'ai-chatbot', // 定义机器人名字
});

// 配置 Moonshot AI 客户端
const client = new OpenAI({
  apiKey: "你自己在kimi后台创建的API key", // 替换为你的API密钥
  baseURL: "https://api.moonshot.cn/v1", // Moonshot API 的基础路径
});

// 会话管理对象,存储每个用户的对话历史
const sessions = {};

// 预设性格:程序员
const systemMessage = {
  role: "system",
  content:
    "你是一个闷骚的程序员,热爱开发!对别人的回复要充满对代码开发的激情!",
};

// 监听扫码事件
bot.on('scan', (qrcode, status) => {
  if (status === ScanStatus.Waiting || status === ScanStatus.Timeout) {
    const qrcodeImageUrl = `https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`;
    log.info('AI Chatbot', `Scan QR Code to login: ${qrcodeImageUrl}`);
    qrcodeTerminal.generate(qrcode, { small: true }); // 在终端打印二维码
  }
});

// 调用 Moonshot API 获取 AI 回复
async function getAIResponse(sessionId, message) {
  try {
    // 如果该会话还没有历史记录,初始化它
    if (!sessions[sessionId]) {
      sessions[sessionId] = [];
    }

    // 在每个会话开始时加上系统消息来设定机器人的性格
    sessions[sessionId] = [systemMessage, ...sessions[sessionId]];

    // 将用户消息添加到历史记录
    const userMessage = { role: "user", content: message };
    sessions[sessionId].push(userMessage);
    
    // 调用 Moonshot API 获取 AI 回复
    const response = await client.chat.completions.create({
      model: "moonshot-v1-8k", // 使用你选择的模型
      messages: sessions[sessionId], // 传递完整的对话历史
      temperature: 0.3, // 控制回答的随机性
    });

    // 获取 AI 回复内容
    const assistantMessage = response.choices[0]?.message?.content || "抱歉,我无法回答您的问题。";
    sessions[sessionId].push({ role: "assistant", content: assistantMessage }); // 记录 AI 回复

    // 返回 AI 回复
    return assistantMessage;
  } catch (error) {
    console.error("AI Error:", error);
    return "抱歉,我的大脑短路了,请稍后再试!";
  }
}

// 监听消息事件
bot.on('message', async (msg) => {
  const room = msg.room(); // 获取群聊
  const text = msg.text(); // 消息内容
  // 忽略自己的消息
  if (msg.self()) return;
  // 如果在群聊中,且 @ 了机器人
  if (room && text.includes(`@${bot.name()}`)) {
    const cleanText = text.replace(`@${bot.name()}`, '').trim(); // 去除 @ 内容
    const sessionId = msg.talker().id; // 使用 talker 的 ID 来唯一标识会话
    const reply = await getAIResponse(sessionId, cleanText); // 调用 AI 接口并获取回答
    await room.say(reply, msg.talker()); // 回复消息
  }
});

// 监听登录和登出事件
bot.on('login', (user) => log.info('AI Chatbot', `${user} logged in`));
bot.on('logout', (user) => log.info('AI Chatbot', `${user} logged out`));

// 启动机器人
bot.start().catch((err) => log.error('AI Chatbot', err));

总结

通过 Wechaty 提供的扫码功能,我们能够非常轻松地在控制台中实现微信机器人的登录。扫码登录过程简单易懂,通过 qrcode-terminal 生成二维码,并在微信中扫码完成登录。一旦登录成功,机器人就能开始监听消息并通过调用第三方AI大模型智能回复。


感兴趣的各位可以去试试~ 关注我,我是石小石~

注:不建议使用个人主微信号尝试,避免官方误封!