Галоўная / Артыкулы / Ацэнка LLM без залежнасцяў, дзе єсць суддзі, якому можна рэальна даверыцца

Ацэнка LLM без залежнасцяў, дзе єсць суддзі, якому можна рэальна даверыцца

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

2109 слоў

Единичныя тэсты працуюць, таму што детерміністычны код дае адно і тое жа рэшэння ў кожны раз: якщо праглядаць, што функцыя вяртае чатыры, яна завжды так і робіць. Рэзультаты работы мовнага моделі зменяюцца з кожным вызывам, таму няма стандартнага текста, з якім можна было б пораўняваць, і команды часта вырашаюць адмахнуцца ад гэтага, выбіраючы платформу для оцэнкі, якая викорыстоўвае іншую модель для атрымання балав. Самэй модэль оцэнкі є тым моментам, калі большасць оцэнак практычна перестае ўжо чыгураваць якія-небудзь показнікі, таму што ніхто не пераканаўся, чы ёй паслухаецца людзіня. Шырокі падчынак прадстаўляе можлівасць стварыць цэлую систему оцэнкі простаю мовай Python за калькі гадзін, пры чым найважлівейшая ў яе частка прыдзеляе налаштаванню механізма оцэнкі, каб рэзультаты можна было абяцаць.

Тры складнікі будзь-яй оцэнкі

Як толькі адмахнуцца ад дапаможных інструментаў, оцэнка складаецца з трохо складнікаў, для якіх не патрабуецца жадных бібліятэкаў:

  • Набор дадзеных уваходу, які б лепш быў адняты з рэальнага выкарыстоўвання, а не створаны вымышлена.
  • Спосаб пры генераванні выходу для кожнага вхіднага дадзення, якім проста ўсё тое ж сістэма, якая апрацоўваная.
  • Функцыя аблікавання, якая ператварае кожны выход у вердыкт, які можна падсчытаць.
  • Дашборды, трэйсінг і хоставаныя наборы дадзення — это зручнасці, створаныя на адной з гэтых базаў. Дзеяныя з іх дапамагаюць рэальна, але сама сутніса заўсёды запішваецца у або-восьці рядкоў коду на Python, і такі маленькі код будзе працаваць дужо дыяўно, нават калі якая-небудзь платформа змяніцца чы пропадзе.

    Шаг 1: Зберыце сто рэальных вхідных дадзенняў

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

    Завантажэнне іх — гэта проста задача:

    import json
    with open("requests.jsonl") as f:
        cases = [json.loads(line) for line in f][:100]
    

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

    Якщо у вас яшчэ няма лог-файлаў, самі напісце ста кейсоў, але чакайце, што рэзультаты будуць выглядаць краща, чым ў рэальнасці, пакуль іх не заменяе рэальны трафік.

    Шаг 2: Раздзеліцьваець пераканальванне коду ад рашынняў

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

    • Рэзультат — гэта правільны JSON.
    • Категорыя належыць да вядомага набору.
    • Чысла знаходзіцца ў дазволеным дыяпазоне.
    • Існуюць неабходныя поля.
    • Размяр адпаведзі
      • Кожна з гэтых пунктаў ёсць тверджэнням. Наступная функцыя (Python, незважаючы на ўсё, як яна можа быць пазначаная) выконвае калькі з іх і вяртае словнік з адпаведнымі рэзультатамі:

    def code_checks(output):
        checks = {}
        try:
            parsed = json.loads(output)
            checks["valid_json"] = True
            checks["has_fields"] = all(k in parsed for k in ("answer", "confidence"))
        except json.JSONDecodeError:
            checks["valid_json"] = False
            checks["has_fields"] = False
        checks["under_limit"] = len(output) < 2000
        return checks
    

    Верненне адміністратыўных перакананняў замест адзінаго булева значэння дазволяе пазначыць, якая власнасць не працавала, калі ўтварылася проблема. Тое, што застаецца пасля дэтерміністычных перакананняў, — гэта та частка, якая вымагае адгукнення: чы рэспанс з’явіў адпаведны на запыт, чы ён уключыў факты, якіх не было ў вачоўнай інфармацыі, чы ён адмовіўся, калі трэба было падтрымаць. Гэтыя власнасці трэбуюць судды, а суддзя — парадактавання.

    Шаг 3: Напісаць судду, які оцэнюе аднае

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

    JUDGE = """You are grading one property of a response.
    
    PROPERTY: Does the response contain any claim that is not supported by the
    source text provided?
    
    SOURCE:
    {source}
    
    RESPONSE:
    {response}
    
    Answer with exactly one word, PASS or FAIL, then a new line, then one
    sentence explaining your verdict. Do not explain anything else."""
    
    def judge(source, response, call_model):
        out = call_model(JUDGE.format(source=source, response=response))
        verdict = out.strip().split("\n")[0].strip().upper()
        return verdict == "PASS", out
    

    Умовы формата маюць такое ж значэнне, як і самі критэрыя. Такое трэбаванне, каб на першай лініі была толькі адна слова – PASS чыў FAIL, – дапамагае лёгка аналізаваць рэзультат. Вердыкты у вольнай форме разлічаюцца за структурой з аднаго выкліку да іншага, і якщо неудача пад час аналізу будзе спрыяць уваажацца за успех, то кожны рэзультат, які вы пасля цього аддасте, будзе завышаны, без таго, каб хтось гэта пазнаў. Што стосуецца данай рэалізацыі, яна выбирае апатрофны варыянт: будзь-што, кроме точна PASS, укладаючы PASS. чы вердыкт, упакаваны ў форматаванне, лічыцца як неудача. Варта фіксаваць, насколькі часта гэта трапляецца, адказы, якія немагчыма аналізаваць, самыя по сабе ёсць сигналамі.

    Шаг 4: Запускайце все і зберагаюце неадрасаваны выход

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

    results = []
    for case in cases:
        output = call_model(case["prompt"])
        passed, reasoning = judge(case["source"], output, call_model)
        results.append({
            "id": case["id"],
            "output": output,
            "code_checks": code_checks(output),
            "judge_pass": passed,
            "judge_reasoning": reasoning,
        })
    rate = sum(r["judge_pass"] for r in results) / len(results)
    print(f"{rate:.1%} pass on {len(results)} cases")
    

    Цыкл фіксуе прагматычныя пераконтроўкі разам з рэшэнням судды, хоць асновны паказначык урачыстае толькі рэшэння судды. У практыцы трэба выказваць аба, таму што адпаведзь, якая не прыменяеся па правілам JSON, ўважаецца невялікай, незалежна ад таго, што думае судда. Таксама зазначыце, што тая ж функцыя call_model генеруе та оцінюе тут; часта выбіраюць іншы або сильнейшы модэль для судды, але які бы вы не выбралі, наступны крок і ўладае тым, чыго ён будзе надзяйны.

    У гэты момент у вас є процэнт. Ён яшчо нічога не значыць.

    Крок 5: Калібруванне судды па вашых сабецоўых атрыбутах

    Гэты крок большасць нарадчыкаў праігноравае, і ён займае або трохі больш часу. Выберыце пяцьдзiesять з ста прыкладоў і самі пазначыце кожны з іх як PASS або FAIL, не заглядаючы спачатку ў вердыкт судды. Потым паўпоручыце два наборы атрыбутаў:

    agree = sum(1 for r, human in zip(results[:50], human_labels)
                if r["judge_pass"] == human)
    print(f"judge agrees with me on {agree}/50 = {agree/50:.0%}")
    both_fail = sum(1 for r, h in zip(results[:50], human_labels)
                    if not r["judge_pass"] and not h)
    judge_fails = sum(1 for r in results[:50] if not r["judge_pass"])
    human_fails = sum(1 for h in human_labels if not h)
    print(f"judge caught {both_fail}/{human_fails} of the failures I found")
    print(f"judge flagged {judge_fails - both_fail} things I considered fine")
    

    Скрыпт паказвае тры показнікі: загальную ступень згоды, колькі з вашых памылак таксаваў і суддзя, і колькі случаяў суддзя не пазнаў, якія вы вважалі прийнятнымі. Код прыпускае, што human_labels — это спіс ложных значэнняў у тым жа порядку, што і першыя пяцьдзесят рэзультатаў, і ён выконае дзеленне на ноль, якщо вы зовсама не знайшлі памылак, што сама по сабе ўскажоўвае, што ваш набор дадзеных занадта просты.

    Чаму чыстая ступень згоды вводзіць у глухое

    Загальная ступень згоды — это менш значны показнік, хоць яго і часта цитуюць. Якщо дзевяноста процэнта вашых случаяў прыймаюцца, суддзя, які на всё адпаведае «ПРАЙМУ», досягне дзевяноста процэнта згоды, не пазначыўшы нічога.

    Найважлівейшы показнік: памылакі, якія былі выявлены

    Тое, што заслуговае на вашу увагу, — это частка вашых сабеякороў FAIL, якія таксавальнік таксаваў таксама. У тэрмінах класыфікацыі гэта ўсвядомленне таксавальніка пра клас неудач. Таксавальнік, який выявляе два з вашых адзинадцатых бракоў, на самай працэ практычна нічога не оцінюе; ён проста затверджуе все, дадаўшы пераканлівае поясненне. Трэці показнік, ложныя аўтаматычныя сигналы, таксама мае значэнне, адтолькі ўважайце, што таксавальнік, який пазначае правільныя адпаведзі, можа змусіць вас „вылагодзіць“ тое, што ніколі не было зламана.

    Калі вы і таксавальнік не пагоджываецеся

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

    Критэрыя є нечысткімі

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

    Вашы сабеяннікі некалькаваны

    Гэта трапляецца чащэ, чым людзі спадзяваюцца. Людскія атрыбутацыі змінююцца ў пяцьдзесят прыкладаў, больш за ўсё у пригранічных прыкладах напрыканце сесіі. Перэатрыбутаваць спараныя прыклады новым поглядам, перш чым крытыкаваць суддю.

    Этая характэрыстыка ў сваім сутнасці суб’ектываўная

    Дзеяныя якосці нельга адносна і непакрыткована оцэніць нікаму. Якщо такая ситуацыя, ніхто з суддзяў не будзе надзеяным. Або раздзеліце характэрыстыку на меньшыя, можна пераканаць сабе падразделы, або прыміце, што яе нельга оцэніць.

    Павтараць: скорэктуйте критэрыя, практычна перазначыце атрыбуты там, дзе трэба, і запускайце знову, пакуль суддзя не зафіксуе достатню колькасць вашых адмышлень, якія пагрожуюць рэзультату, і тады вам даведзецца захіщаць гэты показнік на зустрэчы. Пасля чаго зафіксавайце критэрыя і зберагаюце ўсі ўсунутыя версіі разам з кожным наступным рэзультатам. Рэзультаты, ацэнены за дапамою разных критэрыяў, нельга пораўняваць. Як падтрымліваць „здаров’е“ суддзі пад час стацыонарнай роботы, адзін у адзін, дакладна описана ў стацыяні „Управлінне LLM як суддзёй як жывай системай вырабоцтва“.

    Што дае вам калібруваная ацэнка

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

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

    Меры лімітаў ацэнкі за ста прыкладоў

    Перад тым, як працаваць за гэтым падходам, варта разумець тры абмежэнні.

    Маленькія змены застаюцца непазначальнымі

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

    Ручная маркавання не падлягае масштабаванню

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

    Калібрацыя выгорае

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

    Две дапамогі пасля запуску

    • Зберагаюце версію всього. Зберагайце версію модэлі і версію критэрыяў разам з кожным рэзультатам. Рэйтынг, у якога не ўсё гэта ёсць, нельга паўставіць у адносе да іншых рэйтынгаў, і таму показнік без адпаведных критэрыяў мало чаго гаворыць.
    • Зберагаюце набор неспакоў. Случаі, калі вы і судзія не пагадаліся, — гэта найціннае ў всім заведамстве. Перапрыявленне іх пасля кожных змян у критэрыях — гэта шырэйшы спосаб з’ясавіць, чыякія змены былі корыстныя.

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

    Ключовыя выводы

    • Ацэнка — это набор дадзеных, генератор і система расчытку рэйтынгу; усе іншае — факультатывныя інструменты.
  • Ўзайце рэальныя, складныя даны і пераканаўваеце ўсё, што можна адначыткальна вылічыць, за дапамогою коду, а не модэлю.
  • Даўайце кожнаму суддзі адны крэтарыя і строгі, можна парасаваць формат выходных даных.
  • Адзвярцайце, сколькі неудач, выяўленых людзьмі, знаходзі суддзя, а не толькі загальную згоду.
  • Заморажавайце і версіявайце крэтарыя, паўтарна пераверачайце іх пасля змян у модэлі, а калі эфекты маленькія — выкарыстоўвайце парныя парабяранні.
  • Спаднёе чытанне