«Вау!» или почему это первый локальный AI-агент, который делает всё сам
Представьте: вы вводите одно-единственное описание задачи, а искусственный интеллект полностью сам пишет нужный код, сохраняет его в файл, автоматически устанавливает необходимые зависимости (если они требуются) и сразу же запускает полученный скрипт!И всё это в локальном окружении, без отправки вашего кода в чужое «облако». Если происходит ошибка, AI-агент может сам понять, что пошло не так, и скорректировать запрос к модели, пытаясь устранить проблему. Это действительно впечатляет!
Как и любая экспериментальная технология, этот AI-агент далёк от идеала и может допускать ошибки:
- Возможны ложные срабатывания или ситуации, когда агент не сможет правильно исправить ошибку и будет бесконечно переформулировать запрос.
- Код, который генерирует агент, может иногда не работать так, как вы ожидаете. Иногда могут появляться логические ошибки или несоответствия с вашим окружением.
Важно понимать, что это пока бета-версия и не гарантирует 100% стабильной работы. В некоторых случаях придётся вручную вмешиваться и корректировать результат. Однако даже сейчас это демонстрирует, насколько далеко продвинулась автоматизация разработки.
- Python 3.8+Убедитесь, что у вас установлена современная версия Python. Проверить можно командой: python --version
2. LLM-сервер Ollama (или другой вариант локального/удалённого LLM-сервера)
- В примере код настроен на сервер по адресу http://localhost:11434/v1.
- Если вы используете Ollama, запустите Ollama-сервер локально. Убедитесь, что он принимает запросы на нужном порту (по умолчанию 11434).
- Если вы хотите использовать другой LLM-сервис, замените адрес http://localhost:11434/v1 на соответствующий.
3. qwen_agent (или аналогичный пакет для взаимодействия с вашей LLM)
- Установите через PyPI: pip install qwen-agent
Сохраните этот код в файл, например, agent.py:
import json
import os
import subprocess
from qwen_agent.llm import get_chat_model
def reformulate_request_agent(user_request, error_description=None):
"""
Функция для переформулирования запроса к модели.
Принимает:
- user_request: исходный текст запроса от пользователя.
- error_description: сообщение об ошибке, если код не запустился.
Возвращает:
- Переформулированный текст запроса для повторной генерации кода.
"""
llm = get_chat_model({
'model': 'qwen2.5-coder:14b', # Название модели
'model_server': 'http://localhost:11434/v1', # Адрес вашего Ollama или другого LLM-сервера
'api_key': 'EMPTY', # При необходимости указать ключ
})
# Формируем сообщение для системы
base_message = user_request
if error_description:
base_message += f" Было получено сообщение об ошибке: {error_description}."
messages = [
{
'role': 'system',
'content': (
"You are an assistant that reformulates user requests to ensure they are suitable "
"for generating Python code. Your reformulated request should be clear and precise."
)
},
{'role': 'user', 'content': base_message}
]
# Здесь модель генерирует ответ (переформулированный запрос).
responses = []
for responses in llm.chat(messages=messages, stream=True):
pass
# Возвращаем итоговое переформулирование
return responses[0]['content']
def save_and_run_code(code, name_file, dependencies=None):
"""
Функция, которая:
1. Сохраняет переданный Python-код в файл.
2. Устанавливает зависимости (если указано).
3. Запускает созданный файл и возвращает результат (или ошибку).
:param code: Строка с Python-кодом.
:param name_file: Имя файла для сохранения кода.
:param dependencies: Строка со списком зависимостей (через пробел).
:return: Словарь формата {"success": bool, "output" или "error": str}
"""
# Приводим код к нужному формату (вдруг пришли эскейп-символы '\n' или '\t')
formatted_code = code.replace("\\n", "\n").replace("\\t", "\t")
# 1. Сохраняем код в файл
with open(name_file, "w", encoding="utf-8") as file:
file.write(formatted_code)
print(f"Код сохранён в файл: {name_file}")
# 2. Установка зависимостей (если они есть)
if dependencies:
print(f"Установка зависимостей: {dependencies}")
try:
# pip install <dependencies>
subprocess.run(["pip", "install"] + dependencies.split(), check=True, capture_output=True, text=True)
print("Зависимости успешно установлены.")
except subprocess.CalledProcessError as e:
error_message = f"Ошибка при установке зависимостей: {e.stderr}"
print(error_message)
return {"success": False, "error": error_message}
# 3. Запуск кода
try:
result = subprocess.run(["python", name_file], capture_output=True, text=True)
if result.returncode != 0:
# Если код вернулся с ошибкой (не 0)
return {"success": False, "error": result.stderr}
# Если всё ок, возвращаем результат
print(f"Результат выполнения файла {name_file}:\n{result.stdout}")
return {"success": True, "output": result.stdout}
except Exception as e:
print(f"Ошибка при запуске файла {name_file}: {e}")
return {"success": False, "error": str(e)}
def reformulate_request(error_description):
"""
Простейшая функция, которая формирует новый запрос с учётом ошибки.
"""
return f"Исправь ошибку: {error_description}"
def test():
"""
Основная функция, показывающая пример работы агента.
Шаги:
1. Получаем от пользователя запрос (описание задачи).
2. Формируем сообщения для LLM, где указываем, что мы хотим получить готовый Python-код.
3. Модель пытается сгенерировать код, вызывая функцию save_and_run_code.
4. Если возникает ошибка, у пользователя запрашивается обновлённый запрос (либо автоматически переформулируется).
5. Повторяем, пока не будет получен корректный результат.
Важно: Поскольку агент ещё в бета-версии, иногда могут возникать циклические попытки исправить ошибку.
Если видите, что он слишком долго не может разобраться, прервите выполнение и откорректируйте код вручную.
"""
# Подключаем модель (указываем сервер и имя модели)
llm = get_chat_model({
'model': 'qwen2.5-coder:14b', # Название модели
'model_server': 'http://localhost:11434/v1', # Адрес Ollama или другого LLM-сервера
'api_key': 'EMPTY',
})
# Пример запроса (вместо input можно просто задать строку)
req_user = str(input("Введите ваше описание кода: "))
req_user2 = req_user
while True:
# Печатаем запрос, чтобы видеть, что отправляем
print("Текущий запрос к модели:", req_user)
# Формируем сообщения для LLM
messages = [
{
'role': 'system',
'content': (
"You are an assistant that generates Python code based on user descriptions. "
"In addition to generating the code, you are responsible for providing the file name "
"where the code will be saved and a list of dependencies required to execute the code. "
"Ensure the output is executable and properly formatted."
)
},
{'role': 'user', 'content': req_user}
]
# Описываем функцию, которую модель может вызвать (function call)
functions = [{
'name': 'save_and_run_code',
'description': 'Generates Python code, saves it to a specified file, installs dependencies, and executes it.',
'parameters': {
'type': 'object',
'properties': {
'code': {
'type': 'string',
'description': 'Python code',
},
'name_file': {
'type': 'string',
'description': 'file name for saving the code',
},
'dependencies': {
'type': 'string',
'description': 'A space-separated list of dependencies to install before running the code',
},
},
'required': ['code', 'name_file'],
},
}]
# Отправляем запрос модели с описанием функций
responses = []
for responses in llm.chat(messages=messages, functions=functions, stream=True):
pass
# Добавляем ответ модели в историю сообщений
messages.extend(responses)
last_response = messages[-1]
# Если модель хочет вызвать функцию (function_call), то вызываем её
if last_response.get('function_call', None):
try:
available_functions = {
'save_and_run_code': save_and_run_code,
}
function_name = last_response['function_call']['name']
function_to_call = available_functions[function_name]
# Аргументы для функции
function_args = json.loads(last_response['function_call']['arguments'])
# Вызываем функцию (сохраняем, устанавливаем зависимости, запускаем код)
function_response = function_to_call(
code=function_args.get('code'),
name_file=function_args.get('name_file'),
dependencies=function_args.get('dependencies'),
)
# Проверяем результат (успех или ошибка)
if function_response.get("success"):
print("Код выполнен успешно!")
print(f"Результат: {function_response['output']}")
break
else:
error_description = function_response.get("error")
print(f"Обнаружена ошибка: {error_description}")
# Можно попросить пользователя уточнить, или переформулировать запрос автоматически
req_user = reformulate_request_agent(req_user, error_description)
except:
# Если произошла ошибка, пробуем переформулировать
print('Ошибка в процессе вызова функции.')
req_user = reformulate_request_agent(req_user)
else:
# Модель не смогла сгенерировать корректный function_call
print("Модель не смогла сгенерировать функцию. Попробуем переформулировать запрос.")
req_user = reformulate_request_agent(req_user2, "Модель не сформировала корректный запрос.")
if __name__ == '__main__':
test()
Как запустить: python agent.py
После этого в консоли появится приглашение: «Введите ваше описание кода:».Например, можно ввести: Напиши программу, которая выводит числа от 1 до 5.
Агент попытается сгенерировать код, сохранить его, установить зависимости (если указаны) и выполнить.
В качестве наглядного примера можно попросить нашего AI-агента сгенерировать код, рисующий треугольник Серпинского (часто называют его пирамидой) на Python с помощью модуля turtle. Агент не всегда справляется с первого раза: могут возникать ошибки, опечатки или неверные вызовы функций. Однако после нескольких уточнений он предложил следующий рабочий код:
import turtle
def sierpinski(degree, points):
"""
Рекурсивная функция, которая рисует треугольник Серпинского
в зависимости от глубины рекурсии degree и координат точек points.
"""
colormap = ['blue', 'red', 'green', 'white', 'yellow', 'violet']
draw_triangle(points, colormap[degree % 6])
if degree > 0:
sierpinski(degree - 1,
{
'left': get_mid(points['left'], points['top']),
'right': get_mid(points['right'], points['top']),
'top': points['top']
})
sierpinski(degree - 1,
{
'left': points['left'],
'right': get_mid(points['left'], points['right']),
'top': get_mid(points['left'], points['right'])
})
sierpinski(degree - 1,
{
'left': get_mid(points['right'], points['left']),
'right': points['right'],
'top': get_mid(points['right'], points['top'])
})
def draw_triangle(points, color):
"""
Рисует закрашенный треугольник по координатам в словаре points.
"""
turtle.fillcolor(color)
turtle.up()
turtle.goto(points['left'])
turtle.down()
turtle.begin_fill()
turtle.goto(points['right'])
turtle.goto(points['top'])
turtle.goto(points['left'])
turtle.end_fill()
def get_mid(p1, p2):
"""
Возвращает координату середины между двумя точками (p1 и p2).
"""
return ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
# Настраиваем окно turtle
wn = turtle.Screen()
wn.bgcolor('black')
# Определяем три основные точки (вершины) большого треугольника
points = {
'left': (-300, -150),
'right': (300, -150),
'top': (0, 300)
}
# Рисуем треугольник Серпинского глубины 5
sierpinski(5, points)
# Скрываем «черепашку» и ждём закрытия окна
turtle.hideturtle()
wn.exitonclick()
- Основная функция sierpinski(degree, points):Рисует треугольник на каждом уровне рекурсии.Если degree > 0, вызывает себя же три раза с новыми координатами («подтреугольниками») меньшего размера.
- Рисует треугольник на каждом уровне рекурсии.
- Если degree > 0, вызывает себя же три раза с новыми координатами («подтреугольниками») меньшего размера.
- Функция draw_triangle(points, color):Получает словарь с тремя координатами ('left', 'right', 'top') и закрашивает треугольник соответствующим цветом.
- Получает словарь с тремя координатами ('left', 'right', 'top') и закрашивает треугольник соответствующим цветом.
- Функция get_mid(p1, p2):Возвращает точку — середину отрезка между p1 и p2.
- Возвращает точку — середину отрезка между p1 и p2.
- Настройка окна turtle.Screen(), выбор цвета фона, и установка базовых координат для большого треугольника.
- Вызов sierpinski(5, points) даёт глубину рекурсии (количество уровней «вырезания») — чем больше глубина, тем детальнее рисунок, но дольше отрисовка.
- Сначала агент мог сгенерировать неполный или некорректный код, где не были объявлены переменные или функции, либо пропускались важные части логики.
- После того как агенту сообщили об ошибке (или он сам нашёл ошибку при запуске), он переформулировалзапрос и скорректировал свой код.
- В результате спустя несколько итераций был получен рабочий пример.
Это отлично иллюстрирует плюсы и минусы использования бета-версии AI-агента:
- Плюс: агент может выполнить большую часть рутины и «вспомнить» синтаксис, отрисовку, рекурсию и т.д.
- Минус: при возникновении ошибки не всегда сразу понимает, как её исправить; иногда требуется вмешательство человека, который точно укажет на проблему.
Таким образом, наш AI-агент хоть и не совершенен, но уже сейчас помогает экономить время и упрощает процесс создания кода — даже для построения таких любопытных фигур, как треугольник (или пирамида) Серпинского с помощью библиотеки turtle.
- Полная автоматизация: AI-агент работает локально и выполняет все шаги — от генерации кода до его запуска.
- Экономия времени и сил: Вам не нужно переключаться между редактором кода, терминалом и браузером для поиска зависимостей — агент берёт это на себя.
- Бета-версия: Важно помнить, что система пока сыровата и не всегда корректно обрабатывает ошибки. Может возникнуть ситуация, когда она «зациклится» в попытках исправить код.
- Готовая основа для расширения: Хотите дополнить проверки, добавить тесты или реализовать поддержку других языков? Всё это возможно в рамках той же архитектуры, где модель взаимодействует с функциями Python.
Приятного использования!
Комментарии 0
Авторизуйтесь чтобы оставить комментарий