Código
Vercel AI SDK
Crie um provider nokeep com createOpenAICompatible de @ai-sdk/openai-compatible. Depois, generateText, streamText e as ferramentas funcionam como com qualquer modelo do AI SDK.
Verificado em 29 de outubro de 2026
Instale e configure o provider
npm install ai @ai-sdk/openai-compatible zod
export NOKEEP_API_KEY="sk-nokeep-test" # your own key once it connectsimport { createOpenAICompatible } from "@ai-sdk/openai-compatible"
export const nokeep = createOpenAICompatible({
name: "nokeep",
apiKey: process.env.NOKEEP_API_KEY,
baseURL: "https://nokeep.ai/v1",
includeUsage: true, // token counts on streamed replies too
})nokeep("<ID do modelo>") cria um modelo. Os IDs são deepseek-v4.1-flash-uncensored e glm-5.3-flash-uncensored: compare-os em Modelos, ou leia-os em GET /v1/models. includeUsage: true pede contagens de tokens nas respostas em streaming; sem ele, o streamText não informa nenhuma.
generateText
import { generateText } from "ai"
import { nokeep } from "./nokeep.js"
const { text, usage } = await generateText({
model: nokeep("deepseek-v4.1-flash-uncensored"),
system: "You are a blunt editor.",
prompt: "Cut this opening line to ten words: ...",
})
console.log(text)
console.log(usage.inputTokens, usage.outputTokens)streamText
import { streamText } from "ai"
import { nokeep } from "./nokeep.js"
const result = streamText({
model: nokeep("deepseek-v4.1-flash-uncensored"),
prompt: "Tell me a story in three lines.",
})
for await (const text of result.textStream) process.stdout.write(text)
// With includeUsage on, the counts arrive once the stream ends.
console.log(await result.usage)Em um route handler do Next.js, retorne result.toUIMessageStreamResponse() para useChat, ou result.toTextStreamResponse() para texto puro. Para parar uma resposta, aborte a requisição (abortSignal); você paga pelo que foi escrito antes de parar. Veja Streaming.
Chamada de ferramentas
import { generateText, stepCountIs, tool } from "ai"
import { z } from "zod"
import { nokeep } from "./nokeep.js"
const { text } = await generateText({
model: nokeep("deepseek-v4.1-flash-uncensored"),
tools: {
weather: tool({
description: "Get the weather in a city",
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => ({ city, celsius: 18 }),
}),
},
stopWhen: stepCountIs(5), // let the model call the tool, read the result and answer
prompt: "What's the weather in Lisbon?",
})
console.log(text)Os dois modelos chamam ferramentas. glm-5.3-flash-uncensored escolhe sozinho: toolChoice: "required" ou uma ferramenta nomeada recebe um 400, então use o DeepSeek quando uma ferramenta precisar rodar. Veja Chamadas de ferramentas.
Esforço de raciocínio
import { generateText } from "ai"
import { nokeep } from "./nokeep.js"
const { text, reasoningText } = await generateText({
model: nokeep("deepseek-v4.1-flash-uncensored"),
prompt: "Plan a three-act heist story in five bullet points.",
maxOutputTokens: 4000, // thinking counts toward the limit
providerOptions: { nokeep: { reasoningEffort: "high" } },
})
console.log(reasoningText) // the thinking, apart from the answer
console.log(text)A chave dentro de providerOptions é o name que você deu ao provider. Ela é enviada como reasoning_effort, sem mudança. O DeepSeek V4.1 Flash Uncensored responde na hora, a menos que você peça para pensar: ela aceita none, low, high, max. A opção reasoning: "high" do próprio AI SDK envia o mesmo campo. Veja Raciocínio.
Imagens (DeepSeek)
import { readFile } from "node:fs/promises"
import { generateText } from "ai"
import { nokeep } from "./nokeep.js"
const { text } = await generateText({
model: nokeep("deepseek-v4.1-flash-uncensored"),
messages: [{
role: "user",
content: [
{ type: "text", text: "What is in this picture?" },
{ type: "file", mediaType: "image/jpeg", data: await readFile("photo.jpg") },
],
}],
})
console.log(text)deepseek-v4.1-flash-uncensoredlê até 10 imagens por pedido.glm-5.3-flash-uncensoredlê só texto e responde400 unsupported_input.- O AI SDK envia cada imagem dentro do pedido, em base64. Passe uma
URLcomodatae ele baixa o arquivo antes. Um pedido pode ter até 12 MB, então reduza fotos grandes. - Imagens são partes
filecom um media typeimage/*. A parteimagemais antiga ainda funciona, mas está obsoleta. - Outros arquivos, como PDFs ou áudio, são recusados com
400 unsupported_input. Veja Imagens.
Armadilhas
- `reasoning_effort` aceita só os valores do próprio modelo.
deepseek-v4.1-flash-uncensoredaceitanone,low,high,max;glm-5.3-flash-uncensoredaceitalow,high. Os valoresminimal,mediumexhighde outros apps rodam no nível mais próximo do modelo (mediumcomohigh,xhighcomomaxonde o modelo tem esse nível); qualquer outro valor recebe400 invalid_reasoning_effort. Veja Raciocínio. - Campos que um modelo não aceita são descartados, não recusados. A chamada ainda responde, e o cabeçalho de resposta
x-nokeep-ignoreddiz o que ficou de fora. O GLM mantém sótools,tool_choiceereasoning_effort, então seustemperatureeresponse_formatsão descartados. Veja quais campos cada modelo aceita. - `n` tem de ser 1. Para pedir várias respostas, faça várias chamadas.
- Use `@ai-sdk/openai-compatible`, não `@ai-sdk/openai`. O provider da OpenAI chama
/v1/responsespor padrão, que o nokeep não tem.
Perguntas
Existe um pacote de provider nokeep para o AI SDK?
Não precisa. @ai-sdk/openai-compatible é o pacote próprio do AI SDK para APIs compatíveis com OpenAI, e todo recurso desta página funciona por ele.
O streamText informa o uso?
Sim, quando o provider é criado com includeUsage: true. Aí await result.usage dá as contagens de tokens da chamada.
Posso testar sem pagar?
Pode. Use a chave sk-nokeep-test: cada chamada responde com uma linha fixa e não custa nada, então você configura seu app primeiro. A chave de teste grátis.