Skip to content

DeepSeek plugin

The deepseek plugin gives Genkit access to DeepSeek’s models through DeepSeek’s OpenAI-compatible API. Models are named under the deepseek/ provider prefix.

Add &deepseek.DeepSeek{} to your plugin list. The plugin reads the API key from the DEEPSEEK_API_KEY environment variable.

package main
import (
"context"
"github.com/firebase/genkit/go/genkit"
"github.com/firebase/genkit/go/plugins/compat_oai/deepseek"
)
func main() {
ctx := context.Background()
g := genkit.Init(ctx,
genkit.WithPlugins(&deepseek.DeepSeek{}),
genkit.WithDefaultModel("deepseek/deepseek-v4-flash"),
)
}

You must provide an API key from DeepSeek. You can get an API key from your DeepSeek account settings. Set DEEPSEEK_API_KEY, or set the APIKey field. Extra OpenAI client request options ride in Opts, applied after the plugin defaults so they win on overlap.

import (
"context"
"os"
"github.com/firebase/genkit/go/genkit"
"github.com/firebase/genkit/go/plugins/compat_oai/deepseek"
)
func main() {
ctx := context.Background()
g := genkit.Init(ctx, genkit.WithPlugins(&deepseek.DeepSeek{
APIKey: os.Getenv("MY_DEEPSEEK_KEY"),
}))
}

genkit.Init panics when neither the APIKey field nor DEEPSEEK_API_KEY is set. The endpoint defaults to https://api.deepseek.com; override it with the DEEPSEEK_BASE_URL environment variable, or with option.WithBaseURL in Opts to reach DeepSeek’s beta endpoint.

As always, avoid embedding API keys directly in your code.

The plugin registers two models when it initializes:

  • deepseek-v4-flash: the fast, cost-effective model
  • deepseek-v4-pro: the flagship, with the strongest reasoning and agent capabilities

Both take text input, answer with text or JSON, call tools, and support thinking. The catalog is deliberately short rather than exhaustive: any other DeepSeek model ID, including the older deepseek-chat and deepseek-reasoner aliases, resolves on demand and takes the same defaults.

DeepSeek’s response_format accepts json_object but not json_schema, so no model advertises constrained generation and an output schema reaches the model as prompt instructions.

deepseek.ModelRef pairs a model ID with a typed deepseek.ChatConfig, so the config is checked where you write it and validated against the model’s schema before the request goes out. Thinking is on by default, so turn it off for a quick conversational answer.

resp, err := genkit.Generate(ctx, g,
ai.WithModel(deepseek.ModelRef("deepseek-v4-flash", &deepseek.ChatConfig{
Thinking: &deepseek.ThinkingConfig{Type: deepseek.ThinkingTypeDisabled},
})),
ai.WithPrompt("Tell me a fun fact about Mars."),
)
if err != nil {
log.Fatalf("could not generate: %v", err)
}
fmt.Println(resp.Text())

The ID passed to ModelRef works bare or provider-prefixed. You can also name a model as a string with ai.WithModelName("deepseek/deepseek-v4-flash") or genkit.WithDefaultModel, and pass the config separately with ai.WithConfig(&deepseek.ChatConfig{...}). The DeepSeek sample runs this as a streaming flow you can call from the Dev UI.

When thinking is on, the model’s reasoning arrives as a Genkit reasoning part alongside the answer. Read it with resp.Reasoning().

resp, err := genkit.Generate(ctx, g,
ai.WithModel(deepseek.ModelRef("deepseek-v4-pro", &deepseek.ChatConfig{
ReasoningEffort: deepseek.ReasoningEffortMax,
})),
ai.WithPrompt("What is heavier, one kilo of steel or one kilo of feathers?"),
)
if err != nil {
log.Fatalf("could not generate: %v", err)
}
fmt.Println(resp.Reasoning())
fmt.Println(resp.Text())

deepseek.ChatConfig carries the generation fields DeepSeek accepts plus its thinking controls:

FieldTypeNotes
Temperature*float64Randomness of token selection, 0 to 2. DeepSeek’s default is 1.
TopP*float64Nucleus sampling threshold, up to 1.
MaxOutputTokensintSent as the API’s max_tokens.
StopSequences[]stringUp to sixteen.
LogProbs*boolRequests log probabilities for the output tokens.
TopLogProbs*int0 to 20. Requires LogProbs.
UserIDstringUp to 512 characters of letters, digits, hyphen, and underscore. Sent as the API’s user_id, which partitions DeepSeek’s context cache, not OpenAI’s user.
ReasoningEffortdeepseek.ReasoningEffortlow, high, or max. DeepSeek’s default is high.
Thinking*deepseek.ThinkingConfigType is enabled or disabled. Thinking is on by default.

Pointer fields separate unset from a deliberate zero. The frequency and presence penalties are deliberately absent, because DeepSeek no longer supports them.

ChatConfig also embeds compat_oai.RequestConfig, which every plugin in the family shares: a per-request APIKey, a Version pin, and an Extra map whose keys ride to the wire verbatim under DeepSeek’s own names. See the OpenAI-compatible plugin page.

Correcting what the plugin knows about a model

Section titled “Correcting what the plugin knows about a model”

Every DeepSeek model works without an entry in Models. Supply one only to correct or extend the capabilities the plugin resolves, most often for a model released after your Genkit version. Fields left at their zero value keep what the plugin resolved.

g := genkit.Init(ctx, genkit.WithPlugins(&deepseek.DeepSeek{
Models: map[string]ai.ModelOptions{
"deepseek-v4-pro": {
Supports: &ai.ModelSupports{
Multiturn: true,
Tools: true,
SystemRole: true,
},
},
},
}))

Reasoning text, streamed token usage, cached prompt tokens, and mid-generation provider failures are handled the same way for every plugin in this family. See the OpenAI-compatible plugin page.