ChatModel - gemini
A Google Gemini implementation for Eino that implements the ToolCallingChatModel interface. This enables seamless integration with Eino’s LLM capabilities for enhanced natural language processing and generation.
Features
- Implements
github.com/cloudwego/eino/components/model.Model - Easy integration with Eino’s model system
- Configurable model parameters
- Support for chat completion
- Support for streaming responses
- Custom response parsing support
- Flexible model configuration
Installation
go get github.com/cloudwego/eino-ext/components/model/gemini@latest
Quick start
Here’s a quick example of how to use the Gemini model:
package main
import (
"context"
"fmt"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: "gemini-2.5-flash",
ThinkingConfig: &genai.ThinkingConfig{
IncludeThoughts: true,
ThinkingBudget: nil,
},
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
// If you are using a model that supports image understanding (e.g., gemini-2.5-flash-image-preview),
// you can provide both image and text input like this:
/*
image, err := os.ReadFile("./path/to/your/image.jpg")
if err != nil {
log.Fatalf("os.ReadFile failed, err=%v\n", err)
}
imageStr := base64.StdEncoding.EncodeToString(image)
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
UserInputMultiContent: []schema.MessageInputPart{
{
Type: schema.ChatMessagePartTypeText,
Text: "What do you see in this image?",
},
{
Type: schema.ChatMessagePartTypeImageURL,
Image: &schema.MessageInputImage{
MessagePartCommon: schema.MessagePartCommon{
Base64Data: &imageStr,
MIMEType: "image/jpeg",
},
Detail: schema.ImageURLDetailAuto,
},
},
},
},
})
*/
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
Content: "What is the capital of France?",
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
fmt.Printf("Assistant: %s\n", resp.Content)
if len(resp.ReasoningContent) > 0 {
fmt.Printf("ReasoningContent: %s\n", resp.ReasoningContent)
}
}
Configuration
The model can be configured using the gemini.Config struct:
type Config struct {
// Client is the Gemini API client instance
// Required for making API calls to Gemini
Client *genai.Client
// Model specifies which Gemini model to use
// Examples: "gemini-pro", "gemini-pro-vision", "gemini-1.5-flash"
Model string
// MaxTokens limits the maximum number of tokens in the response
// Optional. Example: maxTokens := 100
MaxTokens *int
// Temperature controls randomness in responses
// Range: [0.0, 1.0], where 0.0 is more focused and 1.0 is more creative
// Optional. Example: temperature := float32(0.7)
Temperature *float32
// TopP controls diversity via nucleus sampling
// Range: [0.0, 1.0], where 1.0 disables nucleus sampling
// Optional. Example: topP := float32(0.95)
TopP *float32
// TopK controls diversity by limiting the top K tokens to sample from
// Optional. Example: topK := int32(40)
TopK *int32
// ResponseSchema defines the structure for JSON responses
// Optional. Used when you want structured output in JSON format
ResponseSchema *openapi3.Schema
// EnableCodeExecution allows the model to execute code
// Warning: Be cautious with code execution in production
// Optional. Default: false
EnableCodeExecution bool
// SafetySettings configures content filtering for different harm categories
// Controls the model's filtering behavior for potentially harmful content
// Optional.
SafetySettings []*genai.SafetySetting
ThinkingConfig *genai.ThinkingConfig
// ResponseModalities specifies the modalities the model can return.
// Optional.
ResponseModalities []GeminiResponseModality
}
examples
generate
package main
import (
"context"
"fmt"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
modelName := os.Getenv("GEMINI_MODEL")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: modelName,
ThinkingConfig: &genai.ThinkingConfig{
IncludeThoughts: true,
ThinkingBudget: nil,
},
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
Content: "What is the capital of France?",
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
fmt.Printf("Assistant: %s\n", resp.Content)
if len(resp.ReasoningContent) > 0 {
fmt.Printf("ReasoningContent: %s\n", resp.ReasoningContent)
}
}
generate_with_image
package main
import (
"context"
"encoding/base64"
"fmt"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
modelName := os.Getenv("GEMINI_MODEL")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: modelName,
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
image, err := os.ReadFile("./examples/generate_with_image/test.jpg")
if err != nil {
log.Fatalf("os.ReadFile failed, err=%v\n", err)
}
imageStr := base64.StdEncoding.EncodeToString(image)
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
UserInputMultiContent: []schema.MessageInputPart{
{
Type: schema.ChatMessagePartTypeText,
Text: "What do you see in this image?",
},
{
Type: schema.ChatMessagePartTypeImageURL,
Image: &schema.MessageInputImage{
MessagePartCommon: schema.MessagePartCommon{
Base64Data: &imageStr,
MIMEType: "image/jpeg",
},
Detail: schema.ImageURLDetailAuto,
},
},
},
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
fmt.Printf("Assistant: %s\n", resp.Content)
}
stream
package main
import (
"context"
"fmt"
"io"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
modelName := os.Getenv("GEMINI_MODEL")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: modelName,
ThinkingConfig: &genai.ThinkingConfig{
IncludeThoughts: true,
ThinkingBudget: nil,
},
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
stream, err := cm.Stream(ctx, []*schema.Message{
{
Role: schema.User,
Content: "Write a short poem about spring.",
},
})
if err != nil {
log.Fatalf("Stream error: %v", err)
}
fmt.Println("Assistant: ")
for {
resp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Stream receive error: %v", err)
}
fmt.Println("frame: ")
if len(resp.Content) > 0 {
fmt.Println("content: ", resp.Content)
}
if len(resp.ReasoningContent) > 0 {
fmt.Printf("ReasoningContent: %s\n", resp.ReasoningContent)
}
}
fmt.Println()
}
image_generate
package main
import (
"context"
"encoding/json"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
modelName := os.Getenv("GEMINI_MODEL")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: modelName,
ResponseModalities: []gemini.GeminiResponseModality{
gemini.GeminiResponseModalityText,
gemini.GeminiResponseModalityImage,
},
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
/*
The generated multimodal content is stored in the `AssistantGenMultiContent` field.
For this example, the resulting message will have a structure similar to this:
resp := &schema.Message{
Role: schema.Assistant,
AssistantGenMultiContent: []schema.MessageOutputPart{
{
Type: schema.ChatMessagePartTypeImageURL,
Image: &schema.MessageOutputImage{
MessagePartCommon: schema.MessagePartCommon{
Base64Data: &base64String, // The base64 encoded image data
MIMEType: "image/png",
},
},
},
},
}
*/
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
UserInputMultiContent: []schema.MessageInputPart{
{
Type: schema.ChatMessagePartTypeText,
Text: "Generate an image of a cat",
},
},
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
log.Printf("\ngenerate output: \n")
respBody, _ := json.MarshalIndent(resp, " ", " ")
log.Printf(" body: %s\n", string(respBody))
}
intent_tool
package main
import (
"context"
"fmt"
"log"
"os"
"google.golang.org/genai"
"github.com/cloudwego/eino-ext/components/model/gemini"
"github.com/cloudwego/eino/schema"
)
func main() {
apiKey := os.Getenv("GEMINI_API_KEY")
modelName := os.Getenv("GEMINI_MODEL")
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: apiKey,
})
if err != nil {
log.Fatalf("NewClient of gemini failed, err=%v", err)
}
cm, err := gemini.NewChatModel(ctx, &gemini.Config{
Client: client,
Model: modelName,
ThinkingConfig: &genai.ThinkingConfig{
IncludeThoughts: true,
ThinkingBudget: nil,
},
})
if err != nil {
log.Fatalf("NewChatModel of gemini failed, err=%v", err)
}
err = cm.BindTools([]*schema.ToolInfo{
{
Name: "book_recommender",
Desc: "Recommends books based on user preferences and provides purchase links",
ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
"genre": {
Type: "string",
Desc: "Preferred book genre",
Enum: []string{"fiction", "sci-fi", "mystery", "biography", "business"},
},
"max_pages": {
Type: "integer",
Desc: "Maximum page length (0 for no limit)",
},
"min_rating": {
Type: "number",
Desc: "Minimum user rating (0-5 scale)",
},
}),
},
})
if err != nil {
log.Fatalf("Bind tools error: %v", err)
}
resp, err := cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
Content: "Recommend business books with minimum 4.3 rating and max 350 pages",
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
if len(resp.ToolCalls) > 0 {
fmt.Printf("Function called: \n")
if len(resp.ReasoningContent) > 0 {
fmt.Printf("ReasoningContent: %s\n", resp.ReasoningContent)
}
fmt.Println("Name: ", resp.ToolCalls[0].Function.Name)
fmt.Printf("Arguments: %s\n", resp.ToolCalls[0].Function.Arguments)
} else {
log.Printf("Function called without tool calls: %s\n", resp.Content)
}
resp, err = cm.Generate(ctx, []*schema.Message{
{
Role: schema.User,
Content: "Recommend business books with minimum 4.3 rating and max 350 pages",
},
resp,
{
Role: schema.Tool,
ToolCallID: resp.ToolCalls[0].ID,
Content: "{\"book name\":\"Microeconomics for Managers\"}",
},
})
if err != nil {
log.Fatalf("Generate error: %v", err)
}
fmt.Printf("Function call final result: %s\n", resp.Content)
}
For More Details
最后修改
October 22, 2025
: doc(Eino): add chatmodel docs (#1446) (4d2c2e5e0b)