Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве вы создадите интерактивный помощник чата, который работает полностью на устройстве. Помощник поддерживает контекст беседы в нескольких обменах, поэтому он запоминает то, что вы обсуждали ранее в беседе. Локальный SDK Foundry используется для выбора модели, определения системного запроса и потоковой передачи ответов по токену.
В этом руководстве вы узнаете, как:
- Настройка проекта и установка локального SDK Foundry
- Просмотр каталога моделей и выбор модели
- Задайте системную подсказку для формирования поведения ассистента
- Внедрение многоэтапного диалога с историей сообщений
- Потоковая обработка ответов для отзывчивого взаимодействия
- Очистите ресурсы, когда разговор заканчивается
Необходимые условия
- Компьютер Windows, macOS или Linux с не менее 8 ГБ ОЗУ.
Репозиторий примеров
Полный исходный код примера для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к образцу, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/csharp/foundry-local/tutorial-chat-assistant
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Примеры C# в репозитории GitHub предварительно настроены. Если вы создаете с нуля, ознакомьтесь со справочником по локальному пакету SDK Foundry для получения дополнительных сведений о настройке проекта C# с помощью Foundry Local.
Обзор каталога и выбор модели
Локальный пакет SDK Foundry предоставляет каталог моделей, который содержит список всех доступных моделей. На этом шаге вы инициализируете пакет SDK и выберите модель для помощника чата.
Откройте
Program.csи замените его содержимое следующим кодом, чтобы инициализировать пакет SDK и выбрать модель: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();Метод
GetModelAsyncпринимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. МетодDownloadAsyncизвлекает вес модели в локальный кэш иLoadAsyncделает модель готовой к выводу.
Определите системный запрос
Системный запрос задает личность и поведение помощника. Это первое сообщение в журнале бесед, а модель ссылается на него на протяжении всего разговора.
Добавьте системный запрос для формирования ответа помощника:
// 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."
}
};
Подсказка
Экспериментируйте с различными системными запросами, чтобы изменить поведение помощника. Например, вы можете указать ему ответить как пират, учитель или эксперт по домену.
реализовать многоэтапную беседу;
Помощник чата должен поддерживать контекст в нескольких обменах. Для этого необходимо сохранить список всех сообщений (системных, пользователей и помощников) и отправить полный список с каждым запросом. Модель использует эту историю для создания контекстно соответствующих ответов.
Добавьте цикл беседы, который:
- Считывает входные данные пользователя из консоли.
- Добавляет сообщение пользователя в историю.
- Отправляет полный журнал в модель.
- Добавляет ответ помощника к истории для следующего шага.
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 });
}
Каждый вызов CompleteChatAsync получает полный журнал сообщений. Это то, как модель "запоминает" предыдущие этапы — она не сохраняет состояние между вызовами.
Добавьте потоковые ответы
Потоковая передача выводит каждый токен по мере его генерации, что делает помощника более отзывчивым. Замените вызов функции CompleteChatAsync на CompleteChatStreamingAsync, чтобы токенизировать поток ответа.
Обновите цикл беседы для использования потоковой передачи:
// 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");
Версия потоковой передачи накапливает полный ответ, чтобы его можно было добавить в журнал бесед после завершения потока.
Полный код
Замените содержимое Program.cs следующим полным кодом:
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!");
Запустите помощник по чату:
dotnet run
Выходные данные похожи на следующие:
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!
Обратите внимание, как помощник запоминает контекст из предыдущих поворотов - когда вы спрашиваете: "Почему важно для других живых вещей?", он знает, что вы все еще говорите о фотоинтезии.
Репозиторий примеров
Полный код примеров для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к образцу, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/javascript/foundry-local/tutorial-chat-assistant
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
npm install foundry-local-sdk-winml openai
Обзор каталога и выбор модели
Локальный пакет SDK Foundry предоставляет каталог моделей, который содержит список всех доступных моделей. На этом шаге вы инициализируете пакет SDK и выберите модель для помощника чата.
Создайте файл с именем
index.js.Добавьте следующий код для инициализации пакета SDK и выберите модель:
// 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();Метод
getModelпринимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Методdownloadизвлекает вес модели в локальный кэш иloadделает модель готовой к выводу.
Определите системный запрос
Системный запрос задает личность и поведение помощника. Это первое сообщение в журнале бесед, а модель ссылается на него на протяжении всего разговора.
Добавьте системный запрос для формирования ответа помощника:
// 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.'
}
];
Подсказка
Экспериментируйте с различными системными запросами, чтобы изменить поведение помощника. Например, вы можете указать ему ответить как пират, учитель или эксперт по домену.
реализовать многоэтапную беседу;
Помощник чата должен поддерживать контекст в нескольких обменах. Для этого необходимо сохранить список всех сообщений (системных, пользователей и помощников) и отправить полный список с каждым запросом. Модель использует эту историю для создания контекстно соответствующих ответов.
Добавьте цикл беседы, который:
- Считывает входные данные пользователя из консоли.
- Добавляет сообщение пользователя в историю.
- Отправляет полный журнал в модель.
- Добавляет ответ помощника к истории для следующего шага.
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 });
}
Каждый вызов completeChat получает полный журнал сообщений. Это то, как модель "запоминает" предыдущие этапы — она не сохраняет состояние между вызовами.
Добавьте потоковые ответы
Потоковая передача выводит каждый токен по мере его генерации, что делает помощника более отзывчивым. Замените вызов функции completeChat на completeStreamingChat, чтобы токенизировать поток ответа.
Обновите цикл беседы для использования потоковой передачи:
// 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');
Версия потоковой передачи накапливает полный ответ, чтобы его можно было добавить в журнал бесед после завершения потока.
Полный код
Создайте файл с именем index.js и добавьте следующий полный код:
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) => {
if (rl.closed) return resolve('quit');
const onClose = () => resolve('quit');
rl.once('close', onClose);
try {
rl.question(prompt, (answer) => {
rl.off('close', onClose);
resolve(answer);
});
} catch {
rl.off('close', onClose);
resolve('quit');
}
});
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();
Запустите помощник по чату:
node index.js
Выходные данные похожи на следующие:
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!
Обратите внимание, как помощник запоминает контекст из предыдущих поворотов - когда вы спрашиваете: "Почему важно для других живых вещей?", он знает, что вы все еще говорите о фотоинтезии.
Репозиторий примеров
Полный пример кода для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к образцу, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/python/foundry-local/tutorial-chat-assistant
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
pip install foundry-local-sdk-winml openai
Обзор каталога и выбор модели
Локальный пакет SDK Foundry предоставляет каталог моделей, который содержит список всех доступных моделей. На этом шаге вы инициализируете пакет SDK и выберите модель для помощника чата.
Создайте файл с именем
main.py.Добавьте следующий код для инициализации пакета SDK и выберите модель:
# 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()Метод
get_modelпринимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Методdownloadизвлекает вес модели в локальный кэш иloadделает модель готовой к выводу.
Определите системный запрос
Системный запрос задает личность и поведение помощника. Это первое сообщение в журнале бесед, а модель ссылается на него на протяжении всего разговора.
Добавьте системный запрос для формирования ответа помощника:
# 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.",
}
]
Подсказка
Экспериментируйте с различными системными запросами, чтобы изменить поведение помощника. Например, вы можете указать ему ответить как пират, учитель или эксперт по домену.
реализовать многоэтапную беседу;
Помощник чата должен поддерживать контекст в нескольких обменах. Для этого необходимо сохранить список всех сообщений (системных, пользователей и помощников) и отправить полный список с каждым запросом. Модель использует эту историю для создания контекстно соответствующих ответов.
Добавьте цикл беседы, который:
- Считывает входные данные пользователя из консоли.
- Добавляет сообщение пользователя в историю.
- Отправляет полный журнал в модель.
- Добавляет ответ помощника к истории для следующего шага.
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):
if not chunk.choices:
continue
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})
Каждый вызов complete_chat получает полный журнал сообщений. Это то, как модель "запоминает" предыдущие этапы — она не сохраняет состояние между вызовами.
Добавьте потоковые ответы
Потоковая передача выводит каждый токен по мере его генерации, что делает помощника более отзывчивым. Замените вызов функции complete_chat на complete_streaming_chat, чтобы токенизировать поток ответа.
Обновите цикл беседы для использования потоковой передачи:
# Stream the response token by token
print("Assistant: ", end="", flush=True)
full_response = ""
for chunk in client.complete_streaming_chat(messages):
if not chunk.choices:
continue
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
full_response += content
print("\n")
Версия потоковой передачи накапливает полный ответ, чтобы его можно было добавить в журнал бесед после завершения потока.
Полный код
Создайте файл с именем main.py и добавьте следующий полный код:
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):
if not chunk.choices:
continue
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()
Запустите помощник по чату:
python main.py
Выходные данные похожи на следующие:
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!
Обратите внимание, как помощник запоминает контекст из предыдущих поворотов - когда вы спрашиваете: "Почему важно для других живых вещей?", он знает, что вы все еще говорите о фотоинтезии.
Репозиторий примеров
Полный исходный код примеров для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к образцу, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/rust/foundry-local/tutorial-chat-assistant
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Обзор каталога и выбор модели
Локальный пакет SDK Foundry предоставляет каталог моделей, который содержит список всех доступных моделей. На этом шаге вы инициализируете пакет SDK и выберите модель для помощника чата.
Откройте
src/main.rsи замените его содержимое следующим кодом, чтобы инициализировать пакет SDK и выбрать модель:// Initialize the Foundry Local SDK let manager = FoundryLocalManager::create(FoundryLocalConfig::new("foundry_local_samples"))?; // Download and register all execution providers. manager .download_and_register_eps_with_progress(None, { let mut current_ep = String::new(); move |ep_name: &str, percent: f64| { if ep_name != current_ep { if !current_ep.is_empty() { println!(); } current_ep = ep_name.to_string(); } print!("\r {:<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);Метод
get_modelпринимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Методdownloadизвлекает вес модели в локальный кэш иloadделает модель готовой к выводу.
Определите системный запрос
Системный запрос задает личность и поведение помощника. Это первое сообщение в журнале бесед, а модель ссылается на него на протяжении всего разговора.
Добавьте системный запрос для формирования ответа помощника:
// 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(),
];
Подсказка
Экспериментируйте с различными системными запросами, чтобы изменить поведение помощника. Например, вы можете указать ему ответить как пират, учитель или эксперт по домену.
реализовать многоэтапную беседу;
Помощник чата должен поддерживать контекст в нескольких обменах. Это можно сделать, сохранив вектор всех сообщений (системных, пользователей и помощников) и отправив полный список с каждым запросом. Модель использует эту историю для создания контекстно соответствующих ответов.
Добавьте цикл беседы, который:
- Считывает входные данные пользователя из консоли.
- Добавляет сообщение пользователя в историю.
- Отправляет полный журнал в модель.
- Добавляет ответ помощника к истории для следующего шага.
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);
}
Каждый вызов complete_chat получает полный журнал сообщений. Это то, как модель "запоминает" предыдущие этапы — она не сохраняет состояние между вызовами.
Добавьте потоковые ответы
Потоковая передача выводит каждый токен по мере его генерации, что делает помощника более отзывчивым. Замените вызов функции complete_chat на complete_streaming_chat, чтобы токенизировать поток ответа.
Обновите цикл беседы для использования потоковой передачи:
// 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");
Версия потоковой передачи накапливает полный ответ, чтобы его можно было добавить в журнал бесед после завершения потока.
Полный код
Замените содержимое src/main.rs следующим полным кодом:
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("foundry_local_samples"))?;
// Download and register all execution providers.
manager
.download_and_register_eps_with_progress(None, {
let mut current_ep = String::new();
move |ep_name: &str, percent: f64| {
if ep_name != current_ep {
if !current_ep.is_empty() {
println!();
}
current_ep = ep_name.to_string();
}
print!("\r {:<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(())
}
Запустите помощник по чату:
cargo run
Выходные данные похожи на следующие:
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!
Обратите внимание, как помощник запоминает контекст из предыдущих поворотов - когда вы спрашиваете: "Почему важно для других живых вещей?", он знает, что вы все еще говорите о фотоинтезии.
Очистите ресурсы
Вес модели остается в локальном кэше после выгрузки модели. Это означает, что при следующем запуске приложения шаг загрузки пропускается, а модель загружается быстрее. Дополнительная очистка не требуется, если вы не хотите освободить место на диске.