Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här självstudien skapar du en interaktiv chattassistent som körs helt på din enhet. Assistenten upprätthåller konversationskontexten över flera utbyten, så den kommer ihåg vad du diskuterade tidigare i konversationen. Du använder Foundry Local SDK för att välja en modell, definiera en systemprompt och strömma svaren token för token.
I den här tutorialen lär du dig följande:
- Konfigurera ett projekt och installera Foundry Local SDK
- Bläddra i modellkatalogen och välj en modell
- Definiera en systemprompt för att forma assistentens beteende
- Implementera konversation med flera turer med meddelandehistorik
- Stream-svar för en dynamisk upplevelse
- Rensa resurser när konversationen avslutas
Förutsättningar
- En Windows-, macOS- eller Linux-dator med minst 8 GB RAM-minne.
Exempellagringsplats
Den fullständiga exempelkoden för den här artikeln finns på lagringsplatsen Foundry Local GitHub. Klona lagringsplatsen och gå till exempelanvändningen:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/cs/tutorial-chat-assistant
Installera paket
Om du utvecklar eller skickar på Windows väljer du fliken Windows. Windows-paketet integreras med Windows ML-körning – det ger samma API-yta med en bredare bredd av maskinvaruacceleration.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
C#-exemplen på GitHub-lagringsplatsen är förkonfigurerade projekt. Om du skapar från grunden bör du läsa Foundry Local SDK-referensen för mer information om hur du konfigurerar ditt C#-projekt med Foundry Local.
Bläddra i katalogen och välj en modell
Foundry Local SDK innehåller en modellkatalog som visar alla tillgängliga modeller. I det här steget initierar du SDK och väljer en modell för chattassistenten.
Öppna
Program.csoch ersätt innehållet med följande kod för att initiera SDK:et och välj en modell: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();Metoden
GetModelAsyncaccepterar ett modellalias, vilket är ett kort eget namn som mappar till en specifik modell i katalogen. MetodenDownloadAsynchämtar modellvikterna till din lokala cache ochLoadAsyncgör modellen redo för slutsatsdragning.
Definiera en systemprompt
En systemprompt anger assistentens personlighet och beteende. Det är det första meddelandet i konversationshistoriken och modellen refererar till det under hela konversationen.
Lägg till en systemprompt för att forma hur assistenten svarar:
// 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."
}
};
Tips/Råd
Experimentera med olika systemprompter för att ändra assistentens beteende. Du kan till exempel instruera den att svara som pirat, lärare eller domänexpert.
Implementera konversation med flera turer
En chattassistent måste behålla kontexten över flera interaktioner. Du uppnår detta genom att hålla en lista över alla meddelanden (system, användare och assistent) och skicka den fullständiga listan med varje begäran. Modellen använder den här historiken för att generera kontextuellt relevanta svar.
Lägg till en konversationsloop som:
- Läser indata från konsolen.
- Lägger till användarmeddelandet i historiken.
- Skickar hela historiken till modellen.
- Lägger till assistentens svar i historiken inför nästa omgång.
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 });
}
Varje anrop till CompleteChatAsync tar emot den fullständiga meddelandehistoriken. Det är så modellen "kommer ihåg" tidigare vändningar – den lagrar inte tillstånd mellan anrop.
Lägga till direktuppspelningssvar
Direktuppspelning skriver ut varje token när den genereras, vilket gör att assistenten känns mer responsiv. Ersätt anropet CompleteChatAsync med CompleteChatStreamingAsync för att strömma svarstoken efter token.
Uppdatera konversationsloopen så att den använder strömning:
// 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");
Strömningsversionen ackumulerar det fullständiga svaret så att det kan läggas till i konversationshistoriken när strömmen har slutförts.
Fullständig kod
Ersätt innehållet i Program.cs med följande fullständiga kod:
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!");
Kör chattassistenten:
dotnet run
Du ser utdata som liknar:
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!
Observera hur assistenten minns kontexten från tidigare svängar – när du frågar "Varför är det viktigt för andra levande saker?", vet den att du fortfarande pratar om fotosyntes.
Exempellagringsplats
Den fullständiga exempelkoden för den här artikeln finns på lagringsplatsen Foundry Local GitHub. Klona lagringsplatsen och gå till exempelanvändningen:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/js/tutorial-chat-assistant
Installera paket
Om du utvecklar eller skickar på Windows väljer du fliken Windows. Windows-paketet integreras med Windows ML-körning – det ger samma API-yta med en bredare bredd av maskinvaruacceleration.
npm install foundry-local-sdk-winml openai
Bläddra i katalogen och välj en modell
Foundry Local SDK innehåller en modellkatalog som visar alla tillgängliga modeller. I det här steget initierar du SDK och väljer en modell för chattassistenten.
Skapa en fil med namnet
index.js.Lägg till följande kod för att initiera SDK och välj en modell:
// 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();Metoden
getModelaccepterar ett modellalias, vilket är ett kort eget namn som mappar till en specifik modell i katalogen. Metodendownloadhämtar modellvikterna till din lokala cache ochloadgör modellen redo för slutsatsdragning.
Definiera en systemprompt
En systemprompt anger assistentens personlighet och beteende. Det är det första meddelandet i konversationshistoriken och modellen refererar till det under hela konversationen.
Lägg till en systemprompt för att forma hur assistenten svarar:
// 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.'
}
];
Tips/Råd
Experimentera med olika systemprompter för att ändra assistentens beteende. Du kan till exempel instruera den att svara som pirat, lärare eller domänexpert.
Implementera konversation med flera turer
En chattassistent måste behålla kontexten över flera interaktioner. Du uppnår detta genom att hålla en lista över alla meddelanden (system, användare och assistent) och skicka den fullständiga listan med varje begäran. Modellen använder den här historiken för att generera kontextuellt relevanta svar.
Lägg till en konversationsloop som:
- Läser indata från konsolen.
- Lägger till användarmeddelandet i historiken.
- Skickar hela historiken till modellen.
- Lägger till assistentens svar i historiken inför nästa omgång.
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 });
}
Varje anrop till completeChat tar emot den fullständiga meddelandehistoriken. Det är så modellen "kommer ihåg" tidigare vändningar – den lagrar inte tillstånd mellan anrop.
Lägga till direktuppspelningssvar
Direktuppspelning skriver ut varje token när den genereras, vilket gör att assistenten känns mer responsiv. Ersätt anropet completeChat med completeStreamingChat för att strömma svarstoken efter token.
Uppdatera konversationsloopen så att den använder strömning:
// 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');
Strömningsversionen ackumulerar det fullständiga svaret så att det kan läggas till i konversationshistoriken när strömmen har slutförts.
Fullständig kod
Skapa en fil med namnet index.js och lägg till följande fullständiga kod:
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();
Kör chattassistenten:
node index.js
Du ser utdata som liknar:
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!
Observera hur assistenten minns kontexten från tidigare svängar – när du frågar "Varför är det viktigt för andra levande saker?", vet den att du fortfarande pratar om fotosyntes.
Exempellagringsplats
Den fullständiga exempelkoden för den här artikeln finns på lagringsplatsen Foundry Local GitHub. Klona lagringsplatsen och gå till exempelanvändningen:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/python/tutorial-chat-assistant
Installera paket
Om du utvecklar eller skickar på Windows väljer du fliken Windows. Windows-paketet integreras med Windows ML-körning – det ger samma API-yta med en bredare bredd av maskinvaruacceleration.
pip install foundry-local-sdk-winml openai
Bläddra i katalogen och välj en modell
Foundry Local SDK innehåller en modellkatalog som visar alla tillgängliga modeller. I det här steget initierar du SDK och väljer en modell för chattassistenten.
Skapa en fil med namnet
main.py.Lägg till följande kod för att initiera SDK och välj en modell:
# 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()Metoden
get_modelaccepterar ett modellalias, vilket är ett kort eget namn som mappar till en specifik modell i katalogen. Metodendownloadhämtar modellvikterna till din lokala cache ochloadgör modellen redo för slutsatsdragning.
Definiera en systemprompt
En systemprompt anger assistentens personlighet och beteende. Det är det första meddelandet i konversationshistoriken och modellen refererar till det under hela konversationen.
Lägg till en systemprompt för att forma hur assistenten svarar:
# 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."
}
]
Tips/Råd
Experimentera med olika systemprompter för att ändra assistentens beteende. Du kan till exempel instruera den att svara som pirat, lärare eller domänexpert.
Implementera konversation med flera turer
En chattassistent måste behålla kontexten över flera interaktioner. Du uppnår detta genom att hålla en lista över alla meddelanden (system, användare och assistent) och skicka den fullständiga listan med varje begäran. Modellen använder den här historiken för att generera kontextuellt relevanta svar.
Lägg till en konversationsloop som:
- Läser indata från konsolen.
- Lägger till användarmeddelandet i historiken.
- Skickar hela historiken till modellen.
- Lägger till assistentens svar i historiken inför nästa omgång.
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})
Varje anrop till complete_chat tar emot den fullständiga meddelandehistoriken. Det är så modellen "kommer ihåg" tidigare vändningar – den lagrar inte tillstånd mellan anrop.
Lägga till direktuppspelningssvar
Direktuppspelning skriver ut varje token när den genereras, vilket gör att assistenten känns mer responsiv. Ersätt anropet complete_chat med complete_streaming_chat för att strömma svarstoken efter token.
Uppdatera konversationsloopen så att den använder strömning:
# 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")
Strömningsversionen ackumulerar det fullständiga svaret så att det kan läggas till i konversationshistoriken när strömmen har slutförts.
Fullständig kod
Skapa en fil med namnet main.py och lägg till följande fullständiga kod:
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()
Kör chattassistenten:
python main.py
Du ser utdata som liknar:
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!
Observera hur assistenten minns kontexten från tidigare svängar – när du frågar "Varför är det viktigt för andra levande saker?", vet den att du fortfarande pratar om fotosyntes.
Exempellagringsplats
Den fullständiga exempelkoden för den här artikeln finns på lagringsplatsen Foundry Local GitHub. Klona lagringsplatsen och gå till exempelanvändningen:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/rust/tutorial-chat-assistant
Installera paket
Om du utvecklar eller skickar på Windows väljer du fliken Windows. Windows-paketet integreras med Windows ML-körning – det ger samma API-yta med en bredare bredd av maskinvaruacceleration.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Bläddra i katalogen och välj en modell
Foundry Local SDK innehåller en modellkatalog som visar alla tillgängliga modeller. I det här steget initierar du SDK och väljer en modell för chattassistenten.
Öppna
src/main.rsoch ersätt innehållet med följande kod för att initiera SDK:et och välj en modell:// 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);Metoden
get_modelaccepterar ett modellalias, vilket är ett kort eget namn som mappar till en specifik modell i katalogen. Metodendownloadhämtar modellvikterna till din lokala cache ochloadgör modellen redo för slutsatsdragning.
Definiera en systemprompt
En systemprompt anger assistentens personlighet och beteende. Det är det första meddelandet i konversationshistoriken och modellen refererar till det under hela konversationen.
Lägg till en systemprompt för att forma hur assistenten svarar:
// 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(),
];
Tips/Råd
Experimentera med olika systemprompter för att ändra assistentens beteende. Du kan till exempel instruera den att svara som pirat, lärare eller domänexpert.
Implementera konversation med flera turer
En chattassistent måste behålla kontexten över flera interaktioner. Du uppnår detta genom att behålla en vektor för alla meddelanden (system, användare och assistent) och skicka den fullständiga listan med varje begäran. Modellen använder den här historiken för att generera kontextuellt relevanta svar.
Lägg till en konversationsloop som:
- Läser indata från konsolen.
- Lägger till användarmeddelandet i historiken.
- Skickar hela historiken till modellen.
- Lägger till assistentens svar på historiken för nästa tur.
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);
}
Varje anrop till complete_chat tar emot den fullständiga meddelandehistoriken. Det är så modellen "kommer ihåg" tidigare omgångar – den lagrar inte tillstånd mellan anrop.
Lägga till direktuppspelningssvar
Direktuppspelning skriver ut varje token när den genereras, vilket gör att assistenten känns mer responsiv. Byt ut anropet complete_chat mot complete_streaming_chat för att strömma svaret token för token.
Uppdatera konversationsloopen så att den använder strömning:
// 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");
Strömningsversionen ackumulerar det fullständiga svaret så att det kan läggas till i konversationshistoriken när strömmen har slutförts.
Fullständig kod
Ersätt innehållet i src/main.rs med följande fullständiga kod:
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(())
}
Kör chattassistenten:
cargo run
Du ser utdata som liknar:
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!
Observera hur assistenten minns kontexten från tidigare svängar – när du frågar "Varför är det viktigt för andra levande saker?", vet den att du fortfarande pratar om fotosyntes.
Rensa resurser
Modellvikterna finns kvar i din lokala cache efter att du har avladdat en modell. Det innebär att nästa gång du kör programmet utelämnas nedladdningssteget och modellen läses in snabbare. Ingen extra rensning krävs om du inte vill frigöra diskutrymme.