Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Neste tutorial, você criará um assistente de chat interativo que é executado inteiramente em seu dispositivo. O assistente mantém o contexto de conversa em várias trocas, portanto, ele se lembra do que você discutiu anteriormente na conversa. Você usa o Foundry Local SDK para selecionar um modelo, definir um prompt do sistema e transmitir as respostas token por token.
Neste tutorial, você aprenderá como:
- Configurar um projeto e instalar o SDK Local do Foundry
- Navegue pelo catálogo de modelos e selecione um modelo
- Definir um prompt do sistema para moldar o comportamento do assistente
- Implementar uma conversa de vários turnos com histórico de mensagens
- Transmitir respostas para uma experiência responsiva
- Liberar recursos quando a conversa terminar
Pré-requisitos
- Um computador Windows, macOS ou Linux com pelo menos 8 GB de RAM.
Repositório de exemplos
O código de exemplo completo deste artigo está disponível no repositório Foundry Local GitHub. Para clonar o repositório e acessar o exemplo, use:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/cs/tutorial-chat-assistant
Instalar pacotes
Se você estiver desenvolvendo ou enviando em Windows, selecione a guia Windows. O pacote Windows integra-se ao runtime Windows ML – ele fornece a mesma área de superfície de API com uma amplitude maior de aceleração de hardware.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Os exemplos de C# no repositório GitHub são projetos pré-configurados. Se você estiver criando do zero, leia a referência do SDK Local do Foundry para obter mais detalhes sobre como configurar seu projeto em C# com o Foundry Local.
Navegue pelo catálogo e selecione um modelo
O SDK Local do Foundry fornece um catálogo de modelos que lista todos os modelos disponíveis. Nesta etapa, você inicializa o SDK e seleciona um modelo para seu assistente de chat.
Abra
Program.cse substitua seu conteúdo pelo seguinte código para inicializar o SDK e selecionar um modelo: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();O método
GetModelAsyncaceita um apelido de modelo, que é um nome amigável curto que corresponde a um modelo específico no catálogo. ODownloadAsyncmétodo busca os pesos do modelo para o cache local eLoadAsyncprepara o modelo para inferência.
Definir um prompt do sistema
Um prompt do sistema define a personalidade e o comportamento do assistente. É a primeira mensagem no histórico de conversas e o modelo faz referência a ela durante toda a conversa.
Adicione um prompt do sistema para moldar como o assistente responde:
// 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."
}
};
Dica
Experimente diferentes prompts do sistema para alterar o comportamento do assistente. Por exemplo, você pode instruí-lo a responder como um pirata, um professor ou um especialista em domínio.
Implementar diálogo em várias etapas
Um assistente de chat precisa manter o contexto em várias trocas. Você consegue isso mantendo uma lista de todas as mensagens (sistema, usuário e assistente) e enviando a lista completa com cada solicitação. O modelo usa esse histórico para gerar respostas contextualmente relevantes.
Adicione um loop de conversa que:
- Lê a entrada do usuário do console.
- Acrescenta a mensagem do usuário ao histórico.
- Envia o histórico completo para o modelo.
- Adiciona a resposta do assistente ao histórico para o próximo turno.
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 });
}
Cada chamada para CompleteChatAsync recebe o histórico completo de mensagens. É assim que o modelo "lembra" de turnos anteriores — ele não armazena o estado entre as chamadas.
Adicionar respostas de streaming
O streaming imprime cada token conforme ele é gerado, o que faz com que o assistente se sinta mais responsivo. Substitua a chamada CompleteChatAsync por CompleteChatStreamingAsync para transmitir a resposta token por token.
Atualize o loop de conversa para usar o streaming:
// 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");
A versão de streaming acumula a resposta completa para que ela possa ser adicionada ao histórico de conversas após a conclusão do fluxo.
Código completo
Substitua o conteúdo de Program.cs pelo seguinte código completo:
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!");
Execute o assistente de chat:
dotnet run
Você vê uma saída semelhante a:
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!
Observe como o assistente se lembra do contexto de turnos anteriores – quando você pergunta "Por que é importante para outros seres vivos?", ele sabe que você ainda está falando sobre fotossíntese.
Repositório de exemplos
O código de exemplo completo deste artigo está disponível no repositório Foundry Local GitHub. Para clonar o repositório e acessar o exemplo, use:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/js/tutorial-chat-assistant
Instalar pacotes
Se você estiver desenvolvendo ou enviando em Windows, selecione a guia Windows. O pacote Windows integra-se ao runtime Windows ML – ele fornece a mesma área de superfície de API com uma amplitude maior de aceleração de hardware.
npm install foundry-local-sdk-winml openai
Navegue pelo catálogo e selecione um modelo
O SDK Local do Foundry fornece um catálogo de modelos que lista todos os modelos disponíveis. Nesta etapa, você inicializa o SDK e seleciona um modelo para seu assistente de chat.
Crie um ficheiro chamado
index.js.Adicione o seguinte código para inicializar o SDK e selecione um modelo:
// 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();O método
getModelaceita um apelido de modelo, que é um nome amigável curto que corresponde a um modelo específico no catálogo. Odownloadmétodo busca os pesos do modelo para o cache local eloadprepara o modelo para inferência.
Definir um prompt do sistema
Um prompt do sistema define a personalidade e o comportamento do assistente. É a primeira mensagem no histórico de conversas e o modelo faz referência a ela durante toda a conversa.
Adicione um prompt do sistema para moldar como o assistente responde:
// 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.'
}
];
Dica
Experimente diferentes prompts do sistema para alterar o comportamento do assistente. Por exemplo, você pode instruí-lo a responder como um pirata, um professor ou um especialista em domínio.
Implementar diálogo em várias etapas
Um assistente de chat precisa manter o contexto em várias trocas. Você consegue isso mantendo uma lista de todas as mensagens (sistema, usuário e assistente) e enviando a lista completa com cada solicitação. O modelo usa esse histórico para gerar respostas contextualmente relevantes.
Adicione um loop de conversa que:
- Lê a entrada do usuário do console.
- Acrescenta a mensagem do usuário ao histórico.
- Envia o histórico completo para o modelo.
- Adiciona a resposta do assistente ao histórico para o próximo turno.
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 });
}
Cada chamada para completeChat recebe o histórico completo de mensagens. É assim que o modelo "lembra" de turnos anteriores — ele não armazena o estado entre as chamadas.
Adicionar respostas de streaming
O streaming imprime cada token conforme ele é gerado, o que faz com que o assistente se sinta mais responsivo. Substitua a chamada completeChat por completeStreamingChat para transmitir a resposta token por token.
Atualize o loop de conversa para usar o streaming:
// 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');
A versão de streaming acumula a resposta completa para que ela possa ser adicionada ao histórico de conversas após a conclusão do fluxo.
Código completo
Crie um arquivo nomeado index.js e adicione o seguinte código completo:
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();
Execute o assistente de chat:
node index.js
Você vê uma saída semelhante a:
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!
Observe como o assistente se lembra do contexto de turnos anteriores – quando você pergunta "Por que é importante para outros seres vivos?", ele sabe que você ainda está falando sobre fotossíntese.
Repositório de exemplos
O código de exemplo completo deste artigo está disponível no repositório Foundry Local GitHub. Para clonar o repositório e acessar o exemplo, use:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/python/tutorial-chat-assistant
Instalar pacotes
Se você estiver desenvolvendo ou enviando em Windows, selecione a guia Windows. O pacote Windows integra-se ao runtime Windows ML – ele fornece a mesma área de superfície de API com uma amplitude maior de aceleração de hardware.
pip install foundry-local-sdk-winml openai
Navegue pelo catálogo e selecione um modelo
O SDK Local do Foundry fornece um catálogo de modelos que lista todos os modelos disponíveis. Nesta etapa, você inicializa o SDK e seleciona um modelo para seu assistente de chat.
Crie um ficheiro chamado
main.py.Adicione o seguinte código para inicializar o SDK e selecione um modelo:
# 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()O método
get_modelaceita um apelido de modelo, que é um nome amigável curto que corresponde a um modelo específico no catálogo. Odownloadmétodo busca os pesos do modelo para o cache local eloadprepara o modelo para inferência.
Definir um prompt do sistema
Um prompt do sistema define a personalidade e o comportamento do assistente. É a primeira mensagem no histórico de conversas e o modelo faz referência a ela durante toda a conversa.
Adicione um prompt do sistema para moldar como o assistente responde:
# 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."
}
]
Dica
Experimente diferentes prompts do sistema para alterar o comportamento do assistente. Por exemplo, você pode instruí-lo a responder como um pirata, um professor ou um especialista em domínio.
Implementar diálogo em várias etapas
Um assistente de chat precisa manter o contexto em várias trocas. Você consegue isso mantendo uma lista de todas as mensagens (sistema, usuário e assistente) e enviando a lista completa com cada solicitação. O modelo usa esse histórico para gerar respostas contextualmente relevantes.
Adicione um loop de conversa que:
- Lê a entrada do usuário do console.
- Acrescenta a mensagem do usuário ao histórico.
- Envia o histórico completo para o modelo.
- Adiciona a resposta do assistente ao histórico para o próximo turno.
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})
Cada chamada para complete_chat recebe o histórico completo de mensagens. É assim que o modelo "lembra" de turnos anteriores — ele não armazena o estado entre as chamadas.
Adicionar respostas de streaming
O streaming imprime cada token conforme ele é gerado, o que faz com que o assistente se sinta mais responsivo. Substitua a chamada complete_chat por complete_streaming_chat para transmitir a resposta token por token.
Atualize o loop de conversa para usar o streaming:
# 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")
A versão de streaming acumula a resposta completa para que ela possa ser adicionada ao histórico de conversas após a conclusão do fluxo.
Código completo
Crie um arquivo nomeado main.py e adicione o seguinte código completo:
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()
Execute o assistente de chat:
python main.py
Você vê uma saída semelhante a:
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!
Observe como o assistente se lembra do contexto de turnos anteriores – quando você pergunta "Por que é importante para outros seres vivos?", ele sabe que você ainda está falando sobre fotossíntese.
Repositório de exemplos
O código de exemplo completo deste artigo está disponível no repositório Foundry Local GitHub. Para clonar o repositório e acessar o exemplo, use:
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/rust/tutorial-chat-assistant
Instalar pacotes
Se você estiver desenvolvendo ou enviando em Windows, selecione a guia Windows. O pacote Windows integra-se ao runtime Windows ML – ele fornece a mesma área de superfície de API com uma amplitude maior de aceleração de hardware.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Navegue pelo catálogo e selecione um modelo
O SDK Local do Foundry fornece um catálogo de modelos que lista todos os modelos disponíveis. Nesta etapa, você inicializa o SDK e seleciona um modelo para seu assistente de chat.
Abra
src/main.rse substitua seu conteúdo pelo seguinte código para inicializar o SDK e selecionar um modelo:// 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);O método
get_modelaceita um apelido de modelo, que é um nome amigável curto que corresponde a um modelo específico no catálogo. Odownloadmétodo busca os pesos do modelo para o cache local eloadprepara o modelo para inferência.
Definir um prompt do sistema
Um prompt do sistema define a personalidade e o comportamento do assistente. É a primeira mensagem no histórico de conversas e o modelo faz referência a ela durante toda a conversa.
Adicione um prompt do sistema para moldar como o assistente responde:
// 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(),
];
Dica
Experimente diferentes prompts do sistema para alterar o comportamento do assistente. Por exemplo, você pode instruí-lo a responder como um pirata, um professor ou um especialista em domínio.
Implementar diálogo em várias etapas
Um assistente de chat precisa manter o contexto em várias trocas. Você consegue isso mantendo um vetor de todas as mensagens (sistema, usuário e assistente) e enviando a lista completa com cada solicitação. O modelo usa esse histórico para gerar respostas contextualmente relevantes.
Adicione um loop de conversa que:
- Lê a entrada do usuário do console.
- Acrescenta a mensagem do usuário ao histórico.
- Envia o histórico completo para o modelo.
- Adiciona a resposta do assistente ao histórico para o próximo turno.
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);
}
Cada chamada para complete_chat recebe o histórico completo de mensagens. É assim que o modelo "lembra" de turnos anteriores — ele não armazena o estado entre as chamadas.
Adicionar respostas de streaming
O streaming imprime cada token conforme ele é gerado, o que faz com que o assistente se sinta mais responsivo. Substitua a chamada complete_chat por complete_streaming_chat para transmitir a resposta token por token.
Atualize o loop de conversa para usar o streaming:
// 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");
A versão de streaming acumula a resposta completa para que ela possa ser adicionada ao histórico de conversas após a conclusão do fluxo.
Código completo
Substitua o conteúdo de src/main.rs pelo seguinte código completo:
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(())
}
Execute o assistente de chat:
cargo run
Você vê uma saída semelhante a:
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!
Observe como o assistente se lembra do contexto de turnos anteriores – quando você pergunta "Por que é importante para outros seres vivos?", ele sabe que você ainda está falando sobre fotossíntese.
Limpar os recursos
Os pesos do modelo permanecem no cache local depois que você descarrega um modelo. Isso significa que, na próxima vez que você executar o aplicativo, a etapa de download será ignorada e o modelo será carregado mais rapidamente. Nenhuma limpeza extra é necessária, a menos que você queira recuperar espaço em disco.