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.
Configuration
Section titled “Configuration”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.
Models
Section titled “Models”The plugin registers two models when it initializes:
deepseek-v4-flash: the fast, cost-effective modeldeepseek-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.
Reasoning
Section titled “Reasoning”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())Generation config
Section titled “Generation config”deepseek.ChatConfig carries the generation fields DeepSeek accepts plus its thinking controls:
| Field | Type | Notes |
|---|---|---|
Temperature | *float64 | Randomness of token selection, 0 to 2. DeepSeek’s default is 1. |
TopP | *float64 | Nucleus sampling threshold, up to 1. |
MaxOutputTokens | int | Sent as the API’s max_tokens. |
StopSequences | []string | Up to sixteen. |
LogProbs | *bool | Requests log probabilities for the output tokens. |
TopLogProbs | *int | 0 to 20. Requires LogProbs. |
UserID | string | Up 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. |
ReasoningEffort | deepseek.ReasoningEffort | low, high, or max. DeepSeek’s default is high. |
Thinking | *deepseek.ThinkingConfig | Type 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, }, }, },}))Response behavior
Section titled “Response behavior”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.