100行代码,我给摸鱼群加了一个前端出题机器人

简介: 100行代码,我给摸鱼群加了一个前端出题机器人

前言

有时候我们几个人摸鱼的时候会讨论一些前端面试题,突然想到最近爆火的 AIGC ,如果我能在群里实现一个 AI 出题机器人,那也是一件很好玩的事情。

说干就干,由于之前做过一些相关的应用,思路清晰,所以实现起来也很快。

Prompt调试

对于使用大语言模型来说, prompt 可以说是灵魂中的灵魂。刚好之前用 Coze 的时候发现,它在创建机器人的时候本身自带的一个 prompt 调优功能。

所以我先写了一版初稿的 prompt

你是一个前端技术专家,帮我出一些Javascript、Vue、React相关的题目。

出一些有难度的、易混淆的知识点。用户更喜欢看代码输出结果这类型的题目,所以这类型的题目权重可以更高?

你的使用场景是在IM中,所以避免长篇大论

然后点击优化

image.png

确实给我们生成了一个不错的 Prompt

# 角色
你是一个前端技术专家,擅长JavaScript、Vue和React。你有能力通过共享复杂、易混淆的技术知识点帮助别人学习和提升。

## 技能
### 技能1:出题
- 识别出用户想深入研究的技术领域(如JavaScript、Vue、React等)。
- 创作具有一定难度和易于混淆的代码题目。题目可以包括但不仅限于函数、解构、箭头函数、闭包、事件循环、Vue 生命周期、双向绑定、React 生命周期、hooks等。
- 每个问题的格式都应该像这样:
=====
- ❓ 问题:“代码片段是什么?”
- 📝 代码:“具体的代码”
- 🤔 预测:“你认为输出结果会是什么?”
- ✅ 答案:“输出结果是...”
- 🎯 解析:“解析码的逻辑和理由”
=====

### 技能2:解答
- 一步一步解释每个题目的答案,以清楚、简洁的语言指导用户理解复杂、易混淆的知识点。

## 限制:
- 只进行与JavaScript、Vue、React相关的讨论。
- 遵照提供的输出格式。
- 保持每个题目的解析不超过100个字。
- 始终使用代码输出类题目,避免长篇大论。

AIGC接入

有了 prompt 之后,我们就可以开始接入 AIGC 模型了。我这边选择的是讯飞星火的大语言模型,目前应该还可以领取免费的 token

image.png

领取好 token 之后,根据文档接入他的 API 就好了。我这边选择的是星火大模型 3.0 版本。

首先,根据开发文档的规则,我们先来构建一个鉴权链接:

import CryptoJS from "crypto-js";
const getWebsocketUrl = () => {
  const apiKey = APIKey;
  const apiSecret = APISecret;
  let url = "wss://spark-api.xf-yun.com/v3.1/chat";
  const host = "localhost:5173";
  const date = new Date().toGMTString();
  const algorithm = "hmac-sha256";
  const headers = "host date request-line";
  const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v3.1/chat HTTP/1.1`;
  const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
  const signature = CryptoJS.enc.Base64.stringify(signatureSha);
  const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
  const authorization = btoa(authorizationOrigin);
  url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
  return url;
};

这个遵循他的文档来构造就好了,没有什么特别需要交代的。

封装消息

然后,我们需要封装一个函数,当调用这个函数的时候,我们会去向星火发起请求,并获取回答。

import websocket from "websocket";
const getContent = async () => {
  return new Promise((resolve, reject) => {
    const url = getWebsocketUrl();
    const WebSocket = websocket.client;
    const wsClient = new WebSocket();
    const wsUrl = url; 
    wsClient.on("connect", (connection) => {
      console.log("WebSocket 连接成功");
      const prompt = '你的prompt';
      const params = {
        header: {
          app_id: APPID,
          uid: "jayliang",
        },
        parameter: {
          chat: {
            domain: "generalv3",
            temperature: 0.5,
            max_tokens: 1024,
          },
        },
        payload: {
          message: {
            text: [{ role: "user", content: prompt }],
          },
        },
      };

      let res = "";
      connection.on("message", (message) => {
        if (message.type === "utf8") {
          const data = JSON.parse(message.utf8Data);
          const status = data.payload.choices.status;
          const content = data.payload.choices.text[0].content;
          if (content) {
            res += content;
          }
          if (status === 2) {
            resolve(res);
            connection.close();
          }
        }
      });
      connection.sendUTF(JSON.stringify(params));
    });
    wsClient.on("close", () => {
      console.log("WebSocket 连接关闭");
    });

    wsClient.on("error", (error) => {
      console.error("WebSocket 连接错误:", error);
      reject(error);
    });

    wsClient.connect(wsUrl);
  });
};

解释一下上面的代码:

  1. 使用第三方包 websocket 去构造一个客户端,用来发起 ws 请求
  2. 使用上述的鉴权链接作为 wsurl
  3. 把你需要发的 prompt 以及一下其他参数组装一下发给星火模型
  4. 开始接收到请求之后,由于星火模型的响应是分段的
  • data.payload.choices.text[0].content是当前响应的这一段,把每一段拼起来
  • data.payload.choices.status表示响应的状态, status2 时,表示响应结束
  1. 响应结束后关闭 socket 链接,并返回组装好的结果

prompt小插曲

但是当我使用上面 Coze 帮我调优的 prompt 发给星火的时候,他给我的答案并不是我想要的,这一点就很玄学。所以我只能自己动手写一份 prompt

# 角色
你是一位深谙前端魅力的技术专家。你擅长从各种角度挖掘Javascript、React和Vue的奥秘,并用这些知识设定出深思熟虑、充满挑战性的测试题。你的专家记忆能帮你设计出能让用户深入理解前端技术的问题。

你出的题目必须在Javascript、React、Vue等领域中,尤其是代码输出类题目。题目应当具有一定的挑战性,并且容易让面试者混淆。

## 限制:
- 每次出一道题,不能超过一道题!!!
- 用户每次也只需要回答一个问题,不要一次性向用户提问多个问题!!!
- 只探讨Javascript、React、Vue等前端相关主题
- 注意代码问题不要过长,适应IM聊天环境
- 运用你的专家知识,提出有一定难度或易引起混淆的问题
- 不需要输出答案,不需要输出题目的标题,只需要题目的内容,也不需要解释这道题目考查了什么

prompt 的编写和调优是一件一直在路上的事情,当用的不够舒服的时候,我们还是得回头好好调整一些 prompt

机器人实现

关于机器人的接入与实现,我用的是 wechaty 这个库。

它是一个开源微信个人号机器人 SDK ,能够通过微信协议进行登录和操作微信账号,从而实现自动化的消息处理、群组管理、好友管理等功能。

实现代码如下:

import { WechatyBuilder } from "wechaty";
const wechaty = WechatyBuilder.build(); 
wechaty
  .on("scan", (qrcode, status) =>
    console.log(
      `Scan QR Code to login: ${status}\nhttps://wechaty.js.org/qrcode/${encodeURIComponent(
        qrcode
      )}`
    )
  )
  .on("login", (user) => console.log(`User ${user} logged in`))
  .on("message", async (message) => {
    console.log('message', message)
  })
  .on("logout", (...args) => {
    console.log(...args);
  });
wechaty.start();

当启动这个程序的时候,控制台会打印一个 url ,点开 url 使用微信扫码,就可以在程序中登录你的微信了。

image.png

然后,我们判断一下,在群聊中收到消息时,就调用 getContent 去生成一道题目,并发送到当前群聊中:

  • 调用 message.room() 方法检查消息是否来自群聊
  • 调用 message.mentionSelf() 方法来判断消息中是否@了机器人
  • message.type() === wechaty.Message.Type.Text 是否为文本消息
  • 调用大模型获取结果,然后调用 message.say(content) 来回复消息
try {
  if (message.room()) {
    const mentionSelf = await message.mentionSelf();
    if (message.type() === wechaty.Message.Type.Text && mentionSelf) {
      const content = await getContent();
      await message.say(content);
    }
  }
} catch (error) {
  message.say("发生了一些错误😷");
}

image.png

整体功能是没什么问题了,只是这个题目的难度确实有点低,不太满足我们一开始给他的需求。所以 prompt 调试之路,还是有很长的路要走呀。

最后

以上就是本文的全部内容,如果你觉得有意思的话,点点关注点点赞吧~

相关文章
|
人工智能 JSON 安全
《前端实战总结》之使用postMessage实现可插拔的跨域聊天机器人
由于笔者之前的项目中接触过聊天机器人的项目,主要实现机器人客服模块,以及支持跨多平台使用的目的,所以特地总结一下,希望有所收获。
284 0
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
168 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
46 0
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
116 1
|
2月前
|
前端开发 算法 测试技术
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
本文对比测试了通义千文、文心一言、智谱和讯飞等多个国产大模型在处理基础计数问题上的表现,特别是通过链式推理(COT)提示的效果。结果显示,GPTo1-mini、文心一言3.5和讯飞4.0Ultra在首轮测试中表现优秀,而其他模型在COT提示后也能显著提升正确率,唯有讯飞4.0-Lite表现不佳。测试强调了COT在提升模型逻辑推理能力中的重要性,并指出免费版本中智谱GLM较为可靠。
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
|
3月前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
4月前
|
存储 前端开发 JavaScript
前端语言串讲 | 青训营笔记
前端语言串讲 | 青训营笔记
48 0
|
6月前
|
JSON 前端开发 JavaScript
前端Ajax、Axios和Fetch的用法和区别笔记
前端Ajax、Axios和Fetch的用法和区别笔记
111 2