Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans ce tutoriel, vous créez un assistant de conversation interactif qui s’exécute entièrement sur votre appareil. L’assistant gère le contexte de conversation entre plusieurs échanges, ce qui vous rappelle ce que vous avez abordé précédemment dans la conversation. Vous utilisez le Kit de développement logiciel (SDK) Local Foundry pour sélectionner un modèle, définir une invite système et diffuser en continu le jeton de réponses par jeton.
Dans ce tutoriel, vous allez apprendre à :
- Configurer un projet et installer le Kit de développement logiciel (SDK) Local Foundry
- Parcourir le catalogue de modèles et sélectionner un modèle
- Définir une invite système pour mettre en forme le comportement de l’Assistant
- Implémenter une conversation à plusieurs tour avec l’historique des messages
- Diffuser des réponses pour une expérience réactive
- Nettoyer les ressources lorsque la conversation se termine
Prerequisites
- Un ordinateur Windows, macOS ou Linux avec au moins 8 Go de RAM.
Référentiel d’exemples
L’exemple de code complet de cet article est disponible dans le dépôt Foundry Local GitHub. Pour cloner le référentiel et accéder à l’exemple d’utilisation :
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/cs/tutorial-chat-assistant
Installer des packages
Si vous développez ou expédiez sur Windows, sélectionnez l'onglet Windows. Le package Windows s’intègre au runtime Windows ML . Il fournit la même surface d’surface d’API avec une étendue plus large d’accélération matérielle.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Les exemples C# dans le référentiel GitHub sont des projets préconfigurés. Si vous développez ex nihilo, vous devez lire la référence de Foundry Local SDK pour plus d’informations sur la configuration de votre projet C# avec Foundry Local.
Parcourir le catalogue et sélectionner un modèle
Le SDK Local Foundry fournit un catalogue de modèles qui répertorie tous les modèles disponibles. Dans cette étape, vous initialisez le Kit de développement logiciel (SDK) et sélectionnez un modèle pour votre assistant conversation.
Ouvrez et remplacez
Program.csson contenu par le code suivant pour initialiser le Kit de développement logiciel (SDK) et sélectionnez un modèle :CancellationToken ct = CancellationToken.None; var config = new Configuration { AppName = "foundry_local_samples", LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information }; using var loggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information); }); var logger = loggerFactory.CreateLogger<Program>(); // Initialize the singleton instance await FoundryLocalManager.CreateAsync(config, logger); var mgr = FoundryLocalManager.Instance; // Download and register all execution providers. var currentEp = ""; await mgr.DownloadAndRegisterEpsAsync((epName, percent) => { if (epName != currentEp) { if (currentEp != "") Console.WriteLine(); currentEp = epName; } Console.Write($"\r {epName.PadRight(30)} {percent,6:F1}%"); }); if (currentEp != "") Console.WriteLine(); // Select and load a model from the catalog var catalog = await mgr.GetCatalogAsync(); var model = await catalog.GetModelAsync("qwen2.5-0.5b") ?? throw new Exception("Model not found"); await model.DownloadAsync(progress => { Console.Write($"\rDownloading model: {progress:F2}%"); if (progress >= 100f) Console.WriteLine(); }); await model.LoadAsync(); Console.WriteLine("Model loaded and ready."); // Get a chat client var chatClient = await model.GetChatClientAsync();La
GetModelAsyncméthode accepte un alias de modèle, qui est un nom convivial court qui correspond à un modèle spécifique dans le catalogue. LaDownloadAsyncméthode extrait les pondérations du modèle dans votre cache local etLoadAsyncrend le modèle prêt pour l’inférence.
Définir une invite système
Une invite système définit la personnalité et le comportement de l’assistant. Il s’agit du premier message de l’historique des conversations et du modèle le référence tout au long de la conversation.
Ajoutez une invite système pour mettre en forme la façon dont l’Assistant répond :
// Start the conversation with a system prompt
var messages = new List<ChatMessage>
{
new ChatMessage
{
Role = "system",
Content = "You are a helpful, friendly assistant. Keep your responses " +
"concise and conversational. If you don't know something, say so."
}
};
Conseil / Astuce
Expérimentez avec différentes invites système pour modifier le comportement de l’assistant. Par exemple, vous pouvez lui demander de répondre en tant que pirate, enseignant ou expert de domaine.
Implémenter une conversation multitour
Un assistant de conversation doit maintenir le contexte entre plusieurs échanges. Pour ce faire, conservez la liste de tous les messages (système, utilisateur et Assistant) et envoyez la liste complète avec chaque requête. Le modèle utilise cet historique pour générer des réponses contextuellement pertinentes.
Ajoutez une boucle de conversation qui :
- Lit l’entrée utilisateur à partir de la console.
- Ajoute le message utilisateur à l’historique.
- Envoie l’historique complet au modèle.
- Ajoute la réponse de l’assistant à l’historique pour le tour suivant.
while (true)
{
Console.Write("You: ");
var userInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(userInput) ||
userInput.Equals("quit", StringComparison.OrdinalIgnoreCase) ||
userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
// Add the user's message to conversation history
messages.Add(new ChatMessage { Role = "user", Content = userInput });
// Stream the response token by token
Console.Write("Assistant: ");
var fullResponse = string.Empty;
var streamingResponse = chatClient.CompleteChatStreamingAsync(messages, ct);
await foreach (var chunk in streamingResponse)
{
var content = chunk.Choices[0].Message.Content;
if (!string.IsNullOrEmpty(content))
{
Console.Write(content);
Console.Out.Flush();
fullResponse += content;
}
}
Console.WriteLine("\n");
// Add the complete response to conversation history
messages.Add(new ChatMessage { Role = "assistant", Content = fullResponse });
}
Chaque appel pour CompleteChatAsync reçoit l’historique complet des messages. Il s’agit de la façon dont le modèle « se souvient » des tours précédents : il ne stocke pas l’état entre les appels.
Ajouter des réponses en flux
La diffusion en continu imprime chaque jeton au fur et à mesure qu’il est généré, ce qui rend l’assistant plus réactif. Remplacez l’appel CompleteChatAsync par CompleteChatStreamingAsync le flux du jeton de réponse par jeton.
Mettez à jour la boucle de conversation pour utiliser la diffusion en continu :
// Stream the response token by token
Console.Write("Assistant: ");
var fullResponse = string.Empty;
var streamingResponse = chatClient.CompleteChatStreamingAsync(messages, ct);
await foreach (var chunk in streamingResponse)
{
var content = chunk.Choices[0].Message.Content;
if (!string.IsNullOrEmpty(content))
{
Console.Write(content);
Console.Out.Flush();
fullResponse += content;
}
}
Console.WriteLine("\n");
La version de diffusion en continu accumule la réponse complète afin qu’elle puisse être ajoutée à l’historique des conversations une fois le flux terminé.
Code complet
Remplacez le contenu de Program.cs par le code complet suivant :
using Microsoft.AI.Foundry.Local;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using Microsoft.Extensions.Logging;
CancellationToken ct = CancellationToken.None;
var config = new Configuration
{
AppName = "foundry_local_samples",
LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
});
var logger = loggerFactory.CreateLogger<Program>();
// Initialize the singleton instance
await FoundryLocalManager.CreateAsync(config, logger);
var mgr = FoundryLocalManager.Instance;
// Download and register all execution providers.
var currentEp = "";
await mgr.DownloadAndRegisterEpsAsync((epName, percent) =>
{
if (epName != currentEp)
{
if (currentEp != "") Console.WriteLine();
currentEp = epName;
}
Console.Write($"\r {epName.PadRight(30)} {percent,6:F1}%");
});
if (currentEp != "") Console.WriteLine();
// Select and load a model from the catalog
var catalog = await mgr.GetCatalogAsync();
var model = await catalog.GetModelAsync("qwen2.5-0.5b")
?? throw new Exception("Model not found");
await model.DownloadAsync(progress =>
{
Console.Write($"\rDownloading model: {progress:F2}%");
if (progress >= 100f) Console.WriteLine();
});
await model.LoadAsync();
Console.WriteLine("Model loaded and ready.");
// Get a chat client
var chatClient = await model.GetChatClientAsync();
// Start the conversation with a system prompt
var messages = new List<ChatMessage>
{
new ChatMessage
{
Role = "system",
Content = "You are a helpful, friendly assistant. Keep your responses " +
"concise and conversational. If you don't know something, say so."
}
};
Console.WriteLine("\nChat assistant ready! Type 'quit' to exit.\n");
while (true)
{
Console.Write("You: ");
var userInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(userInput) ||
userInput.Equals("quit", StringComparison.OrdinalIgnoreCase) ||
userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
// Add the user's message to conversation history
messages.Add(new ChatMessage { Role = "user", Content = userInput });
// Stream the response token by token
Console.Write("Assistant: ");
var fullResponse = string.Empty;
var streamingResponse = chatClient.CompleteChatStreamingAsync(messages, ct);
await foreach (var chunk in streamingResponse)
{
var content = chunk.Choices[0].Message.Content;
if (!string.IsNullOrEmpty(content))
{
Console.Write(content);
Console.Out.Flush();
fullResponse += content;
}
}
Console.WriteLine("\n");
// Add the complete response to conversation history
messages.Add(new ChatMessage { Role = "assistant", Content = fullResponse });
}
// Clean up - unload the model
await model.UnloadAsync();
Console.WriteLine("Model unloaded. Goodbye!");
Exécutez l'assistant de chat :
dotnet run
Vous voyez un résultat similaire à :
Downloading model: 100.00%
Model loaded and ready.
Chat assistant ready! Type 'quit' to exit.
You: What is photosynthesis?
Assistant: Photosynthesis is the process plants use to convert sunlight, water, and carbon
dioxide into glucose and oxygen. It mainly happens in the leaves, inside structures
called chloroplasts.
You: Why is it important for other living things?
Assistant: It's essential because photosynthesis produces the oxygen that most living things
breathe. It also forms the base of the food chain — animals eat plants or eat other
animals that depend on plants for energy.
You: quit
Model unloaded. Goodbye!
Notez comment l’assistant mémorise le contexte des tours précédents , quand vous demandez « Pourquoi est-il important pour d’autres choses vivantes ? », il sait que vous parlez toujours de photosynthèse.
Référentiel d’exemples
L’exemple de code complet de cet article est disponible dans le dépôt Foundry Local GitHub. Pour cloner le référentiel et accéder à l’exemple d’utilisation :
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/js/tutorial-chat-assistant
Installer des packages
Si vous développez ou expédiez sur Windows, sélectionnez l'onglet Windows. Le package Windows s’intègre au runtime Windows ML . Il fournit la même surface d’surface d’API avec une étendue plus large d’accélération matérielle.
npm install foundry-local-sdk-winml openai
Parcourir le catalogue et sélectionner un modèle
Le SDK Local Foundry fournit un catalogue de modèles qui répertorie tous les modèles disponibles. Dans cette étape, vous initialisez le Kit de développement logiciel (SDK) et sélectionnez un modèle pour votre assistant conversation.
Créez un fichier appelé
index.js.Ajoutez le code suivant pour initialiser le Kit de développement logiciel (SDK) et sélectionnez un modèle :
// Initialize the Foundry Local SDK const manager = FoundryLocalManager.create({ appName: 'foundry_local_samples', logLevel: 'info' }); // Download and register all execution providers. let currentEp = ''; await manager.downloadAndRegisterEps((epName, percent) => { if (epName !== currentEp) { if (currentEp !== '') process.stdout.write('\n'); currentEp = epName; } process.stdout.write(`\r ${epName.padEnd(30)} ${percent.toFixed(1).padStart(5)}%`); }); if (currentEp !== '') process.stdout.write('\n'); // Select and load a model from the catalog const model = await manager.catalog.getModel('qwen2.5-0.5b'); await model.download((progress) => { process.stdout.write(`\rDownloading model: ${progress.toFixed(2)}%`); }); console.log('\nModel downloaded.'); await model.load(); console.log('Model loaded and ready.'); // Create a chat client const chatClient = model.createChatClient();La
getModelméthode accepte un alias de modèle, qui est un nom convivial court qui correspond à un modèle spécifique dans le catalogue. Ladownloadméthode extrait les pondérations du modèle dans votre cache local etloadrend le modèle prêt pour l’inférence.
Définir une invite système
Une invite système définit la personnalité et le comportement de l’assistant. Il s’agit du premier message de l’historique des conversations et du modèle le référence tout au long de la conversation.
Ajoutez une invite système pour mettre en forme la façon dont l’Assistant répond :
// Start the conversation with a system prompt
const messages = [
{
role: 'system',
content: 'You are a helpful, friendly assistant. Keep your responses ' +
'concise and conversational. If you don\'t know something, say so.'
}
];
Conseil / Astuce
Expérimentez avec différentes invites système pour modifier le comportement de l’assistant. Par exemple, vous pouvez lui demander de répondre en tant que pirate, enseignant ou expert de domaine.
Implémenter une conversation multitour
Un assistant de conversation doit maintenir le contexte entre plusieurs échanges. Pour ce faire, conservez la liste de tous les messages (système, utilisateur et Assistant) et envoyez la liste complète avec chaque requête. Le modèle utilise cet historique pour générer des réponses contextuellement pertinentes.
Ajoutez une boucle de conversation qui :
- Lit l’entrée utilisateur à partir de la console.
- Ajoute le message utilisateur à l’historique.
- Envoie l’historique complet au modèle.
- Ajoute la réponse de l’assistant à l’historique pour le tour suivant.
while (true) {
const userInput = await askQuestion('You: ');
if (userInput.trim().toLowerCase() === 'quit' ||
userInput.trim().toLowerCase() === 'exit') {
break;
}
// Add the user's message to conversation history
messages.push({ role: 'user', content: userInput });
// Stream the response token by token
process.stdout.write('Assistant: ');
let fullResponse = '';
for await (const chunk of chatClient.completeStreamingChat(messages)) {
const content = chunk.choices?.[0]?.delta?.content;
if (content) {
process.stdout.write(content);
fullResponse += content;
}
}
console.log('\n');
// Add the complete response to conversation history
messages.push({ role: 'assistant', content: fullResponse });
}
Chaque appel pour completeChat reçoit l’historique complet des messages. Il s’agit de la façon dont le modèle « se souvient » des tours précédents : il ne stocke pas l’état entre les appels.
Ajouter des réponses en flux
La diffusion en continu imprime chaque jeton au fur et à mesure qu’il est généré, ce qui rend l’assistant plus réactif. Remplacez l'appel completeChat par completeStreamingChat pour diffuser le flux du jeton de réponse par jeton.
Mettez à jour la boucle de conversation pour utiliser la diffusion en continu :
// Stream the response token by token
process.stdout.write('Assistant: ');
let fullResponse = '';
for await (const chunk of chatClient.completeStreamingChat(messages)) {
const content = chunk.choices?.[0]?.delta?.content;
if (content) {
process.stdout.write(content);
fullResponse += content;
}
}
console.log('\n');
La version de diffusion en continu accumule la réponse complète afin qu’elle puisse être ajoutée à l’historique des conversations une fois le flux terminé.
Code complet
Créez un fichier nommé index.js et ajoutez le code complet suivant :
import { FoundryLocalManager } from 'foundry-local-sdk';
import * as readline from 'readline';
// Initialize the Foundry Local SDK
const manager = FoundryLocalManager.create({
appName: 'foundry_local_samples',
logLevel: 'info'
});
// Download and register all execution providers.
let currentEp = '';
await manager.downloadAndRegisterEps((epName, percent) => {
if (epName !== currentEp) {
if (currentEp !== '') process.stdout.write('\n');
currentEp = epName;
}
process.stdout.write(`\r ${epName.padEnd(30)} ${percent.toFixed(1).padStart(5)}%`);
});
if (currentEp !== '') process.stdout.write('\n');
// Select and load a model from the catalog
const model = await manager.catalog.getModel('qwen2.5-0.5b');
await model.download((progress) => {
process.stdout.write(`\rDownloading model: ${progress.toFixed(2)}%`);
});
console.log('\nModel downloaded.');
await model.load();
console.log('Model loaded and ready.');
// Create a chat client
const chatClient = model.createChatClient();
// Start the conversation with a system prompt
const messages = [
{
role: 'system',
content: 'You are a helpful, friendly assistant. Keep your responses ' +
'concise and conversational. If you don\'t know something, say so.'
}
];
// Set up readline for console input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const askQuestion = (prompt) => new Promise((resolve) => rl.question(prompt, resolve));
console.log('\nChat assistant ready! Type \'quit\' to exit.\n');
while (true) {
const userInput = await askQuestion('You: ');
if (userInput.trim().toLowerCase() === 'quit' ||
userInput.trim().toLowerCase() === 'exit') {
break;
}
// Add the user's message to conversation history
messages.push({ role: 'user', content: userInput });
// Stream the response token by token
process.stdout.write('Assistant: ');
let fullResponse = '';
for await (const chunk of chatClient.completeStreamingChat(messages)) {
const content = chunk.choices?.[0]?.delta?.content;
if (content) {
process.stdout.write(content);
fullResponse += content;
}
}
console.log('\n');
// Add the complete response to conversation history
messages.push({ role: 'assistant', content: fullResponse });
}
// Clean up - unload the model
await model.unload();
console.log('Model unloaded. Goodbye!');
rl.close();
Exécutez l'assistant de chat :
node index.js
Vous voyez un résultat similaire à :
Downloading model: 100.00%
Model downloaded.
Model loaded and ready.
Chat assistant ready! Type 'quit' to exit.
You: What is photosynthesis?
Assistant: Photosynthesis is the process plants use to convert sunlight, water, and carbon
dioxide into glucose and oxygen. It mainly happens in the leaves, inside structures
called chloroplasts.
You: Why is it important for other living things?
Assistant: It's essential because photosynthesis produces the oxygen that most living things
breathe. It also forms the base of the food chain — animals eat plants or eat other
animals that depend on plants for energy.
You: quit
Model unloaded. Goodbye!
Notez comment l’assistant mémorise le contexte des tours précédents , quand vous demandez « Pourquoi est-il important pour d’autres choses vivantes ? », il sait que vous parlez toujours de photosynthèse.
Référentiel d’exemples
L’exemple de code complet de cet article est disponible dans le dépôt Foundry Local GitHub. Pour cloner le référentiel et accéder à l’exemple d’utilisation :
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/python/tutorial-chat-assistant
Installer des packages
Si vous développez ou expédiez sur Windows, sélectionnez l'onglet Windows. Le package Windows s’intègre au runtime Windows ML . Il fournit la même surface d’surface d’API avec une étendue plus large d’accélération matérielle.
pip install foundry-local-sdk-winml openai
Parcourir le catalogue et sélectionner un modèle
Le SDK Local Foundry fournit un catalogue de modèles qui répertorie tous les modèles disponibles. Dans cette étape, vous initialisez le Kit de développement logiciel (SDK) et sélectionnez un modèle pour votre assistant conversation.
Créez un fichier appelé
main.py.Ajoutez le code suivant pour initialiser le Kit de développement logiciel (SDK) et sélectionnez un modèle :
# Initialize the Foundry Local SDK config = Configuration(app_name="foundry_local_samples") FoundryLocalManager.initialize(config) manager = FoundryLocalManager.instance # Download and register all execution providers. current_ep = "" def ep_progress(ep_name: str, percent: float): nonlocal current_ep if ep_name != current_ep: if current_ep: print() current_ep = ep_name print(f"\r {ep_name:<30} {percent:5.1f}%", end="", flush=True) manager.download_and_register_eps(progress_callback=ep_progress) if current_ep: print() # Select and load a model from the catalog model = manager.catalog.get_model("qwen2.5-0.5b") model.download(lambda progress: print(f"\rDownloading model: {progress:.2f}%", end="", flush=True)) print() model.load() print("Model loaded and ready.") # Get a chat client client = model.get_chat_client()La
get_modelméthode accepte un alias de modèle, qui est un nom convivial court qui correspond à un modèle spécifique dans le catalogue. Ladownloadméthode extrait les pondérations du modèle dans votre cache local etloadrend le modèle prêt pour l’inférence.
Définir une invite système
Une invite système définit la personnalité et le comportement de l’assistant. Il s’agit du premier message de l’historique des conversations et du modèle le référence tout au long de la conversation.
Ajoutez une invite système pour mettre en forme la façon dont l’Assistant répond :
# Start the conversation with a system prompt
messages = [
{
"role": "system",
"content": "You are a helpful, friendly assistant. Keep your responses "
"concise and conversational. If you don't know something, say so."
}
]
Conseil / Astuce
Expérimentez avec différentes invites système pour modifier le comportement de l’assistant. Par exemple, vous pouvez lui demander de répondre en tant que pirate, enseignant ou expert de domaine.
Implémenter une conversation multitour
Un assistant de conversation doit maintenir le contexte entre plusieurs échanges. Pour ce faire, conservez la liste de tous les messages (système, utilisateur et Assistant) et envoyez la liste complète avec chaque requête. Le modèle utilise cet historique pour générer des réponses contextuellement pertinentes.
Ajoutez une boucle de conversation qui :
- Lit l’entrée utilisateur à partir de la console.
- Ajoute le message utilisateur à l’historique.
- Envoie l’historique complet au modèle.
- Ajoute la réponse de l’assistant à l’historique pour le tour suivant.
while True:
user_input = input("You: ")
if user_input.strip().lower() in ("quit", "exit"):
break
# Add the user's message to conversation history
messages.append({"role": "user", "content": user_input})
# Stream the response token by token
print("Assistant: ", end="", flush=True)
full_response = ""
for chunk in client.complete_streaming_chat(messages):
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
full_response += content
print("\n")
# Add the complete response to conversation history
messages.append({"role": "assistant", "content": full_response})
Chaque appel pour complete_chat reçoit l’historique complet des messages. Il s’agit de la façon dont le modèle « se souvient » des tours précédents : il ne stocke pas l’état entre les appels.
Ajouter des réponses en flux
La diffusion en continu imprime chaque jeton au fur et à mesure qu’il est généré, ce qui rend l’assistant plus réactif. Remplacez l'appel complete_chat par complete_streaming_chat pour diffuser le flux du jeton de réponse par jeton.
Mettez à jour la boucle de conversation pour utiliser la diffusion en continu :
# Stream the response token by token
print("Assistant: ", end="", flush=True)
full_response = ""
for chunk in client.complete_streaming_chat(messages):
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
full_response += content
print("\n")
La version de diffusion en continu accumule la réponse complète afin qu’elle puisse être ajoutée à l’historique des conversations une fois le flux terminé.
Code complet
Créez un fichier nommé main.py et ajoutez le code complet suivant :
from foundry_local_sdk import Configuration, FoundryLocalManager
def main():
# Initialize the Foundry Local SDK
config = Configuration(app_name="foundry_local_samples")
FoundryLocalManager.initialize(config)
manager = FoundryLocalManager.instance
# Download and register all execution providers.
current_ep = ""
def ep_progress(ep_name: str, percent: float):
nonlocal current_ep
if ep_name != current_ep:
if current_ep:
print()
current_ep = ep_name
print(f"\r {ep_name:<30} {percent:5.1f}%", end="", flush=True)
manager.download_and_register_eps(progress_callback=ep_progress)
if current_ep:
print()
# Select and load a model from the catalog
model = manager.catalog.get_model("qwen2.5-0.5b")
model.download(lambda progress: print(f"\rDownloading model: {progress:.2f}%", end="", flush=True))
print()
model.load()
print("Model loaded and ready.")
# Get a chat client
client = model.get_chat_client()
# Start the conversation with a system prompt
messages = [
{
"role": "system",
"content": "You are a helpful, friendly assistant. Keep your responses "
"concise and conversational. If you don't know something, say so."
}
]
print("\nChat assistant ready! Type 'quit' to exit.\n")
while True:
user_input = input("You: ")
if user_input.strip().lower() in ("quit", "exit"):
break
# Add the user's message to conversation history
messages.append({"role": "user", "content": user_input})
# Stream the response token by token
print("Assistant: ", end="", flush=True)
full_response = ""
for chunk in client.complete_streaming_chat(messages):
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
full_response += content
print("\n")
# Add the complete response to conversation history
messages.append({"role": "assistant", "content": full_response})
# Clean up - unload the model
model.unload()
print("Model unloaded. Goodbye!")
if __name__ == "__main__":
main()
Exécutez l'assistant de chat :
python main.py
Vous voyez un résultat similaire à :
Downloading model: 100.00%
Model loaded and ready.
Chat assistant ready! Type 'quit' to exit.
You: What is photosynthesis?
Assistant: Photosynthesis is the process plants use to convert sunlight, water, and carbon
dioxide into glucose and oxygen. It mainly happens in the leaves, inside structures
called chloroplasts.
You: Why is it important for other living things?
Assistant: It's essential because photosynthesis produces the oxygen that most living things
breathe. It also forms the base of the food chain — animals eat plants or eat other
animals that depend on plants for energy.
You: quit
Model unloaded. Goodbye!
Notez comment l’assistant mémorise le contexte des tours précédents , quand vous demandez « Pourquoi est-il important pour d’autres choses vivantes ? », il sait que vous parlez toujours de photosynthèse.
Référentiel d’exemples
L’exemple de code complet de cet article est disponible dans le dépôt Foundry Local GitHub. Pour cloner le référentiel et accéder à l’exemple d’utilisation :
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/rust/tutorial-chat-assistant
Installer des packages
Si vous développez ou expédiez sur Windows, sélectionnez l'onglet Windows. Le package Windows s’intègre au runtime Windows ML . Il fournit la même surface d’surface d’API avec une étendue plus large d’accélération matérielle.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Parcourir le catalogue et sélectionner un modèle
Le SDK Local Foundry fournit un catalogue de modèles qui répertorie tous les modèles disponibles. Dans cette étape, vous initialisez le Kit de développement logiciel (SDK) et sélectionnez un modèle pour votre assistant conversation.
Ouvrez et remplacez
src/main.rsson contenu par le code suivant pour initialiser le Kit de développement logiciel (SDK) et sélectionnez un modèle :// Initialize the Foundry Local SDK let manager = FoundryLocalManager::create(FoundryLocalConfig::new("chat-assistant"))?; // 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 {:<30} {:5.1}%", ep_name, percent); io::stdout().flush().ok(); } }) .await?; println!(); // Select and load a model from the catalog let model = manager.catalog().get_model("qwen2.5-0.5b").await?; if !model.is_cached().await? { println!("Downloading model..."); model .download(Some(|progress: f64| { print!("\r {progress:.1}%"); io::stdout().flush().ok(); })) .await?; println!(); } model.load().await?; println!("Model loaded and ready."); // Create a chat client let client = model.create_chat_client().temperature(0.7).max_tokens(512);La
get_modelméthode accepte un alias de modèle, qui est un nom convivial court qui correspond à un modèle spécifique dans le catalogue. Ladownloadméthode extrait les pondérations du modèle dans votre cache local etloadrend le modèle prêt pour l’inférence.
Définir une invite système
Une invite système définit la personnalité et le comportement de l’assistant. Il s’agit du premier message de l’historique des conversations et du modèle le référence tout au long de la conversation.
Ajoutez une invite système pour mettre en forme la façon dont l’Assistant répond :
// Start the conversation with a system prompt
let mut messages: Vec<ChatCompletionRequestMessage> = vec![
ChatCompletionRequestSystemMessage::from(
"You are a helpful, friendly assistant. Keep your responses \
concise and conversational. If you don't know something, say so.",
)
.into(),
];
Conseil / Astuce
Expérimentez avec différentes invites système pour modifier le comportement de l’assistant. Par exemple, vous pouvez lui demander de répondre en tant que pirate, enseignant ou expert de domaine.
Implémenter une conversation multitour
Un assistant de conversation doit maintenir le contexte entre plusieurs échanges. Pour ce faire, conservez un vecteur de tous les messages (système, utilisateur et Assistant) et envoyez la liste complète avec chaque requête. Le modèle utilise cet historique pour générer des réponses contextuellement pertinentes.
Ajoutez une boucle de conversation qui :
- Lit l’entrée utilisateur à partir de la console.
- Ajoute le message utilisateur à l’historique.
- Envoie l’historique complet au modèle.
- Ajoute la réponse de l’assistant à l’historique pour le tour suivant.
loop {
print!("You: ");
io::stdout().flush()?;
let mut input = String::new();
stdin.lock().read_line(&mut input)?;
let input = input.trim();
if input.eq_ignore_ascii_case("quit") || input.eq_ignore_ascii_case("exit") {
break;
}
// Add the user's message to conversation history
messages.push(ChatCompletionRequestUserMessage::from(input).into());
// Stream the response token by token
print!("Assistant: ");
io::stdout().flush()?;
let mut full_response = String::new();
let mut stream = client.complete_streaming_chat(&messages, None).await?;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
if let Some(choice) = chunk.choices.first() {
if let Some(ref content) = choice.delta.content {
print!("{content}");
io::stdout().flush()?;
full_response.push_str(content);
}
}
}
println!("\n");
// Add the complete response to conversation history
let assistant_msg: ChatCompletionRequestMessage = serde_json::from_value(
serde_json::json!({"role": "assistant", "content": full_response}),
)?;
messages.push(assistant_msg);
}
Chaque appel pour complete_chat reçoit l’historique complet des messages. Il s’agit de la façon dont le modèle « se souvient » des tours précédents : il ne stocke pas l’état entre les appels.
Ajouter des réponses en flux
La diffusion en continu imprime chaque jeton au fur et à mesure qu’il est généré, ce qui rend l’assistant plus réactif. Remplacez l'appel complete_chat par complete_streaming_chat pour diffuser le flux du jeton de réponse par jeton.
Mettez à jour la boucle de conversation pour utiliser la diffusion en continu :
// Stream the response token by token
print!("Assistant: ");
io::stdout().flush()?;
let mut full_response = String::new();
let mut stream = client.complete_streaming_chat(&messages, None).await?;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
if let Some(choice) = chunk.choices.first() {
if let Some(ref content) = choice.delta.content {
print!("{content}");
io::stdout().flush()?;
full_response.push_str(content);
}
}
}
println!("\n");
La version de diffusion en continu accumule la réponse complète afin qu’elle puisse être ajoutée à l’historique des conversations une fois le flux terminé.
Code complet
Remplacez le contenu de src/main.rs par le code complet suivant :
use foundry_local_sdk::{
ChatCompletionRequestMessage,
ChatCompletionRequestSystemMessage, ChatCompletionRequestUserMessage,
FoundryLocalConfig, FoundryLocalManager,
};
use std::io::{self, BufRead, Write};
use tokio_stream::StreamExt;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize the Foundry Local SDK
let manager = FoundryLocalManager::create(FoundryLocalConfig::new("chat-assistant"))?;
// 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 {:<30} {:5.1}%", ep_name, percent);
io::stdout().flush().ok();
}
})
.await?;
println!();
// Select and load a model from the catalog
let model = manager.catalog().get_model("qwen2.5-0.5b").await?;
if !model.is_cached().await? {
println!("Downloading model...");
model
.download(Some(|progress: f64| {
print!("\r {progress:.1}%");
io::stdout().flush().ok();
}))
.await?;
println!();
}
model.load().await?;
println!("Model loaded and ready.");
// Create a chat client
let client = model.create_chat_client().temperature(0.7).max_tokens(512);
// Start the conversation with a system prompt
let mut messages: Vec<ChatCompletionRequestMessage> = vec![
ChatCompletionRequestSystemMessage::from(
"You are a helpful, friendly assistant. Keep your responses \
concise and conversational. If you don't know something, say so.",
)
.into(),
];
println!("\nChat assistant ready! Type 'quit' to exit.\n");
let stdin = io::stdin();
loop {
print!("You: ");
io::stdout().flush()?;
let mut input = String::new();
stdin.lock().read_line(&mut input)?;
let input = input.trim();
if input.eq_ignore_ascii_case("quit") || input.eq_ignore_ascii_case("exit") {
break;
}
// Add the user's message to conversation history
messages.push(ChatCompletionRequestUserMessage::from(input).into());
// Stream the response token by token
print!("Assistant: ");
io::stdout().flush()?;
let mut full_response = String::new();
let mut stream = client.complete_streaming_chat(&messages, None).await?;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
if let Some(choice) = chunk.choices.first() {
if let Some(ref content) = choice.delta.content {
print!("{content}");
io::stdout().flush()?;
full_response.push_str(content);
}
}
}
println!("\n");
// Add the complete response to conversation history
let assistant_msg: ChatCompletionRequestMessage = serde_json::from_value(
serde_json::json!({"role": "assistant", "content": full_response}),
)?;
messages.push(assistant_msg);
}
// Clean up - unload the model
model.unload().await?;
println!("Model unloaded. Goodbye!");
Ok(())
}
Exécutez l'assistant de chat :
cargo run
Vous voyez un résultat similaire à :
Downloading model: 100.00%
Model loaded and ready.
Chat assistant ready! Type 'quit' to exit.
You: What is photosynthesis?
Assistant: Photosynthesis is the process plants use to convert sunlight, water, and carbon
dioxide into glucose and oxygen. It mainly happens in the leaves, inside structures
called chloroplasts.
You: Why is it important for other living things?
Assistant: It's essential because photosynthesis produces the oxygen that most living things
breathe. It also forms the base of the food chain — animals eat plants or eat other
animals that depend on plants for energy.
You: quit
Model unloaded. Goodbye!
Notez comment l’assistant mémorise le contexte des tours précédents , quand vous demandez « Pourquoi est-il important pour d’autres choses vivantes ? », il sait que vous parlez toujours de photosynthèse.
Nettoyer les ressources
Les poids du modèle restent dans votre cache local après avoir déchargé un modèle. Cela signifie que la prochaine fois que vous exécutez l’application, l’étape de téléchargement est ignorée et le modèle se charge plus rapidement. Aucun nettoyage supplémentaire n’est nécessaire, sauf si vous souhaitez récupérer de l’espace disque.