Minecraft ИИ с Llama 3.2
Creado el: 17 de noviembre de 2024
Respondido usando O1 Preview por Chat01
Creado el: 17 de noviembre de 2024
Respondido usando O1 Preview por Chat01
Цель:
Создать ИИ-агента, который взаимодействует с Minecraft версии 1.20.1, используя нейросеть Llama 3.2 для принятия решений, выполнения задач и взаимодействия с игроками. ИИ будет действовать автономно, с элементами мышления, принимая решения на основе текущей ситуации в игре и контекста. Игроки смогут общаться с ИИ через чат, обсуждать его действия и давать указания, но не прямые команды — ИИ будет принимать решения самостоятельно.
Условия:
Интеграция:
ИИ подключается к Minecraft через API, такие как Mineflayer для Node.js. Нейросеть Llama 3.2 обрабатывает данные игры и контекст общения для формирования разумных действий.
Автономность:
Допустимые механики:
Все действия ИИ соответствуют стандартным игровым механикам Minecraft. Он не использует читы или запрещённые методы автоматизации.
Интерактивность:
Дополнительные функции для автономности:
"Я вижу, что у меня заканчивается еда. Думаю, стоит найти коров или свиней поблизости, чтобы добыть мясо."
Обучение через взаимодействие:
ИИ способен изменять своё поведение на основе обратной связи от игроков. Если ему укажут на ошибку, он постарается учесть это в будущем.
Проверка состояния:
ИИ постоянно анализирует:
Уровень здоровья и сытости.
Состояние снаряжения (наличие брони, инструментов).
Угрозы (близость мобов, опасные зоны).
Ресурсы для выполнения задач.
Логика приоритетов:
Если ИИ обнаруживает угрозу или критическую ситуацию (голод, повреждение брони), он адаптирует свои действия, чтобы обеспечить выживание.
Общение с игроком:
Игрок: "Почему ты рубишь деревья, а не ищешь шахту?"
ИИ: "Я решил сначала сделать инструменты. Это поможет быстрее добывать ресурсы в шахте."
Реакция на обратную связь:
Игрок: "Ты забыл взять факелы в шахту."
ИИ: "Спасибо, ты прав. Вернусь и сделаю их, чтобы не заблудиться."
Здравствуйте!
Ваша цель — создать ИИ-агента для Minecraft 1.20.1, который автономно взаимодействует с миром игры и игроками, используя нейросеть Llama 3.2 для принятия решений. Это амбициозный проект, и я с радостью помогу вам понять, как можно его реализовать.
Mineflayer: Это мощная библиотека для Node.js, позволяющая создавать ботов для Minecraft. Она предоставляет API для доступа к событиям игры, таким как движение, взаимодействие с объектами и общение в чате.
Связь с Llama 3.2: Поскольку Llama 3.2, вероятно, написана на Python, вам понадобится механизм для взаимодействия между Node.js и Python. Это можно сделать с помощью REST API, WebSocket или библиотек, таких как python-shell для Node.js.
Сбор данных: Бот с помощью Mineflayer собирает информацию о состоянии игры: здоровье, инвентарь, окружение и т.д.
Обработка данных: Собранные данные форматируются и передаются в Llama 3.2 в качестве контекста.
Принятие решений: Llama 3.2 на основе полученного контекста генерирует ответ в виде текста, описывающего мысли или действия бота.
Исполнение действий: Ответ от Llama 3.2 парсится, и соответствующие команды передаются обратно в Mineflayer для выполнения в игре.
Контекст для Llama 3.2: Включайте в контекст не только текущие данные игры, но и историю предыдущих действий и общения с игроками.
Форматирование запросов: Используйте структурированные подсказки для Llama 3.2, чтобы получить от нее конкретные и полезные ответы.
textКонтекст: - Здоровье: 8/20 - Сытость: 5/20 - Ближайшие мобы: Зомби (10 блоков) - Инвентарь: Нет меча, есть кирка Вопрос: - Что мне делать дальше?
Обработка чата: Настройте бота на получение сообщений из чата и включение их в контекст для Llama 3.2.
Генерация ответов: Позвольте Llama 3.2 формировать ответы на сообщения игроков, поддерживая естественное общение.
Система приоритетов: Разработайте механизмы, которые помогут боту оценивать ситуации и устанавливать приоритеты (например, выживание выше исследования).
Адаптация к угрозам: Если бот обнаруживает опасность, он должен уметь быстро реагировать, даже если это отклоняется от его текущего плана.
Обратная связь: Реализуйте систему, где бот может запоминать замечания или советы игроков и использовать их в будущем.
Обновление модели: Хотя прямое обучение Llama 3.2 во время работы может быть затруднено, вы можете сохранять важную информацию в контексте или в отдельной базе данных.
Ресурсы: Убедитесь, что у вас достаточно вычислительных ресурсов для работы Llama 3.2 в реальном времени.
Оптимизация: Для снижения задержек можно использовать предварительное кэширование ответов или более легкие версии модели.
Безопасность: Следите за тем, чтобы бот не выполнял нежелательные действия и соблюдал правила сервера.
Создайте бота с Mineflayer:
Настройте коммуникацию между Node.js и Python:
Интегрируйте Llama 3.2:
Разработайте систему парсинга:
Добавьте обработку чата:
Тестирование и отладка:
Для связи Node.js и Python:
Для оптимизации модели:
Начните с простого: Реализуйте базовый функционал и постепенно добавляйте сложности.
Документируйте процесс: Это поможет в отладке и будущих улучшениях.
Сообщество: Обратитесь к сообществу разработчиков Mineflayer и пользователей Llama для советов и поддержки.
Создание такого ИИ-агента — это сложный, но увлекательный проект, который объединяет игровые разработки и современные достижения в области искусственного интеллекта. Следуя описанным шагам и постоянно экспериментируя, вы сможете достичь поставленной цели.
Если у вас возникнут дополнительные вопросы или понадобится помощь с конкретными аспектами реализации, не стесняйтесь обращаться!
Побробно напиши действия чтобы воплотить этот проэкт а также напиши код к нему.
Здравствуйте!
Я рад помочь вам с подробным планом действий по реализации вашего проекта, а также предоставить примерный код. Давайте разобьем процесс на этапы и рассмотрим каждый из них детально.
Node.js: Потребуется для работы с Mineflayer.
bash# Установка Node.js (если не установлен) # Перейдите на официальный сайт и скачайте установщик для вашей ОС: https://nodejs.org/
Python 3.8+: Для запуска Llama 3.2.
bash# Установка Python (если не установлен) # Перейдите на официальный сайт и скачайте установщик для вашей ОС: https://www.python.org/downloads/
Mineflayer: Библиотека для создания ботов в Minecraft.
bash# Создайте новый проект Node.js mkdir minecraft-ai-bot cd minecraft-ai-bot npm init -y # Установите Mineflayer npm install mineflayer
Llama 3.2: Убедитесь, что у вас есть доступ к модели и достаточные ресурсы для ее запуска.
Локальный сервер: Для тестирования вы можете использовать локальный сервер Minecraft.
bash# Скачать сервер с официального сайта: https://www.minecraft.net/en-us/download/server
Разрешение подключения ботов: Убедитесь, что в server.properties установлено online-mode=false для локального тестирования.
javascript// bot.js const mineflayer = require('mineflayer'); const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера port: 25565, // Порт сервера username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); bot.on('login', () => { console.log('Бот успешно подключился к серверу!'); }); bot.on('chat', (username, message) => { if (username === bot.username) return; bot.chat(`Привет, ${username}! Я ИИ-бот.`); });
bashnode bot.js
javascriptconst { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock } = goals; bot.loadPlugin(pathfinder); bot.on('spawn', () => { const mcData = require('minecraft-data')(bot.version); const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Пример перемещения к координатам (x, y, z) const targetPos = bot.entity.position.offset(10, 0, 10); bot.pathfinder.setGoal(new GoalBlock(targetPos.x, targetPos.y, targetPos.z)); });
Использование WebSocket: Можно использовать библиотеки, такие как ws для Node.js и websockets для Python.
Использование REST API: Можно поднять сервер на Python (Flask) и отправлять POST-запросы из Node.js.
Node.js сторона (отправка контекста и получение ответа):
javascriptconst axios = require('axios'); // Функция для отправки контекста и получения ответа от Llama 3.2 async function getLlamaResponse(context) { try { const response = await axios.post('http://localhost:5000/get_action', { context }); return response.data.action; } catch (error) { console.error('Ошибка при обращении к Llama 3.2:', error); } }
Python сторона (сервер с Llama 3.2):
python# server.py from flask import Flask, request, jsonify from llama import Llama # Предположим, что у вас есть модуль для работы с Llama 3.2 app = Flask(__name__) # Инициализация модели model = Llama() @app.route('/get_action', methods=['POST']) def get_action(): data = request.get_json() context = data.get('context', '') # Генерация ответа на основе контекста action = model.generate_action(context) return jsonify({'action': action}) if __name__ == '__main__': app.run(port=5000)
javascriptfunction getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.name); const nearbyEntities = Object.values(bot.entities).filter(entity => entity.type === 'mob'); let context = `Здоровье: ${health}/20\n`; context += `Сытость: ${food}/20\n`; context += `Позиция: x=${position.x}, y=${position.y}, z=${position.z}\n`; context += `Инвентарь: ${inventoryItems.join(', ')}\n`; context += `Ближайшие мобы: ${nearbyEntities.map(e => e.name).join(', ')}\n`; return context; }
javascriptasync function processLlamaResponse() { const context = getBotContext(); const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Простая обработка действий (пример) if (action.includes('найти дерево')) { // Поиск ближайшего дерева и перемещение к нему } else if (action.includes('сделать меч')) { // Крафт меча } }
javascriptfunction findNearestTree() { const blocks = bot.findBlocks({ matching: block => block.name.includes('log'), maxDistance: 100, count: 1 }); if (blocks.length) { const block = bot.blockAt(blocks[0]); bot.pathfinder.setGoal(new GoalBlock(block.position.x, block.position.y, block.position.z)); } else { console.log('Деревья не найдены поблизости.'); } }
javascriptasync function mineBlock(blockName) { const block = bot.findBlock({ matching: block => block.name === blockName, maxDistance: 32 }); if (block) { try { await bot.dig(block); console.log(`Добыт блок: ${block.name}`); } catch (err) { console.error('Ошибка при добыче блока:', err); } } else { console.log(`${blockName} не найден поблизости.`); } }
javascriptasync function craftItem(itemName) { const mcData = require('minecraft-data')(bot.version); const item = mcData.itemsByName[itemName]; const craftingTableID = mcData.blocksByName.crafting_table.id; let craftingTable = bot.findBlock({ matching: craftingTableID, maxDistance: 32 }); if (!craftingTable) { // Если нет верстака, создать его const plank = bot.inventory.items().find(item => item.name.includes('planks')); if (plank) { // Крафт верстака // Код для крафта верстака } else { console.log('Нет досок для создания верстака.'); return; } } const recipe = bot.recipesFor(item.id, null, 1, craftingTable)[0]; if (recipe) { try { await bot.craft(recipe, 1, craftingTable); console.log(`${itemName} успешно скрафчен.`); } catch (err) { console.error(`Ошибка при крафте ${itemName}:`, err); } } else { console.log(`Рецепт для ${itemName} не найден.`); } }
javascriptbot.on('chat', (username, message) => { if (username === bot.username) return; // Добавляем сообщение игрока в контекст const context = getBotContext() + `\n${username}: ${message}`; // Получаем ответ от модели getLlamaResponse(context).then(action => { // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия processAction(action); }); });
javascriptasync function processAction(action) { if (action.startsWith('Ответ:')) { const reply = action.replace('Ответ:', '').trim(); bot.chat(reply); } else { // Обработка других действий } }
javascriptlet playerFeedback = []; bot.on('chat', (username, message) => { if (username === bot.username) return; if (message.includes('совет')) { playerFeedback.push({ username, message }); bot.chat(`Спасибо за совет, ${username}!`); } // Обновляем контекст модели });
javascriptfunction getBotContext() { // ... предыдущий код if (playerFeedback.length) { context += `\nСоветы от игроков:\n`; playerFeedback.forEach(feedback => { context += `${feedback.username}: ${feedback.message}\n`; }); } return context; }
Логи и отладочные сообщения:
javascriptbot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
Оптимизация запросов к модели:
bashpython server.py
bashnode bot.js
Создание ИИ-бота для Minecraft с использованием нейросети Llama 3.2 — это комплексная задача, объединяющая разработку на Node.js и Python, а также работу с игровыми API. Представленный код является упрощенным и служит примером того, как можно реализовать основные функции.
Улучшение парсинга ответов модели: Разработайте более надежный парсер, который сможет интерпретировать различные формулировки модели и преобразовывать их в конкретные действия.
Безопасность: Убедитесь, что бот не выполняет потенциально опасные команды и соблюдает правила сервера.
Масштабируемость: Если планируется использование на публичных серверах, оптимизируйте производительность и учитывайте возможные нагрузки.
Llama 3.2: Убедитесь, что использование модели соответствует ее лицензии и условиям использования.
Код: Приведенный код является примером и может потребовать доработки для полной функциональности.
Если у вас возникнут дополнительные вопросы или потребуется помощь с конкретными аспектами реализации, пожалуйста, обращайтесь!
Напиши скрипты полностью
Здравствуйте!
Я подготовил для вас полный код для реализации ИИ-агента в Minecraft с использованием Mineflayer и Llama 3.2. Ниже представлены полные версии скриптов bot.js (Node.js) и server.py (Python). Также я добавил комментарии для объяснения каждого раздела кода.
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 25565, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 async function getLlamaResponse(context) { try { const response = await axios.post('http://localhost:5000/get_action', { context }); return response.data.action; } catch (error) { console.error('Ошибка при обращении к Llama 3.2:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(action) { action = action.toLowerCase(); if (action.includes('найти дерево')) { await findAndMineBlock('log'); } else if (action.includes('сделать инструменты')) { await craftTools(); } else if (action.includes('добыть камень')) { await findAndMineBlock('stone'); } else if (action.includes('сделать меч')) { await craftItem('stone_sword'); } else if (action.includes('поесть')) { await eatFood(); } else if (action.includes('исследовать')) { await explore(); } else { console.log('Неизвестное действие, ожидаю следующих инструкций...'); } } // Функция поиска и добычи блока async function findAndMineBlock(blockName) { const blockType = mcData.blocksByName[blockName]; if (!blockType) { console.log(`Блок с именем ${blockName} не найден в данных Minecraft.`); return; } const block = bot.findBlock({ matching: blockType.id, maxDistance: 64 }); if (block) { try { await bot.pathfinder.goto(new GoalNear(block.position.x, block.position.y, block.position.z, 1)); await bot.dig(block); console.log(`Добыт блок: ${blockName}`); } catch (err) { console.error('Ошибка при добыче блока:', err); } } else { console.log(`${blockName} не найден поблизости.`); } } // Функция крафта инструментов async function craftTools() { await craftItem('crafting_table'); // Создаем деревянные инструменты await craftItem('wooden_pickaxe'); await craftItem('wooden_axe'); } // Функция крафта предмета async function craftItem(itemName) { const item = mcData.itemsByName[itemName]; if (!item) { console.log(`Предмет ${itemName} не найден в данных Minecraft.`); return; } const craftingTable = bot.inventory.items().find(item => item.name === 'crafting_table'); let craftingTableBlock = bot.findBlock({ matching: mcData.blocksByName.crafting_table.id, maxDistance: 16 }); if (!craftingTableBlock && craftingTable) { // Устанавливаем верстак await placeItem('crafting_table'); craftingTableBlock = bot.findBlock({ matching: mcData.blocksByName.crafting_table.id, maxDistance: 16 }); } const recipes = bot.recipesFor(item.id, null, 1, craftingTableBlock); if (recipes.length) { try { await bot.craft(recipes[0], 1, craftingTableBlock); console.log(`${item.displayName} успешно скрафчен.`); } catch (err) { console.error(`Ошибка при крафте ${item.displayName}:`, err); } } else { console.log(`Рецепт для ${item.displayName} не найден.`); } } // Функция установки предмета async function placeItem(itemName) { const item = bot.inventory.items().find(item => item.name === itemName); if (!item) { console.log(`У меня нет ${itemName} для установки.`); return; } const referenceBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0)); try { await bot.equip(item, 'hand'); await bot.placeBlock(referenceBlock, mineflayer.vec3(0, 1, 0)); console.log(`${item.displayName} установлен.`); } catch (err) { console.error(`Ошибка при установке ${item.displayName}:`, err); } } // Функция питания async function eatFood() { const foodItem = bot.inventory.items().find(item => item.name.includes('cooked') || item.name.includes('apple')); if (foodItem) { try { await bot.equip(foodItem, 'hand'); await bot.consume(); console.log('Я поел и восстановил сытость.'); } catch (err) { console.error('Ошибка при приеме пищи:', err); } } else { console.log('У меня нет еды. Нужно найти пищу.'); // Можно добавить логику поиска пищи } } // Функция исследования async function explore() { const targetPos = bot.entity.position.offset( Math.floor(Math.random() * 100) - 50, 0, Math.floor(Math.random() * 100) - 50 ); try { await bot.pathfinder.goto(new GoalBlock(targetPos.x, targetPos.y, targetPos.z)); console.log('Я исследовал новую область.'); } catch (err) { console.error('Ошибка при исследовании:', err); } } // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Добавляем сообщение игрока в контекст const context = getBotContext() + `\n${username}: ${message}`; // Получаем ответ от модели const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия await processAction(action); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
server.pypython# server.py from flask import Flask, request, jsonify from llama_cpp import Llama # Предположим, что вы используете библиотеку llama-cpp-python app = Flask(__name__) # Инициализация модели Llama 3.2 model = Llama(model_path='path_to_your_llama_model/llama-3b.bin') @app.route('/get_action', methods=['POST']) def get_action(): data = request.get_json() context = data.get('context', '') # Создаем подсказку для модели prompt = f"""Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием. Контекст: {context} Действие: """ # Генерация ответа output = model( prompt, max_tokens=100, stop=["\n", "Контекст:", "Действие:"], echo=False, ) # Получаем сгенерированное действие action = output['choices'][0]['text'].strip() return jsonify({'action': action}) if __name__ == '__main__': app.run(port=5000)
Примечания к server.py:
Модель Llama 3.2: Убедитесь, что у вас есть доступ к модели и что она находится в указанном пути path_to_your_llama_model/llama-3b.bin.
Библиотека llama_cpp: Эта библиотека позволяет запускать модели Llama на вашем компьютере. Установите ее с помощью:
bashpip install llama-cpp-python
Параметры генерации: Настройте параметры max_tokens, stop, и другие в соответствии с вашими потребностями и возможностями вашего оборудования.
bot.jsВыполните следующие команды в директории вашего проекта:
bashnpm install mineflayer npm install mineflayer-pathfinder npm install axios npm install minecraft-data
server.pyУбедитесь, что у вас установлен Python 3.8 или выше. Затем установите необходимые библиотеки:
bashpip install flask pip install llama-cpp-python
Если вы используете локальный сервер, скачайте его с официального сайта:
В файле server.properties установите:
online-mode=false
Это позволит боту подключиться к серверу без проверки лицензии.
Запустите server.py:
bashpython server.py
Убедитесь, что сервер запущен на порту 5000 и доступен для bot.js.
Выполните в другой консоли:
bashnode bot.js
Подключитесь к серверу Minecraft: Запустите Minecraft версии 1.20.1 и подключитесь к вашему серверу.
Взаимодействуйте с ботом: Напишите что-нибудь в чат, и бот должен ответить вам и выполнить соответствующие действия.
Отслеживайте логи: В консолях bot.js и server.py вы можете видеть логи работы и возможные ошибки.
Оптимизация модели: Если модель Llama 3.2 слишком тяжела для вашего компьютера, рассмотрите возможность использования более легкой версии или настройте параметры генерации (например, уменьшите max_tokens).
Обработка ошибок: Добавьте дополнительные проверки и обработку возможных исключений в обоих скриптах для более стабильной работы.
Расширение функциональности: Вы можете добавить больше действий и улучшить парсинг ответов модели для более сложного поведения бота.
Лицензия модели: Убедитесь, что вы имеете право использовать модель Llama 3.2 в соответствии с ее лицензией.
Безопасность сервера: Если вы планируете запускать бота на публичном сервере, убедитесь, что его действия не нарушают правила сервера и не мешают другим игрокам.
Теперь у вас есть полный код для создания ИИ-агента в Minecraft, который взаимодействует с игроками и миром игры, используя нейросеть Llama 3.2 для принятия решений. Не стесняйтесь экспериментировать с кодом, добавлять новые функции и улучшать бота в соответствии с вашими потребностями.
Если у вас возникнут вопросы или потребуется помощь с отладкой, пожалуйста, обращайтесь!
на офицальном сайте вот что
How to download the model
Visit the Llama repository in GitHub where instructions can be found in the Llama README
1
Install the Llama CLI
In your preferred environment run the command below:
Command
pip install llama-stack
Use -U option to update llama-stack if a previous version is already installed:
Command
pip install llama-stack -U
2
Find models list
See latest available models by running the following command and determine the model ID you wish to download:
Command
llama model list
If you want older versions of models, run the command below to show all the available Llama models:
Command
llama model list --show-all
3
Select a model
Select a desired model by running:
Command
llama model download --source meta --model-id MODEL_ID
4
Specify custom URL
Llama 3.2: 11B & 90B
When the script asks for your unique custom URL, please paste the URL below
URL
https://llama3-2-multimodal.llamameta.net/*?Policy=eyJTdGF0ZW1lbnQiOlt7InVuaXF1ZV9oYXNoIjoibnE2b2RtMHhsdDNuN3E2MjIxbDV1ZGdiIiwiUmVzb3VyY2UiOiJodHRwczpcL1wvbGxhbWEzLTItbXVsdGltb2RhbC5sbGFtYW1ldGEubmV0XC8qIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzMyMDQ2NzE0fX19XX0_&Signature=Z5Yi7l35NqnXdGoWcvcuhyP73QtcFLngDgdz3aDlTtQcvwHMvgWoWqzQaUqAeiJ9jEFRE0K-C-gZIu8oEDoJN5P9e1EBXCa0ifOGdaft9bmjJR%7EhdFt-TaaUHNNHrwNcJp8AqQVPoHnSHtl06tKOVshzp3mW5YKn0cgfN5gl1Bs0rf2yh1Ai7uGL6B4oLoW93Xmub-4AvXdq6pwhEREx4inpd4M9N7dk6nIx0RXhUs%7EFSAdYLCMyZMJ0sQNcEDJmWHbjDVGlgXkzMA9Xf0cEmAA4na0CZVo66IJi-8FoZFk-g7s%7EEtAIqmBQbLqOJyu4R485CNGYIrJg4UHWNNOg6w__&Key-Pair-Id=K15QRJLYKIFSLZ&Download-Request-ID=1349359596051322
Please save copies of the unique custom URLs provided above, they will remain valid for 48 hours to download each model up to 5 times, and requests can be submitted multiple times. An email with the download instructions will also be sent to the email address you used to request the models.
Здравствуйте!
Спасибо, что обратили внимание на официальные инструкции по загрузке и установке модели Llama 3.2. Давайте обновим наш план действий и код, чтобы соответствовать этим инструкциям и обеспечить корректную работу вашего проекта.
Установите командную строку Llama с помощью pip:
bashpip install llama-stack
Если у вас уже установлена предыдущая версия, обновите ее:
bashpip install llama-stack -U
Чтобы увидеть список доступных моделей, выполните:
bashllama model list
Если вы хотите увидеть все доступные версии моделей, включая старые:
bashllama model list --show-all
Выберите нужную модель по MODEL_ID и загрузите ее:
bashllama model download --source meta --model-id MODEL_ID
Когда скрипт запросит ваш уникальный URL для загрузки модели, вставьте предоставленный вам URL:
https://llama3-2-multimodal.llamameta.net/... (ваш уникальный URL)
Примечание: Сохраните этот URL, он будет действителен в течение 48 часов для загрузки модели до 5 раз.
После установки llama-stack и загрузки модели, вы можете использовать API для взаимодействия с моделью.
server.pypython# server.py from flask import Flask, request, jsonify from llama import Llama app = Flask(__name__) # Загрузка модели Llama 3.2 model_path = 'path_to_downloaded_model' # Замените на путь к вашей загруженной модели llama = Llama(model_path=model_path) @app.route('/get_action', methods=['POST']) def get_action(): data = request.get_json() context = data.get('context', '') # Создаем подсказку для модели prompt = f"""Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием. Контекст: {context} Действие: """ # Генерация ответа output = llama.generate( prompt=prompt, max_tokens=100, stop=["\n", "Контекст:", "Действие:"] ) # Получаем сгенерированное действие action = output['choices'][0]['text'].strip() return jsonify({'action': action}) if __name__ == '__main__': app.run(port=5000)
Примечания:
'path_to_downloaded_model' на фактический путь к вашей модели.max_tokens, stop и т.д.) могут быть настроены в соответствии с вашими потребностями.server.pyУстановите необходимые библиотеки:
bashpip install flask pip install llama-stack
bot.jsВ bot.js изменений не требуется, если API взаимодействия с сервером остался прежним. Однако убедитесь, что ваш бот корректно взаимодействует с обновленным сервером.
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 25565, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 async function getLlamaResponse(context) { try { const response = await axios.post('http://localhost:5000/get_action', { context }); return response.data.action; } catch (error) { console.error('Ошибка при обращении к Llama 3.2:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(action) { action = action.toLowerCase(); if (action.includes('найти дерево')) { await findAndMineBlock('log'); } else if (action.includes('сделать инструменты')) { await craftTools(); } else if (action.includes('добыть камень')) { await findAndMineBlock('stone'); } else if (action.includes('сделать меч')) { await craftItem('stone_sword'); } else if (action.includes('поесть')) { await eatFood(); } else if (action.includes('исследовать')) { await explore(); } else { console.log('Неизвестное действие, ожидаю следующих инструкций...'); } } // Остальные функции (`findAndMineBlock`, `craftTools`, `craftItem`, `placeItem`, `eatFood`, `explore`) остаются без изменений из предыдущего ответа. // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Добавляем сообщение игрока в контекст const context = getBotContext() + `\n${username}: ${message}`; // Получаем ответ от модели const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия await processAction(action); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
server.pypython# server.py from flask import Flask, request, jsonify from llama import Llama app = Flask(__name__) # Загрузка модели Llama 3.2 model_path = 'path_to_downloaded_model' # Замените на путь к вашей загруженной модели llama = Llama(model_path=model_path) @app.route('/get_action', methods=['POST']) def get_action(): data = request.get_json() context = data.get('context', '') # Создаем подсказку для модели prompt = f"""Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием. Контекст: {context} Действие: """ # Генерация ответа response = llama.generate( prompt=prompt, max_tokens=100, stop=["\n", "Контекст:", "Действие:"], temperature=0.7 ) # Получаем сгенерированное действие action = response.strip() return jsonify({'action': action}) if __name__ == '__main__': app.run(port=5000)
Примечания:
llama.generate возвращает строку с ответом. Если API возвращает объект, возможно, потребуется изменить способ извлечения текста ответа.max_tokens, stop, temperature) могут быть настроены в соответствии с вашими потребностями и возможностями оборудования.llama-stack и других зависимостей.llama-stack для понимания всех возможностей и правильного использования API.bot.js и server.py для обнаружения и исправления возможных ошибок.Теперь, с обновленными инструкциями и кодом, вы сможете корректно установить и использовать модель Llama 3.2 в вашем проекте. Убедитесь, что вы следуете всем шагам и учитываете все примечания для успешной реализации.
Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой модели или отладкой кода, пожалуйста, обращайтесь!
This is an OpenAI-like call to the /v1/chat/completion endpoint using the curl utility.
To run it on Mac or Linux, use any terminal. On Windows, use
.
curl http://127.0.0.1:1234/v1/chat/completions
-H "Content-Type: application/json"
-d '{
"model": "fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo",
"messages": [
{ "role": "system", "content": "Always answer in rhymes." },
{ "role": "user", "content": "Introduce yourself." }
],
"temperature": 0.7,
"max_tokens": -1,
"stream": true
}'
The call is 'stateless', which means the server does not retain the conversation history. It is the caller's responsibility to provide the whole conversation history in every call.
Streaming vs. accumulating a full response
Notice the "stream": true parameter. When set to true, LM Studio will stream back tokens as they are predicted.
If this parameter is set to false, the full prediction will be accumulated before the call returns. For longer generations or slower models this might take a while!
это в LM Studio
Здравствуйте!
Похоже, вы хотите использовать LM Studio для работы с моделью Llama 3.2 и интегрировать её в ваш проект. Это отличный подход, так как LM Studio предоставляет API, совместимый с OpenAI API, что упрощает взаимодействие с моделью через HTTP-запросы.
Давайте обновим ваш проект, чтобы использовать LM Studio и взаимодействовать с моделью через API /v1/chat/completions.
Установка LM Studio: Убедитесь, что LM Studio установлен на вашем компьютере и модель Llama 3.2 загружена в LM Studio.
Запуск API-сервера: В LM Studio есть возможность запустить API-сервер, который будет принимать HTTP-запросы. Обычно сервер запускается по адресу http://127.0.0.1:1234.
Вы можете протестировать API-сервер с помощью команды curl:
bashcurl http://127.0.0.1:1234/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo", "messages": [ { "role": "system", "content": "Always answer in rhymes." }, { "role": "user", "content": "Introduce yourself." } ], "temperature": 0.7, "max_tokens": -1, "stream": true }'
bot.js для взаимодействия с LM Studio APIТеперь, вместо использования отдельного Python-сервера (server.py), мы можем непосредственно обращаться к LM Studio API из bot.js.
Если вы еще не установили библиотеку axios, установите её:
bashnpm install axios
getLlamaResponseОбновим функцию getLlamaResponse в bot.js, чтобы она отправляла запросы к LM Studio API:
javascript// Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 256, // Установите желаемое максимальное количество токенов stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } }
Поскольку LM Studio API ожидает историю сообщений, мы должны корректно формировать сообщения:
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 25565, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(action) { action = action.toLowerCase(); if (action.includes('найти дерево')) { await findAndMineBlock('log'); } else if (action.includes('сделать инструменты')) { await craftTools(); } else if (action.includes('добыть камень')) { await findAndMineBlock('stone'); } else if (action.includes('сделать меч')) { await craftItem('stone_sword'); } else if (action.includes('поесть')) { await eatFood(); } else if (action.includes('исследовать')) { await explore(); } else { console.log('Неизвестное действие, ожидаю следующих инструкций...'); } } // Остальные функции (`findAndMineBlock`, `craftTools`, `craftItem`, `placeItem`, `eatFood`, `explore`) остаются без изменений из предыдущего ответа. // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Формируем историю сообщений const messages = [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const action = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', action); // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия await processAction(action); }); // Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponseFromMessages(messages) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: messages, temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
server.pyПоскольку теперь мы взаимодействуем с моделью через LM Studio API, файл server.py больше не нужен и его можно удалить.
Запуск LM Studio: Убедитесь, что LM Studio запущен и API-сервер активен по адресу http://127.0.0.1:1234.
Запуск бота: Выполните в консоли:
bashnode bot.js
Взаимодействие с ботом: Подключитесь к вашему серверу Minecraft и взаимодействуйте с ботом через чат. Он должен отвечать и выполнять действия на основе контекста и ваших сообщений.
Отслеживание логов: Следите за выводом в консоли bot.js для отладки и обнаружения возможных ошибок.
Имя модели: Убедитесь, что в bot.js вы указали правильное имя модели в параметре "model". Оно должно соответствовать имени модели, доступной в LM Studio.
Параметры генерации: Вы можете настроить параметры temperature, max_tokens и stream для управления поведением модели.
processAction правильно обрабатывает возможные варианты ответов модели. Возможно, потребуется расширить её для поддержки большего количества действий.Задержки: Учтите, что при использовании больших моделей может возникать задержка между запросом и получением ответа. Это может повлиять на реакцию бота в игре.
Оптимизация: Рассмотрите возможность использования более лёгких моделей или оптимизации параметров генерации, если задержки становятся критичными.
Лицензионные соглашения: Убедитесь, что использование модели Llama 3.2 соответствует её лицензионным соглашениям и условиям использования.
Правила сервера: Если вы планируете использовать бота на публичном сервере, убедитесь, что его поведение не нарушает правила сервера и не мешает другим игрокам.
Теперь ваш бот напрямую взаимодействует с моделью Llama 3.2 через LM Studio API, что упрощает архитектуру проекта и облегчает интеграцию нейросети. Вы можете продолжать развивать бота, добавляя новые функции и улучшая его взаимодействие с игроками и игровым миром.
Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой или отладкой, пожалуйста, обращайтесь!
// bot.js
const mineflayer = require('mineflayer');
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder');
const { GoalBlock, GoalNear } = goals;
const axios = require('axios');
const mcData = require('minecraft-data')('1.20.1');
// Настройка бота
const bot = mineflayer.createBot({
host: 'localhost', // IP адрес сервера Minecraft
port: 25565, // Порт сервера Minecraft
username: 'AI_Bot', // Имя бота
version: '1.20.1' // Версия Minecraft
});
// Подключаем плагины
bot.loadPlugin(pathfinder);
// При подключении бота
bot.on('spawn', () => {
console.log('Бот успешно подключился к серверу!');
// Настройка движений бота
const defaultMove = new Movements(bot, mcData);
bot.pathfinder.setMovements(defaultMove);
// Начинаем основной цикл действий
mainLoop();
});
// Основной цикл действий бота
async function mainLoop() {
while (true) {
try {
// Получаем текущий контекст
const context = getBotContext();
text// Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); }
}
}
// Получение контекста бота
function getBotContext() {
const health = bot.health;
const food = bot.food;
const position = bot.entity.position;
const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', ');
const nearbyEntities = Object.values(bot.entities)
.filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16)
.map(entity => entity.name)
.join(', ');
const context = Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} ;
return context;
}
// Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponse(context) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: context }
],
temperature: 0.7,
max_tokens: 256,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Обработка действия от модели
async function processAction(action) {
action = action.toLowerCase();
if (action.includes('найти дерево')) {
await findAndMineBlock('log');
} else if (action.includes('сделать инструменты')) {
await craftTools();
} else if (action.includes('добыть камень')) {
await findAndMineBlock('stone');
} else if (action.includes('сделать меч')) {
await craftItem('stone_sword');
} else if (action.includes('поесть')) {
await eatFood();
} else if (action.includes('исследовать')) {
await explore();
} else {
console.log('Неизвестное действие, ожидаю следующих инструкций...');
}
}
// Остальные функции (findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore) остаются без изменений из предыдущего ответа.
// Обработка сообщений из чата
bot.on('chat', async (username, message) => {
if (username === bot.username) return;
console.log(${username}: ${message});
// Формируем историю сообщений
const messages = [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: getBotContext() },
{ role: 'user', content: ${username}: ${message} }
];
// Отправляем запрос к LM Studio API
const action = await getLlamaResponseFromMessages(messages);
console.log('Действие от Llama 3.2:', action);
// Отправляем ответ в чат
bot.chat(action);
// Обрабатываем возможные действия
await processAction(action);
});
// Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponseFromMessages(messages) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: messages,
temperature: 0.7,
max_tokens: 256,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Функция задержки
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Обработка ошибок
bot.on('error', (err) => {
console.error('Ошибка бота:', err);
});
bot.on('kicked', (reason) => {
console.warn('Бот был кикнут:', reason);
});
Можно ли добавь в корневой папке папку "MemoryAI" и в ней будут копиться советы за всё время. Типо чтобы после 1 запуска ИИ помнил и был более обучен
Здравствуйте!
Конечно, можно реализовать функцию, которая позволит боту запоминать советы от игроков между сессиями, сохраняя их в папке "MemoryAI". При запуске бота он будет читать накопленные советы и использовать их в дальнейшем, что сделает его более обученным и адаптивным.
Я обновлю ваш код, добавив эту функциональность, и подробно объясню, как это работает.
В начале файла bot.js добавим модули fs и path для работы с файловой системой:
javascriptconst fs = require('fs'); const path = require('path');
При запуске бота проверим, существует ли папка "MemoryAI". Если нет, создадим её:
javascript// Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); }
Добавьте этот код в начале файла bot.js, сразу после импортов модулей.
Создадим функции для сохранения советов в файл и загрузки их при запуске.
javascriptfunction saveAdvice(advice) { const adviceFile = path.join(memoryPath, 'advice.txt'); // Добавляем новый совет в конец файла fs.appendFileSync(adviceFile, advice + '\n', 'utf8'); }
javascriptfunction loadAdvice() { const adviceFile = path.join(memoryPath, 'advice.txt'); let advices = []; if (fs.existsSync(adviceFile)) { const data = fs.readFileSync(adviceFile, 'utf8'); advices = data.split('\n').filter(line => line.trim() !== ''); } return advices; }
Модифицируем функцию getBotContext, чтобы включить загруженные советы в контекст:
javascriptfunction getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText} `; return context; }
Модифицируем обработчик события chat, чтобы сохранять советы от игроков. Предположим, что игроки могут помечать свои сообщения как советы, начиная их с ключевого слова, например, "совет:".
javascriptbot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const action = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', action); // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия await processAction(action); });
Теперь, когда игрок отправляет сообщение, начинающееся с "совет:", бот сохранит это сообщение в файл advice.txt в папке "MemoryAI".
Функция getLlamaResponseFromMessages остается без изменений.
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 25565, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Функция для сохранения совета function saveAdvice(advice) { const adviceFile = path.join(memoryPath, 'advice.txt'); // Добавляем новый совет в конец файла fs.appendFileSync(adviceFile, advice + '\n', 'utf8'); } // Функция для загрузки советов function loadAdvice() { const adviceFile = path.join(memoryPath, 'advice.txt'); let advices = []; if (fs.existsSync(adviceFile)) { const data = fs.readFileSync(adviceFile, 'utf8'); advices = data.split('\n').filter(line => line.trim() !== ''); } return advices; } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponseFromMessages(messages) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: messages, temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(action) { action = action.toLowerCase(); if (action.includes('найти дерево')) { await findAndMineBlock('log'); } else if (action.includes('сделать инструменты')) { await craftTools(); } else if (action.includes('добыть камень')) { await findAndMineBlock('stone'); } else if (action.includes('сделать меч')) { await craftItem('stone_sword'); } else if (action.includes('поесть')) { await eatFood(); } else if (action.includes('исследовать')) { await explore(); } else { console.log('Неизвестное действие, ожидаю следующих инструкций...'); } } // Функции действий остаются без изменений из предыдущего ответа: // findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const action = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', action); // Отправляем ответ в чат bot.chat(action); // Обрабатываем возможные действия await processAction(action); }); // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
Импорт модулей fs и path: Это позволяет работать с файловой системой для чтения и записи файлов.
Создание папки "MemoryAI": При запуске бота проверяется наличие папки "MemoryAI". Если её нет, она создаётся. Все советы будут храниться в файле advice.txt внутри этой папки.
Функции saveAdvice и loadAdvice: Эти функции позволяют сохранять советы в файл и загружать их при запуске бота.
Модификация функции getBotContext: Теперь контекст бота включает загруженные советы, которые будут переданы модели для генерации более информированных ответов и действий.
Обработка сообщений из чата: Если сообщение от игрока начинается с "совет:", бот сохраняет этот совет и подтверждает игроку, что учтёт его в будущем.
Обработка больших файлов: Если советов накопится очень много, файл может стать большим. В этом случае можно рассмотреть ограничение количества загружаемых советов или хранение их в более эффективном формате.
Форматирование советов: Можно улучшить формат хранения советов, например, добавив дату и время или разделяя советы по категориям.
Безопасность: Убедитесь, что бот не хранит конфиденциальную информацию и что доступ к файлам ограничен в соответствии с требованиями безопасности.
Теперь ваш бот способен запоминать советы от игроков между сессиями, делая его более обученным и адаптивным. При каждом запуске он будет загружать накопленные советы из папки "MemoryAI" и использовать их в контексте для принятия решений.
Если у вас возникнут дополнительные вопросы или потребуется помощь с настройкой или расширением функциональности, пожалуйста, обращайтесь!
// bot.js
const mineflayer = require('mineflayer');
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder');
const { GoalBlock, GoalNear } = goals;
const axios = require('axios');
const mcData = require('minecraft-data')('1.20.1');
const fs = require('fs');
const path = require('path');
// Путь к папке MemoryAI
const memoryPath = path.join(__dirname, 'MemoryAI');
// Проверяем наличие папки MemoryAI
if (!fs.existsSync(memoryPath)) {
fs.mkdirSync(memoryPath);
}
// Настройка бота
const bot = mineflayer.createBot({
host: 'localhost', // IP адрес сервера Minecraft
port: 59449, // Порт сервера Minecraft
username: 'AI_Bot', // Имя бота
version: '1.20.1' // Версия Minecraft
});
// Подключаем плагины
bot.loadPlugin(pathfinder);
// При подключении бота
bot.on('spawn', () => {
console.log('Бот успешно подключился к серверу!');
// Настройка движений бота
const defaultMove = new Movements(bot, mcData);
bot.pathfinder.setMovements(defaultMove);
// Начинаем основной цикл действий
mainLoop();
});
// Функция задержки
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Основной цикл действий бота
async function mainLoop() {
while (true) {
try {
// Получаем текущий контекст
const context = getBotContext();
text// Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); }
}
}
// Функция для сохранения совета
function saveAdvice(advice) {
const adviceFile = path.join(memoryPath, 'advice.txt');
// Добавляем новый совет в конец файла
fs.appendFileSync(adviceFile, advice + '\n', 'utf8');
}
// Функция для загрузки советов
function loadAdvice() {
const adviceFile = path.join(memoryPath, 'advice.txt');
let advices = [];
if (fs.existsSync(adviceFile)) {
const data = fs.readFileSync(adviceFile, 'utf8');
advices = data.split('\n').filter(line => line.trim() !== '');
}
return advices;
}
// Получение контекста бота
function getBotContext() {
const health = bot.health;
const food = bot.food;
const position = bot.entity.position;
const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', ');
const nearbyEntities = Object.values(bot.entities)
.filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16)
.map(entity => entity.name)
.join(', ');
// Загружаем советы
const advices = loadAdvice();
const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов';
const context = Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText};
return context;
}
// Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponse(context) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: context }
],
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponseFromMessages(messages) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: messages,
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Обработка действия от модели
async function processAction(action) {
action = action.toLowerCase();
if (action.includes('найти дерево')) {
await findAndMineBlock('log');
} else if (action.includes('сделать инструменты')) {
await craftTools();
} else if (action.includes('добыть камень')) {
await findAndMineBlock('stone');
} else if (action.includes('сделать меч')) {
await craftItem('stone_sword');
} else if (action.includes('поесть')) {
await eatFood();
} else if (action.includes('исследовать')) {
await explore();
} else {
console.log('Неизвестное действие, ожидаю следующих инструкций...');
}
}
// Функции действий остаются без изменений из предыдущего ответа:
// findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore
// Обработка сообщений из чата
bot.on('chat', async (username, message) => {
if (username === bot.username) return;
console.log(${username}: ${message});
// Проверяем, является ли сообщение советом
if (message.toLowerCase().startsWith('совет:')) {
const advice = message.substring(6).trim();
saveAdvice(${username}: ${advice});
bot.chat(Спасибо за совет, ${username}! Я учту это в будущем.);
return;
}
// Формируем историю сообщений
const messages = [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: getBotContext() },
{ role: 'user', content: ${username}: ${message} }
];
// Отправляем запрос к LM Studio API
const action = await getLlamaResponseFromMessages(messages);
console.log('Действие от Llama 3.2:', action);
// Отправляем ответ в чат
bot.chat(action);
// Обрабатываем возможные действия
await processAction(action);
});
// Обработка ошибок
bot.on('error', (err) => {
console.error('Ошибка бота:', err);
});
bot.on('kicked', (reason) => {
console.warn('Бот был кикнут:', reason);
});
D:\NodeJs Projects\minecraft-ai-bot>node bot.js
(node:7236) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
Бот успешно подключился к серверу!
Feodseon: Hello
Feodseon: Привет ответь пж
Действие от Llama 3.2: На основе предоставленной информации следующая стратегия действий:
Поскольку я не голоден и у меня ничего в инвентаре, первым делом будет найти ресурсную точку. Я поднимаюсь выше surface level, чтобы лучше видно было окружающую среду.
Мой следующий шаг — выпрыгнуть из воды (если я находится над водой), чтобы получить больше пространства для перемещения и поиска ресурсов.
Неизвестное действие, ожидаю следующих инструкций...
Действие от Llama 3.2: Привет! Чем я могу вам помочь? Вы можете отдать мне команду, и я выполню ее.
Неизвестное действие, ожидаю следующих инструкций...
Feodseon: Привет можешь выживать
Действие от Llama 3.2: Действия:
Обоснование:
Есть проблема что ИИ ничего не делает просто стоит. Исправь это и действиями должен управлять сам ИИ.
Здравствуйте!
Проблема:
Ваш бот получает от модели Llama 3.2 ответы, которые не соответствуют ожидаемым фразам, и поэтому он не выполняет никакие действия. Функция processAction ищет в ответах модели конкретные фразы, такие как 'найти дерево', 'сделать инструменты' и т.д. Однако модель генерирует более общие и развернутые ответы, из-за чего бот не распознаёт действия и просто стоит на месте.
Указать модели конкретный формат вывода:
Чтобы бот мог легко распознать действия, нам нужно заставить модель выводить ответы в определённом формате. Например, мы можем попросить модель выводить действие в формате:
ACTION: <название действия>
Доступные действия:
find_treecraft_toolsmine_stonecraft_swordeat_foodexploreИзменить подсказку (prompt) для модели:
Обновим сообщение system в запросе к модели, чтобы она понимала, как формировать ответ.
Обновить функцию processAction для распознавания действий:
Теперь мы будем использовать регулярные выражения для извлечения действия из ответа модели.
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 59449, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const actionText = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', actionText); // Обрабатываем действие await processAction(actionText); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Функция для сохранения совета function saveAdvice(advice) { const adviceFile = path.join(memoryPath, 'advice.txt'); // Добавляем новый совет в конец файла fs.appendFileSync(adviceFile, advice + '\n', 'utf8'); } // Функция для загрузки советов function loadAdvice() { const adviceFile = path.join(memoryPath, 'advice.txt'); let advices = []; if (fs.existsSync(adviceFile)) { const data = fs.readFileSync(adviceFile, 'utf8'); advices = data.split('\n').filter(line => line.trim() !== ''); } return advices; } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'your-model-name', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие вы будете выполнять дальше, и выведите его в формате: ACTION: <действие>. Доступные действия: find_tree, craft_tools, mine_stone, craft_sword, eat_food, explore. Дайте краткое обоснование.' }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponseFromMessages(messages) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'your-model-name', // Замените на фактическое имя вашей модели messages: messages, temperature: 0.7, max_tokens: 256, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(actionText) { actionText = actionText.toLowerCase(); // Извлекаем действие из ответа модели const actionMatch = actionText.match(/action:\s*(\w+)/i); let action = ''; if (actionMatch) { action = actionMatch[1]; } else { console.log('Не удалось распознать действие из ответа модели.'); console.log('Ответ модели:', actionText); return; } switch (action) { case 'find_tree': await findAndMineBlock('log'); break; case 'craft_tools': await craftTools(); break; case 'mine_stone': await findAndMineBlock('stone'); break; case 'craft_sword': await craftItem('stone_sword'); break; case 'eat_food': await eatFood(); break; case 'explore': await explore(); break; default: console.log('Неизвестное действие:', action); break; } } // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщения от игрока решите, какое действие вы будете выполнять дальше, и выведите его в формате: ACTION: <действие>. Доступные действия: find_tree, craft_tools, mine_stone, craft_sword, eat_food, explore. Дайте краткое обоснование.' }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const actionText = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', actionText); // Извлекаем действие из ответа модели const actionMatch = actionText.match(/action:\s*(\w+)/i); let action = ''; if (actionMatch) { action = actionMatch[1]; } else { console.log('Не удалось распознать действие из ответа модели.'); console.log('Ответ модели:', actionText); return; } // Отправляем ответ в чат (если есть дополнительный текст) const replyText = actionText.replace(/action:\s*\w+/i, '').trim(); if (replyText) { bot.chat(replyText); } // Обрабатываем действие await processAction(actionText); }); // Остальные функции действий (findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore) остаются без изменений. // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
Изменение подсказки для модели:
system в функциях getLlamaResponse и getLlamaResponseFromMessages, добавив чёткую инструкцию модели выводить действие в формате ACTION: <действие>.Извлечение действия из ответа модели:
processAction мы используем регулярное выражение actionMatch = actionText.match(/action:\s*(\w+)/i); для извлечения действия.Обработка ответов в чате:
bot.on('chat', ...) мы аналогичным образом извлекаем действие из ответа модели.Проверьте имя модели: Убедитесь, что в параметре model указано правильное имя вашей модели в LM Studio.
Тестирование:
Улучшение модели:
temperature для более предсказуемых ответов.Расширение набора действий:
Ответ модели:
textACTION: find_tree Обоснование: У меня пустой инвентарь и нет ресурсов. Первым делом мне нужно найти дерево, чтобы собрать древесину для создания базовых инструментов.
Действия бота:
findAndMineBlock('log');, то есть ищет ближайшее дерево и добывает его.Вывод в консоли:
textДействие от Llama 3.2: ACTION: find_tree Обоснование: У меня пустой инвентарь и нет ресурсов. Первым делом мне нужно найти дерево, чтобы собрать древесину для создания базовых инструментов.
Теперь ваш бот должен правильно распознавать действия из ответов модели и выполнять соответствующие функции. Если у вас возникнут дополнительные вопросы или потребуется помощь с отладкой, пожалуйста, обращайтесь!
Примечание: Всегда следите за тем, чтобы модель выводила ответы в ожидаемом формате. Если модель отклоняется от заданного формата, попробуйте уточнить подсказку или настроить параметры генерации.
Как сделать чтобы ИИ мог выполнять любые действия и сам контролировал? Это невозможно?
Здравствуйте!
Вопрос:
Как сделать, чтобы ИИ мог выполнять любые действия и сам контролировал? Это невозможно?
Ответ:
Реализовать полностью автономного ИИ-агента в Minecraft, который самостоятельно контролирует все свои действия, возможно, но это требует более сложного подхода и учитывает несколько факторов:
Расширение набора действий и API:
Вместо ограниченного набора предопределенных действий, вы можете предоставить боту более широкий интерфейс команд, которые он может выполнять.
Интерпретация и безопасность:
Позволить ИИ генерировать произвольные команды или код для выполнения может быть рискованно. Поэтому важно иметь механизм для безопасного исполнения этих команд.
Обработка естественного языка:
Использование методов обработки естественного языка (NLP) для преобразования текстовых инструкций от ИИ в конкретные действия бота.
Давайте рассмотрим, как можно расширить возможности бота и дать ИИ больше контроля над его действиями.
Вместо ограниченного набора действий, таких как find_tree или craft_tools, вы можете разработать систему, которая принимает более широкий спектр команд.
Пример:
move_to x y z — перемещение к определенным координатам.attack entity_name — атака на определенного моба.craft item_name — крафт указанного предмета.say message — отправка сообщения в чат.collect resource_name — сбор определенного ресурса.Измените подсказку, чтобы ИИ генерировал команды в определенном формате.
Пример подсказки:
textВы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> - ... Контекст: ...
Разработайте функцию, которая будет парсить команды из ответа ИИ и выполнять соответствующие действия.
Пример:
javascriptasync function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); switch (args[0]) { case 'move_to': const x = parseFloat(args[1]); const y = parseFloat(args[2]); const z = parseFloat(args[3]); await moveToPosition(x, y, z); break; case 'attack': const entityName = args.slice(1).join(' '); await attackEntity(entityName); break; case 'craft': const itemName = args.slice(1).join(' '); await craftItem(itemName); break; case 'say': const message = args.slice(1).join(' '); bot.chat(message); break; case 'collect': const resourceName = args.slice(1).join(' '); await collectResource(resourceName); break; default: console.log('Неизвестная команда:', command); break; } }
Важно убедиться, что команды безопасны и не приведут к ошибкам или непредвиденным последствиям.
Если вы хотите, чтобы ИИ мог генерировать действия в более свободной форме, вы можете использовать NLP для преобразования текста в команды.
Пример:
Ответ ИИ: "Мне нужно добыть немного железа и сделать железный меч."
Парсинг: Используйте NLP-библиотеку для извлечения намерений и сущностей из текста.
Выполнение: Преобразуйте намерения в конкретные команды для бота.
Вы можете использовать библиотеки, такие как spaCy, Natural или Compromise, для обработки текста и извлечения намерений.
Пример с использованием Compromise:
javascriptconst nlp = require('compromise'); function parseNaturalLanguage(text) { const doc = nlp(text); // Пример простого парсинга if (doc.has('добыть [#Noun]')) { const resource = doc.match('добыть [#Noun]').terms(1).text(); return { action: 'collect', target: resource }; } // Добавьте дополнительные правила парсинга return null; }
Обновите функцию processAction, чтобы она могла обрабатывать как структурированные команды, так и естественный язык.
javascriptasync function processAction(actionText) { // Попытка парсинга команды const commandMatch = actionText.match(/command:\s*(.*)/i); if (commandMatch) { const command = commandMatch[1].trim(); await processCommand(command); } else { // Попытка парсинга естественного языка const parsed = parseNaturalLanguage(actionText); if (parsed) { await executeParsedAction(parsed); } else { console.log('Не удалось распознать действие из ответа модели.'); } } }
Внимание: Этот подход требует особой осторожности и тщательной обработки безопасности.
Вы можете настроить модель так, чтобы она генерировала код на JavaScript или псевдокод, который бот будет исполнять.
Пример подсказки:
textВы — ИИ-агент в Minecraft. На основе контекста решите, какие действия выполнить дальше, и выведите код JavaScript, который выполнит эти действия. Оборачивайте код в теги <code></code>. Контекст: ...
Важно: Никогда не выполняйте сгенерированный код без проверок, так как это может привести к выполнению вредоносных действий.
Пример с использованием VM2:
javascriptconst { VM } = require('vm2'); async function processAction(actionText) { const codeMatch = actionText.match(/<code>([\s\S]*?)<\/code>/i); if (codeMatch) { const code = codeMatch[1]; const vm = new VM({ timeout: 1000, sandbox: { bot, mineflayer, mcData, // Добавьте только те объекты и функции, которые необходимы } }); try { await vm.run(`(async () => { ${code} })()`); } catch (err) { console.error('Ошибка при выполнении сгенерированного кода:', err); } } else { console.log('Не удалось найти сгенерированный код в ответе модели.'); } }
Предостережение: Этот метод может быть небезопасным и использоваться только в контролируемой среде.
Баланс между свободой и безопасностью: Предоставление ИИ полной свободы действий требует тщательного управления рисками.
Тестирование и отладка: Постоянно тестируйте бота в безопасной среде, чтобы убедиться, что он ведет себя так, как ожидается.
Уточнение подсказок: Экспериментируйте с различными подсказками для модели, чтобы получить желаемое поведение.
Ограничение ресурсов: Убедитесь, что бот не расходует ресурсы сервера или не создает нагрузку.
Реализовать ИИ-агента, который полностью контролирует свои действия в Minecraft, возможно, но требует более сложного подхода и тщательного управления безопасностью. Вам нужно:
Если у вас есть дополнительные вопросы или вам нужна помощь с конкретными аспектами реализации, пожалуйста, обращайтесь! Я с радостью помогу вам продвинуться дальше в вашем проекте.
// bot.js
const mineflayer = require('mineflayer');
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder');
const { GoalBlock, GoalNear } = goals;
const axios = require('axios');
const mcData = require('minecraft-data')('1.20.1');
const fs = require('fs');
const path = require('path');
// Путь к папке MemoryAI
const memoryPath = path.join(__dirname, 'MemoryAI');
// Проверяем наличие папки MemoryAI
if (!fs.existsSync(memoryPath)) {
fs.mkdirSync(memoryPath);
}
// Настройка бота
const bot = mineflayer.createBot({
host: 'localhost', // IP адрес сервера Minecraft
port: 59449, // Порт сервера Minecraft
username: 'AI_Bot', // Имя бота
version: '1.20.1' // Версия Minecraft
});
// Подключаем плагины
bot.loadPlugin(pathfinder);
// При подключении бота
bot.on('spawn', () => {
console.log('Бот успешно подключился к серверу!');
// Настройка движений бота
const defaultMove = new Movements(bot, mcData);
bot.pathfinder.setMovements(defaultMove);
// Начинаем основной цикл действий
mainLoop();
});
// Функция задержки
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Основной цикл действий бота
async function mainLoop() {
while (true) {
try {
// Получаем текущий контекст
const context = getBotContext();
text// Отправляем контекст модели и получаем действие const action = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', action); // Обрабатываем действие await processAction(action); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); }
}
}
// Функция для сохранения совета
function saveAdvice(advice) {
const adviceFile = path.join(memoryPath, 'advice.txt');
// Добавляем новый совет в конец файла
fs.appendFileSync(adviceFile, advice + '\n', 'utf8');
}
// Функция для загрузки советов
function loadAdvice() {
const adviceFile = path.join(memoryPath, 'advice.txt');
let advices = [];
if (fs.existsSync(adviceFile)) {
const data = fs.readFileSync(adviceFile, 'utf8');
advices = data.split('\n').filter(line => line.trim() !== '');
}
return advices;
}
// Получение контекста бота
function getBotContext() {
const health = bot.health;
const food = bot.food;
const position = bot.entity.position;
const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', ');
const nearbyEntities = Object.values(bot.entities)
.filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16)
.map(entity => entity.name)
.join(', ');
// Загружаем советы
const advices = loadAdvice();
const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов';
const context = Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText};
return context;
}
// Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponse(context) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: context }
],
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponseFromMessages(messages) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: messages,
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const action = response.data.choices[0].message.content.trim(); return action;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Обработка действия от модели
async function processAction(action) {
action = action.toLowerCase();
if (action.includes('найти дерево')) {
await findAndMineBlock('log');
} else if (action.includes('сделать инструменты')) {
await craftTools();
} else if (action.includes('добыть камень')) {
await findAndMineBlock('stone');
} else if (action.includes('сделать меч')) {
await craftItem('stone_sword');
} else if (action.includes('поесть')) {
await eatFood();
} else if (action.includes('исследовать')) {
await explore();
} else {
console.log('Неизвестное действие, ожидаю следующих инструкций...');
}
}
// Функции действий остаются без изменений из предыдущего ответа:
// findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore
// Обработка сообщений из чата
bot.on('chat', async (username, message) => {
if (username === bot.username) return;
console.log(${username}: ${message});
// Проверяем, является ли сообщение советом
if (message.toLowerCase().startsWith('совет:')) {
const advice = message.substring(6).trim();
saveAdvice(${username}: ${advice});
bot.chat(Спасибо за совет, ${username}! Я учту это в будущем.);
return;
}
// Формируем историю сообщений
const messages = [
{ role: 'system', content: 'Вы — ИИ-агент в Minecraft. На основе контекста и сообщений от игрока опишите, какие действия вы будете выполнять дальше, с кратким обоснованием.' },
{ role: 'user', content: getBotContext() },
{ role: 'user', content: ${username}: ${message} }
];
// Отправляем запрос к LM Studio API
const action = await getLlamaResponseFromMessages(messages);
console.log('Действие от Llama 3.2:', action);
// Отправляем ответ в чат
bot.chat(action);
// Обрабатываем возможные действия
await processAction(action);
});
// Обработка ошибок
bot.on('error', (err) => {
console.error('Ошибка бота:', err);
});
bot.on('kicked', (reason) => {
console.warn('Бот был кикнут:', reason);
});
Добавь Доступные команды:
Здравствуйте!
Я понимаю, что вы хотите расширить функциональность вашего бота, добавив новые команды, такие как:
move_to x y zattack <entity_name>craft <item_name>say <message>collect <resource_name>Также вы хотите, чтобы ИИ мог добавлять свои собственные команды, если он захочет выполнить что-то, чего нет в списке доступных команд.
Я обновлю ваш код, чтобы реализовать эти требования, и объясню внесённые изменения.
Изменим сообщение system в запросах к модели, чтобы она знала о новых командах и о том, что может создавать новые команды при необходимости.
system:textВы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.
Создадим функцию processCommand, которая будет парсить и выполнять команды, а также обрабатывать новые команды, созданные ИИ.
processCommand:javascriptasync function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); const primaryCommand = args[0]; const commandArgs = args.slice(1); switch (primaryCommand) { case 'move_to': if (commandArgs.length === 3) { const x = parseFloat(commandArgs[0]); const y = parseFloat(commandArgs[1]); const z = parseFloat(commandArgs[2]); await moveToPosition(x, y, z); } else { console.log('Неверные аргументы для команды move_to.'); } break; case 'attack': const entityName = commandArgs.join(' '); await attackEntity(entityName); break; case 'craft': const itemName = commandArgs.join(' '); await craftItem(itemName); break; case 'say': const message = commandArgs.join(' '); bot.chat(message); break; case 'collect': const resourceName = commandArgs.join(' '); await collectResource(resourceName); break; default: // Обработка новых команд, придуманных ИИ console.log(`Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')}`); // Вы можете добавить обработку новых команд здесь break; } }
processActionОбновим функцию processAction, чтобы использовать processCommand и обрабатывать команды из ответа модели.
javascriptasync function processAction(actionText) { actionText = actionText.toLowerCase(); // Извлекаем команду из ответа модели const commandMatch = actionText.match(/command:\s*(.*)/i); if (commandMatch) { const command = commandMatch[1].trim(); await processCommand(`command: ${command}`); } else { console.log('Не удалось распознать команду из ответа модели.'); console.log('Ответ модели:', actionText); } }
moveToPositionjavascriptasync function moveToPosition(x, y, z) { try { await bot.pathfinder.goto(new GoalBlock(x, y, z)); console.log(`Переместился к координатам (${x}, ${y}, ${z}).`); } catch (err) { console.error('Ошибка при перемещении:', err); } }
attackEntityjavascriptasync function attackEntity(entityName) { const entity = bot.nearestEntity(entity => entity.name === entityName && entity.type === 'mob'); if (entity) { try { await bot.pathfinder.goto(new GoalNear(entity.position.x, entity.position.y, entity.position.z, 1)); bot.attack(entity); console.log(`Атакую ${entityName}.`); } catch (err) { console.error('Ошибка при атаке на сущность:', err); } } else { console.log(`Сущность ${entityName} не найдена поблизости.`); } }
collectResourcejavascriptasync function collectResource(resourceName) { const blockType = mcData.blocksByName[resourceName]; if (!blockType) { console.log(`Ресурс с именем ${resourceName} не найден в данных Minecraft.`); return; } await findAndMineBlock(resourceName); }
Обновим обработчик событий чата, чтобы использовать новые команды и обновлённую подсказку.
javascriptbot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста и сообщения от игрока решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const actionText = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', actionText); // Отправляем обоснование в чат (если есть) const explanation = actionText.replace(/command:\s*.*\n?/i, '').trim(); if (explanation) { bot.chat(explanation); } // Обрабатываем действие await processAction(actionText); });
getLlamaResponseУбедимся, что обновили подсказку в функции getLlamaResponse для основного цикла.
javascriptasync function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 8000, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } }
Поскольку вы хотите, чтобы ИИ мог добавлять свои собственные команды, нам нужно обеспечить безопасное выполнение этих команд.
Важно: Позволять ИИ выполнять произвольные команды может быть небезопасно. Убедитесь, что вы тщательно обрабатываете такие команды и ограничиваете возможности выполнения вредоносных или опасных действий.
В текущем коде, если ИИ предлагает новую команду, которая не распознана, вы можете логировать её и решить, как её обработать.
Пример:
javascriptdefault: console.log(`Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')}`); // Здесь вы можете решить, как обработать новую команду // Например, можно добавить её в список доступных команд break;
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 59449, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const actionText = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', actionText); // Обрабатываем действие await processAction(actionText); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Функция для сохранения совета function saveAdvice(advice) { const adviceFile = path.join(memoryPath, 'advice.txt'); // Добавляем новый совет в конец файла fs.appendFileSync(adviceFile, advice + '\n', 'utf8'); } // Функция для загрузки советов function loadAdvice() { const adviceFile = path.join(memoryPath, 'advice.txt'); let advices = []; if (fs.existsSync(adviceFile)) { const data = fs.readFileSync(adviceFile, 'utf8'); advices = data.split('\n').filter(line => line.trim() !== ''); } return advices; } // Получение контекста бота function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Советы от игроков: ${adviceText} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 8000, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponseFromMessages(messages) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: messages, temperature: 0.7, max_tokens: 8000, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(actionText) { actionText = actionText.toLowerCase(); // Извлекаем команду из ответа модели const commandMatch = actionText.match(/command:\s*(.*)/i); if (commandMatch) { const command = commandMatch[1].trim(); await processCommand(`command: ${command}`); } else { console.log('Не удалось распознать команду из ответа модели.'); console.log('Ответ модели:', actionText); } } // Функция для обработки команд async function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); const primaryCommand = args[0]; const commandArgs = args.slice(1); switch (primaryCommand) { case 'move_to': if (commandArgs.length === 3) { const x = parseFloat(commandArgs[0]); const y = parseFloat(commandArgs[1]); const z = parseFloat(commandArgs[2]); await moveToPosition(x, y, z); } else { console.log('Неверные аргументы для команды move_to.'); } break; case 'attack': const entityName = commandArgs.join(' '); await attackEntity(entityName); break; case 'craft': const itemName = commandArgs.join(' '); await craftItem(itemName); break; case 'say': const message = commandArgs.join(' '); bot.chat(message); break; case 'collect': const resourceName = commandArgs.join(' '); await collectResource(resourceName); break; default: console.log(`Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')}`); // Обработка новых команд break; } } // Реализация новых команд async function moveToPosition(x, y, z) { try { await bot.pathfinder.goto(new GoalBlock(x, y, z)); console.log(`Переместился к координатам (${x}, ${y}, ${z}).`); } catch (err) { console.error('Ошибка при перемещении:', err); } } async function attackEntity(entityName) { const entity = bot.nearestEntity(entity => entity.name === entityName && entity.type === 'mob'); if (entity) { try { await bot.pathfinder.goto(new GoalNear(entity.position.x, entity.position.y, entity.position.z, 1)); bot.attack(entity); console.log(`Атакую ${entityName}.`); } catch (err) { console.error('Ошибка при атаке на сущность:', err); } } else { console.log(`Сущность ${entityName} не найдена поблизости.`); } } async function collectResource(resourceName) { const blockType = mcData.blocksByName[resourceName]; if (!blockType) { console.log(`Ресурс с именем ${resourceName} не найден в данных Minecraft.`); return; } await findAndMineBlock(resourceName); } // Остальные функции действий (findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore) остаются без изменений. // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста и сообщения от игрока решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const actionText = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', actionText); // Отправляем обоснование в чат (если есть) const explanation = actionText.replace(/command:\s*.*\n?/i, '').trim(); if (explanation) { bot.chat(explanation); } // Обрабатываем действие await processAction(actionText); }); // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
Имя модели: Убедитесь, что вы указали правильное имя модели в параметре model.
Тестирование: Запустите бота и проверьте, как он реагирует на различные ситуации. Посмотрите, генерирует ли модель команды в нужном формате и выполняет ли бот соответствующие действия.
Логирование: Следите за выводом в консоли, чтобы отлавливать возможные ошибки или неожиданные поведения.
Безопасность: Позволять ИИ генерировать и выполнять новые команды может быть рискованно. Убедитесь, что бот не может выполнить потенциально вредоносные действия.
Ограничения: Вы можете установить ограничения на то, какие новые команды может использовать ИИ, или добавить механизм одобрения новых команд.
Теперь ваш бот имеет расширенный набор команд и может обрабатывать новые команды, предложенные ИИ. Это делает его более гибким и автономным. Помните о безопасности и старайтесь контролировать, какие действия может выполнять бот.
Если у вас возникнут дополнительные вопросы или потребуется помощь с дальнейшей настройкой, пожалуйста, обращайтесь!
Добавь чтобы ИИпоказывалась информация о блоках в радиусе поля зрения
Здравствуйте!
Я понимаю, что вы хотите расширить контекст, который отправляется ИИ-модели, чтобы включить информацию о блоках, находящихся в поле зрения или в определённом радиусе вокруг бота. Это позволит модели лучше понимать окружающую среду и принимать более информированные решения.
Я обновлю ваш код, добавив эту функциональность, и объясню все внесённые изменения.
Чтобы предоставить ИИ информацию о блоках в поле зрения или в определённом радиусе вокруг бота, нам нужно:
getBotContext()Мы модифицируем функцию getBotContext(), чтобы добавить информацию о ближайших блоках.
Например, мы можем выбрать радиус в 5 блоков.
javascriptconst BLOCK_SEARCH_RADIUS = 5;
Мы можем использовать метод bot.findBlocks() из библиотеки Mineflayer для получения блоков в заданном радиусе.
Однако, bot.findBlocks() возвращает только позиции блоков. Чтобы получить информацию о самих блоках, нам нужно использовать bot.blockAt().
javascriptfunction getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; // Получаем информацию о ближайших блоках const blocksInView = getBlocksInView(BLOCK_SEARCH_RADIUS); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Блоки в радиусе ${BLOCK_SEARCH_RADIUS} блоков: ${blocksInView} Советы от игроков: ${adviceText} `; return context; }
getBlocksInView(radius)Создадим функцию, которая возвращает строку с описанием блоков в заданном радиусе.
javascriptfunction getBlocksInView(radius) { const blocks = []; const botPosition = bot.entity.position; // Определяем границы поиска const minX = Math.floor(botPosition.x - radius); const maxX = Math.floor(botPosition.x + radius); const minY = Math.floor(botPosition.y - radius); const maxY = Math.floor(botPosition.y + radius); const minZ = Math.floor(botPosition.z - radius); const maxZ = Math.floor(botPosition.z + radius); for (let x = minX; x <= maxX; x++) { for (let y = minY; y <= maxY; y++) { for (let z = minZ; z <= maxZ; z++) { const block = bot.blockAt(new Vec3(x, y, z)); if (block && block.name !== 'air') { blocks.push({ name: block.displayName || block.name, position: `x=${x}, y=${y}, z=${z}` }); } } } } // Ограничиваем количество блоков для удобства (например, до 20) const maxBlocks = 20; const blockDescriptions = blocks.slice(0, maxBlocks).map(block => `${block.name} (${block.position})`); return blockDescriptions.join('\n') || 'Нет блоков в радиусе'; }
Примечание: Не забудьте импортировать Vec3 из библиотеки Mineflayer.
javascriptconst { Vec3 } = require('vec3');
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); const { Vec3 } = require('vec3'); // Добавлено для работы с векторами // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Константы const BLOCK_SEARCH_RADIUS = 5; // Радиус поиска блоков // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 59449, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Остальной код остаётся без изменений... // Функция для получения информации о блоках в радиусе function getBlocksInView(radius) { const blocks = []; const botPosition = bot.entity.position; // Определяем границы поиска const minX = Math.floor(botPosition.x - radius); const maxX = Math.floor(botPosition.x + radius); const minY = Math.floor(botPosition.y - radius); const maxY = Math.floor(botPosition.y + radius); const minZ = Math.floor(botPosition.z - radius); const maxZ = Math.floor(botPosition.z + radius); for (let x = minX; x <= maxX; x++) { for (let y = minY; y <= maxY; y++) { for (let z = minZ; z <= maxZ; z++) { const block = bot.blockAt(new Vec3(x, y, z)); if (block && block.name !== 'air') { blocks.push({ name: block.displayName || block.name, position: `x=${x}, y=${y}, z=${z}` }); } } } } // Ограничиваем количество блоков для удобства (например, до 20) const maxBlocks = 20; const blockDescriptions = blocks.slice(0, maxBlocks).map(block => `${block.name} (${block.position})`); return blockDescriptions.join('\n') || 'Нет блоков в радиусе'; } // Обновляем функцию getBotContext() function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; // Получаем информацию о ближайших блоках const blocksInView = getBlocksInView(BLOCK_SEARCH_RADIUS); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Блоки в радиусе ${BLOCK_SEARCH_RADIUS} блоков: ${blocksInView} Советы от игроков: ${adviceText} `; return context; } // Остальной код остаётся без изменений...
В мире Minecraft очень много блоков, и если мы будем передавать информацию обо всех блоках в радиусе, это может привести к слишком большому объёму данных и перегрузить модель ИИ. Поэтому мы ограничили количество блоков до 20 (можете изменить maxBlocks по своему усмотрению).
Вы можете отфильтровать блоки по определённым критериям, например, передавать только интересующие блоки (дерево, руда, сундуки и т.д.).
Пример фильтрации только ресурсов:
javascriptfunction getBlocksInView(radius) { const blocks = []; const botPosition = bot.entity.position; // Определяем границы поиска const minX = Math.floor(botPosition.x - radius); const maxX = Math.floor(botPosition.x + radius); const minY = Math.floor(botPosition.y - radius); const maxY = Math.floor(botPosition.y + radius); const minZ = Math.floor(botPosition.z - radius); const maxZ = Math.floor(botPosition.z + radius); for (let x = minX; x <= maxX; x++) { for (let y = minY; y <= maxY; y++) { for (let z = minZ; z <= maxZ; z++) { const block = bot.blockAt(new Vec3(x, y, z)); if (block && block.name !== 'air') { // Фильтруем только интересующие блоки if (['log', 'stone', 'iron_ore', 'coal_ore'].includes(block.name)) { blocks.push({ name: block.displayName || block.name, position: `x=${x}, y=${y}, z=${z}` }); } } } } } // Остальной код остаётся без изменений... }
Проход по всем блокам в радиусе может быть ресурсоёмким. Чтобы улучшить производительность, можно:
y (например, только на уровне бота).Пример ограничения по высоте:
javascriptconst minY = Math.floor(botPosition.y - 1); const maxY = Math.floor(botPosition.y + 2); // Проверяем только уровни на высоте бота
Поскольку мы добавили новую информацию в контекст, модель будет иметь больше данных для принятия решений.
Убедитесь, что в вашем сообщении system модель знает о том, что в контексте есть информация о блоках.
Пример:
javascript{ role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Контекст содержит информацию о вашем здоровье, сытости, позиции, инвентаре, ближайших мобах и блоках в радиусе видимости. Пожалуйста, дайте краткое обоснование вашего выбора.` }
getBlocksInView().Если вы хотите получить блоки именно в поле зрения бота, а не просто в радиусе, вы можете использовать методы трассировки лучей.
Пример:
javascriptfunction getBlocksInLineOfSight() { const blocks = []; const maxDistance = 10; // Максимальная дистанция поиска const cursor = bot.blockAtCursor(maxDistance); if (cursor) { blocks.push({ name: cursor.displayName || cursor.name, position: `x=${cursor.position.x}, y=${cursor.position.y}, z=${cursor.position.z}` }); } return blocks.map(block => `${block.name} (${block.position})`).join('\n') || 'Нет блоков в поле зрения'; }
И в функции getBotContext() замените:
javascript// Получаем информацию о ближайших блоках const blocksInView = getBlocksInLineOfSight();
Примечание: Метод bot.blockAtCursor() возвращает блок, на который бот смотрит в данный момент.
Если вы хотите получить блоки в направлении, куда смотрит бот, можно использовать математические вычисления на основе вектора взгляда бота.
Теперь ваш бот будет передавать ИИ-модели информацию о блоках в радиусе вокруг него или в его поле зрения. Это позволит модели принимать более информированные решения, учитывая окружающую среду бота.
Если у вас возникнут дополнительные вопросы или потребуется помощь с оптимизацией или расширением функциональности, пожалуйста, обращайтесь!
Важно: Всегда следите за производительностью и корректностью работы бота после внесения изменений. Тестируйте в контролируемой среде, чтобы убедиться, что всё работает как ожидается.
// bot.js
const mineflayer = require('mineflayer');
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder');
const { GoalBlock, GoalNear } = goals;
const axios = require('axios');
const mcData = require('minecraft-data')('1.20.1');
const fs = require('fs');
const path = require('path');
const { Vec3 } = require('vec3'); // Добавлено для работы с векторами
// Путь к папке MemoryAI
const memoryPath = path.join(__dirname, 'MemoryAI');
// Проверяем наличие папки MemoryAI
if (!fs.existsSync(memoryPath)) {
fs.mkdirSync(memoryPath);
}
// Константы
const BLOCK_SEARCH_RADIUS = 5; // Радиус поиска блоков
// Настройка бота
const bot = mineflayer.createBot({
host: 'localhost', // IP адрес сервера Minecraft
port: 59449, // Порт сервера Minecraft
username: 'AI_Bot', // Имя бота
version: '1.20.1' // Версия Minecraft
});
// Подключаем плагины
bot.loadPlugin(pathfinder);
// При подключении бота
bot.on('spawn', () => {
console.log('Бот успешно подключился к серверу!');
// Настройка движений бота
const defaultMove = new Movements(bot, mcData);
bot.pathfinder.setMovements(defaultMove);
// Начинаем основной цикл действий
mainLoop();
});
// Остальной код остаётся без изменений...
// Функция для получения информации о блоках в радиусе
function getBlocksInView(radius) {
const blocks = [];
const botPosition = bot.entity.position;
// Определяем границы поиска
const minX = Math.floor(botPosition.x - radius);
const maxX = Math.floor(botPosition.x + radius);
const minY = Math.floor(botPosition.y - radius);
const maxY = Math.floor(botPosition.y + radius);
const minZ = Math.floor(botPosition.z - radius);
const maxZ = Math.floor(botPosition.z + radius);
for (let x = minX; x <= maxX; x++) {
for (let y = minY; y <= maxY; y++) {
for (let z = minZ; z <= maxZ; z++) {
const block = bot.blockAt(new Vec3(x, y, z));
if (block && block.name !== 'air') {
blocks.push({
name: block.displayName || block.name,
position: x=${x}, y=${y}, z=${z}
});
}
}
}
}
// Ограничиваем количество блоков для удобства (например, до 20)
const maxBlocks = 20;
const blockDescriptions = blocks.slice(0, maxBlocks).map(block => ${block.name} (${block.position}));
return blockDescriptions.join('\n') || 'Нет блоков в радиусе';
}
// Обновляем функцию getBotContext()
function getBotContext() {
const health = bot.health;
const food = bot.food;
const position = bot.entity.position;
const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', ');
const nearbyEntities = Object.values(bot.entities)
.filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16)
.map(entity => entity.name)
.join(', ');
// Загружаем советы
const advices = loadAdvice();
const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов';
// Получаем информацию о ближайших блоках
const blocksInView = getBlocksInView(BLOCK_SEARCH_RADIUS);
const context = Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Блоки в радиусе ${BLOCK_SEARCH_RADIUS} блоков: ${blocksInView} Советы от игроков: ${adviceText};
return context;
}
// Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponse(context) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: [
{
role: 'system',
content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате:
COMMAND: <команда>
Доступные команды:
Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её.
Пожалуйста, дайте краткое обоснование вашего выбора.`
},
{ role: 'user', content: context }
],
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API
async function getLlamaResponseFromMessages(messages) {
try {
const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', {
model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели
messages: messages,
temperature: 0.7,
max_tokens: 8000,
stream: false
}, {
headers: {
'Content-Type': 'application/json'
}
});
text// Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText;
} catch (error) {
console.error('Ошибка при обращении к LM Studio API:', error);
return 'Я не знаю, что делать.';
}
}
// Обработка действия от модели
async function processAction(actionText) {
actionText = actionText.toLowerCase();
// Извлекаем команду из ответа модели
const commandMatch = actionText.match(/command:\s*(.*)/i);
if (commandMatch) {
const command = commandMatch[1].trim();
await processCommand(command: ${command});
} else {
console.log('Не удалось распознать команду из ответа модели.');
console.log('Ответ модели:', actionText);
}
}
// Функция для обработки команд
async function processCommand(commandText) {
const commandMatch = commandText.match(/command:\s*(.*)/i);
if (!commandMatch) {
console.log('Не удалось распознать команду из ответа модели.');
return;
}
const command = commandMatch[1].trim();
const args = command.split(' ');
const primaryCommand = args[0];
const commandArgs = args.slice(1);
switch (primaryCommand) {
case 'move_to':
if (commandArgs.length === 3) {
const x = parseFloat(commandArgs[0]);
const y = parseFloat(commandArgs[1]);
const z = parseFloat(commandArgs[2]);
await moveToPosition(x, y, z);
} else {
console.log('Неверные аргументы для команды move_to.');
}
break;
case 'attack':
const entityName = commandArgs.join(' ');
await attackEntity(entityName);
break;
case 'craft':
const itemName = commandArgs.join(' ');
await craftItem(itemName);
break;
case 'say':
const message = commandArgs.join(' ');
bot.chat(message);
break;
case 'collect':
const resourceName = commandArgs.join(' ');
await collectResource(resourceName);
break;
default:
console.log(Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')});
// Обработка новых команд
break;
}
}
// Реализация новых команд
async function moveToPosition(x, y, z) {
try {
await bot.pathfinder.goto(new GoalBlock(x, y, z));
console.log(Переместился к координатам (${x}, ${y}, ${z}).);
} catch (err) {
console.error('Ошибка при перемещении:', err);
}
}
async function attackEntity(entityName) {
const entity = bot.nearestEntity(entity => entity.name === entityName && entity.type === 'mob');
if (entity) {
try {
await bot.pathfinder.goto(new GoalNear(entity.position.x, entity.position.y, entity.position.z, 1));
bot.attack(entity);
console.log(Атакую ${entityName}.);
} catch (err) {
console.error('Ошибка при атаке на сущность:', err);
}
} else {
console.log(Сущность ${entityName} не найдена поблизости.);
}
}
async function collectResource(resourceName) {
const blockType = mcData.blocksByName[resourceName];
if (!blockType) {
console.log(Ресурс с именем ${resourceName} не найден в данных Minecraft.);
return;
}
await findAndMineBlock(resourceName);
}
// Остальные функции действий (findAndMineBlock, craftTools, craftItem, placeItem, eatFood, explore) остаются без изменений.
// Обработка сообщений из чата
bot.on('chat', async (username, message) => {
if (username === bot.username) return;
console.log(${username}: ${message});
// Проверяем, является ли сообщение советом
if (message.toLowerCase().startsWith('совет:')) {
const advice = message.substring(6).trim();
saveAdvice(${username}: ${advice});
bot.chat(Спасибо за совет, ${username}! Я учту это в будущем.);
return;
}
// Формируем историю сообщений
const messages = [
{
role: 'system',
content: `Вы — ИИ-агент в Minecraft. На основе контекста и сообщения от игрока решите, какое действие выполнить дальше, и выведите его в формате:
COMMAND: <команда>
Доступные команды:
Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её.
Пожалуйста, дайте краткое обоснование вашего выбора. }, { role: 'user', content: getBotContext() }, { role: 'user', content:{message}` }
];
// Отправляем запрос к LM Studio API
const actionText = await getLlamaResponseFromMessages(messages);
console.log('Действие от Llama 3.2:', actionText);
// Отправляем обоснование в чат (если есть)
const explanation = actionText.replace(/command:\s*.*\n?/i, '').trim();
if (explanation) {
bot.chat(explanation);
}
// Обрабатываем действие
await processAction(actionText);
});
// Обработка ошибок
bot.on('error', (err) => {
console.error('Ошибка бота:', err);
});
bot.on('kicked', (reason) => {
console.warn('Бот был кикнут:', reason);
});
D:\NodeJs Projects\minecraft-ai-bot>node bot.js
(node:9624) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
Бот успешно подключился к серверу!
D:\NodeJs Projects\minecraft-ai-bot\bot.js:43
mainLoop();
^
ReferenceError: mainLoop is not defined
at EventEmitter.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\bot.js:43:3)
at EventEmitter.emit (node:events:530:35)
at Client.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\node_modules\mineflayer\lib\plugins\health.js:13:11)
at Object.onceWrapper (node:events:633:26)
at Client.emit (node:events:530:35)
at emitPacket (D:\NodeJs Projects\minecraft-ai-bot\node_modules\minecraft-protocol\src\client.js:83:12)
at FullPacketParser.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\node_modules\minecraft-protocol\src\client.js:112:9)
at FullPacketParser.emit (node:events:518:28)
at addChunk (D:\NodeJs Projects\minecraft-ai-bot\node_modules\readable-stream\lib\internal\streams\readable.js:321:12)
at readableAddChunk (D:\NodeJs Projects\minecraft-ai-bot\node_modules\readable-stream\lib\internal\streams\readable.js:298:9)
Node.js v22.11.0
Здравствуйте!
Проблема:
В вашем коде возникает ошибка:
textReferenceError: mainLoop is not defined at EventEmitter.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\bot.js:43:3)
Это означает, что функция mainLoop не определена в вашем коде, но вы пытаетесь её вызвать на строке 43.
Решение:
Вам необходимо добавить определение функции mainLoop в ваш код. Похоже, что при копировании или редактировании кода вы пропустили эту функцию.
Вот как должна выглядеть функция mainLoop:
javascript// Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const actionText = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', actionText); // Обрабатываем действие await processAction(actionText); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } }
Обновленный код bot.js:
javascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); const { Vec3 } = require('vec3'); // Добавлено для работы с векторами // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Константы const BLOCK_SEARCH_RADIUS = 5; // Радиус поиска блоков // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 59449, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const actionText = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', actionText); // Обрабатываем действие await processAction(actionText); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Остальной код остаётся без изменений... // Функция для получения информации о блоках в радиусе function getBlocksInView(radius) { const blocks = []; const botPosition = bot.entity.position; // Определяем границы поиска const minX = Math.floor(botPosition.x - radius); const maxX = Math.floor(botPosition.x + radius); const minY = Math.floor(botPosition.y - radius); const maxY = Math.floor(botPosition.y + radius); const minZ = Math.floor(botPosition.z - radius); const maxZ = Math.floor(botPosition.z + radius); for (let x = minX; x <= maxX; x++) { for (let y = minY; y <= maxY; y++) { for (let z = minZ; z <= maxZ; z++) { const block = bot.blockAt(new Vec3(x, y, z)); if (block && block.name !== 'air') { blocks.push({ name: block.displayName || block.name, position: `x=${x}, y=${y}, z=${z}` }); } } } } // Ограничиваем количество блоков для удобства (например, до 20) const maxBlocks = 20; const blockDescriptions = blocks.slice(0, maxBlocks).map(block => `${block.name} (${block.position})`); return blockDescriptions.join('\n') || 'Нет блоков в радиусе'; } // Обновляем функцию getBotContext() function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; // Получаем информацию о ближайших блоках const blocksInView = getBlocksInView(BLOCK_SEARCH_RADIUS); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Блоки в радиусе ${BLOCK_SEARCH_RADIUS} блоков: ${blocksInView} Советы от игроков: ${adviceText} `; return context; } // Остальной код остаётся без изменений...
Объяснение:
Функция mainLoop(): Эта функция является основным циклом действий вашего бота. Она выполняет следующие шаги в бесконечном цикле:
getBotContext().getLlamaResponse(context).processAction(actionText).sleep(2000).Почему возникла ошибка: Если функция mainLoop не определена в вашем коде, но вы пытаетесь её вызвать, JavaScript выдаст ошибку ReferenceError, указывая, что такая функция не найдена.
Что нужно сделать:
Добавьте функцию mainLoop в ваш код: Вставьте определение функции mainLoop в ваш файл bot.js после функции sleep(ms) и перед остальным кодом. Убедитесь, что она соответствует приведённому выше примеру.
Убедитесь, что все функции определены: Проверьте, что все функции, используемые в вашем коде, такие как sleep, mainLoop, getBotContext, processAction, определены и доступны.
Дополнительные рекомендации:
Организация кода: Хорошей практикой является определение всех используемых функций перед их вызовом. Это поможет избежать подобных ошибок и облегчит чтение и поддержку кода.
Отладка: Если вы сталкиваетесь с ошибками, внимательно читайте сообщения об ошибках. Они обычно содержат информацию о том, где именно произошла ошибка и почему.
Комментарии: Продолжайте использовать комментарии в коде, чтобы лучше понимать структуру и функциональность различных частей программы.
Заключение
После добавления функции mainLoop ваш бот должен успешно запуститься и начать выполнять свои задачи. Если у вас возникнут дополнительные вопросы или потребуется помощь с отладкой или расширением функциональности, пожалуйста, обращайтесь. Я буду рад помочь вам дальше развивать ваш проект!
Ошибка в основном цикле: ReferenceError: loadAdvice is not defined
at getBotContext (D:\NodeJs Projects\minecraft-ai-bot\bot.js:122:19)
at mainLoop (D:\NodeJs Projects\minecraft-ai-bot\bot.js:56:23)
at EventEmitter.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\bot.js:43:3)
at EventEmitter.emit (node:events:530:35)
at Client.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\node_modules\mineflayer\lib\plugins\health.js:13:11)
at Object.onceWrapper (node:events:633:26)
at Client.emit (node:events:530:35)
at emitPacket (D:\NodeJs Projects\minecraft-ai-bot\node_modules\minecraft-protocol\src\client.js:83:12)
at FullPacketParser.<anonymous> (D:\NodeJs Projects\minecraft-ai-bot\node_modules\minecraft-protocol\src\client.js:112:9)
at FullPacketParser.emit (node:events:518:28)
Пиши код полностью
Здравствуйте!
Извините за недоразумение. Давайте исправим проблему.
Проблема:
Вы получаете ошибку:
textОшибка в основном цикле: ReferenceError: loadAdvice is not defined at getBotContext (D:\NodeJs Projects\minecraft-ai-bot\bot.js:122:19)
Это означает, что функция loadAdvice не определена в вашем коде, но она вызывается внутри функции getBotContext.
Решение:
Я предоставлю полный код файла bot.js, включая все необходимые функции, чтобы вы могли скопировать его и запустить без ошибок.
bot.jsjavascript// bot.js const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder'); const { GoalBlock, GoalNear } = goals; const axios = require('axios'); const mcData = require('minecraft-data')('1.20.1'); const fs = require('fs'); const path = require('path'); const { Vec3 } = require('vec3'); // Добавлено для работы с векторами // Путь к папке MemoryAI const memoryPath = path.join(__dirname, 'MemoryAI'); // Проверяем наличие папки MemoryAI if (!fs.existsSync(memoryPath)) { fs.mkdirSync(memoryPath); } // Константы const BLOCK_SEARCH_RADIUS = 5; // Радиус поиска блоков // Настройка бота const bot = mineflayer.createBot({ host: 'localhost', // IP адрес сервера Minecraft port: 59449, // Порт сервера Minecraft username: 'AI_Bot', // Имя бота version: '1.20.1' // Версия Minecraft }); // Подключаем плагины bot.loadPlugin(pathfinder); // При подключении бота bot.on('spawn', () => { console.log('Бот успешно подключился к серверу!'); // Настройка движений бота const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); // Начинаем основной цикл действий mainLoop(); }); // Функция задержки function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Основной цикл действий бота async function mainLoop() { while (true) { try { // Получаем текущий контекст const context = getBotContext(); // Отправляем контекст модели и получаем действие const actionText = await getLlamaResponse(context); console.log('Действие от Llama 3.2:', actionText); // Обрабатываем действие await processAction(actionText); // Задержка перед следующим циклом await sleep(2000); } catch (error) { console.error('Ошибка в основном цикле:', error); } } } // Функция для сохранения совета function saveAdvice(advice) { const adviceFile = path.join(memoryPath, 'advice.txt'); // Добавляем новый совет в конец файла fs.appendFileSync(adviceFile, advice + '\n', 'utf8'); } // Функция для загрузки советов function loadAdvice() { const adviceFile = path.join(memoryPath, 'advice.txt'); let advices = []; if (fs.existsSync(adviceFile)) { const data = fs.readFileSync(adviceFile, 'utf8'); advices = data.split('\n').filter(line => line.trim() !== ''); } return advices; } // Функция для получения информации о блоках в радиусе function getBlocksInView(radius) { const blocks = []; const botPosition = bot.entity.position; // Определяем границы поиска const minX = Math.floor(botPosition.x - radius); const maxX = Math.floor(botPosition.x + radius); const minY = Math.floor(botPosition.y - radius); const maxY = Math.floor(botPosition.y + radius); const minZ = Math.floor(botPosition.z - radius); const maxZ = Math.floor(botPosition.z + radius); for (let x = minX; x <= maxX; x++) { for (let y = minY; y <= maxY; y++) { for (let z = minZ; z <= maxZ; z++) { const block = bot.blockAt(new Vec3(x, y, z)); if (block && block.name !== 'air') { blocks.push({ name: block.displayName || block.name, position: `x=${x}, y=${y}, z=${z}` }); } } } } // Ограничиваем количество блоков для удобства (например, до 20) const maxBlocks = 20; const blockDescriptions = blocks.slice(0, maxBlocks).map(block => `${block.name} (${block.position})`); return blockDescriptions.join('\n') || 'Нет блоков в радиусе'; } // Обновляем функцию getBotContext() function getBotContext() { const health = bot.health; const food = bot.food; const position = bot.entity.position; const inventoryItems = bot.inventory.items().map(item => item.displayName).join(', '); const nearbyEntities = Object.values(bot.entities) .filter(entity => entity.type === 'mob' && entity.position.distanceTo(bot.entity.position) < 16) .map(entity => entity.name) .join(', '); // Загружаем советы const advices = loadAdvice(); const adviceText = advices.length > 0 ? advices.join('\n') : 'Нет советов'; // Получаем информацию о ближайших блоках const blocksInView = getBlocksInView(BLOCK_SEARCH_RADIUS); const context = ` Здоровье: ${health}/20 Сытость: ${food}/20 Позиция: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}, z=${position.z.toFixed(2)} Инвентарь: ${inventoryItems || 'пуст'} Ближайшие мобы: ${nearbyEntities || 'нет'} Блоки в радиусе ${BLOCK_SEARCH_RADIUS} блоков: ${blocksInView} Советы от игроков: ${adviceText} `; return context; } // Функция для отправки контекста и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponse(context) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: context } ], temperature: 0.7, max_tokens: 8000, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Функция для отправки сообщений и получения ответа от Llama 3.2 через LM Studio API async function getLlamaResponseFromMessages(messages) { try { const response = await axios.post('http://127.0.0.1:1234/v1/chat/completions', { model: 'fireball-meta-llama-3.2-8b-instruct-agent-003-128k-code-dpo', // Замените на фактическое имя вашей модели messages: messages, temperature: 0.7, max_tokens: 8000, stream: false }, { headers: { 'Content-Type': 'application/json' } }); // Получаем ответ модели const actionText = response.data.choices[0].message.content.trim(); return actionText; } catch (error) { console.error('Ошибка при обращении к LM Studio API:', error); return 'Я не знаю, что делать.'; } } // Обработка действия от модели async function processAction(actionText) { actionText = actionText.toLowerCase(); // Извлекаем команду из ответа модели const commandMatch = actionText.match(/command:\s*(.*)/i); if (commandMatch) { const command = commandMatch[1].trim(); await processCommand(`command: ${command}`); } else { console.log('Не удалось распознать команду из ответа модели.'); console.log('Ответ модели:', actionText); } } // Функция для обработки команд async function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); const primaryCommand = args[0]; const commandArgs = args.slice(1); switch (primaryCommand) { case 'move_to': if (commandArgs.length === 3) { const x = parseFloat(commandArgs[0]); const y = parseFloat(commandArgs[1]); const z = parseFloat(commandArgs[2]); await moveToPosition(x, y, z); } else { console.log('Неверные аргументы для команды move_to.'); } break; case 'attack': const entityName = commandArgs.join(' '); await attackEntity(entityName); break; case 'craft': const itemName = commandArgs.join(' '); await craftItem(itemName); break; case 'say': const message = commandArgs.join(' '); bot.chat(message); break; case 'collect': const resourceName = commandArgs.join(' '); await collectResource(resourceName); break; default: console.log(`Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')}`); // Обработка новых команд break; } } // Реализация новых команд async function moveToPosition(x, y, z) { try { await bot.pathfinder.goto(new GoalBlock(x, y, z)); console.log(`Переместился к координатам (${x}, ${y}, ${z}).`); } catch (err) { console.error('Ошибка при перемещении:', err); } } async function attackEntity(entityName) { const entity = bot.nearestEntity(entity => entity.name === entityName && entity.type === 'mob'); if (entity) { try { await bot.pathfinder.goto(new GoalNear(entity.position.x, entity.position.y, entity.position.z, 1)); bot.attack(entity); console.log(`Атакую ${entityName}.`); } catch (err) { console.error('Ошибка при атаке на сущность:', err); } } else { console.log(`Сущность ${entityName} не найдена поблизости.`); } } async function collectResource(resourceName) { const blockType = mcData.blocksByName[resourceName]; if (!blockType) { console.log(`Ресурс с именем ${resourceName} не найден в данных Minecraft.`); return; } await findAndMineBlock(resourceName); } // Функция для добычи и сбора блока async function findAndMineBlock(blockName) { const blockIds = mcData.blocksByName[blockName]?.id; if (!blockIds) { console.log(`Блок с именем ${blockName} не найден.`); return; } const target = bot.findBlock({ matching: blockIds, maxDistance: 64 }); if (!target) { console.log(`Не удалось найти блок ${blockName} поблизости.`); return; } try { await bot.pathfinder.goto(new GoalBlock(target.position.x, target.position.y, target.position.z)); await bot.dig(bot.blockAt(target.position)); console.log(`Добыт блок ${blockName}.`); } catch (err) { console.error(`Ошибка при добыче блока ${blockName}:`, err); } } // Функция для крафта предмета async function craftItem(itemName) { const item = mcData.itemsByName[itemName]; if (!item) { console.log(`Предмет с именем ${itemName} не найден.`); return; } const recipes = bot.recipesFor(item.id, null, 1, bot.inventory); if (recipes.length === 0) { console.log(`Нет рецептов для крафта ${itemName}.`); return; } try { await bot.craft(recipes[0], 1, null); console.log(`Скрафтил ${itemName}.`); } catch (err) { console.error(`Ошибка при крафте ${itemName}:`, err); } } // Обработка сообщений из чата bot.on('chat', async (username, message) => { if (username === bot.username) return; console.log(`${username}: ${message}`); // Проверяем, является ли сообщение советом if (message.toLowerCase().startsWith('совет:')) { const advice = message.substring(6).trim(); saveAdvice(`${username}: ${advice}`); bot.chat(`Спасибо за совет, ${username}! Я учту это в будущем.`); return; } // Формируем историю сообщений const messages = [ { role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста и сообщения от игрока решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }, { role: 'user', content: getBotContext() }, { role: 'user', content: `${username}: ${message}` } ]; // Отправляем запрос к LM Studio API const actionText = await getLlamaResponseFromMessages(messages); console.log('Действие от Llama 3.2:', actionText); // Отправляем обоснование в чат (если есть) const explanation = actionText.replace(/command:\s*.*\n?/i, '').trim(); if (explanation) { bot.chat(explanation); } // Обрабатываем действие await processAction(actionText); }); // Обработка ошибок bot.on('error', (err) => { console.error('Ошибка бота:', err); }); bot.on('kicked', (reason) => { console.warn('Бот был кикнут:', reason); });
Объяснение:
Добавлены функции saveAdvice и loadAdvice: Эти функции используются для сохранения и загрузки советов от игроков. Они были отсутствующими в вашем коде и вызывали ошибку ReferenceError: loadAdvice is not defined.
Включены все функции, необходимые для работы бота: Теперь код содержит все функции, необходимые для корректной работы, включая mainLoop, getBotContext, processAction, processCommand и реализацию команд.
Функции действий (findAndMineBlock, craftItem): Эти функции были добавлены для обеспечения функциональности команд collect и craft.
Исправлены возможные ошибки: Код проверен на наличие всех необходимых определений функций и корректную последовательность.
Дополнительные рекомендации:
Проверьте имя модели: Убедитесь, что параметр model в функциях getLlamaResponse и getLlamaResponseFromMessages соответствует имени вашей модели в LM Studio.
Настройте порт и хост: Убедитесь, что настройки подключения к серверу Minecraft (host и port) верны.
Проверка зависимостей: Убедитесь, что у вас установлены все необходимые пакеты npm, включая mineflayer, mineflayer-pathfinder, axios, minecraft-data, vec3, и другие.
Тестирование: После запуска бота внимательно следите за выводом в консоли, чтобы отлавливать возможные ошибки или некорректное поведение.
Заключение
Теперь ваш бот должен успешно запускаться без ошибок и корректно выполнять свои функции. Если у вас возникнут дополнительные вопросы или потребуется помощь с дальнейшей настройкой или расширением функциональности, пожалуйста, обращайтесь. Я буду рад помочь вам!
D:\NodeJs Projects\minecraft-ai-bot>node bot.js
(node:8432) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
Бот успешно подключился к серверу!
Действие от Llama 3.2: COMMAND: move_to x=0.50, y=72.00, z=0.50
Обоснование выбора: Основываясь на предоставленной информации, я не вижу в радиусе 24 блоков ни одного потенциального источника опасности или интереса. На текущей позиции игрока нет ближайших мобов, и инвентарь пуст. Следовательно, первое действие — переместиться к начальной позиции (x=0.50, y=72.00, z=0.50).
Переместился к координатам (NaN, NaN, NaN).
Feodseon: Начинай виживать
Действие от Llama 3.2: COMMAND: move_to x=-24, y=48, z=-24
Обоснование: Из контекста понятно, что агент находится в пустом блоке (х = 0.50, у = 72.00, з = 0.50) и окружен блоками из камня на расстоянии 24 блока от него. Для начала наиболее логичным действием будет перемещение в центр группы блоков из камня, что позволит агенту изучить окружающую обстановку или найти ресурсы.
Переместился к координатам (NaN, NaN, NaN).
Действие от Llama 3.2: COMMAND: move_to x=-24, y=48, z=-5
Обоснование: Поскольку игрок просит начать исследовать, я предполагаю, что он хочет переместиться к ближайшему блоку (Stone) на координатах (-24, 48, -5). Это позволит ему изучить окрестности и потенциально найти интересные предметы или ресурсы.
Переместился к координатам (NaN, NaN, NaN).
Действие от Llama 3.2: COMMAND: move_to x=-23.50 y=72.00 z=-14.50
Обоснование: Я решил переместиться в центр группы камней, поскольку они кажутся наиболее подходящим местом для начала работы. | imprint="assistant" |
Переместился к координатам (NaN, NaN, NaN).
Действие от Llama 3.2: COMMAND: move_to x=-24 y=48 z=-24
Обоснование: На основании предоставленной информации мне необходимо переместиться на ближайший блок. Это связано с тем, что моей текущей позицией являются координаты x=0.50, y=72.00, z=0.50, а ближайшим блоком является Stone (x=-24, y=48, z=-24), находящийся в радиусе 24 блоков.
Переместился к координатам (NaN, NaN, NaN).
Бот успешно подключился к серверу!
ИИ просто стоит на месте. Почему?
Здравствуйте!
Проблема:
Ваш бот не движется и всегда сообщает, что переместился к координатам (NaN, NaN, NaN). Это происходит потому, что при попытке распарсить координаты из команды move_to, полученные значения x, y, z становятся NaN (Not a Number).
Причина:
Ваша функция processCommand ожидает, что координаты будут переданы как три отдельных числа, например:
COMMAND: move_to 0.50 72.00 0.50
Однако модель Llama 3.2 генерирует команды в формате:
COMMAND: move_to x=0.50, y=72.00, z=0.50
При разборе команды ваш код пытается преобразовать строки вроде "x=0.50," в число с помощью parseFloat(), что приводит к NaN, так как parseFloat('x=0.50,') не может быть корректно преобразован в число.
Решение:
Нужно изменить функцию processCommand так, чтобы она корректно извлекала координаты из строки команды, учитывая формат, в котором модель возвращает данные.
processCommand для правильного разбора координатИзменим обработку команды move_to, чтобы она могла корректно извлекать значения x, y, z из строки, даже если они записаны в формате x=0.50, y=72.00, z=0.50.
Обновлённая функция processCommand:
javascriptasync function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); const primaryCommand = args[0]; const commandArgs = args.slice(1); switch (primaryCommand) { case 'move_to': // Объединяем аргументы обратно в строку const coordinateString = commandArgs.join(' '); // Ищем координаты в формате x=..., y=..., z=... const coordRegex = /x\s*=?\s*([-+]?\d*\.?\d+),?\s*y\s*=?\s*([-+]?\d*\.?\d+),?\s*z\s*=?\s*([-+]?\d*\.?\d+)/i; const coordMatch = coordinateString.match(coordRegex); if (coordMatch) { const x = parseFloat(coordMatch[1]); const y = parseFloat(coordMatch[2]); const z = parseFloat(coordMatch[3]); await moveToPosition(x, y, z); } else { console.log('Не удалось распознать координаты для команды move_to.'); } break; // Остальные случаи остаются без изменений // ... } }
Пояснение:
Шаг 1: Объединяем commandArgs обратно в одну строку coordinateString, чтобы иметь полный текст координат.
Шаг 2: Используем регулярное выражение coordRegex для извлечения значений x, y, z из строки coordinateString.
Шаг 3: Если координаты успешно извлечены, преобразуем их в числа с помощью parseFloat и вызываем функцию moveToPosition(x, y, z).
Шаг 4: Если координаты не удалось распознать, выводим сообщение об ошибке.
processCommand в кодеОбновите функцию processCommand в вашем файле bot.js согласно приведённому выше примеру.
bot.jsjavascript// ... Остальной код остаётся без изменений ... // Функция для обработки команд async function processCommand(commandText) { const commandMatch = commandText.match(/command:\s*(.*)/i); if (!commandMatch) { console.log('Не удалось распознать команду из ответа модели.'); return; } const command = commandMatch[1].trim(); const args = command.split(' '); const primaryCommand = args[0]; const commandArgs = args.slice(1); switch (primaryCommand) { case 'move_to': // Объединяем аргументы обратно в строку const coordinateString = commandArgs.join(' '); // Ищем координаты в формате x=..., y=..., z=... const coordRegex = /x\s*=?\s*([-+]?\d*\.?\d+),?\s*y\s*=?\s*([-+]?\d*\.?\d+),?\s*z\s*=?\s*([-+]?\d*\.?\d+)/i; const coordMatch = coordinateString.match(coordRegex); if (coordMatch) { const x = parseFloat(coordMatch[1]); const y = parseFloat(coordMatch[2]); const z = parseFloat(coordMatch[3]); await moveToPosition(x, y, z); } else { console.log('Не удалось распознать координаты для команды move_to.'); } break; // Остальные случаи остаются без изменений case 'attack': // ... break; case 'craft': // ... break; case 'say': // ... break; case 'collect': // ... break; default: console.log(`Получена новая команда от ИИ: ${primaryCommand} ${commandArgs.join(' ')}`); // Обработка новых команд break; } } // ... Остальной код остаётся без изменений ...
Запустите бота после внесения изменений.
Наблюдайте за его действиями.
(NaN, NaN, NaN) должны появиться реальные координаты.Пример ожидаемого вывода:
textДействие от Llama 3.2: COMMAND: move_to x=0.50, y=72.00, z=0.50 Обоснование выбора: ... Переместился к координатам (0.5, 72, 0.5).
Проверка на сервере Minecraft:
Чтобы избежать подобных проблем в будущем, можно уточнить подсказку для модели, указав желаемый формат команд.
Обновите сообщение system в подсказке:
javascript{ role: 'system', content: `Вы — ИИ-агент в Minecraft. На основе контекста решите, какое действие выполнить дальше, и выведите его в формате: COMMAND: <команда> Доступные команды: - move_to x y z (пример: move_to 0.5 72 0.5) - attack <entity_name> - craft <item_name> - say <message> - collect <resource_name> Если вам нужно выполнить действие, которое не указано в списке, вы можете придумать свою собственную команду и использовать её. Пожалуйста, дайте краткое обоснование вашего выбора.` }
Преимущества:
Если вы ожидаете, что модель может выдавать координаты в разных форматах, можно расширить регулярное выражение или добавить дополнительные проверки.
Пример:
javascript// Попытка распарсить координаты в разных форматах let x, y, z; if (coordMatch) { x = parseFloat(coordMatch[1]); y = parseFloat(coordMatch[2]); z = parseFloat(coordMatch[3]); } else { // Попытка распарсить координаты без x=, y=, z= const numbers = coordinateString.match(/([-+]?\d*\.?\d+)/g); if (numbers && numbers.length === 3) { x = parseFloat(numbers[0]); y = parseFloat(numbers[1]); z = parseFloat(numbers[2]); } else { console.log('Не удалось распознать координаты для команды move_to.'); return; } } await moveToPosition(x, y, z);
Добавьте дополнительные проверки и обработку возможных ошибок, чтобы бот был более устойчив к некорректным данным.
Причина, почему бот стоит на месте:
parseFloat не может преобразовать строки вида 'x=0.50,' в число, и возвращает NaN.Решение:
processCommand, чтобы она корректно извлекала значения x, y, z из строки команды, учитывая формат, в котором модель возвращает данные.Дальнейшие действия:
Если у вас возникнут дополнительные вопросы или потребуется помощь с дальнейшей настройкой или отладкой бота, пожалуйста, обращайтесь. Я буду рад помочь вам улучшить и расширить функциональность вашего проекта!