Skip to main content
在本指南中,我们将介绍如何使用 UpstashRatelimitHandler 根据请求数或令牌数添加速率限制。此处理程序使用 Upstash 的速率限制库,该库利用了 Upstash Redis Upstash Ratelimit 的工作原理是每次调用 limit 方法时向 Upstash Redis 发送 HTTP 请求。检查并更新用户的剩余令牌/请求。根据剩余令牌,我们可以停止执行昂贵的操作,例如调用 LLM 或查询向量存储:
const response = await ratelimit.limit();
if (response.success) {
  execute_costly_operation();
}
UpstashRatelimitHandler 允许你在几分钟内将此速率限制逻辑合并到你的链中。

设置

首先,你需要前往 Upstash 控制台 并创建一个 redis 数据库(请参阅我们的文档)。创建数据库后,你需要设置环境变量:
UPSTASH_REDIS_REST_URL="****"
UPSTASH_REDIS_REST_TOKEN="****"
接下来,你需要安装 Upstash Ratelimit 和 @langchain/community
npm
npm install @upstash/ratelimit @langchain/community @langchain/core
现在你已准备好向你的链添加速率限制!

每个请求的速率限制

假设我们要允许我们的用户每分钟调用我们的链 10 次。实现这一点很简单:
const UPSTASH_REDIS_REST_URL = "****";
const UPSTASH_REDIS_REST_TOKEN = "****";

import {
  UpstashRatelimitHandler,
  UpstashRatelimitError,
} from "@langchain/community/callbacks/handlers/upstash_ratelimit";
import { RunnableLambda } from "@langchain/core/runnables";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

// create ratelimit
const ratelimit = new Ratelimit({
  redis: new Redis({
    url: UPSTASH_REDIS_REST_URL,
    token: UPSTASH_REDIS_REST_TOKEN,
  }),
  // 10 requests per window, where window size is 60 seconds:
  limiter: Ratelimit.fixedWindow(10, "60 s"),
});

// create handler
const user_id = "user_id"; // should be a method which gets the user id
const handler = new UpstashRatelimitHandler(user_id, {
  requestRatelimit: ratelimit,
});

// create mock chain
const chain = new RunnableLambda({ func: (str: string): string => str });

try {
  const response = await chain.invoke("hello world", {
    callbacks: [handler],
  });
  console.log(response);
} catch (err) {
  if (err instanceof UpstashRatelimitError) {
    console.log("Handling ratelimit.");
  }
}
请注意,我们将处理程序传递给 invoke 方法,而不是在定义链时传递处理程序。 对于除 FixedWindow 之外的速率限制算法,请参阅 upstash-ratelimit 文档 在执行我们管道中的任何步骤之前,ratelimit 将检查用户是否已通过请求限制。如果是,则引发 UpstashRatelimitError

每个令牌的速率限制

另一个选项是根据以下内容限制链调用:
  1. 提示中的令牌数
  2. 提示和 LLM 补全中的令牌数
这仅在你链中有 LLM 时才有效。另一个要求是你使用的 LLM 应在其 LLMOutput 中返回令牌使用情况。返回的令牌使用字典的格式取决于 LLM。要了解如何根据你的 LLM 配置处理程序,请参阅下面“配置”部分的末尾。

工作原理

处理程序将在调用 LLM 之前获取剩余令牌。如果剩余令牌大于 0,则将调用 LLM。否则将引发 UpstashRatelimitError 在调用 LLM 后,令牌使用信息将用于从用户的剩余令牌中减去。在此阶段的链中不会引发错误。

配置

对于第一种配置,只需像这样初始化处理程序:
const user_id = "user_id"; // should be a method which gets the user id
const handler = new UpstashRatelimitHandler(user_id, {
  requestRatelimit: ratelimit,
});
对于第二种配置,这是初始化处理程序的方法:
const user_id = "user_id"; // should be a method which gets the user id
const handler = new UpstashRatelimitHandler(user_id, {
  tokenRatelimit: ratelimit,
});
你还可以通过同时传递 request_ratelimittoken_ratelimit 参数来同时采用基于请求和令牌的速率限制。 为了使令牌使用正常工作,LangChain.js 中的 LLM 步骤应以以下格式返回令牌使用字段:
{
  "tokenUsage": {
    "totalTokens": 123,
    "promptTokens": 456,
    "otherFields: "..."
  },
  "otherFields: "..."
}
但是,并非 LangChain.js 中的所有 LLM 都符合此格式。如果你的 LLM 返回具有不同键的相同值,你可以通过将参数 llmOutputTokenUsageFieldllmOutputTotalTokenFieldllmOutputPromptTokenField 传递给处理程序来使用它们:
const handler = new UpstashRatelimitHandler(
  user_id,
  {
    requestRatelimit: ratelimit
    llmOutputTokenUsageField: "usage",
    llmOutputTotalTokenField: "total",
    llmOutputPromptTokenField: "prompt"
  }
)
这是一个使用 LLM 的链的示例:
const UPSTASH_REDIS_REST_URL = "****";
const UPSTASH_REDIS_REST_TOKEN = "****";
const OPENAI_API_KEY = "****";

import {
  UpstashRatelimitHandler,
  UpstashRatelimitError,
} from "@langchain/community/callbacks/handlers/upstash_ratelimit";
import { RunnableLambda, RunnableSequence } from "@langchain/core/runnables";
import { OpenAI } from "@langchain/openai";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

// create ratelimit
const ratelimit = new Ratelimit({
  redis: new Redis({
    url: UPSTASH_REDIS_REST_URL,
    token: UPSTASH_REDIS_REST_TOKEN,
  }),
  // 500 tokens per window, where window size is 60 seconds:
  limiter: Ratelimit.fixedWindow(500, "60 s"),
});

// create handler
const user_id = "user_id"; // should be a method which gets the user id
const handler = new UpstashRatelimitHandler(user_id, {
  tokenRatelimit: ratelimit,
});

// create mock chain
const asStr = new RunnableLambda({ func: (str: string): string => str });
const model = new OpenAI({
  apiKey: OPENAI_API_KEY,
});
const chain = RunnableSequence.from([asStr, model]);

// invoke chain with handler:
try {
  const response = await chain.invoke("hello world", {
    callbacks: [handler],
  });
  console.log(response);
} catch (err) {
  if (err instanceof UpstashRatelimitError) {
    console.log("Handling ratelimit.");
  }
}