Главная / Статьи / Практические заметки: Очистка данных и предобработка для производственных RAG: построение

Практические заметки: Очистка данных и предобработка для производственных RAG: построение

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

4234 слов

Используйте это как переработанную версию идей из статьи «Очистка данных и предобработка для производственных систем RAG: создание документов, готовых к поиску», ориентированную на операторов: четкие этапы, упорядоченные блоки кода и записи для восстановления, которые сохраняются при передаче задач. Этап обзора работает наилучшим образом, если рассматривать его как измеримую основу. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-либо шаг терпит неудачу, причина сбоя должна указывать на конкретный ответственный элемент, а не на запутанную цепочку операций.

CONFIDENTIAL - INTERNAL USE ONLY
Group Financial Crime Compliance
Page 47 of 132

Место очистки данных в конвейере RAG

На этапе «Где применяется очистка данных» необходимо определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия результатам обработки, определите критерии успеха и не допускайте молчаливого частичного завершения работы. Указывайте конкретные фрагменты текста, на которых основан ответ. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации.

Нормализация кодирования: исправьте текст перед его анализом

Для устранения проблем с кодировкой и нормализацией необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение стоимости заранее предотвращает неожиданные счета при переходе с демо-среды в общедоступные среды. Указывайте те фрагменты текста, которые легли в основу ответа. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации.

Customer’s identity must be verified before account opening.
The customer must provide proof of address.
Enhanced Due Diligence â€" High Risk Customers

Исправление поврежденного Unicode с помощью ftfy

Для процедуры устранения поврежденных символов Unicode определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь код. Указывайте те участки текста, которые фактически легли в основу ответа. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации. Для процедуры устранения поврежденных символов Unicode определите входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Когда шаг терпит неудачу, причина должна указывать на конкретную ответственность, а не на целый комплекс факторов.

запутанная система трубопроводов.

import re
import unicodedata
from dataclasses import dataclass, field
import ftfy

@dataclass
class TextCleaningResult:
    original_text: str
    cleaned_text: str
    transformations: list[str] = field(default_factory=list)
    quality_flags: list[str] = field(default_factory=list)
def normalize_encoding(text: str) -> TextCleaningResult:
    """
    Repair common encoding problems while preserving meaningful Unicode.
    Suitable for policy, AML/KYC, payment, and regulatory documents where
    accented names, currency symbols, and multilingual text must survive.
    """
    transformations: list[str] = []
    quality_flags: list[str] = []
    if not text:
        return TextCleaningResult(original_text=text, cleaned_text=text)
    cleaned = text
    # Repair mojibake and common Unicode encoding mistakes.
    repaired = ftfy.fix_text(cleaned)
    if repaired != cleaned:
        transformations.append("ftfy_encoding_repair")
        cleaned = repaired
    # NFC preserves characters while producing a consistent Unicode
    # representation. Safer than aggressively stripping accents.
    normalized = unicodedata.normalize("NFC", cleaned)
    if normalized != cleaned:
        transformations.append("unicode_nfc_normalization")
        cleaned = normalized
    # Replace non-breaking spaces with normal spaces.
    if "\u00a0" in cleaned:
        cleaned = cleaned.replace("\u00a0", " ")
        transformations.append("non_breaking_space_normalization")
    # Remove zero-width characters that frequently leak from PDFs,
    # web pages, and copied Office content.
    zero_width_chars = {"\u200b", "\u200c", "\u200d", "\ufeff"}
    if any(char in cleaned for char in zero_width_chars):
        cleaned = "".join(char for char in cleaned if char not in zero_width_chars)
        transformations.append("zero_width_character_removal")
    # Remove control characters; preserve newline and tab because
    # they may still carry document structure needed downstream.
    cleaned_without_controls = "".join(
        char for char in cleaned
        if char in "\n\t" or unicodedata.category(char) != "Cc"
    )
    if cleaned_without_controls != cleaned:
        transformations.append("control_character_removal")
        cleaned = cleaned_without_controls
    # Normalize horizontal whitespace without flattening paragraphs.
    whitespace_normalized = re.sub(r"[ \t]+", " ", cleaned)
    whitespace_normalized = re.sub(r"\n{3,}", "\n\n", whitespace_normalized)
    if whitespace_normalized != cleaned:
        transformations.append("whitespace_normalization")
        cleaned = whitespace_normalized
    cleaned = cleaned.strip()
    # Keep suspicious replacement characters observable rather than silently deleting them.
    if "\ufffd" in cleaned:
        quality_flags.append("unicode_replacement_character_detected")
    return TextCleaningResult(
        original_text=text,
        cleaned_text=cleaned,
        transformations=transformations,
        quality_flags=quality_flags,
    )

Почему агрессивная обработка текста вредит технологии RAG

При работе над этапом «Почему агрессивная обработка текста вредит технологии RAG» сначала запишите условия соглашения: необходимые входные данные, сигнал успешного выполнения и последствия частичной неудачи. Такой список помогает сохранять честность при последующих изменениях кода. Рассматривайте этот этап как соглашение между входными данными и проверенными выходными результатами. Дайте названия создаваемым элементам, определите критерии успешности и не допускайте беззвучного частичного выполнения задачи. Измеряйте показатель воспроизведения информации на фиксированном наборе вопросов перед настройкой подсказок. Частая смена подсказок редко помогает улучшить качество поиска информации.

Customer must NOT be classified as low risk.

Удаление шаблонного кода: с учетом структуры, а не ключевых слов

При работе над этапом «Удаление шаблонного кода с учётом структуры» сначала запишите описание функционала: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Запишите также время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счёты при переходе от демо-среды к общедоступным средам. Перед настройкой подсказок измерьте точность восстановления информации на фиксированном наборе вопросов. Частая смена подсказок редко помогает улучшить качество поиска.

KYC Policy | Version 7.2 | Page 41 of 132
KYC Policy | Version 7.2 | Page 42 of 132
import re
from collections import Counter
from dataclasses import dataclass

@dataclass
class BoilerplatePattern:
    normalized_text: str
    occurrences: int
    page_ratio: float
    position: str
def normalize_boilerplate_candidate(line: str) -> str:
    """
    Normalize variable fields so structurally identical headers and
    footers can be compared across pages.
    """
    normalized = line.strip()
    normalized = re.sub(
        r"\bpage\s+\d+\s+of\s+\d+\b", "page <n> of <n>",
        normalized, flags=re.IGNORECASE,
    )
    normalized = re.sub(r"\bpage\s+\d+\b", "page <n>", normalized, flags=re.IGNORECASE)
    normalized = re.sub(r"\s+", " ", normalized)
    return normalized.casefold()
def detect_repeated_marginal_text(
    pages: list[dict],
    margin_lines: int = 3,
    min_page_ratio: float = 0.6,
) -> list[BoilerplatePattern]:
    """
    Detect repeated text in page-header or page-footer regions.
    A candidate is considered boilerplate only when it appears in the same
    marginal position across a substantial fraction of the document.
    """
    if not pages:
        return []
    header_counts: Counter = Counter()
    footer_counts: Counter = Counter()
    for page in pages:
        lines = [line.strip() for line in page["text"].splitlines() if line.strip()]
        if not lines:
            continue
        header_counts.update(normalize_boilerplate_candidate(l) for l in lines[:margin_lines])
        footer_counts.update(normalize_boilerplate_candidate(l) for l in lines[-margin_lines:])
    total_pages = len(pages)
    patterns: list[BoilerplatePattern] = []
    for position, counts in (("header", header_counts), ("footer", footer_counts)):
        for normalized_text, occurrences in counts.items():
            page_ratio = occurrences / total_pages
            if page_ratio >= min_page_ratio:
                patterns.append(BoilerplatePattern(
                    normalized_text=normalized_text,
                    occurrences=occurrences,
                    page_ratio=page_ratio,
                    position=position,
                ))
    return patterns

Удаление дубликатов: точные совпадения — это самая простая часть

При работе над этапом «Дедупликация: точные совпадения» сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность последующих изменений в коде. Храните конфигурацию отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Измеряйте показатель воспроизводимости на фиксированном наборе вопросов перед настройкой подсказок. Частая смена подсказок редко помогает улучшить качество поиска. При работе над этапом «Дедупликация: точные совпадения» сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность последующих изменений в коде. Воздерживайтесь от использования обширных скриптов в пользу небольших, тестируемых единиц кода. Если какой-то шаг не сработает, причина неудачи должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

AML_Policy_v8_Final.docx
AML_Policy_v8_Final_Approved.docx
AML_Policy_v8_Final_Copy.docx
AML_Policy_v8_Approved_2026.docx

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

Этап точного удаления дубликатов с использованием хеширования контента работает наилучшим образом, если рассматривать его как измеримую основу. Сначала соберите один эталонный вариант, один пример сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работ. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия создаваемым файлам, определите критерии успешного выполнения задачи и не допускайте молчаливого частичного завершения работы. Разделяйте политику разбиения данных на части и политику их поиска. Изменение одной из них не должно приводить к переписыванию другой при изменении показателей качества.

import hashlib
from dataclasses import dataclass

@dataclass
class DeduplicationRecord:
    document_id: str
    source: str
    content_hash: str
    duplicate_of: str | None = None
def canonicalize_for_hashing(text: str) -> str:
    """
    Deterministic normalization before hashing.
    Does not lowercase or remove punctuation because those transformations
    could collapse documents that are not actually identical.
    """
    lines = [" ".join(line.split()) for line in text.splitlines()]
    return "\n".join(lines).strip()
def calculate_content_hash(text: str) -> str:
    canonical_text = canonicalize_for_hashing(text)
    return hashlib.sha256(canonical_text.encode("utf-8")).hexdigest()
def find_exact_duplicates(
    documents: list[dict],
) -> tuple[list[dict], list[DeduplicationRecord]]:
    """
    Keep one canonical copy of each identical document while preserving
    duplicate lineage for auditability.
    """
    seen_hashes: dict[str, str] = {}
    unique_documents: list[dict] = []
    records: list[DeduplicationRecord] = []
    for document in documents:
        content_hash = calculate_content_hash(document["clean_text"])
        if content_hash in seen_hashes:
            records.append(DeduplicationRecord(
                document_id=document["document_id"],
                source=document["source"],
                content_hash=content_hash,
                duplicate_of=seen_hashes[content_hash],
            ))
            continue
        seen_hashes[content_hash] = document["document_id"]
        unique_documents.append(document)
        records.append(DeduplicationRecord(
            document_id=document["document_id"],
            source=document["source"],
            content_hash=content_hash,
        ))
    return unique_documents, records

Обнаружение почти одинаковых данных с использованием MinHash LSH

Метод обнаружения почти идентичных записей с использованием MinHash работает наилучшим образом, если рассматриваться как измеримая характеристика. Сначала необходимо зафиксировать один эталонный вариант, один пример сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем работы. Рядом с функциональными результатами следует записывать временные показатели, а также стоимость обработки токенов или запросов. Отслеживание затрат на раннем этапе помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Политику разбиения данных на части следует отделять от политики поиска. Изменение одной из них не должно приводить к необходимости переписывания другой при изменении показателей качества.

import re
from datasketch import MinHash, MinHashLSH

def create_word_shingles(text: str, shingle_size: int = 5) -> set[str]:
    """
    Five-word shingles work well for long policy and regulatory documents
    because they capture local textual structure without being overly
    sensitive to isolated formatting changes.
    """
    tokens = re.findall(r"\b\w+\b", text.casefold())
    if len(tokens) < shingle_size:
        return {" ".join(tokens)} if tokens else set()
    return {
        " ".join(tokens[i:i + shingle_size])
        for i in range(len(tokens) - shingle_size + 1)
    }
def create_minhash(text: str, num_perm: int = 128) -> MinHash:
    shingles = create_word_shingles(text)
    minhash = MinHash(num_perm=num_perm)
    for shingle in shingles:
        minhash.update(shingle.encode("utf-8"))
    return minhash
def build_duplicate_index(
    documents: list[dict],
    threshold: float = 0.85,
    num_perm: int = 128,
) -> tuple[MinHashLSH, dict[str, MinHash]]:
    """
    Build an LSH index for candidate near-duplicate discovery.
    The threshold identifies candidates. It does not automatically
    determine whether a document is deleted.
    """
    lsh = MinHashLSH(threshold=threshold, num_perm=num_perm)
    signatures: dict[str, MinHash] = {}
    for document in documents:
        document_id = document["document_id"]
        signature = create_minhash(document["clean_text"], num_perm=num_perm)
        signatures[document_id] = signature
        lsh.insert(document_id, signature)
    return lsh, signatures

Исправление ошибок OCR: когда текст выглядит правильно, но ошибочен

Этап коррекции ошибок OCR работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример транскрипции, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Разделяйте политику разбиения на части и политику поиска данных. Изменение одной из них не должно приводить к переписыванию другой при изменении показателей качества. Этап коррекции ошибок OCR работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример транскрипции, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-либо шаг срабатывает некорректно, причина сбоя должна указывать на конкретную ответственность, а не на запутанную цепочку операций.

import re
from dataclasses import dataclass

@dataclass
class OCRIssue:
    token: str
    issue_type: str
    risk_level: str
    suggested_value: str | None
    requires_review: bool
CURRENCY_PATTERN = re.compile(r"\b(EUR|USD|GBP|INR)\s+([A-Za-z0-9.,]+)\b")
PERCENTAGE_PATTERN = re.compile(r"\b([A-Za-z0-9.,]+)\s*%")
def detect_numeric_ocr_issues(text: str) -> list[OCRIssue]:
    """
    Detect suspicious OCR substitutions inside financial values.
    This function identifies candidates. It does not silently rewrite
    high-risk values in the source text.
    """
    issues: list[OCRIssue] = []
    substitutions = {"O": "0", "o": "0", "I": "1", "l": "1"}
    def inspect_numeric_token(token: str, issue_type: str) -> None:
        if token.replace(",", "").replace(".", "").isdigit():
            return
        corrected = "".join(substitutions.get(char, char) for char in token)
        numeric_candidate = corrected.replace(",", "").replace(".", "")
        if numeric_candidate.isdigit() and corrected != token:
            issues.append(OCRIssue(
                token=token,
                issue_type=issue_type,
                risk_level="high",
                suggested_value=corrected,
                requires_review=True,
            ))
    for match in CURRENCY_PATTERN.finditer(text):
        inspect_numeric_token(match.group(2), issue_type="currency_value")
    for match in PERCENTAGE_PATTERN.finditer(text):
        inspect_numeric_token(match.group(1), issue_type="percentage")
    return issues

Мультиязычная предобработка: один документ, несколько языков

На этапе мультиязычной предобработки одного документа необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Операторы должны иметь возможность перезапустить этот шаг, исходя из известной точки контроля, без необходимости угадывать скрытое состояние. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Укажите названия создаваемых файлов, определите критерии успеха и не допускайте молчаливого частичного выполнения задачи. Цитируйте те фрагменты текста, которые легли в основу ответа. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации.

from dataclasses import dataclass
from langdetect import DetectorFactory, LangDetectException, detect_langs

DetectorFactory.seed = 0  # Makes pipeline output reproducible.
@dataclass
class LanguagePrediction:
    language: str
    confidence: float
    alternatives: list[tuple[str, float]]
    needs_review: bool
def detect_document_language(
    text: str,
    confidence_threshold: float = 0.85,
) -> LanguagePrediction:
    sample = text.strip()
    if not sample:
        return LanguagePrediction(language="unknown", confidence=0.0, alternatives=[], needs_review=True)
    try:
        predictions = detect_langs(sample)
    except LangDetectException:
        return LanguagePrediction(language="unknown", confidence=0.0, alternatives=[], needs_review=True)
    best = predictions[0]
    alternatives = [(p.lang, round(p.prob, 4)) for p in predictions]
    return LanguagePrediction(
        language=best.lang,
        confidence=best.prob,
        alternatives=alternatives,
        needs_review=best.prob < confidence_threshold,
    )
metadata = {
    "primary_language": "en",
    "languages": ["en", "de", "fr"],
    "language_distribution": {"en": 0.72, "de": 0.21, "fr": 0.07},
    "is_multilingual": True,
}

Личные данные и конфиденциальная информация: обнаружение перед встраиванием

На этапе обработки персональных данных и конфиденциальной информации необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не пытаясь угадать скрытое состояние. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение стоимости на раннем этапе предотвращает неожиданные счета при переходе с демо-среды в общедоступные среды. Необходимо указывать конкретные фрагменты текста, на которых основан ответ. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации.

from dataclasses import dataclass, field
from presidio_analyzer import AnalyzerEngine

@dataclass
class SensitiveEntity:
    entity_type: str
    start: int
    end: int
    score: float
    original_value: str
@dataclass
class PIIScanResult:
    entities: list[SensitiveEntity] = field(default_factory=list)
    needs_review: bool = False
class BankingPIIDetector:
    def __init__(self) -> None:
        self.analyzer = AnalyzerEngine()
    def detect(
        self,
        text: str,
        language: str = "en",
        score_threshold: float = 0.70,
    ) -> PIIScanResult:
        """
        Detect sensitive entities without modifying the source text.
        Detection is deliberately separated from anonymization because
        different entity types require different handling policies.
        """
        results = self.analyzer.analyze(
            text=text, language=language, score_threshold=score_threshold
        )
        entities = [
            SensitiveEntity(
                entity_type=r.entity_type,
                start=r.start,
                end=r.end,
                score=r.score,
                original_value=text[r.start:r.end],
            )
            for r in results
        ]
        high_risk_types = {"CREDIT_CARD", "IBAN_CODE", "US_SSN", "IP_ADDRESS"}
        return PIIScanResult(
            entities=entities,
            needs_review=any(e.entity_type in high_risk_types for e in entities),
        )
Customer IBAN: <IBAN>
Customer Email: <EMAIL_ADDRESS>

Собирание всего воедино: инструментарий очистки производственного уровня

На этапе «Сборка воедино» необходимо определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь граф. Указывайте те участки текста, которые фактически легли в основу ответа. Без цитат операторы не смогут отличить галлюцинации от пробелов в индексации. На этапе «Сборка воедино» необходимо определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Когда шаг терпит неудачу, причина должна указывать на конкретную ответственность, а не на запутанную структуру обработки данных.

e.

from dataclasses import dataclass, field
from enum import Enum
from typing import Any

class QualityStatus(str, Enum):
    PASS = "pass"
    REVIEW = "review"
    REJECT = "reject"
@dataclass
class Transformation:
    stage: str
    operation: str
    details: dict[str, Any] = field(default_factory=dict)
@dataclass
class QualityFlag:
    code: str
    severity: str
    details: dict[str, Any] = field(default_factory=dict)
@dataclass
class RetrievalReadyDocument:
    document_id: str
    source: str
    raw_text: str
    clean_text: str
    language: str | None = None
    language_confidence: float | None = None
    content_hash: str | None = None
    duplicate_of: str | None = None
    transformations: list[Transformation] = field(default_factory=list)
    quality_flags: list[QualityFlag] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)
    status: QualityStatus = QualityStatus.PASS
import logging
logger = logging.getLogger(__name__)

class ProductionDocumentCleaner:
    def __init__(
        self,
        pii_detector: BankingPIIDetector,
        pii_anonymizer,
        redact_pii_for_embeddings: bool = True,
    ) -> None:
        self.pii_detector = pii_detector
        self.pii_anonymizer = pii_anonymizer
        self.redact_pii_for_embeddings = redact_pii_for_embeddings
    def clean(self, document: dict) -> RetrievalReadyDocument:
        result = RetrievalReadyDocument(
            document_id=document["document_id"],
            source=document["source"],
            raw_text=document["text"],
            clean_text=document["text"],
            metadata=document.get("metadata", {}).copy(),
        )
        try:
            self._normalize_text(result)
            self._detect_language(result)
            self._validate_ocr(result)
            self._handle_sensitive_data(result)
            self._calculate_hash(result)
            self._apply_quality_gate(result)
        except Exception as exc:
            logger.exception("Preprocessing failed for document %s", result.document_id)
            result.quality_flags.append(QualityFlag(
                code="PREPROCESSING_EXCEPTION",
                severity="critical",
                details={"error": str(exc)},
            ))
            result.status = QualityStatus.REJECT
        return result
    def _apply_quality_gate(self, document: RetrievalReadyDocument) -> None:
        severities = {flag.severity for flag in document.quality_flags}
        if "critical" in severities:
            document.status = QualityStatus.REJECT
        elif "high" in severities:
            document.status = QualityStatus.REVIEW
        else:
            document.status = QualityStatus.PASS

Компромиссы в производстве

При работе над этапом компромиссов в производстве сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Укажите названия элементов, определите критерии успешности и не допускайте молчаливого частичного выполнения задачи. Оцените точность воспроизведения ответов на фиксированном наборе вопросов перед настройкой подсказок. Частая смена подсказок редко помогает улучшить качество поиска информации.

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

При работе на этапе «Что это означает» сначала запишите условия контракта: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Рядом с функциональными результатами занесите информацию о времени выполнения и стоимости токенов или запросов. Отслеживание затрат с самого начала предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам. Перед настройкой подсказок измерьте точность воспроизведения ответов на фиксированный набор вопросов. Частая смена подсказок редко помогает улучшить качество поиска.

Чек-лист для производственной среды перед началом разбиения на чанки

При работе над этапом «A Production Checklist Before» сначала запишите условия работы системы: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность последующих изменений в коде. Храните конфигурацию отдельно от кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Измеряйте точность воспроизведения ответов на фиксированном наборе вопросов перед настройкой подсказок. Изменение подсказок редко помогает улучшить качество поиска. При работе над этапом «A Production Checklist Before» сначала запишите условия работы системы: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность последующих изменений в коде. Предпочитайте небольшие, тестируемые единицы кода большим скриптам. Если какой-то шаг не сработает, причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций.

Чек-лист для эксплуатации

При работе над этапом операционного чек-листа сначала запишите условия контракта: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода.

Документируйте одновременно «идеальный» сценарий работы и сценарий восстановления. Повторные попытки, проверки со стороны человека и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки.

Измеряйте точность воспроизведения ответов на фиксированном наборе вопросов до настройки подсказок. Изменение подсказок редко помогает улучшить слабую систему поиска информации.

Заморозьте эталонный набор данных до изменения подсказок или моделей. Изменение как самой системы, так и критериев оценки маскирует возможные ухудшения.

Когда позволяет бюджет, добавьте тест на проверку критического пути в процессе интеграционного тестирования с использованием фикстур, а не реальных платных API.

Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости заранее помогает избежать неожиданных счетов при переходе с демо-среды в общедоступные среды.

Перед тем как переводить решение в более широкое использование, заморозьте версии, сохраните эталонный отчет для критически важных этапов и уточните шаги для отката. В общедоступных средах необходимы ограничения на количество запросов, проверки принадлежности и четко определенный ответственный за обновление секретов. Лучше выбирать надежность, чем креативные одноразовые демонстрации.

Примечание для af00655fb2bc: не храните ключи поставщика в репозитории, установите лимит токенов на одну сессию и сохраняйте отчеты рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.

На этапе 0 записей по укреплению безопасности лучше всего работает подход, при котором рассматривается измеримая поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Записывайте время выполнения, стоимость токенов или запросов вместе с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам.

Подробности укрепления безопасности 0/902: измерьте время выполнения, класс ошибки и расход токенов для данной записи, затем решите, следует ли сохранять изменения, опираясь на фиксированный набор вопросов, а не на устные описания.

Для этапа 1 записей по укреплению безопасности определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Документируйте как успешный путь выполнения, так и путь восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки.

Подробность укрепления 1/902: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменение на основе фиксированного набора вопросов, а не на основе единичных примеров.

При работе над вторым этапом записи о укреплении сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и то, что происходит при частичной неудаче. Такой чек-лист обеспечивает честность последующих изменений в коде. Рассматривайте этот этап как контракт между входными данными и проверенными выходными данными. Дайте названия элементам, определите критерии успеха и не допускайте безответственного частичного выполнения задачи.

Подробность укрепления 2/902: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменение на основе фиксированного набора вопросов, а не на основе единичных примеров.

Этап 3 инструкций по усилению безопасности работает наилучшим образом, если рассматривать его как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код.

Подробность усиления безопасности 3/902: измеряйте время выполнения, класс ошибок и расход токенов для этой инструкции, затем принимайте решение о сохранении изменений на основе определенного набора критериев, а не на основе единичных примеров.

Для четвертой стадии усиления безопасности необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии системы. Желательно использовать небольшие, тестируемые единицы вместо обширных скриптов. При сбое шага причина должна быть связана с конкретной областью ответственности, а не с запутанной цепочкой операций.

Подробности усиления безопасности 4/902: измеряйте время выполнения, класс ошибок и расход токенов для данной стадии, затем принимайте решение о сохранении изменений на основе установленного набора критериев, а не на основе устных замечаний.

При работе над этапом усиления безопасности 5 сначала запишите условия работы: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Рядом с функциональными результатами записывайте время выполнения, стоимость токенов или запросов. Отслеживание затрат с самого начала предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.

Подробности усиления безопасности 5/902: измерьте время выполнения, класс ошибки и расход токенов для данного этапа, затем решите, следует ли сохранять изменения на основе определенного набора критериев, а не на основе устных оценок.

Этап усиления безопасности 6 будет работать наилучшим образом, если рассматривать его как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Документируйте одновременно успешный сценарий работы и сценарий восстановления. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не элементами последующей доработки.

Подробности усиления безопасности 6/902: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора вопросов, а не на основе единичных примеров.

На этапе 7 записи о усилении безопасности определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Укажите названия элементов, определите критерии успеха и не допускайте безответственного частичного выполнения.

Подробности усиления безопасности 7/902: измерьте время выполнения, класс ошибки и расход токенов для этой записи, затем решите, следует ли сохранить изменения на основе фиксированного набора вопросов, а не на основе единичных примеров.

При работе над восьмым этапом рекомендаций по усилению безопасности сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет сохранять честность при последующих изменениях кода. Храните конфигурацию отдельно от кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код.

Подробности усиления безопасности 8/902: измеряйте время выполнения, класс ошибок и количество использованных токенов для данной рекомендации, затем принимайте решение о сохранении изменений на основе определенного набора критериев, а не на основе устных замечаний.