10 KiB
1C RAG
Цель: подготовить локальный корпус знаний по 1С для поиска и ответов без дообучения модели.
Principles
- Сначала RAG и инструменты, потом fine-tuning.
- Не загружать в репозиторий базы, выгрузки, приватные документы, персональные данные и секреты.
- Не выдумывать метаданные конкретной базы 1С. Если нужны реквизиты или объекты, использовать tool boundary.
Add Sources
Кладем материалы в:
plugins/1c/rag/sources
Поддерживаемые форматы:
.md.txt.bsl.os
Prepare Corpus
python scripts/validate_1c_rag_sources.py --print
python scripts/prepare_1c_rag_corpus.py
Результат:
plugins/1c/datasets/prepared/rag_corpus.jsonl
plugins/1c/datasets/prepared/rag_manifest.json
Этот файл не коммитится.
Test With Example
python scripts/prepare_1c_rag_corpus.py --source-dir plugins/1c/rag/examples --output plugins/1c/datasets/prepared/rag_corpus.example.jsonl
Build Search Index
python scripts/build_1c_rag_index.py
Для синтетического примера:
python scripts/build_1c_rag_index.py --corpus plugins/1c/datasets/prepared/rag_corpus.example.jsonl --output plugins/1c/datasets/prepared/rag_index.example.json
Build Vector Index
python scripts/build_1c_rag_vector_index.py
Результат:
plugins/1c/datasets/prepared/rag_vector_index.sqlite
Индекс хранит corpus_hash, embedding_model, размерность, дату сборки и метаданные чанков.
Текущий provider local-hashing-v1 - это локальный deterministic vector baseline, а не нейросемантическая embedding-модель. Он нужен, чтобы отладить формат, freshness и hybrid retrieval без скачивания модели. Нейросемантический provider подключается следующим слоем без смены SQLite-схемы.
OpenAI-compatible embedding endpoint:
$env:EMBEDDING_API_KEY = "<token-if-needed>"
python scripts/build_1c_rag_vector_index.py `
--embedding-provider openai-compatible `
--embedding-model "<embedding-model-name>" `
--embedding-base-url "http://docker-gpu.cin.su:8000" `
--embedding-api-key-env EMBEDDING_API_KEY
Для поиска по такому индексу query embedding должен считаться тем же provider/model:
python scripts/search_1c_rag_hybrid.py "реквизиты справочника номенклатура" `
--profile metadata `
--embedding-base-url "http://docker-gpu.cin.su:8000" `
--embedding-api-key-env EMBEDDING_API_KEY
Ключ не пишется в индекс и читается только из переменной окружения.
Полная сборка knowledge base теперь строит corpus, lexical index и vector index:
python scripts/build_1c_knowledge_base.py --include-example-bsl
Если vector index временно не нужен:
python scripts/build_1c_knowledge_base.py --skip-vector-index
Search
python scripts/search_1c_rag.py "метаданные справочника" --index plugins/1c/datasets/prepared/rag_index.example.json
Поиск использует локальный lexical BM25-подобный индекс с нормализацией 1С-терминов и алиасами вроде 1с/bsl, справочник/catalog, метаданные/metadata.
Профили RAG лежат в:
plugins/1c/rag/profiles.yaml
Основные профили:
autogeneralmetadatabslquerysafe-change
auto выбирает профиль по тексту вопроса. Например, вопросы про реквизиты уходят в metadata, вопросы про процедуры и ошибки BSL - в bsl, вопросы с ВЫБРАТЬ - в query.
При подготовке корпуса источники получают смысловой source_type:
metadatabslquerysafetydocs
Полезные параметры:
python scripts/search_1c_rag.py "реквизиты справочника номенклатура" `
--index plugins/1c/datasets/prepared/rag_index.example.json `
--profile metadata `
--limit 5 `
--candidate-limit 30 `
--dedupe-by-document
Vector search:
python scripts/search_1c_rag_vector.py "реквизиты справочника номенклатура" --profile metadata --limit 5
Hybrid search объединяет lexical и vector результаты через reciprocal-rank fusion:
python scripts/search_1c_rag_hybrid.py "реквизиты справочника номенклатура" --profile metadata --limit 5
Если vector_freshness.status = stale, нужно пересобрать vector index после обновления corpus.
Ask With Context
Без вызова модели, только сборка prompt:
python scripts/ask_1c_rag.py "Какие реквизиты есть у справочника Номенклатура?" --index plugins/1c/datasets/prepared/rag_index.example.json --print-prompt
С явным профилем:
python scripts/ask_1c_rag.py "Проверь BSL-код процедуры ПередЗаписью" --profile bsl --print-prompt
Проверка обязательных правил в prompt:
python scripts/check_1c_rag_prompt.py
Проверка качества поиска по smoke-набору:
python scripts/check_1c_rag_quality.py --print
Проверка auto-routing профилей:
python scripts/check_1c_rag_profiles.py --print
С запущенной моделью:
python scripts/ask_1c_rag.py "Какие реквизиты есть у справочника Номенклатура?" --index plugins/1c/datasets/prepared/rag_index.example.json --base-url http://docker-gpu.cin.su:8000 --model qwen3-4b-instruct
Tool Contract
Контракт инструментов:
plugins/1c/tools/tool-contract.yaml
Главное правило: модель не должна придумывать структуру базы 1С. Если ответ зависит от метаданных, сначала нужен вызов инструмента.
Metadata Snapshot Flow
Для проверки RAG на структуре 1С можно сгенерировать source из metadata snapshot:
python scripts/validate_1c_metadata_snapshot.py plugins/1c/metadata/examples/metadata.example.json
python scripts/convert_1c_metadata_to_rag.py --input plugins/1c/metadata/examples/metadata.example.json --output plugins/1c/rag/sources/metadata.example.generated.md
python scripts/build_1c_knowledge_base.py --include-example-bsl
python scripts/ask_1c_rag.py "Какие реквизиты есть у справочника Номенклатура?" --print-prompt
build_1c_knowledge_base.py выполняет валидацию snapshot, конвертацию источников, сборку corpus и индекса за один проход.
Перед сборкой corpus он также запускает validate_1c_rag_sources.py, чтобы заблокировать неподдерживаемые расширения, пустые файлы и вероятные секреты.
Manifest содержит source path, source type, file type, content hash и число чанков. Его удобно использовать для аудита и будущего инкрементального обновления индекса.
Проверить, не устарел ли manifest относительно plugins/1c/rag/sources:
python scripts/check_1c_rag_freshness.py --print
Статус stale означает, что появились новые файлы, изменился hash, был удален источник или изменился source_type. После этого нужно пересобрать knowledge base.
Проверить, не устарел ли vector index относительно corpus:
python scripts/check_1c_rag_vector_freshness.py --print
Semantic Cache Embedding Worker
Для live 1C-адаптера semantic cache заполняется отдельно от RAG corpus. Адаптер отдает pending документы с document_id и content_sha1; worker считает embedding и вызывает semantic.cache.embedding.upsert. Если документ изменился, адаптер отвергнет embedding по content_sha1.
Dry-run:
python scripts/embed_1c_semantic_cache.py --base-id upo_test --kind Template --limit 20 --dry-run --json
Запись baseline-векторов:
python scripts/embed_1c_semantic_cache.py --base-id upo_test --kind Template --limit 20
Поиск по semantic cache с автоматически рассчитанным query embedding:
python scripts/search_1c_semantic_cache.py "ОбластьШапка" --base-id upo_test --kind Template --limit 5 --validate-candidates
Если нужно перед поиском автоматически дозаполнить pending embeddings:
python scripts/search_1c_semantic_cache.py "ОбластьШапка" --base-id upo_test --kind Template --embed-pending --validate-candidates
С OpenAI-compatible embedding endpoint:
$env:EMBEDDING_API_KEY = "<token-if-needed>"
python scripts/embed_1c_semantic_cache.py `
--base-id upo_test `
--kind Template `
--embedding-provider openai-compatible `
--embedding-model "<embedding-model-name>" `
--embedding-base-url "http://docker-gpu.cin.su:8000" `
--embedding-api-key-env EMBEDDING_API_KEY
Semantic cache остается candidate-only: перед программными изменениями использовать validate_candidates=true или live read-selector из результата.