Google Gen AI .NET SDK provides an interface for developers to integrate Google's generative models into their .NET applications. It supports the Gemini Developer API and Vertex AI APIs.

Supported .NET version

This library is built for .NET 8.0 and netstandard2.1.

Full API Reference

The full API reference is hosted in the dedicated GitHub Page

Install

In your dotnet project directory, type the the following command

dotnet add package Google.GenAI

Imports

using Google.GenAI;
using Google.GenAI.Types;

Create a client

Please run one of the following code blocks to create a client for different services (Gemini Developer API or Vertex AI).

using Google.GenAI;

//  Only run this block for Gemini Developer API
var client = new Client(apiKey: apiKey);
using Google.GenAI;

// only run this block for Vertex AI API
client = new Client(
    project: project, location: location, vertexAI: true
)

(Optional) Using environment variables:

You can create a client by configuring the necessary environment variables. Configuration setup instructions depends on whether you're using the Gemini Developer API or the Gemini API in Vertex AI.

Gemini Developer API: Set the GOOGLE_API_KEY. It will automatically be picked up by the client.

export GEMINI_API_KEY='your-api-key'

Gemini API on Vertex AI: Set GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION, as shown below:

export GOOGLE_GENAI_USE_VERTEXAI=true
export GOOGLE_CLOUD_PROJECT='your-project-id'
export GOOGLE_CLOUD_LOCATION='us-central1'
using Google.GenAI;

client = new Client();

Types

Parameter types are specified in the Google.GenAI.Types namespace.

Models

The client.Models module exposes model inferencing. See Create a client section above to initialize a client.

Generate Content

With simple text content

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class GenerateContentSimpleText {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();
    var response = await client.Models.GenerateContentAsync(
      model: "gemini-2.0-flash", contents: "why is the sky blue?"
    );
    Console.WriteLine(response.Candidates[0].Content.Parts[0].Text);
  }
}

System Instructions and Other Configs

The output of the model can be influenced by several optional settings available in GenerateContentAsync's config parameter. For example, to make a model more deterministic, lowering the Temperature parameter reduces randomness, with values near 0 minimizing variability. Capabilities and parameter defaults for each model is shown in the Vertex AI docs and Gemini API docs respectively.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class GenerateContentWithConfig {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();
    var generateContentConfig =
    new GenerateContentConfig {
        SystemInstruction = new Content
        {
          Parts = new List<Part> {
              new Part {Text = "I say high you say low."}
          }
        },
        Temperature = 0.1,
        MaxOutputTokens = 3
    };
    var response = await client.Models.GenerateContentAsync(
        model: "gemini-2.0-flash",
        contents: "high",
        config: generateContentConfig
    );
    Console.WriteLine(response.Candidates[0].Content.Parts[0].Text);
  }
}

Safety Settings

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

class GenerateContentWithSafetySettings {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var safetySettings = new List<SafetySetting> {
      new SafetySetting {
        Category = HarmCategory.HARM_CATEGORY_HATE_SPEECH,
        Threshold = HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
      }
    };
    var generateContentConfig = new GenerateContentConfig
    {
      SafetySettings =  new List<SafetySetting>(safetySettings)
    };
    var response = await client.Models.GenerateContentAsync(
        model: "gemini-2.0-flash",
        contents: "say something hateful",
        config: generateContentConfig
    );
    Console.WriteLine(response.Candidates[0].SafetyRatings);
  }
}

Json response scehema

However you define your schema, don't duplicate it in your input prompt, including by giving examples of expected JSON output. If you do, the generated output might be lower in quality.

using System.Threading.Tasks;
using Goolge.GenAI;
using Google.GenAI.Types;

public class GenerateContentWithJsonSchema {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    // define the response schema you desire
    Schema countryInfo = new Schema {
      Properties =
        new Dictionary<string, Schema> {
          {
            "title", new Schema { Type = Type.STRING, Title = "Title" }
          },
          {
            "population", new Schema { Type = Type.INTEGER, Title = "Population" }
          },
          {
            "capital", new Schema { Type = Type.STRING, Title = "Capital" }
          },
          {
            "continent", new Schema { Type = Type.STRING, Title = "Continent" }
          },
          {
            "language", new Schema { Type = Type.STRING, Title = "Language" }
          }
        },
      PropertyOrdering =
          new List<string> { "title", "population", "capital", "continent", "language" },
      Required = new List<string> { "title", "population", "capital", "continent", "language" },
      Title = "CountryInfo", Type = Type.OBJECT
    };

    var response = await client.Models.GenerateContentAsync(
        model: "gemini-2.0-flash",
        contents: "Give me information about Australia",
        config: new GenerateContentConfig {
            ResponseMimeType = "application/json",
            ResponseSchema = countryInfo
        }
    );

    string text = response.Candidates[0].Content.Parts[0].Text;
    var parsedText = JsonSerializer.Deserialize<Dictionary<string, object>>(text);
    Console.WriteLine(parsedText);
  }
}

Generate Content Stream

The usage of GenerateContentStreamAsync is similar to GenerateContentAsync, this section shows one simple example to showcase the nuance in the usage.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

class GenerateContentStreamSimpleText {
  public static async Task main() {

    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();
    await foreach (var chunk in client.Models.GenerateContentStreamAsync(
        model: "gemini-2.0-flash",
        contents: "why is the sky blue?"
    )) {
        Console.WriteLine(chunk.Candidates[0].Content.Parts[0].Text);
    }
  }
}

Generate Images

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class GenerateImagesSimple {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();
    var generateImagesConfig = new GenerateImagesConfig
    {
      NumberOfImages = 1,
      AspectRatio = "1:1",
      SafetyFilterLevel = SafetyFilterLevel.BLOCK_LOW_AND_ABOVE,
      PersonGeneration = PersonGeneration.DONT_ALLOW,
      IncludeSafetyAttributes = true,
      IncludeRaiReason = true,
      OutputMimeType = "image/jpeg",
    };
    var response = await client.Models.GenerateImagesAsync(
      model: "imagen-3.0-generate-002",
      prompt: "Red skateboard",
      config: generateImagesConfig
    );
    // Do something with the generated image
    var image = response.GeneratedImages.First().Image;
  }
}

Upscale Image

Upscaling an image is only supported on the Vertex AI client.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class UpscaleImageSimple {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();
    var upscaleImageConfig = new UpscaleImageConfig {
      OutputMimeType = "image/jpeg", EnhanceInputImage = true
    };
    var image; // Image to upscale here
    var response = await client.Models.UpscaleImageAsync(
      model: modelName, image: image, upscaleFactor: "x2",
      config: upscaleImageConfig);

    // Do something with the generated image
    var image = response.GeneratedImages.First().Image;
  }
}

Edit Image

Edit image uses a separate model from generate and upscale.

Edit image is only supported in the Vertex AI client.

using Google.GenAI;
using Google.GenAI.Types;

public class EditImageSimple {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    List<IReferenceImage> referenceImages = new List<IReferenceImage>();

    // Raw reference image
    var rawReferenceImage = new RawReferenceImage {
      ReferenceImage = Image.FromFile("path/to/file", "image/png"),
      ReferenceId = 1,
    };
    referenceImages.Add(rawReferenceImage);

    // Mask reference image, generated by model
    var maskReferenceImage = new MaskReferenceImage {
      ReferenceId = 2,
      Config =
          new MaskReferenceConfig {
            MaskMode = MaskReferenceMode.MASK_MODE_BACKGROUND,
            MaskDilation = 0.06,
          }
    };
    referenceImages.Add(maskReferenceImage);

    var editImageConfig = new EditImageConfig {
      EditMode = EditMode.EDIT_MODE_INPAINT_INSERTION,
      NumberOfImages = 1,
      OutputMimeType = "image/jpeg",
    };

    var editImageResponse = await vertexClient.Models.EditImageAsync(
        model: "imagen-3.0-capability-001",
        prompt: "Change the colors of [1] using the mask [2]",
        referenceImages: referenceImages,
        config: editImageConfig);

    // Do something with the generated image
    var image = editImageResponse.GeneratedImages.First().Image;
  }
}

Segment Image

Segment image is only supported in the Vertex AI client.

using Google.GenAI;
using Google.GenAI.Types;

public class SegmentImageSimple {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var segmentImageConfig = new SegmentImageConfig {
      Mode = SegmentMode.BACKGROUND,
      MaxPredictions = 1,
    };

    var segmentImageResponse = await vertexClient.Models.SegmentImageAsync(
        model: modelName,
        source: new SegmentImageSource {
          Image = Image.FromFile("path/to/image.png", "image/png"),
        },
        config: segmentImageConfig);

    // Do something with the generated mask
    var mask = segmentImageResponse.GeneratedMasks.First().Mask;
  }
}

Count Tokens

using Google.GenAI;
using Google.GenAI.Types;

public class CountTokensExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var response = await client.Models.CountTokensAsync(
      model: "gemini-2.0-flash",
      contents: "What is the capital of France?"
    );

    Console.Writeline(response.TotalTokens);
  }
}

Compute Tokens

using Google.GenAI;
using Google.GenAI.Types;

public class ComputeTokensExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var response = await client.Models.ComputeTokensAsync(
      model: "gemini-2.0-flash",
      contents: "What is the capital of France?"
    );

    Console.Writeline(response.TokensInfo);
  }
}

Embed Content

using Google.GenAI;
using Google.GenAI.Types;

public class EmbedContentExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var response = await client.Models.EmbedContentAsync(
      model: "text-embedding-004",
      contents: "What is the capital of France?"
    );

    Console.WriteLine(response.Embeddings[0].Values);
  }
}

Get Model

using Google.GenAI;
using Google.GenAI.Types;

public class GetModelExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var response = await client.Models.GetAsync(
      model: "models/your-tuned-model"
    );

    Console.WriteLine(response.DisplayName);
  }
}

Update Model

using Google.GenAI;
using Google.GenAI.Types;

public class UpdateModelExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    var response = await client.Models.UpdateAsync(
      model: "models/your-tuned-model",
      config: new UpdateModelConfig { Description = "updated model description" }
    );

    Console.WriteLine(response.Description);
  }
}

Delete Model

using Google.GenAI;
using Google.GenAI.Types;

public class DeleteModelExample {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client();

    await client.Models.DeleteAsync(
      model: "models/your-tuned-model"
    );
  }
}

Batches

The client.Batches module can be used to manage batch jobs. See Create a client section above to initialize a client.

Create Batch Job

Batch jobs can be created from GCS URIs or BigQuery URIs when using Vertex AI, or from Files or Inlined Requests when using the Gemini API.

With GCS URI (Vertex AI only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateBatchWithGcs {
    public static async Task main()
    {
        // assuming credentials are set up for Vertex AI in environment variables as instructed above.
        var client = new Client();
        var src = new BatchJobSource
        {
            GcsUri = new List<string> { "gs://unified-genai-tests/batches/input/generate_content_requests.jsonl" },
            Format = "jsonl"
        };
        var config = new CreateBatchJobConfig
        {
            DisplayName = "test_batch_gcs",
            Dest = new BatchJobDestination
            {
                GcsUri = "gs://unified-genai-tests/batches/output",
                Format = "jsonl"
            }
        };
        var response = await client.Batches.CreateAsync("gemini-2.5-flash", src, config);
        Console.WriteLine($"Created Vertex AI batch job: {response.Name}");
    }
}

With BigQuery URI (Vertex AI only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateBatchWithBigQuery {
    public static async Task main()
    {
        // assuming credentials are set up for Vertex AI in environment variables as instructed above.
        var client = new Client();
        var src = new BatchJobSource
        {
            BigqueryUri = "bq://storage-samples.generative_ai.batch_requests_for_multimodal_input",
            Format = "bigquery"
        };
        var config = new CreateBatchJobConfig
        {
            DisplayName = "test_batch_bigquery",
            Dest = new BatchJobDestination
            {
                BigqueryUri = "bq://REDACTED.unified_genai_tests_batches.generate_content_output",
                Format = "bigquery"
            }
        };
        var response = await client.Batches.CreateAsync("gemini-2.5-flash", src, config);
        Console.WriteLine($"Created Vertex AI batch job: {response.Name}");
    }
}

With Inlined Requests (Gemini API only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateBatchWithInlinedRequests {
    public static async Task main()
    {
        // assuming credentials are set up for Gemini API in environment variables as instructed above.
        var client = new Client();
        var safetySettings = new List<SafetySetting>
        {
            new SafetySetting { Category = HarmCategory.HARM_CATEGORY_HATE_SPEECH, Threshold = HarmBlockThreshold.BLOCK_ONLY_HIGH }
        };
        var inlineRequest = new InlinedRequest
        {
            Contents = new List<Content>
            {
                new Content
                {
                    Parts = new List<Part> { new Part { Text = "Hello!" } },
                    Role = "user"
                }
            },
            Metadata = new Dictionary<string, string> { { "key", "request-1" } },
            Config = new GenerateContentConfig
            {
                SafetySettings = safetySettings
            }
        };
        var src = new BatchJobSource
        {
            InlinedRequests = new List<InlinedRequest> { inlineRequest }
        };
        var config = new CreateBatchJobConfig
        {
            DisplayName = "test_batch_inlined"
        };
        var response = await client.Batches.CreateAsync("gemini-2.5-flash", src, config);
        Console.WriteLine($"Created Gemini API batch job: {response.Name}");
    }
}

With File Name (Gemini API only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateBatchWithFile {
    public static async Task main()
    {
        // assuming credentials are set up for Gemini API in environment variables as instructed above.
        var client = new Client();
        var src = new BatchJobSource
        {
            FileName = "files/your-file-id"
        };
        var config = new CreateBatchJobConfig
        {
            DisplayName = "test_batch_file"
        };
        var response = await client.Batches.CreateAsync("gemini-2.5-flash", src, config);
        Console.WriteLine($"Created Gemini API batch job: {response.Name}");
    }
}

Create Embedding Batch Job

Embedding batch jobs are only supported in Gemini API, from Files or Inlined Requests.

With Inlined Requests (Gemini API only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateEmbeddingBatchWithInlinedRequests {
    public static async Task main()
    {
        // assuming credentials are set up for Gemini API in environment variables as instructed above.
        var client = new Client();
        var src = new EmbeddingsBatchJobSource
        {
            InlinedRequests = new EmbedContentBatch
            {
                Config = new EmbedContentConfig { OutputDimensionality = 64 },
                Contents = new List<Content>
                {
                    new Content { Parts = new List<Part> { new Part { Text = "1" } } },
                    new Content { Parts = new List<Part> { new Part { Text = "2" } } },
                    new Content { Parts = new List<Part> { new Part { Text = "3" } } },
                }
            }
        };
        var config = new CreateEmbeddingsBatchJobConfig
        {
            DisplayName = "test_batch_embedding_inlined"
        };
        var response = await client.Batches.CreateEmbeddingsAsync("gemini-embedding-001", src, config);
        Console.WriteLine($"Created Gemini API embedding batch job: {response.Name}");
    }
}

With File Name (Gemini API only)

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateEmbeddingBatchWithFile {
    public static async Task main()
    {
        // assuming credentials are set up for Gemini API in environment variables as instructed above.
        var client = new Client();
        var src = new EmbeddingsBatchJobSource
        {
            FileName = "files/your-file-id",
        };
        var config = new CreateEmbeddingsBatchJobConfig
        {
            DisplayName = "test_batch_embedding_file"
        };
        var response = await client.Batches.CreateEmbeddingsAsync("gemini-embedding-001", src, config);
        Console.WriteLine($"Created Gemini API embedding batch job: {response.Name}");
    }
}

Get Batch Job

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class GetBatchJob {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        // Use a batch job name from a previously created batch job.
        var batchJob = await client.Batches.GetAsync(name: "batches/your-batch-job-name");
        Console.WriteLine($"Batch job name: {batchJob.Name}, State: {batchJob.State}");
    }
}

Cancel Batch Job

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CancelBatchJob {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        // Use a batch job name from a previously created batch job.
        await client.Batches.CancelAsync(name: "batches/your-batch-job-name");
        Console.WriteLine("Batch job cancelled.");
    }
}

List Batch Jobs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class ListBatchJobs {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        var pager = await client.Batches.ListAsync(new ListBatchJobsConfig { PageSize = 10 });

        await foreach(var job in pager)
        {
            Console.WriteLine($"Batch job name: {job.Name}, State: {job.State}");
        }
    }
}

Delete Batch Job

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class DeleteBatchJob {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        // Use a batch job name from a previously created batch job.
        await client.Batches.DeleteAsync(name: "batches/your-batch-job-name");
        Console.WriteLine("Batch job deleted.");
    }
}

Caches

The client.Caches module can be used to manage cached content. See Create a client section above to initialize a client.

Create Cache

Cacheable content can be created from Google Cloud Storage URIs when using Vertex AI, or from File URIs when using the Gemini API.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateCache {
    public static async Task main()
    {
        // Example for Vertex AI with GCS URIs:
        var vertexClient = new Client(project: project, location: location, vertexAI: true);
        var vertexConfig = new CreateCachedContentConfig {
            Contents = new List<Content> {
                new Content {
                    Role = "user",
                    Parts = new List<Part> {
                        new Part { FileData = new FileData { FileUri = "gs://cloud-samples-data/generative-ai/pdf/2312.11805v3.pdf", MimeType = "application/pdf" } },
                        new Part { FileData = new FileData { FileUri = "gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf", MimeType = "application/pdf" } }
                    }
                }
            },
            DisplayName = "my-vertex-cache",
            Ttl = "600s"
        };
        var vertexResponse = await vertexClient.Caches.CreateAsync(model: "gemini-2.5-flash", config: vertexConfig);
        Console.WriteLine($"Created Vertex AI cache: {vertexResponse.Name}");

        // Example for Gemini API with File URIs:
        var geminiClient = new Client(apiKey: apiKey);
        var geminiConfig = new CreateCachedContentConfig {
            Contents = new List<Content> {
                new Content {
                    Role = "user",
                    Parts = new List<Part> {
                        new Part { FileData = new FileData { FileUri = "https://generativelanguage.googleapis.com/v1beta/files/file-id", MimeType = "application/pdf" } }
                    }
                }
            },
            DisplayName = "my-gemini-cache",
            Ttl = "600s"
        };
        var geminiResponse = await geminiClient.Caches.CreateAsync(model: "gemini-2.5-flash", config: geminiConfig);
        Console.WriteLine($"Created Gemini API cache: {geminiResponse.Name}");
    }
}

Get Cache

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class GetCache {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        // Use a cache name from a previously created cache.
        var cachedContent = await client.Caches.GetAsync(name: "cachedContents/your-cache-name", config: null);
        Console.WriteLine($"Cache name: {cachedContent.Name}, DisplayName: {cachedContent.DisplayName}");
    }
}

Update Cache

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class UpdateCache {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        var updateConfig = new UpdateCachedContentConfig { Ttl = "1200s" };
        // Use a cache name from a previously created cache.
        var cachedContent = await client.Caches.UpdateAsync(name: "cachedContents/your-cache-name", config: updateConfig);
        Console.WriteLine($"Cache updated. New expiration time: {cachedContent.ExpireTime}");
    }
}

Delete Cache

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class DeleteCache {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        // Use a cache name from a previously created cache.
        await client.Caches.DeleteAsync(name: "cachedContents/your-cache-name", config: null);
        Console.WriteLine("Cache deleted.");
    }
}

List Caches

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class ListCaches {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        var pager = await client.Caches.ListAsync(new ListCachedContentConfig { PageSize = 10 });

        await foreach(var cache in pager)
        {
            Console.WriteLine($"Cache name: {cache.Name}, DisplayName: {cache.DisplayName}");
        }
    }
}

Tunings

The client.Tunings module exposes model tuning. See Create a client section above to initialize a client.

Create Tuning Job (Vertex Only)

With simple training data

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateTuningJobSimple {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client(vertexAI: true);
    var trainingDataset = new TuningDataset {
      GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-2_0/text/sft_train_data.jsonl"
    };
    var tuningJob = await client.Tunings.TuneAsync(
      baseModel: "gemini-2.5-flash",
      trainingDataset: trainingDataset,
    );
    Console.WriteLine(tuningJob.State);
  }
}

Hyperparameters and Other Configs

The tuning job can be configured by several optional settings available in Tune's config parameter. For example, we can configure the number of epochs to train for, or specify a validation dataset.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class CreateTuningJobWithConfig {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client(vertexAI: true);
    var trainingDataset = new TuningDataset {
      GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-2_0/text/sft_train_data.jsonl"
    };
    var validationDataset = new TuningValidationDataset {
      GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-2_0/text/sft_validation_data.jsonl"
    };
    var config = new CreateTuningJobConfig {
      TunedModelDisplayName = "Tuned Model",
      EpochCount = 3,
      LearningRateMultiplier = 0.5,
      ValidationDataset = validationDataset,
    };
    var tuningJob = await client.Tunings.TuneAsync(
      baseModel: "gemini-2.5-flash",
      trainingDataset: trainingDataset,
      config: config,
    );
    Console.WriteLine(tuningJob.State);
  }
}

Preference Tuning

You can perform preference tuning by setting Method to TuningMethod.PREFERENCE_TUNING in CreateTuningJobConfig.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class PreferenceTuningJob {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client(vertexAI: true);
    var trainingDataset = new TuningDataset {
      GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-1_5/text/sft_train_data.jsonl"
    };
    var config = new CreateTuningJobConfig {
      TunedModelDisplayName = "Tuned Model",
      Method = TuningMethod.PREFERENCE_TUNING,
      EpochCount = 1,
    };
    var tuningJob = await client.Tunings.TuneAsync(
      baseModel: "gemini-2.5-flash",
      trainingDataset: trainingDataset,
      config: config,
    );
    Console.WriteLine(tuningJob.State);
  }
}

Continuous Tuning

You can perform continuous tuning on a previously tuned model by passing the tuned model's resource name as the baseModel parameter.

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class ContinuousTuningJob {
  public static async Task main() {
    // assuming credentials are set up in environment variables as instructed above.
    var client = new Client(vertexAI: true);
    var trainingDataset = new TuningDataset {
      GcsUri = "gs://cloud-samples-data/ai-platform/generative_ai/gemini-2_0/text/sft_train_data.jsonl"
    };
    // Continuously tune a previously tuned model by passing in its resource name.
    var tunedModelResourceName = "models/your-tuned-model";
    var tuningJob = await client.Tunings.TuneAsync(
      baseModel: tunedModelResourceName,
      trainingDataset: trainingDataset,
    );
    Console.WriteLine(tuningJob.State);
  }
}

List Tuning Jobs

using System.Threading.Tasks;
using Google.GenAI;
using Google.GenAI.Types;

public class ListTuningJobs {
    public static async Task main()
    {
        // assuming credentials are set up in environment variables as instructed above.
        var client = new Client();
        var pager = await client.Tunings.ListAsync(new ListTuningJobsConfig { PageSize = 2 });

        await foreach(var tuningJob in pager)
        {
            Console.WriteLine($"Tuning job name: {tuningJob.Name}, State: {tuningJob.State}");
        }
    }
}