惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Инженерия качества: Как перестать надеяться на удачу и начать измерять своих ИИ-агентов [Часть 1]
kobets87 · 2026-05-12 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение6 мин

Охват и читатели668

Туториал

Доброго времени суток!

Хочется поговорить об одной из самых «больных» тем в современной AI-разработке — как проверить, что система работает правильно. :-)

Удивительно, но текущий хайп вокруг LLM привел к довольно значительной деградации инженерной культуры в этой области («в среднем по больнице»). В эпоху первых трансформеров (да и более ранние эпохи) ни у кого не возникало сомнений: нужен «Golden Set», ручная разметка и жесткий контроль метрик. NLP был уделом специалистов по машинному обучению.

С приходом LLM порог входа упал. Теперь любой может написать промпт и получить ответ. Проверка качества превратилась в «vibe-check»: разработчик задает три вопроса, видит, что агент ответил «вроде нормально», и считает задачу решенной.

Но тут есть проблема: LLM вероятностна. Если она ответила правильно 5 (или даже 500) раз подряд, это не значит, что на 6-й (или 501-й) раз она не улетит в галлюцинации. Без продуманного процесса непрерывной оценки вы строите крайне хрупкую конструкцию.

Первое, что разумно ввести в ваши практики — это вспомнить про Golden Set. :-)

Golden Set — это эталонный набор данных «вопрос-ответ», на котором вы гоняете свою систему. Но для агентов старый формат пар «запрос-текст» уже не всегда достаточен.

Агент — это система, которая совершает действия. Поэтому современный Golden Set должен содержать траектории:

  • Эталонные рассуждения (Chain-of-Thought).

  • Эталонные вызовы инструментов (Function Calling): какие функции и с какими аргументами должны быть вызваны.

  • Эталонные данные (Ground Truth): не просто текст ответа, а факты, которые должны в нем присутствовать.

Где взять данные?

Собирать такие данные вручную — это долго, дорого и больно (именно поэтому об этом так любят забывать :-)). Но у некоторых типов ИИ-систем, скажем самой популярной агентской топологии RAG, есть «читерское» преимущество: ваши документы сами по себе — идеальный источник данных для тестов.

Генерация GoldenSet для RAG системы

Один из самых эффективных способов получить Golden Set для RAG — при помощи LLM построить Граф Знаний (Knowledge Graph) на основе ваших же документов.

Есть отличная реализация в рамках популярной библиотеки оценки ИИ-систем RAGAS. Используя её и Конституцию России, взятую в качестве примера PDF-документа, давайте рассмотрим, как это работает. :-)

Процесс выглядит так:

  1. Построение графа (Knowledge Graph): Мы разбиваем документы на иерархические узлы (Document -> Section -> Chunk). К каждому узлу LLM добавляет метаданные:

    • Summary: Краткое резюме контента.

    • Entities: Имена, даты, специфические термины.

  2. Связи (Relationships): Узлы связываются на основе структуры (следующий/предыдущий) или семантической близости извлеченных сущностей.

  3. Синтез вопросов: На основе структуры графа мы запускаем «синтезаторы», которые обходят получившийся граф и создают вопросы разной сложности.

Как синтезируются вопросы?

Ragas предлагает довольно гибкую систему синтезаторов, позволяющую проверить RAG под разными углами:

Simple (Single-Hop): Проверяет базовый поиск. Вопрос касается одного конкретного факта в одном документе. Пример: «В каком году была принята текущая Конституция РФ?»

Multi-Hop: Самый важный тест. Требует сопоставления фактов из разных частей документа или даже разных файлов. Это проверяет способность ретривера собирать разрозненный контекст. Пример: «Какие ограничения накладываются на президента, если он одновременно является главой совета безопасности?»

Comparative: Заставляет модель сравнивать сущности. Пример: «Чем полномочия Государственной Думы отличаются от полномочий Совета Федерации в вопросе принятия федеральных законов?»

Specific vs Abstract: Мы можем генерировать как очень конкретные вопросы (фактология), так и абстрактные (обобщение темы).

Давайте рассмотрим, как выглядит в коде:

Я буду использовать в качестве LLM qwen/qwen3.6-35b-a3b, а в качестве модели эмбеддинга text-embedding-qwen3-embedding-0.6b. И одна и вторая запущенна локально в LM_Studio.

import argparse
import asyncio
import logging
import os

import instructor
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_openai import OpenAIEmbeddings
from openai import AsyncOpenAI
from ragas.embeddings.base import LangchainEmbeddingsWrapper
from ragas.llms.base import InstructorLLM, InstructorModelArgs
from ragas.testset import TestsetGenerator
from ragas.testset.graph import KnowledgeGraph
from ragas.testset.synthesizers.multi_hop.specific import MultiHopSpecificQuerySynthesizer
from ragas.testset.synthesizers.single_hop.specific import SingleHopSpecificQuerySynthesizer

# Настройка логирования
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

async def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--pdf", type=str, default="constitution.pdf", help="Путь к PDF")
    parser.add_argument("--num-pages", type=int, default=5, help="Сколько страниц использовать (по умолчанию 5, -1 — все)")
    parser.add_argument("--output", type=str, default="golden_set.csv", help="Путь для сохранения Golden Set")
    args = parser.parse_args()

    # 1. Конфигурация из переменных окружения
    base_url = os.getenv("LLM_BASE_URL", "http://127.0.0.1:1234/v1")
    api_key = os.getenv("LLM_API_KEY", "lm-studio")
    model = os.getenv("LLM_MODEL", "qwen/qwen3.6-35b-a3b")
    emb_model = os.getenv("LLM_EMBEDDING_MODEL", "text-embedding-qwen3-embedding-0.6b")

    # Путь к PDF
    pdf_path = args.pdf
    if not os.path.exists(pdf_path):
        logger.error(f"Файл {pdf_path} не найден. Положите constitution.pdf рядом со скриптом.")
        return

    # 2. Загрузка страниц
    logger.info(f"Загрузка PDF: {pdf_path}")
    loader = PyMuPDFLoader(pdf_path)
    all_documents = loader.load()

    if args.num_pages != -1:
        documents = all_documents[:args.num_pages]
        logger.info(f"Ограничение: используем первые {args.num_pages} страниц из {len(all_documents)}")
    else:
        documents = all_documents
        logger.info(f"Используем все страницы: {len(documents)}")

    # 3. Сооружаем обертки которые ожидает Ragas, заодно чиня ряд проблем LM_Studio :)
    client = AsyncOpenAI(base_url=base_url, api_key=api_key)
    # Используем MD_JSON для корректной работы структурного вывода с моделью, запущенной в LM_Studio
    patched_client = instructor.from_openai(client, mode=instructor.Mode.MD_JSON)

    # Провайдер "custom" предотвращает некоторые проблемы библиотеки с попыткой ходить не локально, а в облачный OpenAI
    ragas_llm = InstructorLLM(
        client=patched_client,
        model=model,
        provider="custom",
        model_args=InstructorModelArgs(temperature=0.2)
    )

    # Эмбеддинги через LangChain-обертку, снова чиним особенности LM_Studio :)
    emb_lc = OpenAIEmbeddings(
        base_url=base_url,
        api_key=api_key,
        model=emb_model,
        check_embedding_ctx_length=False
    )
    ragas_emb = LangchainEmbeddingsWrapper(emb_lc)

    # 4. Генерация Knowledge Graph и Golden Set
    logger.info(f"--- Запуск генерации Knowledge Graph (страниц: {len(documents)}) ---")
    try:
        kg = KnowledgeGraph()
        generator = TestsetGenerator(llm=ragas_llm, embedding_model=ragas_emb, knowledge_graph=kg)

        # Настройка синтезаторов вопросов
        distribution = [
            (SingleHopSpecificQuerySynthesizer(llm=ragas_llm), 0.5),
            (MultiHopSpecificQuerySynthesizer(llm=ragas_llm), 0.5),
        ]

        # Адаптация промптов под русский язык...
        # Это не исключит генерации на английском на 100%, но минимизирует такие случаи
        for query, _ in distribution:
            prompts = await query.adapt_prompts("russian", llm=ragas_llm, adapt_instruction=True)
            query.set_prompts(**prompts)

        # Генерируем 10 вопросов, настоящий GoldenSet обычно содержит больше 100...
        testset = generator.generate_with_langchain_docs(
            documents,
            testset_size=10,
            query_distribution=distribution
        )

        df = testset.to_pandas()
        logger.info("Генерация успешно завершена!")

        # Сохранение в файл
        output_file = args.output
        df.to_csv(output_file, index=False)
        logger.info(f"Golden Set сохранен в: {output_file}")

    except Exception as e:
        logger.error(f"Ошибка при генерации: {e}")

if __name__ == "__main__":
    asyncio.run(main())

Обратите внимание на конструкцию query.adapt_prompts(…). Библиотека оперирует для генерации англоязычными промптами, что может приводить к тому, что генерируемые вопросы и ответы, будут на английском, это предусмотренный авторами способ минимизировать такие случаи (хотя иногда она все равно будет писать транслитом) :)

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

Благодарю за внимание!

В следующей, части статьи поговорим, что вообще разумно измерять в агенсткой ИИ системе, а затем перейдем к Е-Е как совместить такой Golden Set с процессом непрерывной проверки.