Агент-инженер по репозиторию · Модуль 3 · Урок 3.2

Чанкинг по функциям и файлам

Зачем (какую проблему чиним)

Чтобы извлекать «куски», нужно сперва разрезать репозиторий на осмысленные единицы. Наивный чанкинг «по N символов» рвёт функции посередине и смешивает несвязный код. Для кода естественная единица — функция/метод/тип, с запасом — файл.

Решение и альтернативы

Решение: чанкер для Go использует go/parser (AST): каждая функция, метод и объявление типа — отдельный чанк с метаданными (файл, имя, диапазон строк). Для не-Go файлов и докладов (.md) — чанкинг по заголовкам/абзацам с перекрытием. Чанк хранит достаточно контекста (имя файла, сигнатуру), чтобы быть понятным в отрыве.

Альтернативы: фиксированный размер в символах/токенах — прост, но рвёт смысловые границы; по строкам с перекрытием — лучше, но всё равно слепой к структуре. AST-чанкинг для кода точнее всего; символьный оставляем как фолбэк для незнакомых форматов.

DIFF

Добавляем пакет чанкинга: AST для .go, эвристики для текста; на выходе — []Chunk с метаданными.

Проверка

На самом репозитории агента чанкер выдаёт по чанку на функцию с корректными строками; safeJoin гарантирует, что индексируется только дерево репозитория (без .git/секретов).

Глубже

Стратегии чанкинга и их влияние на качество поиска — курс «Продакшн-разработка», Модуль 2 (продвинутый RAG, гл. 3).

chunk.go: AST-чанкинг Go-кода по функциям/типам (новый файл, фрагмент)
+package main
+
+import (
+	"go/ast"
+	"go/parser"
+	"go/token"
+)
+
+// Chunk — индексируемая единица с метаданными для источника и ранжирования.
+type Chunk struct {
+	Path      string // путь относительно корня
+	Symbol    string // имя функции/типа (если применимо)
+	StartLine int
+	EndLine   int
+	Text      string
+}
+
+// chunkGoFile режет один .go-файл на чанки уровня объявлений (func/type).
+func chunkGoFile(path, src string) ([]Chunk, error) {
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, path, src, 0)
+	if err != nil {
+		return symbolicFallback(path, src), nil // битый файл — символьный фолбэк
+	}
+	var chunks []Chunk
+	for _, decl := range f.Decls {
+		start := fset.Position(decl.Pos())
+		end := fset.Position(decl.End())
+		chunks = append(chunks, Chunk{
+			Path:      path,
+			Symbol:    declName(decl),
+			StartLine: start.Line,
+			EndLine:   end.Line,
+			Text:      sliceLines(src, start.Line, end.Line),
+		})
+	}
+	return chunks, nil
+}

Anti-patterns

Грабли чанкинга кода
ГрабляПочему плохоКак правильно
Резать код по фиксированному числу символовФункции рвутся посередине; чанк смешивает несвязные куски — поиск деградируетЧанк = функция/метод/тип (AST); символьный фолбэк только для незнакомых форматов
Чанк без метаданных (только текст)Нельзя показать источник и ранжировать по файлу/символуХранить путь, символ, диапазон строк — для источника и буста релевантности

Практическое задание (RA-v2)

  • Реализовать AST-чанкинг для .go (go/parser) и текстовый чанкинг для .md с перекрытием.
  • Добавить символьный фолбэк для файлов, которые не парсятся.
  • Закоммитить: git commit -m "v2: AST-based chunking".

Проверка знаний

Почему для кода чанкинг по функциям (AST) обычно лучше, чем по фиксированному числу символов?

  • A AST быстрее работает
  • B Функция — естественная смысловая единица; символьная нарезка рвёт логику и смешивает несвязный код, ухудшая поиск и понимание
  • C Символьная нарезка не поддерживается в Go
  • D AST уменьшает размер индекса