Comece a usar o Foundry Local

Neste quickstart, cria uma aplicação de consola que descarrega um modelo de IA local, gera uma resposta de chat em streaming e descarrega o modelo. Tudo corre no seu dispositivo sem dependência da cloud ou subscrição do Azure.

Pré-requisitos

Repositório de samples

Pode encontrar o código de exemplo completo deste artigo no repositório de exemplos do Foundry no GitHub. Para clonar o repositório e navegar até à amostra, utilize:

git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/csharp/foundry-local/native-chat-completions

Instalar pacotes

dotnet add package Microsoft.AI.Foundry.Local
dotnet add package OpenAI

Os exemplos de C# no repositório GitHub são projetos pré-configurados. Se está a construir do zero, deve ler a referência do Foundry Local SDK para mais detalhes sobre como configurar o seu projeto C# com o Foundry Local.

Usar API nativa de completação de chat

Copie e cole o seguinte código num ficheiro C# chamado Program.cs:

using Microsoft.AI.Foundry.Local;

CancellationToken ct = new CancellationToken();

var config = new Configuration
{
    AppName = "foundry_local_samples",
    LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};


// Initialize the singleton instance.
await FoundryLocalManager.CreateAsync(config, Utils.GetAppLogger());
var mgr = FoundryLocalManager.Instance;


// Discover available execution providers and their registration status.
var eps = mgr.DiscoverEps();
int maxNameLen = 30;
Console.WriteLine("Available execution providers:");
Console.WriteLine($"  {"Name".PadRight(maxNameLen)}  Registered");
Console.WriteLine($"  {new string('─', maxNameLen)}  {"──────────"}");
foreach (var ep in eps)
{
    Console.WriteLine($"  {ep.Name.PadRight(maxNameLen)}  {ep.IsRegistered}");
}

// Download and register all execution providers with per-EP progress.
// EP packages include dependencies and may be large.
// Download is only required again if a new version of the EP is released.
// For cross platform builds there is no dynamic EP download and this will return immediately.
Console.WriteLine("\nDownloading execution providers:");
if (eps.Length > 0)
{
    string currentEp = "";
    await mgr.DownloadAndRegisterEpsAsync((epName, percent) =>
    {
        if (epName != currentEp)
        {
            if (currentEp != "")
            {
                Console.WriteLine();
            }
            currentEp = epName;
        }
        Console.Write($"\r  {epName.PadRight(maxNameLen)}  {percent,6:F1}%");
    });
    Console.WriteLine();
}
else
{
    Console.WriteLine("No execution providers to download.");
}


// Get the model catalog
var catalog = await mgr.GetCatalogAsync();


// Get a model using an alias.
var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found");

// Download the model (the method skips download if already cached)
await model.DownloadAsync(progress =>
{
    Console.Write($"\rDownloading model: {progress:F2}%");
    if (progress >= 100f)
    {
        Console.WriteLine();
    }
});

// Load the model
Console.Write($"Loading model {model.Id}...");
await model.LoadAsync();
Console.WriteLine("done.");

// Create a stateful native chat session and enable streaming.
using var chatSession = new ChatSession(model);
chatSession.SetStreaming(true);
using var request = new Request();
request.AddItem(MessageItem.User("Why is the sky blue?"));

// Get a streaming chat completion response
Console.WriteLine("Chat completion response:");
await using var streamingResponse = chatSession.ProcessStreamingRequestAsync(request, ct);
await foreach (var item in streamingResponse)
{
    using (item)
    {
        if (item is TextItem { Type: TextItemType.Default } text)
        {
            Console.Write(text.Text);
            Console.Out.Flush();
        }
    }
}
using var finalResponse = await streamingResponse.FinalResponse;
Console.WriteLine();

// Tidy up - unload the model
finalResponse.Dispose();
await streamingResponse.DisposeAsync();
request.Dispose();
chatSession.Dispose();
await model.UnloadAsync();

Execute o código usando o seguinte comando:

dotnet run

Solução de problemas

  • Erros de compilação referentes a net8.0: Instala o SDK .NET 8.0 e depois reconstrói a aplicação.
  • Model not found: Executa o excerto opcional de listagem de modelos para encontrar um alias disponível no teu dispositivo, depois atualiza o alias passado para GetModelAsync.
  • Primeira execução lenta: Os downloads de modelos podem demorar à primeira vez que executas a aplicação.

Pré-requisitos

Repositório de samples

O código de exemplo completo deste artigo está disponível no repositório foundry-samples do GitHub. Para clonar o repositório e navegar até ao exemplo de uso:

git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/javascript/foundry-local/native-chat-completions

Instalar pacotes

npm install foundry-local-sdk openai

Usar API nativa de completação de chat

Copie e cole o seguinte código num ficheiro JavaScript chamado app.js:

import {
    ChatSession,
    FoundryLocalManager,
    Item,
    Request
} from 'foundry-local-sdk';

// Initialize the Foundry Local SDK
console.log('Initializing Foundry Local SDK...');

const manager = FoundryLocalManager.create({
    appName: 'foundry_local_samples',
    logLevel: 'info'
});
console.log('✓ SDK initialized successfully');

// Discover available execution providers and their registration status.
const eps = manager.discoverEps();
const maxNameLen = 30;
console.log('\nAvailable execution providers:');
console.log(`  ${'Name'.padEnd(maxNameLen)}  Registered`);
console.log(`  ${'─'.repeat(maxNameLen)}  ──────────`);
for (const ep of eps) {
    console.log(`  ${ep.name.padEnd(maxNameLen)}  ${ep.isRegistered}`);
}

// Download and register all execution providers with per-EP progress.
// EP packages include dependencies and may be large.
// Download is only required again if a new version of the EP is released.
console.log('\nDownloading execution providers:');
if (eps.length > 0) {
    let currentEp = '';
    await manager.downloadAndRegisterEps((epName, percent) => {
        if (epName !== currentEp) {
            if (currentEp !== '') {
                process.stdout.write('\n');
            }
            currentEp = epName;
        }
        process.stdout.write(`\r  ${epName.padEnd(maxNameLen)}  ${percent.toFixed(1).padStart(5)}%`);
    });
    process.stdout.write('\n');
} else {
    console.log('No execution providers to download.');
}

// Get the model object
const modelAlias = 'qwen2.5-0.5b'; // Using an available model from the list above
const model = await manager.catalog.getModel(modelAlias);

// Download the model
console.log(`\nDownloading model ${modelAlias}...`);
await model.download((progress) => {
    process.stdout.write(`\rDownloading... ${progress.toFixed(2)}%`);
});
console.log('\n✓ Model downloaded');

// Load the model
console.log(`\nLoading model ${modelAlias}...`);
await model.load();
console.log('✓ Model loaded');

// Create a stateful native chat session
console.log('\nCreating chat session...');
const chatSession = new ChatSession(model);
chatSession.setOptions({
    search: { temperature: 0.7, maxOutputTokens: 256 }
});
console.log('✓ Chat session created');

// Example chat completion
console.log('\nTesting chat completion...');
const completion = await chatSession.processRequest(
    new Request().addItem(Item.userMessage('Why is the sky blue?'))
);

console.log('\nChat completion result:');
for (const item of completion.output) {
    if (item.type === 'message') {
        process.stdout.write(item.content ?? item.parts?.map((part) => part.text ?? '').join('') ?? '');
    } else if (item.type === 'text' && item.textType === 'default') {
        process.stdout.write(item.text);
    }
}
console.log();

// Example streaming completion
console.log('\nTesting streaming completion...');
const stream = chatSession.processStreamingRequest(
    new Request().addItem(Item.userMessage(
        'Write a short poem about programming.'
    ))
);
for await (const item of stream) {
    if (item.type === 'text' && item.textType === 'default') {
        process.stdout.write(item.text);
    }
}
await stream.response;
console.log('\n');

// Unload the model
console.log('Unloading model...');
chatSession.dispose();
await model.unload();
console.log(`✓ Model unloaded`);

Execute o código usando o seguinte comando:

node app.js

Pré-requisitos

Repositório de samples

O código de exemplo completo deste artigo está disponível no repositório foundry-samples do GitHub. Para clonar o repositório e navegar até ao exemplo de uso:

git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/python/foundry-local/native-chat-completions

Instalar pacotes

pip install foundry-local-sdk openai

Usar API nativa de completação de chat

Copie e cole o seguinte código num ficheiro Python chamado app.py:

from foundry_local_sdk import (
    ChatSession,
    Configuration,
    FoundryLocalManager,
    MessageItem,
    Request,
    RequestOptions,
    SearchOptions,
    TextItem,
    TextItemType,
)



def main():
    # Initialize the Foundry Local SDK
    config = Configuration(app_name="foundry_local_samples")
    FoundryLocalManager.initialize(config)
    manager = FoundryLocalManager.instance

    # Discover and register execution providers that are not already available.
    eps = manager.discover_eps()
    missing_eps = [ep.name for ep in eps if not ep.is_registered]
    if missing_eps:
        manager.download_and_register_eps(missing_eps)

    # Select and load a model from the catalog.
    model = manager.catalog.get_model("qwen2.5-0.5b")
    if model is None:
        raise RuntimeError("Model 'qwen2.5-0.5b' was not found in the catalog.")
    if not model.is_cached:
        model.download(
            lambda progress: print(
                f"\rDownloading model: {progress:.2f}%",
                end="",
                flush=True,
            )
        )
        print()
    model.load()
    print("Model loaded and ready.")

    try:
        # Create a native chat session and stream the response token by token.
        with ChatSession(model) as session:
            session.set_options(
                RequestOptions(
                    search=SearchOptions(temperature=0.0, max_output_tokens=256)
                )
            )
            session.set_streaming(True)
            with Request().add_item(
                MessageItem.user("What is the golden ratio?")
            ) as request:
                print("Assistant: ", end="", flush=True)
                with session.process_streaming_request(request) as stream:
                    for item in stream:
                        if (
                            isinstance(item, TextItem)
                            and item.type == TextItemType.DEFAULT
                        ):
                            print(item.text, end="", flush=True)
                print()
    finally:
        # Clean up
        if model.is_loaded:
            model.unload()
        manager.close()
        print("Model unloaded.")


if __name__ == "__main__":
    main()

Execute o código usando o seguinte comando:

python app.py

Solução de problemas

  • ModuleNotFoundError: No module named 'foundry_local_sdk': Instale o SDK executando pip install foundry-local-sdk.
  • Model not found: Executa o excerto opcional de listagem de modelos para encontrar um alias disponível no teu dispositivo, depois atualiza o alias passado para get_model.
  • Primeira execução lenta: Os downloads de modelos podem demorar à primeira vez que executas a aplicação.

Pré-requisitos

Repositório de samples

O código de exemplo completo deste artigo está disponível no repositório foundry-samples do GitHub. Para clonar o repositório e navegar até ao exemplo de uso:

git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/rust/foundry-local/native-chat-completions

Instalar pacotes

cargo add foundry-local-sdk
cargo add tokio --features full
cargo add tokio-stream anyhow

Usar API nativa de completação de chat

Substitua o conteúdo do main.rs pelo seguinte código:

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use std::io::{self, Write};

use foundry_local_sdk::{
    ChatSession, FoundryLocalConfig, FoundryLocalManager, Item, Request, RequestOptions,
    SearchOptions, TextKind,
};
use tokio_stream::StreamExt;

const ALIAS: &str = "qwen2.5-0.5b";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Native Chat Completions");
    println!("=======================\n");

    // ── 1. Initialise the manager ────────────────────────────────────────
    let manager = FoundryLocalManager::create(FoundryLocalConfig::new("foundry_local_samples"))?;

    // Download and register all execution providers.
    manager
        .download_and_register_eps_with_progress(None, {
            let mut current_ep = String::new();
            move |ep_name: &str, percent: f64| {
                if ep_name != current_ep {
                    if !current_ep.is_empty() {
                        println!();
                    }
                    current_ep = ep_name.to_string();
                }
                print!("\r  {ep_name:<30}  {percent:5.1}%");
                io::stdout().flush().ok();
            }
        })
        .await?;
    println!();

    // ── 2. Pick a model and ensure it is downloaded ─────────────────────
    let model = manager.catalog().get_model(ALIAS).await?;
    println!("Model: {} (id: {})", model.alias(), model.id());

    if !model.is_cached().await? {
        println!("Downloading model...");
        model
            .download(Some(|progress: f64| {
                print!("\r  {progress:.1}%");
                io::stdout().flush().ok();
            }))
            .await?;
        println!();
    }

    println!("Loading model...");
    model.load().await?;
    println!("✓ Model loaded\n");

    // ── 3. Create a stateful chat session ────────────────────────────────
    let session = ChatSession::new(&model).await?;
    session
        .set_options(RequestOptions {
            search: SearchOptions {
                temperature: Some(0.7),
                max_output_tokens: Some(256),
                ..Default::default()
            },
            ..Default::default()
        })
        .await?;

    // ── 4. Non-streaming chat completion ────────────────────────────────
    let request = Request::from_items(vec![
        Item::system_message(vec![Item::text("You are a helpful assistant.")]),
        Item::user_message(vec![Item::text("What is Rust's ownership model?")]),
    ]);

    println!("--- Non-streaming completion ---");
    let response = session.process_request(request).await?;
    print!("Assistant: ");
    for item in &response.items {
        if let Some(message) = item.as_message() {
            print!("{}", message.text());
        }
    }
    println!();

    // ── 5. Streaming chat completion ────────────────────────────────────
    let request = Request::from_items(vec![Item::user_message(vec![Item::text(
        "Explain the borrow checker in two sentences.",
    )])]);

    println!("\n--- Streaming completion ---");
    print!("Assistant: ");
    let mut stream = session.process_streaming_request(request);
    while let Some(item) = stream.next().await {
        if let Item::Text {
            text,
            kind: TextKind::Default,
        } = item?
        {
            print!("{text}");
            io::stdout().flush().ok();
        }
    }
    println!("\n");

    // ── 6. Unload the model ─────────────────────────────────────────────
    drop(session);
    println!("Unloading model...");
    model.unload().await?;
    println!("Done.");

    Ok(())
}

Execute o código usando o seguinte comando:

cargo run

Solução de problemas

  • Erros de compilação: Certifique-se de que tem o Rust 1.70.0 ou posterior instalado. Corre rustup update para obter a versão mais recente.
  • Model not found: Verifique se o alias do modelo está correto. Use manager.catalog().get_models().await? para listar os modelos disponíveis.
  • Primeira execução lenta: Os downloads de modelos podem demorar à primeira vez que executas a aplicação.

Pré-requisitos

  • CMake 3.20 ou versão posterior.
  • Um compilador C++20.
  • A CLI do NuGet

Repositório de samples

Clone o repositório de samples do Foundry no GitHub e vá ao exemplo de C++:

git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/cpp/foundry-local/native-chat-completions

Instalar pacotes

Os exemplos em C++ requerem:

Configure e construa o exemplo:

cmake -S . -B build
cmake --build build --config Release

Durante a configuração, o sample restaura a versão 2.2.1 do Microsoft.AI.Foundry.Local.Runtime pacote NuGet para build/_packages. O pacote contém os cabeçalhos C++ e as bibliotecas nativas para Windows, Linux e macOS. Não precisas de um pacote WinML separado.

A configuração CMake seleciona os ativos de runtime para o seu sistema operativo e arquitetura e copia as bibliotecas nativas necessárias ao lado do executável. No macOS e Linux, execute o executável a partir de build. No Windows, execute o ficheiro .exe a partir de build.

Use a API nativa de chat completions

O exemplo inicializa o SDK, transfere e carrega um modelo, transmite uma resposta de chat e descarrega o modelo da memória.

#include <foundry_local/foundry_local_cpp.h>

#include <iostream>
#include <memory>
#include <string>

using namespace foundry_local;

std::unique_ptr<IModel> SelectChatModel(ICatalog& catalog) {
  for (const std::string alias : {"qwen2.5-0.5b", "qwen3.5-0.8b"}) {
    auto model = catalog.GetModel(alias);
    if (!model) {
      continue;
    }
    for (const auto& variant : model->GetVariants()) {
      const ModelInfo info = variant->GetInfo();
      if (info.DeviceType() == FOUNDRY_LOCAL_DEVICE_CPU &&
          (info.Task() == "chat-completion" || info.Task() == "coding")) {
        model->SelectVariant(*variant);
        return model;
      }
    }
  }
  return nullptr;
}

void PrintMessages(const Response& response) {
  for (const Item& item : response.GetItems()) {
    if (item.GetType() != FOUNDRY_LOCAL_ITEM_MESSAGE) {
      continue;
    }
    for (const Item& part : item.GetMessage().parts) {
      if (part.GetType() == FOUNDRY_LOCAL_ITEM_TEXT &&
          part.GetText().type == FOUNDRY_LOCAL_TEXT_ITEM_TYPE_DEFAULT) {
        std::cout << part.GetText().text;
      }
    }
  }
  std::cout << "\n";
}

int main() {
  try {
    Configuration config("foundry_local_cpp_native_chat");
    Manager manager(std::move(config));
    auto model = SelectChatModel(manager.GetCatalog());
    if (!model) {
      throw std::runtime_error("No supported CPU chat model was found.");
    }

    if (!model->IsCached()) {
      model->Download([](float progress) {
        std::cout << "\rDownloading model: " << static_cast<int>(progress) << "%" << std::flush;
        return 0;
      });
      std::cout << "\n";
    }
    model->Load();

    {
      ChatSession session(*model);
      Request request{UserMessage("What is the capital of France?")};
      std::cout << "Assistant: ";
      PrintMessages(session.ProcessRequest(request));
    }

    {
      ChatSession session(*model);
      session.SetStreamingCallback([](Item item) {
        if (item.GetType() == FOUNDRY_LOCAL_ITEM_TEXT &&
            item.GetText().type == FOUNDRY_LOCAL_TEXT_ITEM_TYPE_DEFAULT) {
          std::cout << item.GetText().text << std::flush;
        }
        return 0;
      });
      Request request{UserMessage("Name two landmarks in Paris.")};
      std::cout << "Streaming assistant: ";
      session.ProcessRequest(request);
      std::cout << "\n";
    }

    model->Unload();
    manager.Shutdown();
  } catch (const Error& error) {
    std::cerr << "Foundry Local error [" << error.Code() << "]: " << error.what() << "\n";
    return 1;
  } catch (const std::exception& error) {
    std::cerr << "Error: " << error.what() << "\n";
    return 1;
  }

  return 0;
}

Analisa a amostra:

./build/native-chat-completions

Solução de problemas

  • Modelo não encontrado: Verifique o alias do modelo com os modelos disponíveis no catálogo.
  • Primeira execução lenta: Os downloads de modelos podem demorar à primeira vez que executas a aplicação.