narev-nextjs-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Narev Next.js Patterns

Narev Next.js 实践模式

Use this skill when adding or reviewing Narev usage-based billing inside a Next.js App Router app, especially route handlers that call
generateText
,
streamText
, or another Vercel AI SDK method that reaches a provider API.
For raw Pricing API lookup and cost calculation, use
narev-lookup-llm-pricing
. For committed pricing snapshots, use
narev-update-llm-pricing
.
当你在Next.js App Router应用中添加或审核基于Narev用量的计费功能时,可参考本实践,尤其是调用
generateText
streamText
或其他调用提供商API的Vercel AI SDK方法的路由处理器场景。
若需进行原始定价API查询和成本计算,请使用
narev-lookup-llm-pricing
。若需提交定价快照,请使用
narev-update-llm-pricing

What Do You Need?

所需参考资料

TaskReference
Bill a Next.js route handlerreferences/api-routes.md
Pick provider middlewarereferences/provider-middleware.md
Resolve model prices with Narevreferences/price-resolvers.md
Send usage to destinations and tag customersreferences/destinations-and-tags.md
Production-safe setupreferences/production-setup.md
Full-stack Polar integration (existing chatbot)references/polar-integration.md
任务参考文档
为Next.js路由处理器实现计费references/api-routes.md
选择提供商中间件references/provider-middleware.md
通过Narev解析模型价格references/price-resolvers.md
将用量数据发送至目标端并标记客户references/destinations-and-tags.md
生产环境安全配置references/production-setup.md
全栈Polar集成(现有聊天机器人)references/polar-integration.md

Mental Model

核心思路

Narev billing lives on the server, next to the AI provider call:
  1. Create the provider model with
    @ai-sdk/<provider>
    .
  2. Create a provider-specific
    @ai-billing/<provider>
    middleware.
  3. Give that middleware a
    createNarevPriceResolver()
    when it needs live Narev rates.
  4. Add one or more destinations, such as
    consoleDestination()
    while developing or a billing destination in production.
  5. Wrap the language model with
    wrapLanguageModel()
    before passing it to
    generateText
    or
    streamText
    .
  6. Add
    providerOptions['ai-billing-tags']
    with stable customer, user, organization, chat, or plan identifiers.
Keep API keys, billing destinations, and wrapped model factories out of Client Components.
AI Gateway variant: When the app uses
gateway.languageModel()
from the Vercel AI Gateway, substitute
createGatewayV3Middleware
from
@ai-billing/gateway
in place of a provider-specific middleware. The Gateway already resolves per-token pricing, so no
priceResolver
is needed. See
references/polar-integration.md
for the complete end-to-end pattern including customer creation, rate limiting, cost streaming to the browser, and a usage dashboard.
Narev计费逻辑部署在服务器端,与AI提供商的调用代码相邻:
  1. 使用
    @ai-sdk/<provider>
    创建提供商模型。
  2. 创建特定于提供商的
    @ai-billing/<provider>
    中间件。
  3. 当需要实时Narev费率时,为该中间件配置
    createNarevPriceResolver()
  4. 添加一个或多个数据输出目标,比如开发阶段使用
    consoleDestination()
    ,生产阶段使用计费目标端。
  5. 在将语言模型传入
    generateText
    streamText
    之前,先用
    wrapLanguageModel()
    进行包装。
  6. 添加
    providerOptions['ai-billing-tags']
    ,传入稳定的客户、用户、组织、对话或套餐标识。
请勿将API密钥、计费目标端和包装后的模型工厂暴露在客户端组件中。
AI网关变体: 当应用使用Vercel AI Gateway的
gateway.languageModel()
时,用
@ai-billing/gateway
中的
createGatewayV3Middleware
替代特定于提供商的中间件。网关已内置每令牌定价解析,因此无需配置
priceResolver
。如需完整的端到端模式(包括客户创建、速率限制、向浏览器流式传输成本以及用量仪表盘),请查看
references/polar-integration.md

Minimal Pattern

最简实践示例

typescript
import { createOpenAI } from '@ai-sdk/openai';
import { createOpenAIMiddleware } from '@ai-billing/openai';
import { consoleDestination, createNarevPriceResolver } from '@ai-billing/core';
import { convertToModelMessages, generateText, wrapLanguageModel } from 'ai';

const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

const billingMiddleware = createOpenAIMiddleware({
  destinations: [consoleDestination()],
  priceResolver: createNarevPriceResolver({
    apiKey: process.env.NAREV_API_KEY ?? '',
  }),
});

export async function POST(request: Request) {
  const { messages, userId } = await request.json();
  const modelId = 'gpt-4o';

  const result = await generateText({
    model: wrapLanguageModel({
      model: openai(modelId),
      middleware: billingMiddleware,
    }),
    messages: await convertToModelMessages(messages),
    providerOptions: {
      'ai-billing-tags': {
        userId,
        modelId,
      },
    },
  });

  return Response.json(result);
}
typescript
import { createOpenAI } from '@ai-sdk/openai';
import { createOpenAIMiddleware } from '@ai-billing/openai';
import { consoleDestination, createNarevPriceResolver } from '@ai-billing/core';
import { convertToModelMessages, generateText, wrapLanguageModel } from 'ai';

const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

const billingMiddleware = createOpenAIMiddleware({
  destinations: [consoleDestination()],
  priceResolver: createNarevPriceResolver({
    apiKey: process.env.NAREV_API_KEY ?? '',
  }),
});

export async function POST(request: Request) {
  const { messages, userId } = await request.json();
  const modelId = 'gpt-4o';

  const result = await generateText({
    model: wrapLanguageModel({
      model: openai(modelId),
      middleware: billingMiddleware,
    }),
    messages: await convertToModelMessages(messages),
    providerOptions: {
      'ai-billing-tags': {
        userId,
        modelId,
      },
    },
  });

  return Response.json(result);
}

Common Pitfalls

常见问题

SymptomCauseFix
Usage is not recordedRaw provider model is passed to
generateText
Pass the
wrapLanguageModel()
result
Secret leaks into browser bundleBilling code imported by a Client ComponentKeep billing setup in route handlers or server-only modules
Model cost is missing or wrongNo
priceResolver
, wrong provider middleware, or mismatched model ID
Use the provider-specific middleware and
createNarevPriceResolver()
Usage cannot be attributedMissing tagsSet
providerOptions['ai-billing-tags']
with stable customer identifiers
Tests fail or emit billing eventsMiddleware initialized during testsReturn the raw model in test environments
Cold starts do extra workMiddleware created inside every requestCache middleware or wrapped-model helpers at module scope
症状原因解决方法
用量未被记录原始提供商模型直接传入
generateText
传入
wrapLanguageModel()
的返回结果
密钥泄露到浏览器包中计费代码被客户端组件导入将计费配置放在路由处理器或仅服务器端模块中
模型成本缺失或错误未配置
priceResolver
、使用错误的提供商中间件或模型ID不匹配
使用特定于提供商的中间件和
createNarevPriceResolver()
用量无法归属缺少标签设置
providerOptions['ai-billing-tags']
并传入稳定的客户标识
测试失败或触发计费事件测试期间初始化了中间件在测试环境中返回原始模型
冷启动时额外耗时每次请求都创建中间件在模块级别缓存中间件或包装后的模型助手

Package Map

包映射

ProviderAI SDK packageBilling package
OpenAI
@ai-sdk/openai
@ai-billing/openai
Groq
@ai-sdk/groq
@ai-billing/groq
Anthropic
@ai-sdk/anthropic
@ai-billing/anthropic
Google
@ai-sdk/google
@ai-billing/google
GatewayAI Gateway provider
@ai-billing/gateway
OpenRouter
@openrouter/ai-sdk-provider
@ai-billing/openrouter
Use the middleware package that matches the model provider passed to the Vercel AI SDK. Do not share one provider's billing middleware with another provider's model.
Polar destination packages: When routing billing events to Polar, also install
@ai-billing/polar
(destination adapter) and
@polar-sh/sdk
(Polar API client for customer management). For prebuilt usage dashboard UI, install
@ai-billing/nextjs
.
提供商AI SDK包计费包
OpenAI
@ai-sdk/openai
@ai-billing/openai
Groq
@ai-sdk/groq
@ai-billing/groq
Anthropic
@ai-sdk/anthropic
@ai-billing/anthropic
Google
@ai-sdk/google
@ai-billing/google
GatewayAI Gateway provider
@ai-billing/gateway
OpenRouter
@openrouter/ai-sdk-provider
@ai-billing/openrouter
请使用与传入Vercel AI SDK的模型提供商匹配的中间件包。请勿将一个提供商的计费中间件用于另一个提供商的模型。
Polar目标端包: 当将计费事件路由到Polar时,还需安装
@ai-billing/polar
(目标端适配器)和
@polar-sh/sdk
(用于客户管理的Polar API客户端)。如需预构建的用量仪表盘UI,请安装
@ai-billing/nextjs

See Also

相关参考

  • narev
    - Router for Narev Cloud, SDK, and billing questions
  • narev-lookup-llm-pricing
    - Public Pricing API reference
  • narev-update-llm-pricing
    - Pin pricing snapshots into a repo
  • narev
    - Narev Cloud、SDK和计费问题的路由工具
  • narev-lookup-llm-pricing
    - 公开定价API参考
  • narev-update-llm-pricing
    - 将定价快照固定到代码仓库中

Docs

文档