Skip to content

OPENAI API 反向代理教程 使用 AWS Lambda

黑墨水鱼 edited this page Apr 1, 2023 · 2 revisions

同样地,Lambda 只能返回一次数据,因此“stream”模式不可用。

分配 Elastic IP

Elastic IP 将收取每小时 0.005 美元的费用,大约每月 25 人民币。但是似乎只有绑定到网络接口才不会产生费用?文档不太容易理解,但总之似乎没有产生费用。

为了让 Lambda 从特定的 IP 地址出口,需要在 Elastic IPs 控制台中创建一个 Elastic IP。

创建子网 Subnet

需要在 VPC 控制台中创建一个子网 Subnet,Lambda 将在其中启动。这个子网可以位于默认 VPC,也可以创建一个新的 VPC,但是自己创建的 VPC 还需要另外创建一个 Internet Gateway 并将其附加到新的 VPC 上,否则 Lambda 无法访问 Internet。

修改子网的路由表

在路由表列表中找到上面新建的子网的路由表。添加一个规则,将 0.0.0.0/0 路由到该 VPC 的 Internet Gateway。只有这样,运行时程序才能访问 Internet。

创建 Lambda

Lambda 不支持自定义运行时,因此需要编写符合 lambda 规范的 JavaScript 代码。需要使用fetch,因此需要 Node.js 的运行时版本 18.x。

然后

  • 勾选 Enable function URL

  • 勾选 Auth type: NONE

  • 勾选 CORS

  • 勾选 Enable VPC

  • 选择你刚才创建的 VPC, Subnet, Security Group

这些设置虽然可以在创建之后再修改,但是由于某个角色或权限等问题可能会失败。这太复杂了,因此我遇到这种情况时,选择炸掉整个函数并从头开始。

以下是 Lambda 代码

export const handler = async (event) => {
  // 验证自定义 token,方便提供链接给其他人时不泄露真正的 token
  if (event.headers.authorization !== `Bearer miku`) {
    return { statusCode: 403 };
  }
  const data = JSON.parse(event.body);
  data.stream = false;
  const req = await fetch("https://api.openai.com/v1/chat/completions", {
    method: event.requestContext.http.method,
    headers: {
      "content-Type": event.headers["content-type"],
      // 使用真正的 token 发送请求
      authorization: "Bearer sk-xxxxxx (your real token)",
    },
    body: JSON.stringify(data),
  });
  const text = await req.text();
  const response = {
    statusCode: req.status,
    headers: { "content-type": req.headers.get("content-type") },
    body: text,
  };
  return response;
};

更改 Lambda 设置

Lambda 还有很多设置需要修改。

  • General configuration,默认的超时时间为 3 秒,显然不够,需要改成 2 分钟。

  • 在 Function URL 中,将 Origin、Allow headers、Expose header、以及 Allow methods 这些设置全部改为星号*

  • Concurrency 并发限制

关联 Elastic IP 和 子网

记得之前创建的子网 Subnet 和申请到的 Elastic IP 吗?现在需要将它们关联起来。

在 Network Interface 控制台中,找到已关联到 Lambda 所在 Subnet 的 Network Interface,然后选择关联刚刚申请到的 Elastic IP。

至此,Lambda 配置完成。

测试

如果您担心自己的配置有问题,可以将 lambda 代码换成如下内容

export const handler = async(event) => {
    const req = await fetch('https://ifconfig.me/', {
        headers: {'user-agent': 'curl'},
    })
    const response = {
        statusCode: req.status,
        headers: {'content-type': 'text/plain'},
        body: await req.text(),
    };
    return response;
};

Deploy 之后访问此函数URL,您应该能看到您的函数正在使用的出口 IP 地址。