[{"data":1,"prerenderedAt":160},["ShallowReactive",2],{"$fBBQ5ulyG5jVWbIBJe3r8F-kTKQKf1scMJiu0B6qzX5k":3,"$f7AVZHmPutZ23_8XKkLbDtEszKCuiY3yPjIDp9eRXGag":5,"$fKZnaxNa9m5TUuB4tk0VS9LlGYeE4OqHjjqbTSnDs-VI":7,"$fwn0-5pcWc6hDq0xCXLSi1gJCBwuGRLl-pBzsG9KA88Q":137},{"data":4},[],{"data":6},[],{"data":8,"meta":133},[9],{"id":10,"documentId":11,"title":12,"seo_title":12,"summary":13,"seo_description":13,"slug":14,"published_date":15,"body":16,"content":17,"createdAt":39,"updatedAt":40,"publishedAt":41,"blogauthor":42,"cover":87,"categories":122},293,"hni1gv02ioa6ugwkvvds94uh","Локальный ИИ в OpenIDE: Mellum + Continue + Ollama","В этом гайде от команды Spring АйО вы узнаете, как настроить локальную LLM для вашей IDE, будь то IntelliJ IDEA или OpenIDE. ","lokalnyj-ii-v-openide-mellum-continue-ollama","2026-02-09","ИИ в разработке уже не новость, а обыденность. На этом фоне набирает обороты другая тенденция — запускать модели локально. Причины понятны: приватность кода, работа без интернета, предсказуемая задержка и никакого вендор-лок. Вы контролируете, какая модель у вас крутится, какие данные она видит и что именно отправляется «наружу» (спойлер: ничего).\n\nОбратная сторона тоже есть. Большие модели прожорливы: им нужны CPU\u002FGPU, память.. Настройка окружения, версии — всё это ложится на вас. Но хорошая новость в том, что для задач автокомплишена не всегда нужен «монстр» на десятки миллиардов параметров. В связи с этим появились легковесные модели, которые шустро работают на обычном рабочем ноутбуке и при этом прекрасно справляются с рутиной в IDE.\n\nВ этом гайде от команды [Spring АйО](https:\u002F\u002Ft.me\u002F+QmrKn0wA8CdkNjAy) вы узнаете, как настроить локальную LLM для вашей IDE, будь то IntelliJ IDEA или OpenIDE. Я буду использовать последнюю.\n\n\u003Ch2 id=\"llm\">LLM\u003C\u002Fh2>\n\nВ качестве модели будем использовать [Mellum](https:\u002F\u002Fwww.jetbrains.com\u002Fhelp\u002Fide-services\u002Fjetbrains-mellum.html) — это семейство «легких» моделей от JetBrains, заточенных под автодополнение кода и интерактивную работу прямо в IDE.\n\nJetBrains [пришли к Mellum](https:\u002F\u002Fblog.jetbrains.com\u002Fblog\u002F2024\u002F10\u002F22\u002Fintroducing-mellum-jetbrains-new-llm-built-for-developers\u002F) из практической боли: нужен был быстрый и стабильный комплишн в IDE, который помнит длинный контекст проекта и не «расползается» в болтливый чат. Осенью 2024-го они запустили Mellum как облачную модель внутри JetBrains AI Assistant — по сути, новый движок автокомплита с упором на скорость и уместность подсказок.\n\nДальше — логичный шаг к open source. [Весной 2025 JetBrains опубликовали](https:\u002F\u002Fblog.jetbrains.com\u002Fai\u002F2025\u002F04\u002Fmellum-goes-open-source-a-purpose-built-llm-for-developers-now-on-hugging-face\u002F) Mellum: модель, узко заточенная под комплишн, с небольшим размером и понятной лицензией для локального использования и экспериментов. Причины довольно прозрачны: дать разработчикам приватность и офлайн, снизить порог входа для интеграций, а сообществу — возможность проверять и улучшать модель.\n\n\u003Ch2 id=\"kak-mellum-gotovili\">Как Mellum готовили?\u003C\u002Fh2>\n\nКоманда [описала](https:\u002F\u002Fblog.jetbrains.com\u002Fai\u002F2025\u002F04\u002Fmellum-how-we-trained-a-model-to-excel-in-code-completion) трёхэтапный пайплайн: предобучение на массиве автономных файлов, дообучение на контекстных примерах из реальной IDE и выравнивание через RL с AI-фидбеком, чтобы выжечь нежелательные паттерны и подогнать стиль под продуктовые сценарии. Контекстное окно — ~8K токенов, архитектура — LLaMA-style, акцент на комплишн и скорость инференса в редакторе.\n\nВ сухом остатке Mellum — открытая, компактная модель для IDE: не пытается быть всем сразу, зато уверенно дописывает код в стиле проекта и легко заводится локально через Ollama.\n\n\u003Ch2 id=\"zapusk-modeli\">Запуск модели\u003C\u002Fh2>\n\nДля установки и запуска модели нам понадобится рантайм. Будем использовать [Ollama](https:\u002F\u002Fdocs.ollama.com\u002F). Ollama запускает HTTP-сервер на localhost:11434. Мы общаемся не с моделью напрямую, а с Ollama по её REST-API; Ollama принимает запросы (например, \u002Fapi\u002Fgenerate или \u002Fapi\u002Fchat) и сама маршрутизирует их к выбранной модели.\n\nРаботает на macOS\u002FWindows\u002FLinux и не отправляет ваш код в облако — всё общение остаётся локально.\n\nУстановка выполняется прямо из терминала (версия для macOS):\n\n```bash\n# Устанавливаем Ollama через Homebrew\nbrew install ollama\n\n# Запускаем Ollama\nollama serve &\n\n# Выполняем pull нашей модели\nollama pull JetBrains\u002FMellum-4b-sft-all\n\n# Проверяем, что Ollama запущена и видит установленные модели\ncurl http:\u002F\u002Flocalhost:11434\u002Fapi\u002Ftags\n```\nLinux:\n\n```bash\n# Устанавливаем Ollama \ncurl -fsSL https:\u002F\u002Follama.ai\u002Finstall.sh | sh\n\n# Запускаем Ollama\nollama serve\n\n# Выполняем pull нашей модели\nollama pull JetBrains\u002FMellum-4b-sft-all\n\n# Проверяем, что Ollama запущена и видит установленные модели\ncurl http:\u002F\u002Flocalhost:11434\u002Fapi\u002Ftags\n```\nДля Windows:\n\n1. Скачиваем ollama с официального сайта\n2. После установки Ollama запустится автоматически\n3. Выполняем pull нашей модели\n\n```bash\nollama pull JetBrains\u002FMellum-4b-sft-all\n```\n\n\n>Только Mellum?\n> \n> На самом деле нет. Можно использовать и другие модели. Кстати, Continue в некоторых случаях сам рекомендует некоторые модели. Например, для [chat-роли](https:\u002F\u002Fdocs.continue.dev\u002Fcustomize\u002Fmodel-roles\u002Fchat) в топ открытых моделей входят Qwen3 Coder (480B), Qwen3 Coder (30B), gpt-oss (120B), gpt-oss (20B). Список топовых моделей доступен в соответствующих ролях.На самом деле нет. Можно использовать и другие модели. Кстати, Continue в некоторых случаях сам рекомендует некоторые модели. Например, для chat-роли в топ открытых моделей входят [Qwen3 Coder (480B)](https:\u002F\u002Fhub.continue.dev\u002Fopenrouter\u002Fqwen3-coder), [Qwen3 Coder (30B)](https:\u002F\u002Fhub.continue.dev\u002Follama\u002Fqwen3-coder-30b), [gpt-oss (120B)](https:\u002F\u002Fhub.continue.dev\u002Fopenrouter\u002Fgpt-oss-120b), [gpt-oss (20B)](https:\u002F\u002Fhub.continue.dev\u002Follama\u002Fgpt-oss-20b). Список топовых моделей доступен в [соответствующих ролях](https:\u002F\u002Fdocs.continue.dev\u002Fcustomize\u002Fmodel-roles\u002F00-intro).\n\n\u003Ch2 id=\"kak-nauchit-obshhatsya-ide-i-llm\">Как научить общаться IDE и LLM\u003C\u002Fh2>\n\nВ среде разработки нет такой функциональности, который выступала бы посредником между средой разработки и самой моделькой. Для этой задачи есть несколько плагинов, которые доступны для скачивания из маркетплейса OpenIDE. Мы будем использовать [**Continue**](https:\u002F\u002Fwww.continue.dev\u002F) — это открытый плагин-мост между вашей IDE и любыми LLM, в том числе локальными. Проще говоря, Continue — это «адаптер», который превращает локальную Mellum в нативный автокомплит OpenIDE: вы пишете код, Continue берёт контекст из IDE и дергает Mellum через Ollama, а подсказки появляются там, где вы печатаете.\n\nДля его установки нам потребуется пройти в маркетплейс и нехитрым способом его установить.\n\n![1.png]({{strapiUrl}}\u002Fuploads\u002F1_dfc24b0162_6e84185fb9.webp)\n\nПочему и зачем он нужен: \n\n- **Чтобы связать OpenIDE ↔ Ollama\u002FMellum**. В **config.yaml** мы указываем `provider: ollama` и модель `JetBrains\u002FMellum-4b-sft-all`, а в `roles` — `autocomplete`. После этого [Continue становится](http:\u002F\u002Fdocs.continue.dev\u002F) «двигателем» комплишена внутри IDE, используя локальную Mellum.\n- `config.yaml` – это главный конфигурационный файл плагина **Continue**. В нём вы описываете, какие модели использовать (например, в нашем случае, Mellum через provider: ollama), какие роли они выполняют (`autocomplete`, `chat`, `edit`, `apply`), а также дополнительные вещи: контекст-провайдеры, правила (rules), промпты и инструменты (MCP-серверы). Иначе говоря, **config.yaml** определяет «кто» и «как» будет работать в вашем ассистенте прямо из IDE.\n- **Единая точка настройки**. Конфиг открывается прямо из боковой панели Continue в JetBrains, изменения подхватываются без перезапуска. Проще экспериментировать с моделями и параметрами. \n- **Гибкость и контроль**. Continue — open-source, поддерживает разные модели\u002Fрежимы и не навязывает облако: хотите — всё крутится локально через Ollama; хотите — подключаете удалённый сервер.\n\nИтак, после установки плагина нужно его настроить на общение с нашей локально поднятой моделью. Делается это в файле **config.yaml.** Он открывается при первом “касании” с плагином, однако зайти в него, скорее всего, придется не раз. Открыть его можно так: \n\n![2.png]({{strapiUrl}}\u002Fuploads\u002F2_8492601d09_51c5fa0855.webp)\n\nContinue в свою очередь умеет напрямую говорить с **Ollama**, что нам и нужно.\n\nНаш **config.yaml** будет выглядеть так: \n\n\n```yaml\nname: Local Agent\nversion: 1.0.0\nschema: v1\nmodels:\n - name: Mellum\n   provider: ollama\n   model: JetBrains\u002FMellum-4b-sft-all:latest\n   roles:\n     - autocomplete\n```\n\nПомимо указания названия модели и провайдера, важно правильно указать роли, которыми будет заниматься наша модель. Для нашей задачи нам нужна поддержка автокомплишена, поэтому указываем соответствующую роль. Почитать подробнее про роли можно [тут](https:\u002F\u002Fdocs.continue.dev\u002Fcustomize\u002Fmodel-roles\u002F00-intro).\n\n\n> А еще...\n> \n> Continue — не только мост к локальной модели для автокомплита. **Плагин умеет работать в режиме агента**: формулируете задачу в чате, и он пошагово предлагает правки, создает файлы, генерирует тесты и применяет диффы прямо в проекте. Если подключить сильную LLM (OpenAI, Anthropic и др.), можно получить более «умного» помощника, который способен не просто подсказывать строчки, а **писать целые блоки кода**.\n\nContinue — не только мост к локальной модели для автокомплита. Плагин умеет работать в режиме агента: формулируете задачу в чате, и он пошагово предлагает правки, создает файлы, генерирует тесты и применяет диффы прямо в проекте. Если подключить сильную LLM (OpenAI, Anthropic и др.), можно получить более «умного» помощника, который способен не просто подсказывать строчки, а писать целые блоки кода.\n\nНа практике это выглядит так:\n\n- В чате ставим **четкий TLDR-запрос**: цель, ограничения, форматы вывода.\nПримеры:\n«Добавь REST-эндпоинт с валидацией и DTO, верни дифф патчем»;\n«Перепиши поиск на Pageable, сохрани текущие статусы ответов»;\n«Сгенерируй JUnit-тесты для OwnerController».\n- Работать лучше **короткими итерациями**: одна задача → один дифф, затем обзор.\n- **Обязательно проверяем изменения** перед применением: агент ускоряет рутину, но финальная ответственность за код — на нас.\n\nПодробнее про работу с другими режимами поговорим в следующих статьях.\n\n\u003Ch2 id=\"testirovanie\">Тестирование\u003C\u002Fh2>\n\nВ качестве “подопытного” проекта возьмём немалоизвестный [**spring-petclinic**](https:\u002F\u002Fgithub.com\u002Fspring-projects\u002Fspring-petclinic). \n\nОткроем класс [OwnerController.java](https:\u002F\u002Fgithub.com\u002Fspring-projects\u002Fspring-petclinic\u002Fblob\u002Fmain\u002Fsrc\u002Fmain\u002Fjava\u002Forg\u002Fspringframework\u002Fsamples\u002Fpetclinic\u002Fowner\u002FOwnerController.java):\n\n\n```java\n\u002F*\n * Copyright 2012-2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\u002F\npackage org.springframework.samples.petclinic.owner;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.WebDataBinder;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.InitBinder;\nimport org.springframework.web.bind.annotation.ModelAttribute;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport jakarta.validation.Valid;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\n\u002F**\n * @author Juergen Hoeller\n * @author Ken Krebs\n * @author Arjen Poutsma\n * @author Michael Isvy\n * @author Wick Dynex\n *\u002F\n@Controller\nclass OwnerController {\n\n\tprivate static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = \"owners\u002FcreateOrUpdateOwnerForm\";\n\n\tprivate final OwnerRepository owners;\n\n\tpublic OwnerController(OwnerRepository owners) {\n\t\tthis.owners = owners;\n\t}\n\n\t@InitBinder\n\tpublic void setAllowedFields(WebDataBinder dataBinder) {\n\t\tdataBinder.setDisallowedFields(\"id\");\n\t}\n\n\t@ModelAttribute(\"owner\")\n\tpublic Owner findOwner(@PathVariable(name = \"ownerId\", required = false) Integer ownerId) {\n\t\treturn ownerId == null ? new Owner()\n\t\t\t\t: this.owners.findById(ownerId)\n\t\t\t\t\t.orElseThrow(() -> new IllegalArgumentException(\"Owner not found with id: \" + ownerId\n\t\t\t\t\t\t\t+ \". Please ensure the ID is correct \" + \"and the owner exists in the database.\"));\n\t}\n\n\t@GetMapping(\"\u002Fowners\u002Fnew\")\n\tpublic String initCreationForm() {\n\t\treturn VIEWS_OWNER_CREATE_OR_UPDATE_FORM;\n\t}\n\n\t@PostMapping(\"\u002Fowners\u002Fnew\")\n\tpublic String processCreationForm(@Valid Owner owner, BindingResult result, RedirectAttributes redirectAttributes) {\n\t\tif (result.hasErrors()) {\n\t\t\tredirectAttributes.addFlashAttribute(\"error\", \"There was an error in creating the owner.\");\n\t\t\treturn VIEWS_OWNER_CREATE_OR_UPDATE_FORM;\n\t\t}\n\n\t\tthis.owners.save(owner);\n\t\tredirectAttributes.addFlashAttribute(\"message\", \"New Owner Created\");\n\t\treturn \"redirect:\u002Fowners\u002F\" + owner.getId();\n\t}\n\n\t@GetMapping(\"\u002Fowners\u002Ffind\")\n\tpublic String initFindForm() {\n\t\treturn \"owners\u002FfindOwners\";\n\t}\n\n\t@GetMapping(\"\u002Fowners\")\n\tpublic String processFindForm(@RequestParam(defaultValue = \"1\") int page, Owner owner, BindingResult result,\n\t\t\tModel model) {\n\t\t\u002F\u002F allow parameterless GET request for \u002Fowners to return all records\n\t\tif (owner.getLastName() == null) {\n\t\t\towner.setLastName(\"\"); \u002F\u002F empty string signifies broadest possible search\n\t\t}\n\n\t\t\u002F\u002F find owners by last name\n\t\tPage\u003COwner> ownersResults = findPaginatedForOwnersLastName(page, owner.getLastName());\n\t\tif (ownersResults.isEmpty()) {\n\t\t\t\u002F\u002F no owners found\n\t\t\tresult.rejectValue(\"lastName\", \"notFound\", \"not found\");\n\t\t\treturn \"owners\u002FfindOwners\";\n\t\t}\n\n\t\tif (ownersResults.getTotalElements() == 1) {\n\t\t\t\u002F\u002F 1 owner found\n\t\t\towner = ownersResults.iterator().next();\n\t\t\treturn \"redirect:\u002Fowners\u002F\" + owner.getId();\n\t\t}\n\n\t\t\u002F\u002F multiple owners found\n\t\treturn addPaginationModel(page, model, ownersResults);\n\t}\n\n\tprivate String addPaginationModel(int page, Model model, Page\u003COwner> paginated) {\n\t\tList\u003COwner> listOwners = paginated.getContent();\n\t\tmodel.addAttribute(\"currentPage\", page);\n\t\tmodel.addAttribute(\"totalPages\", paginated.getTotalPages());\n\t\tmodel.addAttribute(\"totalItems\", paginated.getTotalElements());\n\t\tmodel.addAttribute(\"listOwners\", listOwners);\n\t\treturn \"owners\u002FownersList\";\n\t}\n\n\tprivate Page\u003COwner> findPaginatedForOwnersLastName(int page, String lastname) {\n\t\tint pageSize = 5;\n\t\tPageable pageable = PageRequest.of(page - 1, pageSize);\n\t\treturn owners.findByLastNameStartingWith(lastname, pageable);\n\t}\n\n\t@GetMapping(\"\u002Fowners\u002F{ownerId}\u002Fedit\")\n\tpublic String initUpdateOwnerForm() {\n\t\treturn VIEWS_OWNER_CREATE_OR_UPDATE_FORM;\n\t}\n\n\t@PostMapping(\"\u002Fowners\u002F{ownerId}\u002Fedit\")\n\tpublic String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable(\"ownerId\") int ownerId,\n\t\t\tRedirectAttributes redirectAttributes) {\n\t\tif (result.hasErrors()) {\n\t\t\tredirectAttributes.addFlashAttribute(\"error\", \"There was an error in updating the owner.\");\n\t\t\treturn VIEWS_OWNER_CREATE_OR_UPDATE_FORM;\n\t\t}\n\n\t\tif (owner.getId() != ownerId) {\n\t\t\tresult.rejectValue(\"id\", \"mismatch\", \"The owner ID in the form does not match the URL.\");\n\t\t\tredirectAttributes.addFlashAttribute(\"error\", \"Owner ID mismatch. Please try again.\");\n\t\t\treturn \"redirect:\u002Fowners\u002F{ownerId}\u002Fedit\";\n\t\t}\n\n\t\towner.setId(ownerId);\n\t\tthis.owners.save(owner);\n\t\tredirectAttributes.addFlashAttribute(\"message\", \"Owner Values Updated\");\n\t\treturn \"redirect:\u002Fowners\u002F{ownerId}\";\n\t}\n\n\t\u002F**\n\t * Custom handler for displaying an owner.\n\t * @param ownerId the ID of the owner to display\n\t * @return a ModelMap with the model attributes for the view\n\t *\u002F\n\t@GetMapping(\"\u002Fowners\u002F{ownerId}\")\n\tpublic ModelAndView showOwner(@PathVariable(\"ownerId\") int ownerId) {\n\t\tModelAndView mav = new ModelAndView(\"owners\u002FownerDetails\");\n\t\tOptional\u003COwner> optionalOwner = this.owners.findById(ownerId);\n\t\tOwner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(\n\t\t\t\t\"Owner not found with id: \" + ownerId + \". Please ensure the ID is correct \"));\n\t\tmav.addObject(owner);\n\t\treturn mav;\n\t}\n    \n}\n\n```\n\nДобавим метод удаления владельца. С новой строки начнем писать сигнатуру нашего метода. Достаточно написать 'public String deleteOwner', после чего Mellum предложит автокомплишн:\n\n![3.png]({{strapiUrl}}\u002Fuploads\u002F3_64a97c2c83_3f86bb62ce.webp)\n_Пример автокомплишена от Mellum_\n\nПо нажатию на **Tab** комплишн будет принят, код будет дополнен. Mellum смотрит на контекст проекта, на код до и после каретки, поэтому он знает, как устроена архитектура вашего приложения и предлагает только то, что будет наиболее уместным. \n\nАналогичным образом работает добавление метода, например, поиска владельца по `id`:\n\n![4.png]({{strapiUrl}}\u002Fuploads\u002F4_8f13fe15f1_6dc6827c19.webp)\n_Пример автокомплишена от Mellum_\n\n\u003Ch2 id=\"vyvod\">Вывод\u003C\u002Fh2>\n\nТо, что раньше требовало мощных серверов и сложной инфраструктуры, сегодня решается на обычном ноутбуке: легковесные модели вроде Mellum дописывают код в темпе IDE, не уводя исходники «куда-то».\n\nПлюсы очевидны: приватность, офлайн-режим, предсказуемая задержка и полный контроль над окружением. Связка OpenIDE + Continue + Ollama показывает, что порог входа уже низкий, а выгода — ощутима.\n\nМинусы тоже есть: локальные модели чувствительны к ресурсам. На слабом железе комплишены предлагаются с задержкой, первый «прогрев» занимаем время, а без GPU ситуация еще более ощутима. Плюс, компактные модели всегда уступают «тяжелым» по глубине понимания — это нормальная цена за приватность и автономность.\n\nПрисоединяйтесь к  Telegram-каналам \u003Ca href=\"https:\u002F\u002Ft.me\u002F+61PSyoKNFAdhN2Ey\" target=\"_blank\">Axiom JDK\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Ft.me\u002Fopenide_official\" target=\"_blank\">OpenIDE\u003C\u002Fa> и \u003Ca href=\"https:\u002F\u002Ft.me\u002Fhaulmont_ru\" target=\"_blank\">Haulmont\u003C\u002Fa>, чтобы первыми получать важные обновления, разборы по Java-стеку, приглашения на важные события и экспертные материалы.",[18],{"title":19,"links":20},"Содержание",[21,24,27,30,33,36],{"label":22,"href":23},"LLM","#llm",{"label":25,"href":26},"Как Mellum готовили?","#kak-mellum-gotovili",{"label":28,"href":29},"Запуск модели","#zapusk-modeli",{"label":31,"href":32},"Как научить общаться IDE и LLM","#kak-nauchit-obshhatsya-ide-i-llm",{"label":34,"href":35},"«Тестирование»","#testirovanie",{"label":37,"href":38},"Вывод","#vyvod","2026-02-10T12:02:58.750Z","2026-11-13T11:49:09.515Z","2026-11-13T11:49:09.591Z",{"id":43,"documentId":44,"firstname":45,"lastname":46,"createdAt":47,"updatedAt":48,"publishedAt":49,"slug":50,"photo":51},39,"dyxqh9wchsixs1rtk3o228ob","Александр","Калинин","2026-02-18T07:54:00.292Z","2026-11-13T11:49:25.149Z","2026-11-13T11:49:25.201Z","aleksandr-kalinin",{"id":52,"documentId":53,"name":54,"alternativeText":55,"caption":55,"width":56,"height":56,"formats":57,"hash":81,"ext":61,"mime":62,"size":82,"url":83,"previewUrl":55,"provider":84,"provider_metadata":55,"createdAt":85,"updatedAt":85,"publishedAt":86,"focalPoint":55},1035,"vfyx5wl5hsxtwhdbokfmuvtn","2024_11_25_15_20_34_e085268646.jpg",null,780,{"thumbnail":58,"small":67,"medium":74},{"name":59,"hash":60,"ext":61,"mime":62,"path":55,"width":63,"height":63,"size":64,"sizeInBytes":65,"url":66},"thumbnail_2024_11_25_15_20_34_e085268646.jpg","thumbnail_2024_11_25_15_20_34_e085268646_e61219ab87",".jpg","image\u002Fjpeg",156,4.37,4367,"\u002Fuploads\u002Fthumbnail_2024_11_25_15_20_34_e085268646_e61219ab87.jpg",{"name":68,"hash":69,"ext":61,"mime":62,"path":55,"width":70,"height":70,"size":71,"sizeInBytes":72,"url":73},"small_2024_11_25_15_20_34_e085268646.jpg","small_2024_11_25_15_20_34_e085268646_e61219ab87",500,33.74,33743,"\u002Fuploads\u002Fsmall_2024_11_25_15_20_34_e085268646_e61219ab87.jpg",{"name":75,"hash":76,"ext":61,"mime":62,"path":55,"width":77,"height":77,"size":78,"sizeInBytes":79,"url":80},"medium_2024_11_25_15_20_34_e085268646.jpg","medium_2024_11_25_15_20_34_e085268646_e61219ab87",750,104.28,104279,"\u002Fuploads\u002Fmedium_2024_11_25_15_20_34_e085268646_e61219ab87.jpg","2024_11_25_15_20_34_e085268646_e61219ab87",112.52,"\u002Fuploads\u002F2024_11_25_15_20_34_e085268646_e61219ab87.jpg","local","2026-11-13T11:40:22.024Z","2026-11-13T11:40:22.025Z",{"id":88,"documentId":89,"name":90,"alternativeText":55,"caption":55,"width":91,"height":92,"formats":93,"hash":118,"ext":97,"mime":98,"size":119,"url":120,"previewUrl":55,"provider":84,"provider_metadata":55,"createdAt":121,"updatedAt":121,"publishedAt":121,"focalPoint":55},1363,"v83romcbxdi5uw7llima5vk5","Local_AI_832x400_9f4ed53ba2.webp",832,400,{"thumbnail":94,"medium":104,"small":111},{"name":95,"hash":96,"ext":97,"mime":98,"path":55,"width":99,"height":100,"size":101,"sizeInBytes":102,"url":103},"thumbnail_Local_AI_832x400_9f4ed53ba2.webp","thumbnail_Local_AI_832x400_9f4ed53ba2_67df5ad2bc",".webp","image\u002Fwebp",245,118,2.63,2630,"\u002Fuploads\u002Fthumbnail_Local_AI_832x400_9f4ed53ba2_67df5ad2bc.webp",{"name":105,"hash":106,"ext":97,"mime":98,"path":55,"width":77,"height":107,"size":108,"sizeInBytes":109,"url":110},"medium_Local_AI_832x400_9f4ed53ba2.webp","medium_Local_AI_832x400_9f4ed53ba2_67df5ad2bc",361,9.6,9602,"\u002Fuploads\u002Fmedium_Local_AI_832x400_9f4ed53ba2_67df5ad2bc.webp",{"name":112,"hash":113,"ext":97,"mime":98,"path":55,"width":70,"height":114,"size":115,"sizeInBytes":116,"url":117},"small_Local_AI_832x400_9f4ed53ba2.webp","small_Local_AI_832x400_9f4ed53ba2_67df5ad2bc",240,6.04,6038,"\u002Fuploads\u002Fsmall_Local_AI_832x400_9f4ed53ba2_67df5ad2bc.webp","Local_AI_832x400_9f4ed53ba2_67df5ad2bc",11.61,"\u002Fuploads\u002FLocal_AI_832x400_9f4ed53ba2_67df5ad2bc.webp","2026-11-13T11:47:20.926Z",[123],{"id":124,"documentId":125,"title":126,"published":127,"weight":128,"slug":129,"createdAt":130,"updatedAt":131,"publishedAt":132,"color":55},4,"ap54riuwcv7sj63auhmb4i6d","Гайды",true,3,"guides","2026-11-12T11:20:31.298Z","2026-11-12T11:22:44.141Z","2026-11-12T11:22:44.122Z",{"pagination":134},{"page":135,"pageSize":136,"pageCount":135,"total":135},1,25,{"data":138,"meta":156},[139,145,151],{"published_date":140,"id":141,"documentId":142,"title":143,"slug":144},"2026-09-28",327,"lruxexelyn19uak89r6dney5","Что такое OpenSpec? Полный гайд по Spec-Driven Development","chto-takoe-openspec-polnyj-gajd-po-spec-driven-development",{"published_date":146,"id":147,"documentId":148,"title":149,"slug":150},"2026-09-10",326,"ymtfa6pslevvkrwnohdfbi1u","Как не потерять интеграцию с Docker в IDE после блокировки JetBrains","kak-ne-poteryat-integracziyu-s-docker-v-ide-posle-blokirovki-jetbrains",{"published_date":152,"id":92,"documentId":153,"title":154,"slug":155},"2026-09-01","dskd9jsck2vjm1d0ztoz91uo","JavaScript и TypeScript в OpenIDE: Node.js, React, Angular, Git и работа с API","javascript-i-typescript-v-openide",{"pagination":157},{"page":135,"pageSize":128,"pageCount":158,"total":159},6,16,1794584601458]