Интеграция Copilot-подобного ассистента для IDE

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Интеграция Copilot-подобного ассистента для IDE
Сложная
~2-4 недели
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    853
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

Интеграция Copilot-подобного ассистента для IDE

AI-ассистент для IDE — это не просто автодополнение на стероидах. Это система, которая держит в контексте весь проект: открытые файлы, историю изменений, схему БД, тесты. Правильно построенный ассистент понимает, что вы пишете функцию регистрации пользователя в Django-проекте с PostgreSQL, и предлагает код, совместимый с вашими моделями и конвенциями — а не абстрактный пример из Stack Overflow.

Архитектура IDE-ассистента

Полноценный Copilot-подобный ассистент состоит из нескольких слоёв:

Context Collector — собирает релевантный контекст: текущий файл, импорты, связанные файлы, cursor position, выделенный код, clipboard.

LSP Bridge — взаимодействует с Language Server Protocol для получения AST, типов, определений. Tree-sitter позволяет парсить код в AST без запуска компилятора.

Retrieval Engine — семантический поиск по кодовой базе. Embeddings для кода (CodeBERT, text-embedding-3-small) + векторное хранилище.

LLM Gateway — маршрутизация запросов: быстрая модель для inline completion, мощная для chat/refactoring.

Response Renderer — форматирование вывода: diff для рефакторинга, ghost text для completion, markdown для chat.

Continue.dev — open-source основа

Continue.dev — наиболее зрелая open-source альтернатива GitHub Copilot. Поддерживает VS Code и JetBrains, конфигурируется через ~/.continue/config.json.

{
  "models": [
    {
      "title": "Claude 3.5 Sonnet",
      "provider": "anthropic",
      "model": "claude-sonnet-4-5",
      "apiKey": "$ANTHROPIC_API_KEY"
    },
    {
      "title": "Ollama Qwen2.5-Coder",
      "provider": "ollama",
      "model": "qwen2.5-coder:7b",
      "apiBase": "http://localhost:11434"
    }
  ],
  "tabAutocompleteModel": {
    "title": "Autocomplete",
    "provider": "ollama",
    "model": "qwen2.5-coder:1.5b"
  },
  "contextProviders": [
    {"name": "code", "params": {}},
    {"name": "docs", "params": {}},
    {"name": "diff", "params": {}},
    {"name": "terminal", "params": {}},
    {"name": "problems", "params": {}},
    {"name": "folder", "params": {}},
    {"name": "codebase", "params": {}}
  ],
  "slashCommands": [
    {"name": "edit", "description": "Edit highlighted code"},
    {"name": "comment", "description": "Write comments for the code"},
    {"name": "tests", "description": "Write unit tests"},
    {"name": "share", "description": "Export the chat session"}
  ]
}

Ключевая особенность: tabAutocompleteModel использует быструю локальную модель (1.5B параметров), а чат — мощную облачную. Latency inline completion: 80–150 мс на Qwen2.5-Coder 1.5B через Ollama.

Кастомный контекст-провайдер

Continue.dev позволяет писать кастомные context providers для специфических источников данных:

// ~/.continue/config.ts
import { ContinueConfig, IContextProvider, ContextProviderDescription } from "@continuedev/core";

class DatabaseSchemaProvider implements IContextProvider {
  get description(): ContextProviderDescription {
    return {
      title: "db",
      displayTitle: "Database Schema",
      description: "Current database schema",
      type: "normal",
    };
  }

  async getContextItems(query: string, extras: any) {
    const schema = await fetchDatabaseSchema(); // ваш API

    return [{
      name: "Database Schema",
      description: "Current DB schema",
      content: schema,
    }];
  }
}

class JiraContextProvider implements IContextProvider {
  get description(): ContextProviderDescription {
    return {
      title: "jira",
      displayTitle: "Jira Ticket",
      description: "Fetch Jira ticket by ID",
      type: "query",
    };
  }

  async getContextItems(query: string, extras: any) {
    // query = "PROJ-123"
    const ticket = await fetchJiraTicket(query);

    return [{
      name: `Jira ${query}`,
      description: ticket.summary,
      content: `**${ticket.summary}**\n\n${ticket.description}\n\nАcceptance Criteria:\n${ticket.acceptance_criteria}`,
    }];
  }
}

export function modifyConfig(config: ContinueConfig): ContinueConfig {
  config.contextProviders = [
    ...(config.contextProviders || []),
    new DatabaseSchemaProvider(),
    new JiraContextProvider(),
  ];
  return config;
}

Inline Completion через Language Server Protocol

Для встраивания в любой LSP-совместимый редактор (Neovim, Emacs, Helix):

from pygls.server import LanguageServer
from lsprotocol.types import (
    TEXT_DOCUMENT_COMPLETION,
    CompletionParams,
    CompletionList,
    CompletionItem,
    CompletionItemKind,
)
from anthropic import Anthropic
import asyncio

server = LanguageServer("ai-completion-server", "v0.1")
anthropic_client = Anthropic()

@server.feature(TEXT_DOCUMENT_COMPLETION)
async def completions(params: CompletionParams):
    document = server.workspace.get_document(params.text_document.uri)

    # Получаем контекст: 50 строк до курсора
    lines = document.lines
    cursor_line = params.position.line
    prefix = "\n".join(lines[max(0, cursor_line - 50):cursor_line + 1])
    suffix = "\n".join(lines[cursor_line + 1:cursor_line + 10])

    # Fill-in-the-middle prompt
    prompt = f"<fim_prefix>{prefix}<fim_suffix>{suffix}<fim_middle>"

    # Используем быструю модель для completion
    response = anthropic_client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=150,
        messages=[{
            "role": "user",
            "content": f"Complete this code (return only the completion, no explanation):\n{prompt}"
        }]
    )

    completion_text = response.content[0].text.strip()

    return CompletionList(
        is_incomplete=False,
        items=[CompletionItem(
            label=completion_text[:50] + "..." if len(completion_text) > 50 else completion_text,
            kind=CompletionItemKind.Snippet,
            insert_text=completion_text,
            detail="AI Suggestion",
        )]
    )

if __name__ == "__main__":
    server.start_io()

Codebase Indexing с Tree-sitter

Семантический поиск по кодовой базе — основа контекстно-зависимых подсказок:

from tree_sitter import Language, Parser
from tree_sitter_languages import get_language, get_parser
from openai import OpenAI
import chromadb
from pathlib import Path

client = OpenAI()
chroma_client = chromadb.PersistentClient(path="./.codebase_index")
collection = chroma_client.get_or_create_collection("code_chunks")

def extract_functions(file_path: str, language: str) -> list[dict]:
    """Извлекает функции/методы через Tree-sitter AST"""
    parser = get_parser(language)

    with open(file_path) as f:
        source = f.read()

    tree = parser.parse(source.encode())

    # Tree-sitter query для Python функций
    lang = get_language(language)
    query = lang.query("""
        (function_definition
            name: (identifier) @func_name
            body: (block) @func_body) @func_def

        (class_definition
            name: (identifier) @class_name
            body: (block) @class_body) @class_def
    """)

    captures = query.captures(tree.root_node)
    functions = []

    for node, capture_name in captures:
        if capture_name == "func_def":
            func_text = source[node.start_byte:node.end_byte]
            functions.append({
                "file": file_path,
                "type": "function",
                "code": func_text,
                "start_line": node.start_point[0],
            })

    return functions

def index_codebase(project_root: str):
    """Индексирует всю кодовую базу"""
    project = Path(project_root)

    all_chunks = []
    for py_file in project.rglob("*.py"):
        if "migrations" in str(py_file) or "__pycache__" in str(py_file):
            continue

        chunks = extract_functions(str(py_file), "python")
        all_chunks.extend(chunks)

    # Batch embedding
    batch_size = 100
    for i in range(0, len(all_chunks), batch_size):
        batch = all_chunks[i:i + batch_size]

        response = client.embeddings.create(
            model="text-embedding-3-small",
            input=[chunk["code"][:2000] for chunk in batch]
        )

        collection.add(
            ids=[f"{c['file']}:{c['start_line']}" for c in batch],
            embeddings=[e.embedding for e in response.data],
            documents=[c["code"] for c in batch],
            metadatas=[{"file": c["file"], "line": c["start_line"]} for c in batch],
        )

    print(f"Indexed {len(all_chunks)} code chunks")

def find_relevant_code(query: str, k: int = 5) -> list[str]:
    """Находит похожий код для контекста"""
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )

    results = collection.query(
        query_embeddings=[response.data[0].embedding],
        n_results=k,
    )

    return results["documents"][0]

Chat-режим с проектным контекстом

class IDEChatAssistant:
    """Полноценный chat-ассистент с проектным контекстом"""

    def __init__(self, project_root: str):
        self.project_root = project_root
        self.client = Anthropic()
        index_codebase(project_root)

    async def chat(
        self,
        user_message: str,
        current_file: str,
        selected_code: str = None,
        conversation_history: list = None,
    ) -> str:

        # Собираем контекст
        context_parts = []

        # Текущий файл
        if current_file:
            with open(current_file) as f:
                file_content = f.read()
            context_parts.append(f"## Текущий файл: {current_file}\n```python\n{file_content[:3000]}\n```")

        # Выделенный код
        if selected_code:
            context_parts.append(f"## Выделенный код\n```python\n{selected_code}\n```")

        # Похожий код из кодовой базы
        relevant = find_relevant_code(user_message, k=3)
        if relevant:
            context_parts.append("## Похожий код из проекта\n" + "\n\n".join(relevant))

        system_prompt = f"""Ты — опытный инженер, работающий над проектом.

{chr(10).join(context_parts)}

Правила:
- Код пиши в стиле существующей кодовой базы
- Используй те же зависимости, что уже есть в проекте
- Объясняй архитектурные решения кратко
- Если изменяешь существующий код — показывай diff"""

        messages = conversation_history or []
        messages.append({"role": "user", "content": user_message})

        response = self.client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=4096,
            system=system_prompt,
            messages=messages,
        )

        return response.content[0].text

Практический кейс: внедрение в команду из 12 разработчиков

Стартовое состояние: команда использовала GitHub Copilot ($19/мес на разработчика), жаловалась на нерелевантные подсказки — Copilot не знал внутренних паттернов Django-проекта с 800+ моделями.

Решение: Continue.dev + локальный Ollama для autocomplete + Claude через API для chat/refactoring + кастомный context provider с индексом кодовой базы.

Инфраструктура: сервер с RTX 4090 (Qwen2.5-Coder 7B для autocomplete), API Claude для сложных запросов.

Результаты через 2 месяца:

  • Принятие inline suggestions: 23% (Copilot) → 41% (кастомный)
  • Среднее время написания типового CRUD endpoint: 52 мин → 31 мин
  • Задачи типа "написать тест для этой функции": 100% ручные → 70% автоматические
  • Стоимость: $228/мес (Copilot) → ~$85/мес (Ollama server amortized + Claude API)

Ключевой фактор улучшения acceptance rate: context provider с индексом кодовой базы давал модели реальные примеры из проекта, а не абстрактный код.

Локальные модели для completion

Для команд с требованиями к конфиденциальности кода — полностью локальный стек:

Модель Размер Latency (RTX 3080) Качество
Qwen2.5-Coder 1.5B 1.5B 50–80 мс Базовое
Qwen2.5-Coder 7B 7B 150–250 мс Хорошее
DeepSeek-Coder 6.7B 6.7B 140–230 мс Хорошее
CodeLlama 13B 13B 350–500 мс Высокое

Для inline completion критична latency < 200 мс — пользователь замечает задержку. Поэтому для FIM (fill-in-the-middle) используют модели до 7B.

Сроки

  • Continue.dev + конфигурация моделей + базовые context providers: 2–3 дня
  • Кастомные context providers (БД, Jira, документация): 1 неделя
  • Индексирование кодовой базы + семантический поиск: 1–2 недели
  • LSP-сервер для нестандартного редактора: 2–3 недели
  • Итого с онбордингом команды: 3–5 недель