Как я подружил ZennoPoster с локальным ИИ — и он сам начал чинить мои скрипты

SAT

Client
Регистрация
24.12.2024
Сообщения
69
Реакции
166
Баллы
33
140543

Привет всем!

Хочу поделиться кейсом — как подключил локальный ИИ

к ZennoPoster через файловый сигнал.

Сразу важный момент про ограничение: проект ZennoPoster
зашифрован, C#-код внутри тоже. Поэтому AI Code Sherlock
не видит скрипты напрямую из проекта.

Workflow такой:
1. Ты открываешь нужный C#-блок в ZennoPoster
2. Копируешь код в текстовый файл или прямо в поле чата
3. Копируешь лог ошибки из ZP
4. AI Code Sherlock анализирует и выдаёт патч
5. Ты применяешь патч обратно в ZP вручную

Либо через File Signal автоматически — ZP сам пишет
запрос в файл, Sherlock отвечает патчем, ZP его читает.

Звучит как лишний шаг — но на практике это быстрее
чем копировать код в ChatGPT и обратно вручную.
Плюс история всех патчей сохраняется, бэкапы
создаются автоматически.

Буду рад фидбеку от тех кто работает с ZP регулярно —
что ещё можно автоматизировать в этом workflow?

Я автоматизирую всё что движется уже несколько лет. ZennoPoster — мой основной инструмент. Шаблоны, парсеры, регистраторы, постеры — всё через него.

И у меня была одна боль, которая не давала покоя.

Боль, которую знает каждый зенно-разработчик

Ты пишешь шаблон. Долго. Потом запускаешь — и он падает. Смотришь в лог:

[ERROR] NullReferenceException at ProcessResponse() line 847

[ERROR] Index was outside the bounds of the array
[ERROR] Object reference not set to an instance of an object

Окей. Открываешь C#-код, ищешь строку 847, пытаешься понять что там происходит. Думаешь 20 минут. Фиксишь. Запускаешь снова. Падает на строке 1203.
Я прогонял через ChatGPT, через Claude. Копировал ошибку, копировал код, ждал ответа, копировал ответ обратно. Потом снова. Потом снова.
Это работало — но это был ад ручного труда.
Я подумал: а что если ИИ будет делать это сам? Читать лог, находить проблему, писать фикс, применять его — без моего участия?
Так начался проект AI Code Sherlock.


140587

Что такое AI Code Sherlock

Если коротко: это бесплатный десктопный IDE-ассистент с открытым исходным кодом, который:

  • Читает логи ошибок
  • Находит первопричину (не симптом, а именно причину)
  • Генерирует точечный патч — только те строки которые нужно изменить
  • Применяет его с бэкапом
  • Может делать это автономно в цикле

Ключевое слово — точечный. Большинство ИИ-инструментов переписывают весь файл целиком. Это катастрофа для рабочего шаблона на 2000 строк. AI Code Sherlock меняет только конкретный блок:

[SEARCH_BLOCK]

result = response.SelectToken("data[0].value");
[REPLACE_BLOCK]
if (response == null || !response.HasValues)
return null;
result = response.SelectToken("data[0].value");

[END_PATCH]

Нашёл точное вхождение → проверил что оно одно → сделал бэкап → заменил. Если что-то пошло не так — один клик и откат.


Самая интересная часть: интеграция с ZennoPoster через File Signal

Вот где начинается магия.

AI Code Sherlock имеет встроенный механизм File Signal — это IPC (межпроцессное взаимодействие) через обычные текстовые файлы на диске.

Схема работает так:

[ZennoPoster шаблон]

↓ пишет запрос в файл
signals/request/req_001.txt

[AI Code Sherlock мониторит папку]
↓ читает запрос, отправляет ИИ
ИИ обрабатывает...
↓ пишет ответ
signals/response/req_001.txt

[ZennoPoster читает ответ]

Никаких API-серверов. Никаких портов. Никаких сетевых настроек. Просто папки на диске.



Как настроить в ZennoPoster

В шаблоне ZennoPoster добавляешь 3 блока C# код с таким содержимым:


Сниппет 1 — Читаем запрос из папки:
Развернуть Свернуть Копировать
string requestFolder  = @"C:\AI Code Sherlock\signals\request";
string responseFolder = @"C:\AI Code Sherlock\signals\response";

System.IO.Directory.CreateDirectory(requestFolder);
System.IO.Directory.CreateDirectory(responseFolder);

project.Variables["signal_request_id"].Value = "";
project.Variables["signal_prompt"].Value     = "";

int waited = 0;
string reqFile = "";

while (waited < 120000)
{
    string[] files = System.IO.Directory.GetFiles(requestFolder, "*.txt");
    if (files.Length > 0)
    {
        reqFile = files[0];
        break;
    }
    System.Threading.Thread.Sleep(500);
    waited += 500;
}

if (string.IsNullOrEmpty(reqFile))
{
    project.SendInfoToLog("Signal: таймаут — нет запроса за 120с", true);
    throw new Exception("no_request");
}

System.Threading.Thread.Sleep(150);

string requestId = System.IO.Path.GetFileNameWithoutExtension(reqFile);
string prompt    = System.IO.File.ReadAllText(reqFile, System.Text.Encoding.UTF8).Trim();

System.IO.File.Delete(reqFile);

project.Variables["signal_request_id"].Value = requestId;
project.Variables["signal_prompt"].Value     = prompt;

project.SendInfoToLog("Signal: получен [" + requestId + "] (" + prompt.Length + " симв.)", true);

Сниппет 2 — Отправляем запрос к ИИ (HTTP):
Развернуть Свернуть Копировать
string prompt = project.Variables["signal_prompt"].Value;

if (string.IsNullOrEmpty(prompt))
{
    project.SendInfoToLog("Signal: промпт пустой", true);
    throw new Exception("empty_prompt");
}

string apiUrl = "http://localhost:11434/v1/chat/completions";
// Для OpenAI: "https://api.openai.com/v1/chat/completions"
string apiKey = "";
// Для OpenAI: "sk-..."
string model  = "gemini-3-flash-preview";
// Или: "gpt-4o", "llama3.2" и т.д.

// Экранируем промпт вручную (без Newtonsoft)
string escapedPrompt = prompt
    .Replace("\\", "\\\\")
    .Replace("\"", "\\\"")
    .Replace("\r\n", "\\n")
    .Replace("\n", "\\n")
    .Replace("\r", "\\n")
    .Replace("\t", "\\t");

string jsonBody = "{\"model\":\"" + model + "\",\"messages\":[{\"role\":\"user\",\"content\":\"" + escapedPrompt + "\"}],\"temperature\":0.2,\"max_tokens\":4096}";

var request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(apiUrl);
request.Method      = "POST";
request.ContentType = "application/json";
request.Timeout     = 120000;

if (!string.IsNullOrEmpty(apiKey))
    request.Headers.Add("Authorization", "Bearer " + apiKey);

byte[] bodyBytes = System.Text.Encoding.UTF8.GetBytes(jsonBody);
request.ContentLength = bodyBytes.Length;

using (var stream = request.GetRequestStream())
    stream.Write(bodyBytes, 0, bodyBytes.Length);

string rawJson = "";
try
{
    using (var resp = (System.Net.HttpWebResponse)request.GetResponse())
    using (var reader = new System.IO.StreamReader(resp.GetResponseStream(), System.Text.Encoding.UTF8))
        rawJson = reader.ReadToEnd();
}
catch (System.Net.WebException ex)
{
    using (var reader = new System.IO.StreamReader(ex.Response.GetResponseStream(), System.Text.Encoding.UTF8))
        rawJson = reader.ReadToEnd();
    project.SendInfoToLog("Signal: ошибка API — " + rawJson, true);
    throw new Exception("api_error");
}

// Парсим без Newtonsoft — ищем "content":"..."
var match = System.Text.RegularExpressions.Regex.Match(
    rawJson,
    "\"content\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"",
    System.Text.RegularExpressions.RegexOptions.Singleline
);

string answer = match.Success ? match.Groups[1].Value : rawJson;

// Обратное экранирование
answer = answer
    .Replace("\\n", "\n")
    .Replace("\\r", "\r")
    .Replace("\\t", "\t")
    .Replace("\\\"", "\"")
    .Replace("\\\\", "\\");

project.Variables["signal_ai_response"].Value = answer.Trim();
project.SendInfoToLog("Signal: ИИ ответил (" + answer.Length + " симв.)", true);

Сниппет 2 — Отправляем запрос к ИИ (local Ollama):
Развернуть Свернуть Копировать
string prompt = project.Variables["signal_prompt"].Value;

if (string.IsNullOrEmpty(prompt))
{
    project.SendInfoToLog("Signal: промпт пустой", true);
    throw new Exception("empty_prompt");
}

// ── Настройки Ollama ────────────────────────────────────────
string ollamaUrl = "http://localhost:11434/api/generate";
string model     = "llama3"; // ← замени на свою модель
// Список моделей: ollama list

// Экранируем промпт
string escapedPrompt = prompt
    .Replace("\\", "\\\\")
    .Replace("\"", "\\\"")
    .Replace("\r\n", "\\n")
    .Replace("\n", "\\n")
    .Replace("\r", "\\n")
    .Replace("\t", "\\t");

// Ollama /api/generate — stream:false чтобы получить один JSON
string jsonBody = "{\"model\":\"" + model + "\",\"prompt\":\"" + escapedPrompt + "\",\"stream\":false,\"options\":{\"temperature\":0.2,\"num_predict\":4096}}";

var request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(ollamaUrl);
request.Method      = "POST";
request.ContentType = "application/json";
request.Timeout     = 300000; // 5 минут — локальные модели медленнее

byte[] bodyBytes = System.Text.Encoding.UTF8.GetBytes(jsonBody);
request.ContentLength = bodyBytes.Length;

using (var stream = request.GetRequestStream())
    stream.Write(bodyBytes, 0, bodyBytes.Length);

string rawJson = "";
try
{
    using (var resp = (System.Net.HttpWebResponse)request.GetResponse())
    using (var reader = new System.IO.StreamReader(resp.GetResponseStream(), System.Text.Encoding.UTF8))
        rawJson = reader.ReadToEnd();
}
catch (System.Net.WebException ex)
{
    string errBody = "";
    try
    {
        using (var reader = new System.IO.StreamReader(ex.Response.GetResponseStream(), System.Text.Encoding.UTF8))
            errBody = reader.ReadToEnd();
    }
    catch {}
    project.SendInfoToLog("Signal: ошибка Ollama — " + ex.Message + " | " + errBody, true);
    throw new Exception("ollama_error");
}

// Ollama возвращает: {"model":"...","response":"текст ответа","done":true,...}
// Парсим поле "response"
var match = System.Text.RegularExpressions.Regex.Match(
    rawJson,
    "\"response\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"",
    System.Text.RegularExpressions.RegexOptions.Singleline
);

string answer = match.Success ? match.Groups[1].Value : rawJson;

// Обратное экранирование
answer = answer
    .Replace("\\n", "\n")
    .Replace("\\r", "\r")
    .Replace("\\t", "\t")
    .Replace("\\\"", "\"")
    .Replace("\\\\", "\\");

project.Variables["signal_ai_response"].Value = answer.Trim();
project.SendInfoToLog("Signal: Ollama ответил (" + answer.Length + " симв.)", true);

Сниппет 3 — Записываем ответ в папку response:
Развернуть Свернуть Копировать
string responseFolder = @"C:\AI Code Sherlock\signals\response";
System.IO.Directory.CreateDirectory(responseFolder);

string requestId  = project.Variables["signal_request_id"].Value;
string aiResponse = project.Variables["signal_ai_response"].Value;

if (string.IsNullOrEmpty(requestId))
{
    project.SendInfoToLog("Signal: нет request_id", true);
    throw new Exception("no_request_id");
}

if (string.IsNullOrEmpty(aiResponse))
{
    project.SendInfoToLog("Signal: ответ пустой", true);
    throw new Exception("empty_response");
}

string resFile = System.IO.Path.Combine(responseFolder, requestId + ".txt");
System.IO.File.WriteAllText(resFile, aiResponse, System.Text.Encoding.UTF8);

project.SendInfoToLog("Signal: записан → " + requestId + ".txt", true);

// Сброс для следующего цикла
project.Variables["signal_request_id"].Value  = "";
project.Variables["signal_prompt"].Value      = "";
project.Variables["signal_ai_response"].Value = "";


И всё. ZennoPoster отправил запрос — AI Code Sherlock ответил.

Для динамической компиляции и удобной отладки используйте этот C#-загрузчик. Он позволяет на лету подтягивать и выполнять вашу основную логику, предварительно сохраненную в .cs файл.
СНИППЕТ ПОД АВТОМАТИЧЕСКИЙ ДЕБАГИНГ ИЛИ AUTO-PIPELINE:
Развернуть Свернуть Копировать
// ── ЗАГРУЗЧИК — вставляй в каждый из 3 кубиков, меняя только methodName ──
string csFile    = @"C:\AI Code Sherlock\zp_scripts\signal_handler.cs";
string methodName = "ReadRequest"; // ← меняй: ReadRequest / QueryOllama / WriteResponse

// Читаем исходник
string sourceCode = System.IO.File.ReadAllText(csFile, System.Text.Encoding.UTF8);

// Компилируем
var provider = new Microsoft.CSharp.CSharpCodeProvider();
var compParams = new System.CodeDom.Compiler.CompilerParameters();
compParams.GenerateInMemory   = true;
compParams.ReferencedAssemblies.Add("System.dll");
compParams.ReferencedAssemblies.Add("System.Net.dll");
compParams.ReferencedAssemblies.Add("System.Core.dll");
// Путь к ZennoPoster DLL — обычно здесь:
compParams.ReferencedAssemblies.Add(@"C:\Program Files\ZennoLab\RU\ZennoPoster Pro V7\7.8.15.0\Progs\ZennoLab.InterfacesLibrary.dll");

var result = provider.CompileAssemblyFromSource(compParams, sourceCode);

if (result.Errors.HasErrors)
{
    string errors = "";
    foreach (System.CodeDom.Compiler.CompilerError e in result.Errors)
        errors += "Строка " + e.Line + ": " + e.ErrorText + "\n";
    System.IO.File.AppendAllText(
        @"C:\AI Code Sherlock\zp_scripts\signal_handler.log",
        "[" + DateTime.Now + "] COMPILE ERROR:\n" + errors,
        System.Text.Encoding.UTF8
    );
    throw new Exception("compile_error: " + errors);
}

// Запускаем нужный метод
var assembly = result.CompiledAssembly;
var type     = assembly.GetType("SignalHandler");
var method   = type.GetMethod(methodName);
method.Invoke(null, new object[] { project });


signal_handler.cs:
Развернуть Свернуть Копировать
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using ZennoLab.InterfacesLibrary.ProjectModel;

public class SignalHandler
{
    // Путь к лог-файлу
    private static string logFile = @"C:\AI Code Sherlock\zp_scripts\signal_handler.log";

    // ── Запись в лог ───────────────────────────────────────
    public static void Log(string message)
    {
        string line = "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "] " + message;
        try { File.AppendAllText(logFile, line + "\r\n", Encoding.UTF8); }
        catch { }
    }

    // ── Сниппет 1: Читаем входящий запрос ─────────────────
    public static void ReadRequest(IZennoPosterProjectModel project)
    {
        string requestFolder  = @"C:\AI Code Sherlock\signals\request";
        string responseFolder = @"C:\AI Code Sherlock\signals\response";

        Directory.CreateDirectory(requestFolder);
        Directory.CreateDirectory(responseFolder);

        project.Variables["signal_request_id"].Value = "";
        project.Variables["signal_prompt"].Value     = "";

        Log("ReadRequest: ожидаем запрос...");

        int waited = 0;
        string reqFile = "";

        while (waited < 120000)
        {
            string[] files = Directory.GetFiles(requestFolder, "*.txt");
            if (files.Length > 0) { reqFile = files[0]; break; }
            Thread.Sleep(500);
            waited += 500;
        }

        if (string.IsNullOrEmpty(reqFile))
        {
            Log("ReadRequest: таймаут 120с — запросов нет");
            throw new Exception("no_request");
        }

        Thread.Sleep(150);

        string requestId = Path.GetFileNameWithoutExtension(reqFile);
        string prompt    = File.ReadAllText(reqFile, Encoding.UTF8).Trim();
        File.Delete(reqFile);

        project.Variables["signal_request_id"].Value = requestId;
        project.Variables["signal_prompt"].Value     = prompt;

        Log("ReadRequest: получен [" + requestId + "] (" + prompt.Length + " симв.)");
        project.SendInfoToLog("Signal: получен [" + requestId + "]", true);
    }

    // ── Сниппет 2: Запрос к Ollama ─────────────────────────
    public static void QueryOllama(IZennoPosterProjectModel project)
    {
        string prompt = project.Variables["signal_prompt"].Value;

        if (string.IsNullOrEmpty(prompt))
        {
            Log("QueryOllama: промпт пустой");
            throw new Exception("empty_prompt");
        }

        string ollamaUrl = "http://localhost:11434/api/generate";
        string model     = "llama3"; // ← меняй модель здесь

        Log("QueryOllama: отправляем запрос к модели " + model);

        string escapedPrompt = prompt
            .Replace("\\", "\\\\").Replace("\"", "\\\"")
            .Replace("\r\n", "\\n").Replace("\n", "\\n")
            .Replace("\r", "\\n").Replace("\t", "\\t");

        string jsonBody = "{\"model\":\"" + model + "\",\"prompt\":\"" + escapedPrompt
            + "\",\"stream\":false,\"options\":{\"temperature\":0.2,\"num_predict\":4096}}";

        var request = (HttpWebRequest)WebRequest.Create(ollamaUrl);
        request.Method      = "POST";
        request.ContentType = "application/json";
        request.Timeout     = 300000;

        byte[] bodyBytes = Encoding.UTF8.GetBytes(jsonBody);
        request.ContentLength = bodyBytes.Length;
        using (var s = request.GetRequestStream()) s.Write(bodyBytes, 0, bodyBytes.Length);

        string rawJson = "";
        try
        {
            using (var resp = (HttpWebResponse)request.GetResponse())
            using (var reader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8))
                rawJson = reader.ReadToEnd();
        }
        catch (WebException ex)
        {
            string err = "";
            try { using (var r = new StreamReader(ex.Response.GetResponseStream(), Encoding.UTF8)) err = r.ReadToEnd(); } catch {}
            Log("QueryOllama: ошибка — " + ex.Message + " | " + err);
            project.SendInfoToLog("Signal: ошибка Ollama — " + ex.Message, true);
            throw new Exception("ollama_error");
        }

        var match = Regex.Match(rawJson,
            "\"response\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"",
            RegexOptions.Singleline);

        string answer = match.Success ? match.Groups[1].Value : rawJson;
        answer = answer.Replace("\\n","\n").Replace("\\r","\r")
                       .Replace("\\t","\t").Replace("\\\"","\"").Replace("\\\\","\\");

        project.Variables["signal_ai_response"].Value = answer.Trim();

        Log("QueryOllama: ответ получен (" + answer.Length + " симв.)");
        project.SendInfoToLog("Signal: Ollama ответил (" + answer.Length + " симв.)", true);
    }

    // ── Сниппет 3: Записываем ответ в response ─────────────
    public static void WriteResponse(IZennoPosterProjectModel project)
    {
        string responseFolder = @"C:\AI Code Sherlock\signals\response";
        Directory.CreateDirectory(responseFolder);

        string requestId  = project.Variables["signal_request_id"].Value;
        string aiResponse = project.Variables["signal_ai_response"].Value;

        if (string.IsNullOrEmpty(requestId))
        {
            Log("WriteResponse: нет request_id");
            throw new Exception("no_request_id");
        }

        string resFile = Path.Combine(responseFolder, requestId + ".txt");
        File.WriteAllText(resFile, aiResponse, Encoding.UTF8);

        Log("WriteResponse: записан → " + requestId + ".txt");
        project.SendInfoToLog("Signal: ответ записан → " + requestId + ".txt", true);

        project.Variables["signal_request_id"].Value  = "";
        project.Variables["signal_prompt"].Value      = "";
        project.Variables["signal_ai_response"].Value = "";
    }
}

Реальный кейс: автономная отладка парсера

Расскажу конкретный пример из своей практики.
У меня был парсер маркетплейса. Работал нормально месяц, потом сайт обновил структуру и всё сломалось. Лог был такой:


[10:23:41][ERR] XPathException: Expression must evaluate to a node-set

at ParseProductCard() line 312
[10:23:41][ERR] Attribute 'data-price' not found on element
at ExtractPrice() line 445

[10:23:41][ERR] Null reference in BuildProductObject() line 521

Три ошибки. Три разных места. Раньше я бы потратил час на отладку.

Вместо этого я открыл AI Code Sherlock, включил Режим Шерлока, вставил лог — и нажал отправить.

Через 15 секунд:

АНАЛИЗ ШЕРЛОКА:

Первопричина: сайт изменил структуру карточки товара —
атрибут data-price перенесён в дочерний span.
Все три ошибки — следствие одного изменения.

Уверенность: ВЫСОКАЯ (94%) — XPath-ошибка однозначно
указывает на изменение структуры DOM.

ПАТЧ:
[SEARCH_BLOCK]

var price = node.SelectSingleNode("@data-price")?.Value;
[REPLACE_BLOCK]
var price = node.SelectSingleNode(".//span[@class='price']/@data-price")
?.Value
?? node.SelectSingleNode("@data-price")?.Value;

[END_PATCH]

Применил. Парсер заработал. Всё время — 3 минуты.


Auto-Improve Pipeline: ИИ итерирует сам

Это самая мощная фича для тех кто пишет алгоритмы обработки данных.
Настраиваешь:

  • Цель: "скрипт должен обрабатывать 1000 записей без ошибок и с точностью > 95%"
  • Скрипт: твой Python/C# скрипт для теста
  • Стратегия: одна из восьми (Safe Ratchet, Balanced, Explorer...)
  • Итераций: до 20
Нажимаешь Run — и идёшь пить кофе.

Pipeline сам:

  1. Запускает скрипт
  2. Читает лог
  3. Генерирует патч
  4. Проверяет синтаксис
  5. Применяет (с бэкапом)
  6. Запускает снова
  7. Проверяет метрики
  8. Повторяет
В моём случае за 7 итераций точность парсера поднялась с 67% до 91%.

[PIPELINE] Итерация 1/20 стратегия=BALANCED

[RUN] test_parser.py → exit 0 (8.2s) точность=0.67
[ПАТЧ] ✓ применён · бэкап создан
[RUN] test_parser.py → exit 0 (8.1s) точность=0.74 ↑+0.07

[PIPELINE] Итерация 4/20
[RUN] точность=0.88 ↑+0.14 от старта
...

[PIPELINE] Итерация 7/20
[RUN] точность=0.91 ↑ ЦЕЛЬ ДОСТИГНУТА

[PIPELINE] ✅ GOAL_ACHIEVED · остановка


8 стратегий ИИ для разных задач
Это не просто настройка — это реально разные подходы к решению проблем:


СтратегияКогда использовать
ConservativeИсправить только ошибки, не трогать рабочее
BalancedИсправить + умеренные улучшения (по умолчанию)
AggressiveРефакторинг, максимум изменений
Safe RatchetПрименять только если метрики улучшились
ExplorerКаждая итерация — принципиально новый подход
HypothesisСформировать гипотезу → проверить → сделать вывод
EnsembleГенерирует 3 варианта патча, выбирает лучший
ExploitУсиливать то что уже работает

Для ZennoPoster-разработки я чаще всего использую Conservative (чинить только сломанное) и Safe Ratchet (только если точность улучшилась).



Работает офлайн — твой код никуда не уходит

Это важно для тех кто работает с коммерческими шаблонами.
AI Code Sherlock работает полностью локально с Ollama:


Bash:
Развернуть Свернуть Копировать
ollama serve

ollama pull deepseek-coder-v2  # лучшая модель для кода

Никаких API-ключей. Никакой отправки кода на чужие серверы. Всё на твоей машине.

Если хочешь мощнее — подключаешь облачные модели: GPT-4o, Gemini 3.0 Flash, Groq (llama3.3-70b бесплатно), Mistral Codestral.




Консенсус-движок: опрашиваем несколько моделей

Для критичных задач можно включить Consensus Engine — это когда несколько моделей отвечают одновременно, а система выбирает лучший ответ:

  • Vote: патч принимается если ≥N моделей согласны
  • Best-of-N: выбирается ответ с наибольшим числом корректных патчей
  • Merge: берём уникальные патчи от всех моделей
  • Judge: одна модель читает ответы остальных и выбирает лучший
Для отладки сложных шаблонов это реально помогает — разные модели видят разные аспекты проблемы.



Карта ошибок: память проекта

Каждая ошибка сохраняется с подтверждённым решением. Когда та же ошибка появляется снова — ИИ видит контекст:

## КАРТА ОШИБОК — ранее решённые проблемы:


Ошибка: NullReferenceException в ParseProductCard()
Причина: отсутствие проверки на null перед обращением к дочерним узлам
Решение: добавить null-guard перед каждым SelectSingleNode()

⚠ ЗАПРЕЩЁННЫЕ ПОДХОДЫ:
- НЕ оборачивать в try/catch без исправления причины — уже пробовали, не помогло

- Вместо этого: проверять наличие узла перед обращением

Меньше повторяющихся ошибок. Меньше кругов отладки.



Честно про статус проекта

Я должен сказать прямо: AI Code Sherlock — ранняя разработка.

Что это значит на практике:

  • Основной функционал работает стабильно — патчи, Pipeline, File Signal, версионирование
  • Интерфейс функциональный, не идеальный — где-то не хватает polish
  • Тестировалось в основном на Python и C# — другие языки работают, но меньше проверены
  • File Signal с ZennoPoster работает, но потребует от тебя немного настройки под свою конкретную конфигурацию
Что уже точно работает хорошо:
  • Парсинг патчей из ответов ИИ
  • Применение с бэкапом и версионированием
  • Pipeline с метриками и auto-rollback
  • Режим Шерлока для анализа ошибок
  • File Signal IPC
  • Работа с Ollama офлайн

Это не продукт корпорации с командой из 50 человек. Это реальный инструмент который я сделал для себя, и который решает реальные задачи прямо сейчас.


Попробовать

GitHub (исходный код, всё бесплатно):

https://github.com/signupss/ai-code-sherlock

Сайт с описанием всех фич:

https://codesherlock.dev

Установка:


Bash:
Развернуть Свернуть Копировать
git clone https://github.com/signupss/ai-code-sherlock.git

cd ai-code-sherlock

pip install -r requirements.txt

python main.py

Нужен Python 3.11+. Зависимостей минимум — PyQt6, aiohttp, aiofiles.

Если захочешь попробовать File Signal с ZennoPoster

Напиши в комментариях — покажу полный пример шаблона ZennoPoster с интеграцией, включая:


  • Чтение лога ошибки из переменной проекта
  • Отправку в AI Code Sherlock
  • Получение патча обратно
  • Автоматическое применение

Буду рад фидбеку — особенно от тех кто работает с ZennoPoster регулярно. Что ещё должен уметь инструмент чтобы реально помогать в этом workflow?



Проект в активной разработке. Звезда на GitHub очень помогает — это сигнал что инструмент нужен людям.


⭐
https://github.com/signupss/ai-code-sherlock
 

Вложения

  • main.zp
    main.zp
    21 KB · Просмотры: 59
Последнее редактирование:
Если захочешь попробовать File Signal с ZennoPoster

Напиши в комментариях — покажу полный пример шаблона ZennoPoster с интеграцией, включая:
Очень интересный кейс! Навыков у меня еще маловато, но в ближайшем будущем будет интересно опробовать. Пишу в комментариях :dz:
 
  • Увидел
Реакции: SAT
Подскажите, какую видеокарту используете для своей llm. Благодарю.
 
Подскажите, какую видеокарту используете для своей llm. Благодарю.
Тут чем новее тем лучше, смотрите сравнительные статистики на просторах интернета под каждую модель :df:
 

Кто просматривает тему: (Всего: 2, Пользователи: 1, Гости: 1)