Хочу поделиться результатом небольшого эксперимента по вайбкодингу. Поставил перед несколькими нейронками одну и ту же задачу – написать код для решения одной и той же задачи. Всего воспользовался несколькими нейронками:
- Llama 3.1 на 8b – работает оффлайн на моем компьютере через Ollama
- qwen3 vl на 8b – также работает на моем компьютере через LM Studio
- Claude Sonnet 4.5
- ChatGPT 5.2
- Grok
- Mistral
Да, я понимаю, что сравнение между ними не совсем корректное с научной точки зрения, потому что у них разные возможности, мощности, параметры и прочие характеристики. Но это оправдано с точки зрения доступа к ним со стороны обычного пользователя. Именно как обычный пользователь я веду себя в этом эксперименте, чтобы понять, чего можно достичь и как, используя нейронки с разным уровнем “прокаченности” и доступа.
Задача
Задача же для всех нейронок звучала так:
Напиши код на Python 3, который будет искат в предоставленном файле CSV вот такие текста: [интернете] (https://www.itu.int/itu-d/reports/statistics/2023/10/10/ff23-youth-internet-use/?utm_source=chatgpt.com) Код должен превращать такие выражения в такой HTML: <a href=’https://www.itu.int/itu-d/reports/statistics/2023/10/10/ff23-youth-internet-use/?utm_source=chatgpt.com’>интернете</a>
Чтобы оценка работы нейронок была также более объективной, сделать это попросил Gemini. В последнее время я всё чаще замечаю, что с кодингом у него получается довольно хорошо. И, чтобы он не понял, что оценивает код других нейронок, ему я сказал, что их написали люди и каждой нейронке дал такие имена:
- Llama – Матинбек
- qwen3 – Курбон
- Claude – Клавдия
- ChatGPT – Фарход
- Grok – Илон
- Mistral – Мишель
Полный промпт
Мой полный промпт был таким – он содержит как роль и задачу самому Gemini, так и весь код, написанный другими нейронками:
Представь, что ты - профессиональный сеньор Python разработчик.
Твоя задача - сделать ревью кодов, которые прислали тебе твои подчиненные.
Перед каждым из них была поставлена одна и та же задача, которая звучала так:
```
Напиши код на Python 3, который будет искат в предоставленном файле CSV вот такие текста: [интернете] (https://www.itu.int/itu-d/reports/statistics/2023/10/10/ff23-youth-internet-use/?utm_source=chatgpt.com) Код должен превращать такие выражения в такой HTML: <a href='https://www.itu.int/itu-d/reports/statistics/2023/10/10/ff23-youth-internet-use/?utm_source=chatgpt.com'>интернете</a>
```
В итоге они прислали такой код, который ниже я обозначу их именами, а ты проведи анализ кода и предложи итоговый профессиональный код, указав, кто их них какие ошибки допустил и что сделал правильно.
Код от Матинбека:
```
import pandas as pd
# Обработчик CSV-файла
def process_csv(file_path):
# Загружаем файл в Dataframe (объект для работы с данными)
df = pd.read_csv(file_path)
# Регулярное выражение, которое мы будем использовать для поиска и замены текста
pattern = r'\[(интернете]\(https://www\.itu\.int/itu-d/reports/statistics/\d{4}/\d{2}/\d{2}/ff23-youth-internet-use/\?utm_source=chatgpt\.com\)\?'
# Функция замены текста
def replace_text(text):
import re
return re.sub(pattern, lambda x: f'<a href="{x.group(0)[1:-1]}">интернете</a>', text)
# Применяем замену всем строкам в Dataframe
df['column_name'] = df.apply(replace_text, axis=1) # Replace 'column_name' with the actual column name
# Сохраняем измененный файл CSV
output_file_path = file_path.replace('.csv', '_processed.csv')
df.to_csv(output_file_path, index=False)
# Используем функцию для обработки файла CSV
process_csv('input.csv') # Replace 'input.csv' with the actual path to your input file
```
Код от Курбона:
```
import csv
import re
def replace_links_in_cell(cell):
"""
Заменяет в ячейке строки вида: [текст] (URL) на <a href='URL'>текст</a>
"""
if not isinstance(cell, str):
return cell
# Регулярное выражение для поиска шаблона: [текст] (URL)
# Группируем текст и URL
pattern = r'$([^$]+)$\s*$([^)]+)$'
def replace_func(match):
text = match.group(1)
url = match.group(2)
return f"<a href='{url}'>{text}</a>"
result = re.sub(pattern, replace_func, cell)
return result
def process_csv(input_file, output_file):
with open(input_file, newline='', encoding='utf-8') as infile, \
open(output_file, 'w', newline='', encoding='utf-8') as outfile:
reader = csv.reader(infile)
writer = csv.writer(outfile)
# Чтение заголовков
headers = next(reader)
writer.writerow(headers)
# Обработка каждой строки
for row in reader:
new_row = [replace_links_in_cell(cell) for cell in row]
writer.writerow(new_row)
if __name__ == "__main__":
input_csv = "input.csv" # Замените на путь к вашему файлу
output_csv = "output.csv" # Выходной файл
process_csv(input_csv, output_csv)
print(f"Обработка завершена. Результат сохранён в {output_csv}")
```
И код, написанный Клавдией:
```
import csv
import re
def convert_markdown_links_to_html(text):
"""
Преобразует ссылки формата [текст] (url) в HTML формат <a href='url'>текст</a>
"""
# Паттерн для поиска ссылок в формате [текст] (url)
# Обратите внимание на пробел между ] и (
pattern = r'\[([^\]]+)\]\s*\(([^\)]+)\)'
# Заменяем найденные совпадения на HTML-ссылки
html_text = re.sub(pattern, r"<a href='\2'>\1</a>", text)
return html_text
def process_csv_file(input_file, output_file):
"""
Обрабатывает CSV файл, преобразуя markdown-ссылки в HTML
"""
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'w', encoding='utf-8', newline='') as outfile:
reader = csv.reader(infile)
writer = csv.writer(outfile)
for row in reader:
# Обрабатываем каждую ячейку в строке
processed_row = [convert_markdown_links_to_html(cell) for cell in row]
writer.writerow(processed_row)
print(f"Обработка завершена. Результат сохранён в {output_file}")
# Пример использования
if __name__ == "__main__":
input_filename = "input.csv" # Укажите имя вашего входного файла
output_filename = "output.csv" # Укажите имя выходного файла
process_csv_file(input_filename, output_filename)
# Пример тестирования функции преобразования
test_text = "[интернете] (https://www.itu.int/itu-d/reports/statistics/2023/10/10/ff23-youth-internet-use/?utm_source=chatgpt.com)"
print("\nПример преобразования:")
print(f"До: {test_text}")
print(f"После: {convert_markdown_links_to_html(test_text)}")
```
Код, написанный Фарходом:
```
#!/usr/bin/env python3
import csv
import re
import html
import argparse
# Ищем: [текст] (url)
# Пробел между ] и ( допускаем; url берём до закрывающей скобки.
PATTERN = re.compile(r"\[([^\]]+)\]\s*\(([^)]+)\)")
def replace_md_links_with_html(value: str) -> str:
if not isinstance(value, str) or not value:
return value
def _repl(m: re.Match) -> str:
text = m.group(1)
url = m.group(2).strip()
# Экранируем текст и URL для HTML
safe_text = html.escape(text, quote=False)
safe_url = html.escape(url, quote=True)
return f"<a href='{safe_url}'>{safe_text}</a>"
return PATTERN.sub(_repl, value)
def process_csv(input_path: str, output_path: str, delimiter: str = ",") -> None:
with open(input_path, "r", encoding="utf-8", newline="") as f_in:
reader = csv.reader(f_in, delimiter=delimiter)
rows = list(reader)
out_rows = []
for row in rows:
out_rows.append([replace_md_links_with_html(cell) for cell in row])
with open(output_path, "w", encoding="utf-8", newline="") as f_out:
writer = csv.writer(f_out, delimiter=delimiter, quoting=csv.QUOTE_MINIMAL)
writer.writerows(out_rows)
def main():
ap = argparse.ArgumentParser(description="Convert markdown-like links [text] (url) in CSV to HTML <a> tags.")
ap.add_argument("input_csv", help="Path to input CSV")
ap.add_argument("output_csv", help="Path to output CSV")
ap.add_argument("--delimiter", default=",", help="CSV delimiter (default: ,). For ; use --delimiter ';'")
args = ap.parse_args()
process_csv(args.input_csv, args.output_csv, delimiter=args.delimiter)
if __name__ == "__main__":
main()
```
Код, который написал Илон:
```
import re
import csv
import sys
from pathlib import Path
# Регулярное выражение для поиска markdown-ссылок
# Группа 1 → текст, Группа 2 → url
LINK_PATTERN = r'\[([^\]]+)\]\((https?://[^\s\)]+)\)'
def convert_markdown_links_to_html(text: str) -> str:
def replace_link(match):
text_part = match.group(1)
url_part = match.group(2)
return f'<a href="{url_part}">{text_part}</a>'
return re.sub(LINK_PATTERN, replace_link, text)
def process_csv_file(input_path: str, output_path: str = None, encoding='utf-8'):
input_path = Path(input_path)
if not input_path.is_file():
print(f"Файл не найден: {input_path}", file=sys.stderr)
return
if output_path is None:
output_path = input_path.with_name(input_path.stem + "_converted" + input_path.suffix)
converted_rows = []
links_found = 0
with open(input_path, encoding=encoding, newline='') as f_in:
reader = csv.reader(f_in)
header = next(reader, None) # читаем заголовок, если есть
if header:
converted_rows.append(header)
for row in reader:
new_row = []
for cell in row:
if not cell:
new_row.append(cell)
continue
new_cell = convert_markdown_links_to_html(cell)
if new_cell != cell:
links_found += len(re.findall(LINK_PATTERN, cell))
new_row.append(new_cell)
converted_rows.append(new_row)
# Записываем результат
with open(output_path, 'w', encoding=encoding, newline='') as f_out:
writer = csv.writer(f_out)
writer.writerows(converted_rows)
print(f"Обработано строк: {len(converted_rows)}")
print(f"Найдено и заменено ссылок: {links_found}")
print(f"Результат сохранён в: {output_path}")
# ────────────────────────────────────────────────
# Пример использования
if __name__ == "__main__":
# Измените на свой путь к файлу
FILE_PATH = "your_file.csv"
process_csv_file(
FILE_PATH,
# output_path="result.html.csv", # можно указать, если хотите другое имя
encoding="utf-8" # или "utf-8-sig", "windows-1251" и т.д.
)
```
И последний код, который написал Мишель:
```
import csv
import re
def replace_markdown_links_with_html(input_file, output_file):
# Регулярное выражение для поиска Markdown-ссылок
pattern = re.compile(r'\[([^\]]+)\]\(([^)]+)\)')
with open(input_file, mode='r', encoding='utf-8') as csv_input, \
open(output_file, mode='w', encoding='utf-8', newline='') as csv_output:
reader = csv.reader(csv_input)
writer = csv.writer(csv_output)
for row in reader:
# Обрабатываем каждую ячейку в строке
processed_row = []
for cell in row:
# Заменяем все найденные Markdown-ссылки на HTML-теги
processed_cell = pattern.sub(r"<a href='\2'>\1</a>", cell)
processed_row.append(processed_cell)
writer.writerow(processed_row)
# Пример использования:
input_csv = 'input.csv' # Замените на имя вашего входного файла
output_csv = 'output.csv' # Замените на имя выходного файла
replace_markdown_links_with_html(input_csv, output_csv)
```
Gemini проанализировал каждый код, оценил работу каждой нейронки. Худшие результаты выдали нейронки, работающие локально. Оно и не удивительно, часто количество параметров играет решающую роль, а тут обе модели были лишь на 8 миллиардов параметров, работали оффлайн, ограничиваясь ресурсами локальной машины.
Лучший по мнению Gemini результат показал Фарход (ChatGPT), хотя и в его работе Gemini нашел определенные недостатки.
Полный ответ Gemini:
Приветствую. Как Senior Python Developer, я провел ревью кода твоих подопечных. Задача кажется простой на первый взгляд, но она требует внимания к деталям: обработке больших файлов, безопасности (XSS), гибкости регулярных выражений и корректной работе с форматом CSV.
Ниже представлен детальный разбор полетов по каждому сотруднику и мой вариант эталонного решения.
Ревью кода сотрудников
1. Матинбек: “Худший результат”
-
Ошибки:
-
Регулярное выражение: Это катастрофа. Паттерн захардкожен под одну конкретную ссылку. Если завтра ссылка изменится, код бесполезен. К тому же, в паттерне синтаксические ошибки (несбалансированные скобки).
-
Производительность: Использование
df.applyна всем DataFrame в Pandas для такой задачи — это “стрельба из пушки по воробьям” с огромным потреблением памяти. -
Импорт внутри функции:
import reвнутриreplace_text— это плохой тон (PEP 8). -
Логика:
x.group(0)[1:-1]просто обрежет первый и последний символ всей найденной строки, что не создаст корректный URL.
-
2. Курбон: “Ошибся в базе”
-
Ошибки:
-
Регулярное выражение: Паттерн
r'$([^$]+)$\s*$([^)]+)$'абсолютно неверен. Символ$в regex означает конец строки. Он пытался экранировать скобки, но перепутал символы. -
Память: Код читает и пишет построчно (через
csv.reader), что хорошо для памяти.
-
-
Плюсы: Разделил логику на функции.
3. Клавдия: “Хороший середнячок”
-
Ошибки:
-
Безопасность: Не учитывает, что в тексте могут быть спецсимволы HTML, которые могут “сломать” верстку или привести к XSS-уязвимости.
-
Регулярное выражение: Достаточно точное, учитывает возможный пробел между скобками.
-
-
Плюсы: Чистый код, наличие примера для тестирования.
4. Фарход: “Почти профессионал”
-
Плюсы: Лучший из представленных.
-
Использует
html.escape— это критически важно для безопасности. -
Использует
argparseдля запуска из консоли. -
Предварительно компилирует регулярное выражение (
re.compile).
-
-
Ошибки: Зачем-то делает
list(reader), загружая весь файл в память. На огромных CSV это вызоветMemoryError.
5. Илон: “Перемудрил”
-
Плюсы: Использует
pathlib, проверяет существование файла. -
Ошибки:
-
Паттерн
https?://...слишком строгий. Markdown-ссылка может быть относительной (на внутренние страницы сайта). -
Опять же, загружает всё в список
converted_rows. -
Счетчик ссылок — лишняя работа, замедляющая процесс.
-
6. Мишель: “Просто и работает (но опасно)”
-
Плюсы: Самый лаконичный и понятный код. Правильно использует генератор для обработки строк.
-
Ошибки: Нет обработки исключений и экранирования HTML.
Итоговый профессиональный код
Как твой Senior, я подготовил версию, которая:
-
Потоковая: Читает файл построчно (не ест память).
-
Безопасная: Экранирует данные для HTML.
-
Гибкая: Обрабатывает любые Markdown-ссылки, а не только одну конкретную.
Python
import csv
import re
import html
import logging
from pathlib import Path
# Настраиваем логирование
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
# Регулярное выражение: [текст](ссылка) или [текст] (ссылка)
# Ищем нежадно [^\]]+ чтобы корректно обрабатывать несколько ссылок в строке
LINK_PATTERN = re.compile(r'\[([^\]]+)\]\s*\(([^)]+)\)')
def md_to_html_link(match: re.Match) -> str:
"""Callback-функция для безопасной замены MD на HTML."""
text = match.group(1)
url = match.group(2).strip()
# Экранируем спецсимволы (напр. & в URL или < в тексте), чтобы не "развалить" HTML
safe_text = html.escape(text)
safe_url = html.escape(url, quote=True)
return f"<a href='{safe_url}'>{safe_text}</a>"
def process_csv(input_file: str, output_file: str):
"""
Обрабатывает CSV файл потоково, заменяя Markdown ссылки на HTML теги.
"""
input_path = Path(input_file)
if not input_path.exists():
logging.error(f"Файл {input_file} не найден.")
return
try:
with open(input_path, 'r', encoding='utf-8', newline='') as f_in, \
open(output_file, 'w', encoding='utf-8', newline='') as f_out:
reader = csv.reader(f_in)
writer = csv.writer(f_out)
for row_idx, row in enumerate(reader, 1):
# Обработка каждой ячейки через регулярное выражение
processed_row = [LINK_PATTERN.sub(md_to_html_link, cell) for cell in row]
writer.writerow(processed_row)
if row_idx % 1000 == 0:
logging.info(f"Обработано {row_idx} строк...")
logging.info(f"Успешно! Результат сохранен в: {output_file}")
except Exception as e:
logging.error(f"Произошла ошибка при обработке: {e}")
if __name__ == "__main__":
# В реальном проекте здесь был бы argparse, но для текущей задачи достаточно так:
INPUT = 'input.csv'
OUTPUT = 'output_processed.csv'
process_csv(INPUT, OUTPUT)
Почему этот код лучше:
-
Память: Мы не используем
list(reader)илиdf.apply. Даже если в CSV будет 10 миллионов строк, программа потребит всего пару мегабайт ОЗУ. -
Безопасность: Если в ссылке из твоего примера есть
?utm_source=...&other=..., символ&будет корректно превращен в&, как того требуют стандарты HTML. -
Читаемость: Использование
pathlibиlogging— это стандарт современной разработки на Python. -
Надежность: Мы используем
newline='', как рекомендует документация модуляcsv, чтобы избежать проблем с переносами строк на разных ОС.
Вместо выводов
Конкретные выводы делать я не буду, призываю сделать это профессиональных Python-разработчиков. Поделитесь своим мнением, как вам работа этих нейронок? Смогли ли они сделать всё правильно? И как отработал Gemini – смогли ли он сделать нормальный анализ?
В свою очередь скажу, что его код сработал с первого раза без каких-либо ошибок.
