分享一种更简单的薅 AWS 羊毛姿势

192 天前
 Jianzs

网上绝大多数薅 AWS 羊毛的教程都是在教大家如何申请创建一年免费的 VPS ,太 OUT 了!就问一个问题,一年到期了那咋办?

其实,除了一年免费的 VPS 外,AWS 足足有 40 多个永久免费的服务,其中就包括的 AWS 最为出名的 Lambda ,以及日常开发常用的 DynamoDB ( NoSQL 数据库)、SNS (发布订阅)。而这么多的服务挨个读文档、装 SDK 太麻烦了,开发个 App 得写一堆的函数,体验实在是,emmmmm...

这篇文章就给大家分享一种简单的方式,来把这些能力都用上,过程中不需要安装任何软件,一切的一切只需要创建一个 AWS 账号就可以了,创建 AWS 账号需要一张外币卡,VISA 、Master 或者运通都 OK 。


这篇文章会以一个“在命令行终端运行的聊天机器”为例,给大家展示如何优雅薅羊毛,这个聊天机器人支持多会话、会话自动保存与恢复,5 分钟拥有自己的 ChatBot 不是梦。效果如下⬇️:

⚠️注意:这只是一个示例,方法通用的,你可以使用这个方法去创建更多不同种类的服务,目前这个方法支持使用 ApiGateway 、消息队列、定时器等多种服务。

环境准备

不需要 VS Code ,不需要 vim ,只需要打开这个网址 👉 「 Plutolang - CodeSandbox 」,然后点右上角的 Fork 就能创建一个你自己的工程环境了。

如果你不想输入代码,也可以直接 Fork 这个环境,这个环境已经准备好代码,只需要配置 AWS 凭证 和 OpenAI Key 就好。

修改代码

首先需要添加一个 OpenAI 的依赖,打开 package.jsondependencies 添加一行,

"openai": "^4.13.0"

添加完后记得 Command/Ctrl-S 保存,然后在点击下方控制台中 终端 的小图标,执行 Install 任务,这会自动下载 NPM 依赖。

接下来就是编写业务代码了。打开 src/index.ts 文件,接下来,我们会先定义用于保存会话的 KV 数据库,然后编写新建会话,和聊天的 HTTP 路由。

1 、 导入 ChatBot 依赖的库。

import OpenAI from "openai";
import { Router, KVStore, HttpRequest, HttpResponse } from "@plutolang/pluto";

2 、 定义 KV 数据库 和 路由 资源变量。

其中 KV 数据库用来保存会话,他会以机器人的名字为 Key ,将消息历史记录为 Value 。Router 就是 Web 开发中的服务器,与 express 库类似。

const kvstore = new KVStore("kvstore");
const router = new Router("router");

3 、 路由:创建新的聊天会话。

给 router 添加一个 /new 路径的处理函数,接受 POST 请求。请求的 query 中会一个 bot 参数,表示机器人的名称,同时请求体( Request Body )里会有这个机器人的角色定位,比如“一个高级前端工程师”之类的。随后会在 KV 数据库中创建一个键值对,来保存这个新的会话。

router.post("/new", async (req: HttpRequest): Promise<HttpResponse> => {
  const bot = req.query["bot"];
  if (!bot) {
    return {
      statusCode: 400,
      body: "Missing bot parameter. Please provide a name and its initialization system message for your bot in order to define the assistant's behavior effectively.",
    };
  }
  const sysMsg = req.body;

  const messages = [{ role: "system", content: sysMsg }];
  await kvstore.set(bot, JSON.stringify(messages));
  return {
    statusCode: 200,
    body: "Now you can enjoy your chatbot.",
  };
});

4 、 路由:进行会话聊天。

因为这个聊天机器人是基于 OpenAI 的 API 实现的,因此需要首先申请一个 Open API Key 。

这里需要你先注册 OpenAI 账户,然后打开这个网页,点击 Create new secret key,设置一个你喜欢的名称。随后,会生成一个密钥,一定要保存这个密钥!你点了 Done 之后,就再看不到这个密钥了。

然后把 OPENAI_API_KEY 替换成你申请到的 OpenAI 的 API Key ,如果你是 OpenAI 的付费用户,你也可以把 MODEL 替换成 gpt-4

router.post("/chat", async (req: HttpRequest): Promise<HttpResponse> => {
  // Replace the placeholder with your OpenAI API Key and DO NOT publish it publicly.
  const OPENAI_API_KEY = "sk-Acj6oPEXKUctapxWxxxxxxxxxxxxxxxx";
  // Replace your desired model. You can find all available models here: https://platform.openai.com/docs/models
  const MODEL = "gpt-3.5-turbo";

  const bot = req.query["bot"] ?? "default";
  const newMsg = req.body;
  console.debug("Received a user message, Bot:", bot, ", Message:", newMsg);

  const record = await kvstore.get(bot).catch(() => undefined);
  const messages = record ? JSON.parse(record) : [];
  messages.push({ role: "user", content: newMsg });

  const openai = new OpenAI({ apiKey: OPENAI_API_KEY });
  const chatCompletion = await openai.chat.completions.create({
    messages: messages,
    model: MODEL,
  });

  // Check if the response is valid.
  const choices = chatCompletion.choices;
  if (choices.length == 0 || choices[0].message.content == null) {
    console.error("OpenAI Response: ", chatCompletion);
    return {
      statusCode: 500,
      body: "Something went wrong. OpenAI did not respond with a valid message. Please try again later.",
    };
  }

  const respMsg = choices[0].message;
  // To maintain the continuity of the conversation, store the response message in the database.
  messages.push(respMsg);
  await kvstore.set(bot, JSON.stringify(messages));
  return {
    statusCode: 200,
    body: respMsg.content!,
  };
});

快速部署

配置 AWS 凭证

进入下方的控制台的 Configure AWS Certificate 标签页,会提示你输入 AWS 凭证信息,这个凭证信息就是 AWS 的 Access KeySecret Access Key,如果你不知道怎么创建凭证,可以根据这篇文档操作。

拿到凭证信息后,按照提示信息输入就好,output format 不需要填写,最后按下回车后,标签页会显示一个小对号✔️。

一键发布

点击下方控制台中 终端 的小图标,执行 Deploy 任务,等待一两分钟,直到输出一条 URL

这时,支持多会话、会话自动保存与恢复的聊天机器人已经部署完成了,接下来就是和聊天机器人对话了。

与机器人对话

这里,我提供了一个命令行工具 chat 来与刚部署的 Chat Bot 服务端交互进行聊天,你在项目根目录创建一个 chat 文件或者在你本地的任何位置,将下面 ⬇️ 的内容复制进去就能使用。

#!/bin/bash
# set -o xtrace

read -p "Input the URL that Pluto has outputted: " URL
if [ -z $URL ]; then
    echo "Please set the BOT_URL env var first";
    exit 1;
fi

echo "Choose mode:"
echo '  1) create a new bot;'
echo '  2) select a existed bot;'
read -p "> " mode
if [[ -z $mode || ( $mode -ne 1 && $mode -ne 2 ) ]]; then
    echo "Invalid mode";
    exit 1;
fi

read -p "Give a name for your bot: " bot_name
if [ -z $bot_name ]; then
    echo "Invalid name";
    exit 1;
fi

if [[ $mode -eq 1 ]]; then
    echo -e "\nHello, I'm $bot_name. "
    echo "What role would you like me to fulfill? Please provide a detailed description of the skills you expect me to possess."
    echo "For example, a TypeScript expert who familiar with the principle of compilation."
    read -p "> " system_message
    echo -e "Got it. Creating..."

    if [[ -n $system_message ]]; then
        curl -s -X POST $URL/new?bot="$bot_name" -d "$system_message" -H 'Content-type: text/plain' > /dev/null
    fi
fi

echo -e "\nNow you can enjoy your chatbot."
user_message=""
while :
do
    echo "Press 'q' to quit."
    read -p "> " user_message
    if [[ $user_message == "q" ]]; then
        echo "Bye. 👋"
        break;
    fi
    curl -X POST $URL/chat?bot="$bot_name" -d "$user_message" -H 'Content-type: text/plain'
    echo -e "\n"
done

在 Web 网站上的使用方法是:点击下方控制台中 终端 的小图标,选择 New Terminal ,然后执行下面这条命令就会进入对话界面,首先会提示你输入刚才部署得到的 URL ,随后继续交互就能完成对话。

bash ./chat

现在就能看到开篇截图的效果:

后记

这种方式就是利用 Plutolang 的能力来降低 AWS 复杂服务的上手难度,想要开发其他的应用完全是 OK 的。对项目感兴趣可以了解了解,蛮有意思。

Refs

完整代码:

import OpenAI from "openai";
import { Router, KVStore, HttpRequest, HttpResponse } from "@plutolang/pluto";

const kvstore = new KVStore("kvstore");
const router = new Router("router");

router.post("/chat", async (req: HttpRequest): Promise<HttpResponse> => {
  // Replace the placeholder with your OpenAI API Key and DO NOT publish it publicly.
  const OPENAI_API_KEY = "sk-Acj6oPEXKUctapxWxxxxxxxxxxxxxxxx";
  // Replace your desired model. You can find all available models here: https://platform.openai.com/docs/models
  const MODEL = "gpt-3.5-turbo";

  const bot = req.query["bot"] ?? "default";
  const newMsg = req.body;
  console.debug("Received a user message, Bot:", bot, ", Message:", newMsg);

  const record = await kvstore.get(bot).catch(() => undefined);
  const messages = record ? JSON.parse(record) : [];
  messages.push({ role: "user", content: newMsg });

  const openai = new OpenAI({ apiKey: OPENAI_API_KEY });
  const chatCompletion = await openai.chat.completions.create({
    messages: messages,
    model: MODEL,
  });

  // Check if the response is valid.
  const choices = chatCompletion.choices;
  if (choices.length == 0 || choices[0].message.content == null) {
    console.error("OpenAI Response: ", chatCompletion);
    return {
      statusCode: 500,
      body: "Something went wrong. OpenAI did not respond with a valid message. Please try again later.",
    };
  }

  const respMsg = choices[0].message;
  // To maintain the continuity of the conversation, store the response message in the database.
  messages.push(respMsg);
  await kvstore.set(bot, JSON.stringify(messages));
  return {
    statusCode: 200,
    body: respMsg.content!,
  };
});

router.post("/new", async (req: HttpRequest): Promise<HttpResponse> => {
  const bot = req.query["bot"];
  if (!bot) {
    return {
      statusCode: 400,
      body: "Missing bot parameter. Please provide a name and its initialization system message for your bot in order to define the assistant's behavior effectively.",
    };
  }
  const sysMsg = req.body;

  const messages = [{ role: "system", content: sysMsg }];
  await kvstore.set(bot, JSON.stringify(messages));
  return {
    statusCode: 200,
    body: "Now you can enjoy your chatbot.",
  };
});
3832 次点击
所在节点    云计算
19 条回复
coinxu
192 天前
虽然是软文,看你这么诚恳,支持一下,不错
zsj1029
192 天前
挺好,降低上手云开发的难度,关注业务,忽略运维细节,支持
apiman
192 天前
薅羊毛的有几个是用来做开发的
qweruiop
192 天前
太软了,实际上 aws lambda 太贵了,不太适合用。现在都用 vercel 或者 cloudflare worker 了。
gps949
192 天前
@apiman
龟壳的 ARM 机器油 24G 内存,用来 vscode 远程开发真的还挺不错的。相比起来我远程回家 AIO 上的虚机或者其他地方买的 VPS (大多数是 8G ),跑两下内存就满了
Jianzs
192 天前
@coinxu 感谢感谢,虽然是软文,但是也是真的想给大家带来一点价值,真诚是必杀技,哈哈哈哈
Jianzs
192 天前
@zsj1029 对!这就是想给大家提供的一点价值,但是总说不好,感觉没有让大家理解的很清楚。大佬感兴趣可以以一起来玩玩呀
Jianzs
192 天前
@qweruiop AWS 永久免费 每月 100 万请求,一般的项目够用啦,vercel 的免费访问限制好像也差不多是这些吧。

另外,vercel 主要是前端嘛,写业务逻辑需要在 api 目录 一个子目录一个子目录 的去写每个函数,个人感觉体验差点意思,你觉得呢?
zsj1029
192 天前
@Jianzs laf.run 我最近在用,这种云开发更贴近用户体验,大佬可以试用下,看看有没有可取之处
Jianzs
191 天前
@zsj1029 #9 巧了,我知道这个项目,你说这种方式更贴近用户体验,我还挺好奇的,你为啥觉得 Laf 更贴近用户体验?从我个人看法来说,我感觉有几点不同,刚好和你探讨一下

1 ) Laf 这种方式还是独立编写每个函数(比如路由处理函数),项目整体性比较差,如果我要写一个多函数的应用程序,就比较麻烦,思维不连贯,容易被打断

2 ) Laf 需要用户自行创建数据库等组件,不过好在创建的体验做了优化,不需要什么成本就能够创建,并在编程时使用。而 Pluto 这种完全是在代码里定义一个变量,组件资源就创建好了,整个开发流程都在代码界面。

3 ) Laf 目前好像存在一定的 运营商锁定 问题,必须使用 K8s 或者它的平台。Pluto 是支持多平台的,目前阶段是在 K8s 和 AWS 上做了验证,一点代码都不需要修改,就能直接迁移平台。这篇文章的例子没有体现,感兴趣欢迎看看 README 中的 例子,这是例子的视频,2 分钟,https://www.bilibili.com/video/BV1HB4y1d7cq/

所以,相较于 Laf ,Pluto 更想做到的是,用户只在代码界面就能完成所有操作,并且还都是以往常的编程方式完成的,类似简简单单定义一个变量。顺带解决运行商锁定问题。

这是我个人角度的想法,你能简单说说为啥你觉得 Laf 更贴近用户体验么?应该是他的开箱即用?
Jianzs
191 天前
@zsj1029 #9 另外,zsj 是你名字的缩写吗?如果是的话,那咱俩一样,哈哈哈哈
zsj1029
191 天前
@Jianzs 是的,开箱即用,web ide ,甚至不需要本地开发环境,配套的对象存储,文档也很完善
保存即发布,对于小项目很合适的,没错是的 zsj 缩写
腾讯云开发也有个类似的,集成组件开发模板,不过两年没更新了
总之你的这个 pluto 还是需要点门槛研究的,考虑整合 cloudflare worker ,这个我也挺看好的,多个运营商可以选择
zsj1029
191 天前
@Jianzs 你这个 pluto 真的挺好的,回头有空研究下,最近对比了不少集成后端开发环境,比如 appwrite ,很感兴趣
Jianzs
191 天前
@zsj1029 好呀好呀,感谢反馈建议。我也尝试对比了与 BaaS 、PaaS 之类产品的不同,大佬可以看看,后续继续交流呀,感兴趣一起玩玩,加个绿色软件? c2hvdWppYW5fNDI2

https://github.com/pluto-lang/pluto/blob/main/docs/zh-CN/whats-different.md
zsj1029
191 天前
@Jianzs 我已经加入了你的 slack ,那边沟通吧
cmhonker
191 天前
AWS ,吃码三折,EC2/Lightsail

my.cloudcpp.com
Jianzs
191 天前
@cmhonker 哈哈哈哈,这也来蹭?问一下,国内用 AWS 的多么?
JIeJaitt
190 天前
aws 有免费的 mysql 数据库?
Jianzs
190 天前
@JIeJaitt 免费 12 个月,没有永久免费,AWS RDS ,支持 MySQL 引擎

https://aws.amazon.com/cn/free/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/987000

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX