Comienza con Foundry Local

En este inicio rápido, creará una aplicación de consola que descarga un modelo de inteligencia artificial local, generará una respuesta de chat en streaming y descargará el modelo. Todo se ejecuta en el dispositivo sin dependencias en la nube ni Azure suscripción.

Prerrequisitos

Repositorio de ejemplos

Puede encontrar el código de ejemplo completo de este artículo en el repositorio de ejemplos de Foundry GitHub. Para clonar el repositorio e ir al ejemplo, utilice:

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

Instalación de paquetes

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

Los ejemplos de C# del repositorio de GitHub son proyectos preconfigurados. Si va a compilar desde cero, debe leer la referencia del SDK local de Foundry para obtener más detalles sobre cómo configurar el proyecto de C# con Foundry Local.

Uso de la API de finalizaciones de chat nativas

Copie y pegue el código siguiente en un archivo de C# denominado 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();

Ejecute el código mediante el comando siguiente:

dotnet run

Solución de problemas

  • Errores de Build que hacen referencia a net8.0: instale el SDK de .NET 8.0 y reconstruya la aplicación.
  • Model not found: ejecute el fragmento de código de lista de modelos opcional para buscar un alias disponible en el dispositivo y, a continuación, actualice el alias pasado a GetModelAsync.
  • Primera ejecución lenta: las descargas de modelos pueden tardar la primera vez que ejecute la aplicación.

Prerrequisitos

  • Se debe tener instalado Node.js 20 o una versión posterior.

Repositorio de ejemplos

El código de ejemplo completo de este artículo está disponible en el repositorio foundry-samples GitHub. Cómo clonar el repositorio y acceder al directorio de ejemplo:

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

Instalación de paquetes

npm install foundry-local-sdk openai

Uso de la API de finalizaciones de chat nativas

Copie y pegue el código siguiente en un archivo javaScript denominado 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`);

Ejecute el código mediante el comando siguiente:

node app.js

Prerrequisitos

Repositorio de ejemplos

El código de ejemplo completo de este artículo está disponible en el repositorio foundry-samples GitHub. Cómo clonar el repositorio y acceder al directorio de ejemplo:

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

Instalación de paquetes

pip install foundry-local-sdk openai

Uso de la API de finalizaciones de chat nativas

Copie y pegue el código siguiente en un archivo de Python denominado 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()

Ejecute el código mediante el comando siguiente:

python app.py

Solución de problemas

  • ModuleNotFoundError: No module named 'foundry_local_sdk': Instale SDK mediante la ejecución de pip install foundry-local-sdk.
  • Model not found: ejecute el fragmento de código de lista de modelos opcional para buscar un alias disponible en el dispositivo y, a continuación, actualice el alias pasado a get_model.
  • Primera ejecución lenta: las descargas de modelos pueden tardar la primera vez que ejecute la aplicación.

Prerrequisitos

Repositorio de ejemplos

El código de ejemplo completo de este artículo está disponible en el repositorio foundry-samples GitHub. Cómo clonar el repositorio y acceder al directorio de ejemplo:

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

Instalación de paquetes

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

Uso de la API de finalizaciones de chat nativas

Reemplace el contenido de main.rs por el código siguiente:

// 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(())
}

Ejecute el código mediante el comando siguiente:

cargo run

Solución de problemas

  • <c0 originalTag="ept" originalId="1">Errores de compilación: asegúrese de que tiene Rust 1.70.0 o posterior instalado. Ejecute rustup update para obtener la versión más reciente.
  • Model not found: compruebe que el alias del modelo es correcto. Use manager.catalog().get_models().await? para enumerar los modelos disponibles.
  • Primera ejecución lenta: las descargas de modelos pueden tardar la primera vez que ejecute la aplicación.

Prerrequisitos

  • CMake 3.20 o posterior.
  • Un compilador de C++20.
  • La CLI de NuGet.

Repositorio de ejemplos

Clone el repositorio de GitHub de ejemplos de Foundry y vaya al ejemplo de C++:

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

Instalación de paquetes

Los ejemplos de C++ requieren:

Configure y cree el ejemplo:

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

Durante la configuración, el ejemplo restaura la versión 2.2.1 del Microsoft.AI.Foundry.Local.Runtime paquete NuGet en build/_packages. El paquete contiene los encabezados de C++ y las bibliotecas nativas para Windows, Linux y macOS. No necesita un paquete WinML independiente.

La configuración de CMake selecciona los recursos en tiempo de ejecución para su sistema operativo y arquitectura y copia las bibliotecas nativas necesarias junto al ejecutable. En macOS y Linux, ejecute el ejecutable desde build. En Windows, ejecute el archivo .exe desde build.

Usa la API nativa de Chat Completions

El ejemplo inicializa el SDK, descarga y carga un modelo, transmite una respuesta de chat y libera el modelo.

#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;
}

Ejecución del ejemplo:

./build/native-chat-completions

Solución de problemas

  • Modelo no encontrado: compruebe el alias del modelo con los modelos disponibles en el catálogo.
  • Primera ejecución lenta: las descargas de modelos pueden tardar la primera vez que ejecute la aplicación.