• 作者:老汪软件技巧
  • 发表时间:2024-09-06 07:02
  • 浏览量:

前言

ChatGPT问世已经两年了, 因为有些功能确实好用,如询问编程问题,生成创意广告文案/总结文章,文生图,文生视频,图形问题识别等,所以ChatGPT类的AI问答工具,如雨后春笋般冒出来。这么多人都做出来这个功能,说明AI问答类的技术壁垒应该不高,笔者也跃跃欲试,想开发一个极简版的AI对话功能。说干就干,到底选哪个大模型了实现AI对话功能呢? 自己平时用的最多的大模型是通义千问,因为它回答编程问题,比百度,字节,科大讯飞的大模型更精准,那就选它吧。现在我们进入今天的正题

第一步 获取API-Key和开通模型服务注册登录阿里云:前往阿里云官网,注册并使用你的账号登录阿里云(Tips: 如果你觉得注册麻烦,可以使用支付宝账号扫描登录).

创建API密钥:进入主页面之后,在顶部的菜单搜索栏, 输入百炼,点击搜索出来的大模型服务平台百炼

进入大模型服务平台百炼后接着点击管理控制台

点击查看我的API-KEY,创建一个API密钥,这个密钥用于调用大模型接口时的身份验证和计费

接着点击创建API KEY按钮,进入创建API KEY弹窗页面

描述不是必填项,可以不填,直接点击确定即可

可以看到,API KEY已经创建好了。

要想使用大模型,光有API KEY不行,还得开通模型服务。

开通模型服务时默认是开通所有。模型有好多种类型:如文本生成,图像生成,语音合成与识别,视频合成,向量(将文本、图像、语音转换成一组数字,适用于音视频分类、图像分类、图文检索等),特定行业(适用于法律咨询、案例分析和法规解读等)。

模型既有阿里自研的:如支持通用文本生成模型、、、超长文档模型以及视觉理解(图生文)模型。也支持开源版本的通用文本生成模型、、。也有第三方的:如、、、等第三方模型。

点开《模型管理服务协议》,协议内容比较长,重点看一下有关收费的条款。点击同意模型协议。

模型更详细的收费信息在模型广场==>某种模型==>查看详情中查找,一般都有免费的额度用于新模型的练手学习。

开通模型服务时又弹出提示要进行实名认证,用支付宝进行实名认证

到此,调用大模型的前置工作都已经准备好了,现在我们来编写调用程序。

第二步 编写调用代码

1.安装openai

pnpm add openai

千问大模型支持使用openAI的API调用自身。在使用 OpenAI 的 API 时,可以通过传递各种参数来控制生成内容的方式和行为。以下是常见的 OpenAI API 参数及其含义:

名称含义示例

apiKey

API 密钥,用于身份验证和授权访问 OpenAI 服务

apiKey: "YOUR_API_KEY"

baseURL

自定义 API 的基础 URL,通常用于指定 OpenAI 服务的访问点

baseURL:

temperature

控制生成的输出的随机性。值范围为 0 到 1。较低的值(如 0.2)会使输出更确定和保守,而较高的值(如 0.8)会增加生成内容的多样性。

temperature: 0.7

maxTokens

控制生成内容的最大长度,以 token 数量为单位(一个 token 约为一个词的一部分)

_手把手指导教学_手把手教学什么意思

maxTokens: 150

topP

核采样策略的参数。值范围为 0 到 1。它与 temperature 类似,控制生成内容的多样性,但通过限制累积概率的方式来选择输出。

topP: 0.9

指定要生成多少个独立的响应

n: 1

stop

一个或多个字符串,用于指定生成应在何处停止。这些字符串会标识输出的截断点。

stop: ["\n", "###"]

presencePenalty

控制生成输出中是否引入新主题的倾向。较高的值会鼓励生成新的主题。

presencePenalty: 0.6

frequencyPenalty

控制模型生成输出时避免重复相同内容的倾向。较高的值会减少重复。

frequencyPenalty: 0.5

logitBias

用于调整特定 token 在生成中的出现概率。可以通过将某些 token 的概率降低来减少其出现频率。

logitBias: {"50256": -100}

配置 API Key 到环境变量

API Key不能以明文外泄到代码中,通常都是通过环境变量来访问。

# 用你的 API Key代替引号中的内容,引号要保留
export DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"
#使环境变量生效
source ~/.bashrc
# 检查环境变量是否生效
echo $DASHSCOPE_API_KEY

调用大模型 API

创建一个index.js文件,添加如下代码:

import OpenAI from "openai";
const openai = new OpenAI({
  apiKey: process.env.DASHSCOPE_API_KEY,
  baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
});
async function main() {
  const completion = await openai.chat.completions.create({
    messages: [
      { role: "system", content: "You are a helpful assistant." },
      { role: "user", content: "你是谁?" },
    ],
    model: "qwen-max",
  });
  console.log(completion.choices[0]["message"]["content"]);
}
main();

在package.json中指明使用esModule语法导入依赖包

{
  "type": "module",
  "dependencies": {
     "openai": "^4.57.1"
  }
}

运行结果如下: 可以看到,返回正确。

第三步 改造成Web版

为了能从环境变量中读取API KEY,我们需要创建一个node项目。这里选择创建一个基于vite构建工具的node项目。

pnpm create vite

项目package.json的内容如下,要将上一步的openai添加到运行时依赖包中。

{
  "name": "ali-chat",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "openai": "^4.57.1"
  },
  "devDependencies": {
    "vite": "^5.4.1"
  }
}

创建好项目之后, 安装依赖,为了能在网页端访问到API KEY环境变量,需要在vite.config.js中进行定义,此外,在本地请求通义千问的api时,浏览器会提示会跨域,需要添加一条代理转发配置。

import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
  server: {
    host: "0.0.0.0",
    hmr: true,
    proxy: {
      "/compatible-mode/v1": {
        target: "https://dashscope.aliyuncs.com",
        changeOrigin: true,
        secure: false,
      },
    },
  },
  define: {
    "process.env": {
      DASHSCOPE_API_KEY: process.env.DASHSCOPE_API_KEY,
    },
  },
});

创建一个简单的 HTML 页面,上方是对话内容显示区域,下方是对话内容输入区和发送按钮

html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>通义千问聊天AItitle>
    <style>
      .chat-content {
        margin: 10px 0;
      }
      .user-input {
        display: block;
        margin: 20px 0;
      }
    style>
  head>
  <body>
    <div id="chat-box">
      
    div>
    <textarea class="user-input" id="user-input" rows="4" cols="50" placeholder="请输入您的问题"> textarea>
    <button id="send-button">发送button>
    <script type="module" src="./src/chat.js">script>
  body>
html>

接着编写对话功能,首先配置OpenAI基础参数, 与服务端调用配置相比,要多加一个参数dangerouslyAllowBrowser: true,不然控制台会产生告警。要想实现持续的对话,每次响应的要做为下一次请求中的 messages 的一部分,从而维持对话的上下文。在 messages 数组中设置第一条消息的 role 为 "system" 而非 "assistant" 是为了设定对话的上下文和基调,而不是直接提供助手的回复。"system" 消息用于设定助手的行为、风格、规则或限制。system 消息可以在对话开始时提供指导,使助手能够更好地理解用户的意图和上下文,通过这样做,可以影响助手在接下来的对话中如何生成回复,从而更好地匹配用户的预期。点击发送按钮事件回调和更新内容区域的功能比较简单,一看就懂,这里不再赘述。chat.js的完整内容如下:

// 引入 OpenAI 的 API 客户端库
import OpenAI from "openai";
// 绑定发送按钮事件
document.getElementById("send-button").addEventListener("click", () => {
  const userInput = document.getElementById("user-input").value;
  if (userInput.trim()) {
    sendMessage(userInput);
    document.getElementById("user-input").value = ""; // 清空输入框
  }
});
const openai = new OpenAI({
  apiKey: process.env.DASHSCOPE_API_KEY,
  dangerouslyAllowBrowser: true, // 允许在浏览器中使用 API
  baseURL: "http://localhost:5173/compatible-mode/v1",
});
// 存储对话的上下文
let messages = [{ role: "system", content: "You are a helpful assistant." }];
// 处理发送消息
async function sendMessage(userInput) {
  // 将用户的消息添加到对话上下文中
  messages.push({ role: "user", content: userInput });
  try {
    // 调用 OpenAI 的 chat completion 接口
    const response = await openai.chat.completions.create({
      model: "qwen-max", // 使用的模型
      messages: messages,
    });
    // 获取助手的回复
    const assistantMessage = response.choices[0].message.content;
    // 将助手的回复添加到对话上下文中
    messages.push({ role: "assistant", content: assistantMessage });
    // 更新对话显示区域
    updateChatBox(userInput, assistantMessage);
  } catch (error) {
    console.error("Error during API call:", error);
  }
}
// 更新对话显示区域
function updateChatBox(userMessage, assistantMessage) {
  const chatBox = document.getElementById("chat-box");
  // 添加用户消息
  const userDiv = document.createElement("div");
  userDiv.classList.add("chat-content");
  userDiv.textContent = `用户: ${userMessage}`;
  chatBox.appendChild(userDiv);
  // 添加助手消息
  const assistantDiv = document.createElement("div");
  userDiv.classList.add("chat-content");
  assistantDiv.textContent = `助手: ${assistantMessage}`;
  chatBox.appendChild(assistantDiv);
  // 滚动到最新的消息
  chatBox.scrollTop = chatBox.scrollHeight;
}

AI对话功能开发完了, 现在我们调试一下,看看效果。执行yarn dev,启动界面

输入问题,这是问答效果,界面比较简陋,但核心功能已经有了。至此我们已经实现了web版的AI对话功能。

最后

简易Web版的AI问答功能开发出来了, 可是如果按token收费,调用成本偏高。要想真正商用的话,可能采用国外/国内开源的大模型,在本地部署一个大模型服务更佳。如何在本地部署一个大模型,这是另一个有探索价值的课题。下一篇我们就讲讲如何在本地部署大模型。