Галоўная / Артыкулы

RAG з розуменням домэна, з рэгістрамі MLflow і маршрутацыяю LLM

RAG, які розумеюць домэн: класіфікуюць намерэнне, завантажаюць правы эмбэдэр з рэжыстра MLflow, шукаюць адпаведную колекцыю Qdrant, а пасля направляюць генераванне да LLM.

Выдавец: REACTAPP.TOP12 хв чытання2688 слоў

Крыніцы: RAG Beyond Retrieval: Model Registry, Vector Search and Intelligent LLM Routing

Большасць дэманаў RAG пінаюць аднаго мадэлі імбеджвання, адну колекцыю дадзеных і аднаго LLM. Гэта прыемна, пакуль запіты ў сферэ іпатак і медыцыны выкарыстоўваюць аднойчы той самы працэс, або пакуль для первачайной адсортавання дадзеных паслужыць маленькі локальны мадэль, а для дэталявання клінічных пытанняў — большы мадэль, якая працюе на даляйнай базе. Болей надзейны падход — спачатку класіфікаваць намер запіту, пасля чаго выбраць адпаведную базу дадзеных і мадэль імбеджвання, запрашаць кантэкст, а потым направіць генераванне тэксту да паслядовага LLM.

У гэтым рашынку гэя ідэя рэалізуецца на скромным апаратным забезпечэнні: MLflow Model Registry на Raspberry Pi для мадэляў імбеджвання, колекцыі Qdrant па адзінам домэне, Ollama для локальной класіфікацыі, а таксама выбраныя вызовы LLM у воблаку для тых домэнаў, якім гэта неабходна. Аднойчы з проблемаў сеціянарнай связі — падключэнне Raspberry Pi да Postgres, таму што рэестры модэляў ёсць корыстныя толькі тады, калі можна з’явіцца да бэкенд-хранілніка.

Связь з Postgres з Raspberry Pi

Калі Postgres быў установлены праз Homebrew на Mac у той самым LAN, пераканайцеся, якая конфігурацыя вікорыстоўваецца працюючым экземплярам, перш чым яе рэдагаваць:

psql -U <your_user> -d postgres -c "SHOW config_file;"

Адрэсы праслухоўвання і супаўзвязанные настройкі знаходзяцца ў postgresql.conf:

cd /opt/homebrew/var/postgresql@15
sed -i '' "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" postgresql.conf

Пераканайцеся ў правільной конфігурацыі:

grep -v "^#" postgresql.conf | grep listen_addresses
# listen_addresses = '*'

Дадзіце IP-адрэсу Pi у белы спіс у pg_hba.conf, ўпэўніўшыся такім чынам, што аўтэнтыфікацыя па паролі будзе дазволена з гэтага хоста:

echo "host  all  all  192.168.1.9/32  md5" >> pg_hba.conf

Пераканайцеся, што правілы запускаюцца так, як вы спадзяваліся:

grep "192.168.1.9" pg_hba.conf

Перазапусціце Postgres і пераканайцеся, што ён праслухоўвае на неабходных інтэрфейсах:

brew services restart postgresql@15
lsof -i -P | grep LISTEN | grep postgres

Пераканайцеся, што існуе ролі з правамі выхаду ў сістэму:

psql -U <admin_user> -d postgres -c "\du"

Установіце або скасаваце пароль, які будзе вікорыстоўвацца MLflow:

psql -U <admin_user> -d postgres -c "ALTER USER root WITH PASSWORD 'root';"

Упэўніцеся, што мэтавая база дадзеных існуе:

psql -U <admin_user> -d postgres -c "\l" | grep mlflow
psql -U <admin_user> -d postgres -c "CREATE DATABASE mlflow OWNER root;"

Апробаваце прымітную з’яўленасць у сеткі з боку Pi перш чым прыўязваць MLflow:

nc -zv 192.168.1.8 5432

Калі маршрут сеткі і абанонентскі даныя працуюць, запускайце MLflow працаваў проты таго аддаленага бэкенд-хранілішча:

mlflow server \
  --backend-store-uri postgresql://root:root@192.168.1.8:5432/mlflow \
  --host 0.0.0.0 \
  --port 5000 \
  --allowed-hosts "192.168.1.9:5000" \
  --cors-allowed-origins "http://192.168.1.9:5000"

Архітэктура у два этапы

Этап 1 — шар знанняў. PDF-файлы домэна раздзеляюцца на часткі і включаюць у сябе мадэлі sentence-transformer, прызначаныя для конкрэтнага домэна, пасля чаго храняцца ў адзінаковых колекцыях Qdrant. MLflow сочыць за тым, якая версія модуля embedder ёсць найкращай для кожнага домэна, ўтаму службы не выкарыстоўваюць жорсткі код мясцовых маршрутаў.

Этап 2 — інтэлігентны маршрутызацыя. Класіфікатор прызначае атрыбут кожнаму запіту корыстніка (для гэтай дэманстрацыі: лейкемія, іпотэка або інша). Для выкарыстоўвання дакументаў выкорыстоўваецца адпаведная колекцыя і модуль embedder. Для генеравання тэкста выкарыстоўваецца LLM, выбраны для данага намеру — мясцовы для дзеякіх маршрутаў, аддалены для іншых — такім чынам вартасць і можлівасці адпавядаюць запыту.

Модулі рэалізацыі

model_registry.py рэгіструе Arctic-embed для крэдытаў на жылё і MiniLM для лейкеміі (або любую іншую пару, яку вы выбералі), фіксае іх у MLflow на прыстрое Pi і стварае аліясы для «чэмпіёнаў»:

import mlflow
import mlflow.sentence_transformers
from mlflow import MlflowClient
from mlflow.models import infer_signature
from sentence_transformers import SentenceTransformer

mlflow.set_tracking_uri("http://192.168.1.9:5000")
mlflow.set_experiment("embedding-models")

EMBEDDERS = {
    "mortgage-embedder": {"source": "Snowflake/snowflake-arctic-embed-m-v1.5"},
    "leukemia-embedder": {"source": "all-MiniLM-L6-v2"},
}

sample_texts = ["MLflow tracks embedding models", "Qdrant stores vectors"]
client = MlflowClient()

for name, cfg in EMBEDDERS.items():
    model = SentenceTransformer(
        cfg["source"],
        trust_remote_code=cfg.get("trust_remote_code", False),
        config_kwargs=cfg.get("config_kwargs"),
        device=cfg.get("device"),
    )
    with mlflow.start_run(run_name=name):
        info = mlflow.sentence_transformers.log_model(
            model=model,
            name="embedder",
            signature=infer_signature(sample_texts, model.encode(sample_texts)),
            input_example=sample_texts,
            registered_model_name=name,
        )
    client.set_registered_model_alias(name, "champion", info.registered_model_version)
    print(f"{name}: v{info.registered_model_version}, dim={model.get_embedding_dimension()}")

ingest_data.py перзбудоввае колекцыі даных, раздзеляе PDF-файлы на часткі з аднаковым акна токенаў і перакрыццем, включае іх за дапамогою модэлі-чэмпіона для таго домэна і адправляе ў Qdrant:

import os
from chonkie import Pipeline
from qdrant_client import QdrantClient
from dotenv import load_dotenv, find_dotenv

load_dotenv(find_dotenv())

client = QdrantClient(url="http://localhost:6333", api_key=os.environ["QDRANT_API_KEY"])
client.delete_collection("leukemia_details") # this will delete and recreate the collection.

(Pipeline()
 .fetch_from("file", dir="../", ext=[".pdf"])
 .process_with("liteparse")
 .chunk_with("recursive", chunk_size=512)
 .refine_with("overlap", context_size=100)
 .store_in("qdrant", collection_name="leukemia_details", client=client,
           embedding_model="sentence-transformers/all-MiniLM-L6-v2")
 .run())

count = client.count("leukemia_details", exact=True).count
print(f"Ingested {count} chunks into leukemia_details")

ai_gateway.py класіфікуе намеры за дапомогою строгага локальнага запіту праз Ollama, а пасля выбірае бэкенды LLM па кожнай класфікацыі:

from openai import OpenAI
import mlflow

mlflow.set_tracking_uri("http://192.168.1.9:5000")

client = OpenAI(
    base_url="http://192.168.1.9:5000/gateway/mlflow/v1",
    api_key="no-api-key",
)

CLASSIFIER_PROMPT = (
    "Classify the user query into exactly one label: LEUKEMIA, MORTGAGE, or OTHER.\n"
    "LEUKEMIA = questions about leukemia (AML, CML, ALL, CLL), its symptoms, diagnosis, "
    "treatment, prognosis, or related blood cancers.\n"
    "MORTGAGE = questions about home loans, mortgage rates, refinancing, EMI, "
    "eligibility, lenders, or mortgage documents.\n"
    "OTHER = everything else, including general medical questions not about leukemia.\n"
    "Reply with only the label."
)

ROUTES = {
    "LEUKEMIA": "openai",
    "MORTGAGE": "gemma",
}

REJECT_MESSAGE = (
    "Sorry, this setup can only answer Leukemia-specific medical questions "
    "and mortgage-related questions."
)


def classify(query: str) -> str:
    resp = client.chat.completions.create(
        model="ollama",  # local Ollama endpoint does the classification
        messages=[
            {"role": "system", "content": CLASSIFIER_PROMPT},
            {"role": "user", "content": query},
        ],
        temperature=0,
    )
    label = resp.choices[0].message.content.strip().upper()
    for intent in ROUTES:
        if intent in label:
            return intent
    return "OTHER"


def route(query: str) -> str:
    intent = classify(query)
    target = ROUTES.get(intent)
    if target is None:
        print(f"[intent={intent} -> rejected]")
        return REJECT_MESSAGE
    resp = client.chat.completions.create(
        model=target,
        messages=[{"role": "user", "content": query}],
    )
    print(f"[intent={intent} -> model={target}]")
    return resp.choices[0].message.content

#
# if __name__ == "__main__":
#     print(route("What are the first-line treatments for acute myeloid leukemia?"))
#     print(route("How does refinancing affect my monthly mortgage EMI?"))
#     print(route("What are the side effects of metformin?"))   # medical but not leukemia -> rejected
#     print(route("Write a haiku about monsoon in Hyderabad."))  # rejected

smart_rag.py спаўнае разам класіфікацыю, выбір колекцыі, адзысканне топ-к элементаў і адпаведныя адказы:

from qdrant_client import QdrantClient
import os

from ai_gateway import client, classify, ROUTES, REJECT_MESSAGE
from embedding_model_inference import EMBEDDERS
from dotenv import load_dotenv, find_dotenv

load_dotenv(find_dotenv())

COLLECTIONS = {
    "LEUKEMIA": {"collection": "leukemia_details", "embedder": "leukemia-embedder"},
    "MORTGAGE": {"collection": "mortgage", "embedder": "mortgage-embedder"},
}
TEXT_FIELD = "text"
EXIT_WORDS = {"bye", "exit", "quit"}


class SmartRAG:
    def __init__(self, qdrant_url="http://localhost:6333", top_k=5):
        self.qdrant = QdrantClient(url=qdrant_url, api_key=os.environ.get("QDRANT_API_KEY"))
        self.top_k = top_k

    def retrieve(self, query, intent):
        cfg = COLLECTIONS[intent]
        embedder = EMBEDDERS[cfg["embedder"]]
        prompt = "query" if "query" in embedder.prompts else None  # arctic needs its query prefix
        vec = embedder.encode(query, prompt_name=prompt, normalize_embeddings=True).tolist()
        hits = self.qdrant.query_points(cfg["collection"], query=vec, limit=self.top_k, with_payload=True).points
        return "\n\n".join(str(h.payload.get(TEXT_FIELD, h.payload)) for h in hits)

    def answer(self, query):
        intent = classify(query)
        if intent not in ROUTES:
            return REJECT_MESSAGE
        context = self.retrieve(query, intent)
        resp = client.chat.completions.create(
            model=ROUTES[intent],
            messages=[
                {"role": "system", "content": f"Answer using only this context:\n{context}"},
                {"role": "user", "content": query},
            ],
        )
        print(f"[intent={intent} -> {COLLECTIONS[intent]['collection']} -> {ROUTES[intent]}]")
        return resp.choices[0].message.content

    def run(self):
        while True:
            query = input("\nyou> ").strip()
            if query.lower() in EXIT_WORDS:
                break
            if query:
                print("\nassistant>", self.answer(query))


if __name__ == "__main__":
    SmartRAG().run()

embedding_model_inference.py завантажае модулі включэння даных з MLflow праз аліясы (models:/...@champion), таму шляхі ў рэальны час ніколі не залежаць ад шляхоў на ноутбуку распрацоўшчыка:

import mlflow
import mlflow.sentence_transformers

mlflow.set_tracking_uri("http://192.168.1.9:5000")

EMBEDDERS = {
    name: mlflow.sentence_transformers.load_model(f"models:/{name}@champion")
    for name in ("leukemia-embedder", "mortgage-embedder")
}

QUERIES = {
    "leukemia-embedder": "What are the first-line treatments for acute myeloid leukemia?",
    "mortgage-embedder": "How does refinancing affect my monthly mortgage EMI?",
}

for name, embedder in EMBEDDERS.items():
    vecs = embedder.encode([QUERIES[name]], normalize_embeddings=True)
    print(f"{name}: shape={vecs.shape}, prompts={list(embedder.prompts) or None}")

Рэзультаты

Запіты, аднасоўваныя да іпатэкі, должны быць атрыманы з колекцыі інфармацыі пра іпатэкі за дапамою адпаведнага эмбэдэра, а адказы — на падставе правіл, прызначаных для працы з LLM у сферэ іпатэкі. Запіты, аднасоўваныя да лейкеміі, должны адпавядаць клінічным прыемам. Запіты, якія не належаць да данай сферы, должны быць проігнораваны або на якія адказваць без адаза, што атрымана інфармацыя з данай сферы.

/Users/pavanmantha/.local/bin/uv run /Users/pavanmantha/Pavans/PracticeExamples/DataScience_Practice/mlflow-tutorials/mlflow_on_edge/.venv/bin/python /Users/pavanmantha/Pavans/PracticeExamples/DataScience_Practice/mlflow-tutorials/mlflow_on_edge/src/smart_rag.py
Downloading artifacts: 100%|██████████| 16/16 [00:19<00:00,  1.19s/it]
2026/09/06 12:48:35 INFO mlflow.sentence_transformers: 'models:/leukemia-embedder@champion' resolved as 'mlflow-artifacts:/3/models/m-f568ee233dd748f997ba66763e41653b/artifacts'
Downloading artifacts: 100%|██████████| 1/1 [00:00<00:00, 76.69it/s]
Loading weights: 100%|██████████| 103/103 [00:00<00:00, 15587.15it/s]
Downloading artifacts: 100%|██████████| 16/16 [01:29<00:00,  5.60s/it]
2026/09/06 12:50:06 INFO mlflow.sentence_transformers: 'models:/mortgage-embedder@champion' resolved as 'mlflow-artifacts:/3/models/m-c4221c844dfb45bfa15c6a4ecde56920/artifacts'
Downloading artifacts: 100%|██████████| 1/1 [00:00<00:00, 27.17it/s]
Loading weights: 100%|██████████| 197/197 [00:00<00:00, 8855.57it/s]
[transformers] BertModel LOAD REPORT from: /var/folders/1x/36nz44_569501n4xs0px2_8m0000gn/T/tmpef4y6tj5/model.sentence_transformer
Key                 | Status  |
--------------------+---------+-
pooler.dense.weight | MISSING |
pooler.dense.bias   | MISSING |

Notes:
- MISSING: those params were newly initialized because missing from the checkpoint. Consider training on your downstream task.
leukemia-embedder: shape=(1, 384), prompts=['query', 'document']
mortgage-embedder: shape=(1, 768), prompts=['query', 'document']
/Users/pavanmantha/Pavans/PracticeExamples/DataScience_Practice/mlflow-tutorials/mlflow_on_edge/src/smart_rag.py:20: UserWarning: Api key is used with an insecure connection.
  self.qdrant = QdrantClient(url=qdrant_url, api_key=os.environ.get("QDRANT_API_KEY"))

you> What are the phases of treatment for acute lymphoblastic leukemia?
[intent=LEUKEMIA -> leukemia_details -> openai]

assistant> The phases of treatment for acute lymphoblastic leukemia (ALL) are:

1. Induction - achieving remission.
2. Consolidation - eradicating residual disease with different agents to circumvent resistance.
3. Maintenance (in ALL) - prolonged low-dose therapy to suppress re-emergence of the clone.

you> What was 30-day Average SOFR referred to in Series issued before July 2023?
[intent=MORTGAGE -> mortgage -> gemma]

assistant> *   Question: "What was 30-day Average SOFR referred to in Series issued before July 2023?"
    *   Constraint: Use *only* the provided context.

    *   Chunk 1: Discusses "Excess inclusion income", Residual Holders, taxable income, Trust REMIC taxable income, etc. No mention of SOFR or July 2023.
    *   Chunk 2: Discusses "Backup withholding", Non-U.S. Persons, Ginnie Mae Guaranty, State/Local/Foreign tax. No mention of SOFR or July 2023.
    *   Chunk 3: Discusses "Residual Holder's share of expenses", REITs, RICs, phantom income. No mention of SOFR or July 2023.
    *   Chunk 4: Discusses "Principal Distribution Amount", Ginnie Mae Project Loan Certificates, Underlying Certificates. No mention of SOFR or July 2023.
    *   Chunk 5: Discusses "OID on a Teaser Security", "Initial Distribution Period", "Excess Interest Payment", "Accrual of Original Issue Discount". No mention of SOFR or July 2023.

    *   I have scanned all five provided text nodes.

you>

Чаму такая структура ўсёга цікавая

Рэжыстры дазволяюць заменяць эмбэдэры без неабходнасці перапрацоўкі кожнага кліента. Колекцыі інфармацыі, прызначаные для конкрэтных сфер, запобегаюць паслядку перакрычання між рознымі сферамі. Механізм направлення запітоў не дазволяе дорогім мадэлям выканаць працу з простымі запітамі. Для рэалізацыі данага патэрна не трэба выканаць MLflow на прыстрое тыпу Pi, але гэта паказвае, што рэжыстры можна размісціваць на кантролюемым апаратным забезпечэнні, якое знаходзіцца поблізу лабораторнай сеткі.

Аператывныя застэрэжэння

Забезпечыце безпеку Postgres пры яго выкліканні ў локальной сеты. Разглядзайце змяны в pg_hba як змяны, якія вплываюць на працу продукту. Фіксавайце версіі MLflow і драйвераў. Следзіце за паказнікамі пакрычэння класыфікатора: некарэктны намер можа выдаты запіт у неправільную колекцыю і стварыць вражанне пра „паслаблены LLM“. Аднакоўна ацэніце працэсы выкарыстоўвання дадзеных і маршрутызацыі запытоў. Калі ў рэестры выклікаюцься змяны, прайдзіце за адпаведнымі тэстамі пры перэхадзе на рэжым працы з рэальным трафікам.

Заключанне

RAG, які выходзіць за межы аднаго толькі шляху выкарыстоўвання дадзеных, ёсць пераважна часткаяю архітэктуры продукту: трэба знаты сферу прыменення, выкарыстоўваць правільную структуру дадзеных і задаваць адпаведныя параметры працы. MLflow, Qdrant і невелікі гейтвэй разрабатываюць такую архітэктуру, якая будзе працаваць нават на столі і застосоўваная ў рэальных умовах.

Забезпечэнне безпекі шляху, які падтрымваецца рэестрам

Аліясы чэмпіонаў должны праходзіць праз стадыянтскі этап. Зазначайце ID версіі модэлі, якая аддае кожную адпаведзь, ўбліжча да таго, каб можна было пераглядзець інцыдэнты пасля змены рэжыстры. Калі прыстрой Pi выйдзе з мерэжы, кліентам патрэбны рэжымы атрыбуту fail-closed, а не тыхае перайшчыце да вялікага локальнага пункта контролю.

Параметры часткавання должны знаходзіцца ў метаданных рэжыстры разам з элементам embedder. Новы чэмпіон з іншай праграмаваной дужыною кантэкста не павінен перадаўаць старыя часткі без флага перабудовы.

Запросы класіфікатораў заслуговуюць на фіксаты: дзесяць формулюванняў для іпотэк, дзесяць клінічных формулюванняў, дзесяць адварсальных „іншых“ формулюванняў. Абліковайце точнасць/працэс выкарыстоўвання пры падборэ LLM. Аднак калі не так, вы будэтэ падбіраць качанасць генератора, хоця справжнім дыфектам ёсць сам прыем роутавання.

Для выкантэнавання Raspberry Pi трэба сочыць за зношвам дыска ад частага запісу даных і вжываць зовнішнія дыскі як месца зберагчыка даных MLflow. Бэкапы Postgres трэба зберагчыць на іншай машыне, чым Raspberry Pi.

Пры адказванні заінтэрэсавленым сторонам на пытанняя пра праект, паказайце последовасць дзействаў: класыфікацыя → выбор алгорытму укладкі/колекцыі → запрашэнне даных → выбор LLM → адказ з цітатамі. Такой практычны прыклад лепшая пераканае, чым толькі спіс інструментоў, і ясна пакажае, дзе вырашаюцься стратэгічныя пытанні.

Расшыроўвайце домены адзячна. Кожны новы тып даных выклікае патрэбу ў колекцыі, адпаведным алгорытме укладкі, заданні на ўрабоцу даных, прыкладах для класыфікатора і правілах дзеяння LLM. Шлюз павінен адкласіць незнаёмыя тыпы даных, а не выбіраць самы большы мадэль.

Шэпет, трэба застаць парадокс «АЎТЭР» чыстым. Адказаць лепш, чым запрашваць даныя з каскаднага домэна, каб утрымацца ад незручнай тышы. Карыстальнікі давяржаюць сістэмам, якія ведаюць, калі ўжо не належаць да сферы дзеяння. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкай запрошэнняў генератора. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкой запрошэнняў генератора. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкой запрошэнняў генератора. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкой запрошэнняў генератора. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкой запрошэнняў генератора. Точнасць маршрута і якосць запрашвання даных трэба мерыць як адзінаковыя крокі прайшчога да выдання, прычым перад дальнейшай наладкой запрошэнняў генератора.

Прампты прыцілююцца далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Точнасць маршруту і якосць адзыскання дакументаў неабходна перамеркнуць як адзіныя крокі прайшлага рыляйнавання, прычаму прампты генератора можна будзе прыцілююць далей. Маршрутточнасць і якасць адзыскання дакументаў неабходна мерыць як адзінакавыя крокі прайшчога да выдання, прычаму запрошэнні для генератора трэба далей налаштаваць.Тэксты-запросы генератора трэба налагодзіць далей толькі пасля таго, як ўсе будзе пераканалізавана як адзінэльныя точкі выпуску. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора. Точнасць маршрута і якосць адзыскання дакументаў таксама трэба пераканалізаваць як адзінэльныя точкі выпуску пры дальшай налагодце запітоў генератора.Перш чым далей налагодзіць заповедзі генератора, неабяжна перавярыць вораты ASE. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора. Точнасць маршрута і якосць адзыскання дакладнаў неабяжна перамерыць як адзінаковыя крытэрыі выпуску прычымо да дальнейшага налагоджэння заповедзяў генератора.Ці параметры трэба ўточніць даўжэй. Точнасць маршрута і якосць адзысквання дакументаў неабходна перамеркнуць як адзлэжыстыя крокі пры выпуску, прычаму параметры генератора можна будзе ўточніць толькі пасля чаго. Точнасць маршрута і якосць адзысквання дакументаў неабходна перамеркнуць як адзлэжыстыя крокі пры выпуску, прычаму параметры генератора можна будзе ўточніць толькі пасля чаго. Точнасць маршрута і якосць адзысквання дакументаў неабходна перамеркнуць як адзлэжыстыя крокі пры выпуску, прычаму параметры генератора можна будзе ўточніць толькі пасля чаго.