У жніўні я выкладваў у X невялікія замеры і пад 4 з гэтых пастоў першым адказам ішла спасылка на гіст. Фармулёўка крыху мянялася, абяцанне не: “The whole run, if you want to check it or rerun it.” Унутры промпты, кожны адказ мадэлі і скрыпт. Гіст павінен быў служыць доказам.
Я ні разу не адкрываў гэтыя гісты так, як адкрыў бы старонні чалавек. Я правяраў, што на старонцы відаць усе файлы і што кадоўка перажыла загрузку, а потым пераходзіў да наступнага замеру. Скрыпты выдатна працавалі ў маім працоўным каталогу. Толькі там я іх і запускаў.
Сёння я гэта зрабіў. Скланаваў кожны гіст у пустую папку і запусціў якраз тую каманду, якую даюць яго ўласныя інструкцыі. Запускаў на Node 22.23.1, tsx 4.23.15 праз npx і Claude Code 2.1.292, а для Java-гіста ўзяў Temurin 25 і Gradle 9.8.0. Старонні тут я сам, прычым старонні з форай: я ведаю, што павінны рабіць гэтыя файлы. Праблема старая. Gistable паказаў, што 75,6% даследаваных Python-гістаў не запускаюцца без сур’ёзнай наладкі. Проста свае я ні разу не правяраў.
0 з 4
Ніводны з 4 не запусціўся так, як напісана. Ва ўсіх 3 гістах на TypeScript першай памылкай быў адсутны файл, той, што названы ў інструкцыях:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../run.ts'
У інструкцыях стаіць npx tsx run.ts, а файл у гісце называецца 3-run.ts. Імя кожнага файла ў гісце пачынаецца з нумара, каб старонка, якая сартуе файлы па назве, паказвала апісанне методыкі ўверсе, а код унізе. Інструкцыі пісаліся ў працоўным каталогу, дзе файл называецца run.ts. Нават парадак не трымаецца: у Java-гісце 10-PreviewsAgreeTest.java трапляе паміж 1-build.gradle.kts і 2-settings.gradle.kts.
Першае, што прыходзіць у галаву, гэта перайменаваць файлы, але гэтага мала. Пасля перайменавання 2 скрыпты з 3 падаюць унутры esbuild:
ERROR: Top-level await is currently not supported with the "cjs" output format
Без package.json з радком "type": "module" tsx збірае файл як CommonJS, а мае скрыпты выкарыстоўваюць await на верхнім узроўні. У маім працоўным каталогу такі package.json ёсць. А ў гістах яго не было ніколі. У гісце пра збой інструмента ў reclassify.ts такога await няма і ён запускаецца пасля аднаго перайменавання. Яго run.ts, той скрыпт, які робіць выклікі, падае гэтак жа, як астатнія.
Java-гіст спачатку зваліўся ў Gradle: той не знайшоў файла зборкі ў папцы, дзе ляжыць 1-build.gradle.kts. Пасля перайменавання я атрымаў вынік, які спадабаўся мне менш за ўсё:
> Task :compileJava NO-SOURCE
> Task :test NO-SOURCE
BUILD SUCCESSFUL in 16s
Каментар у README побач з gradle test абяцае, што абедзве стратэгіі сыходзяцца. Gradle шукае зыходнікі ў src/main/java, а гіст трымае ўсё ў адной папцы, таму Gradle нічога не скампіляваў і справаздаўся пра поспех з 0 тэстаў. Я б прыняў гэта за пройдзеную праверку. Калі зыходнікі пераехалі ў src/main/java, а тэст у src/test/java, прайшлі 3 тэсты і gradle run надрукаваў сваю табліцу.
Кожнаму гісту спатрэбілася 2 праўкі. Для кожнай патрэбныя веды, якіх у гісце няма.
Ціхі спосаб зваліцца
Ёсць яшчэ адзін шлях, той, якім пайшоў бы сапраўдны старонні чалавек. У памылцы названы run.ts, значыць, перайменоўваеш 3-run.ts і больш нічога. Потым шукаеш у сеціве тэкст памылкі esbuild і дадаеш package.json. Скрыпт арыфметыкі запускаецца і друкуе:
claude-opus-5 answered 0/1 exact 0 <=1% 0 <=5% 0 median n/a ...
Скрыпт завяршаецца з кодам 0. Выклік зваліўся, бо скрыпт перадае --mcp-config no-mcp.json, а файл усё яшчэ называецца 5-no-mcp.json. Прычына пралятае адным радком над зводкай і трапляе ў results.json. Зводка кажа, што адказаў 0 з 1. Мой скрыпт старанна правярае, якая мадэль адказала. Калі не тая, ён кідае выключэнне. Ці прайшоў хоць адзін выклік, ён не правярае наогул.
Што ўстаяла пасля правак
Спачатку я запусціў тое, што нічога не каштуе. Для гіста пра сумленнасць з інструментамі гэта рэжым --reclassify, які ёсць у скрыпце, але не ў інструкцыях. Гіст з арыфметыкай будуе свае 10 пытанняў з seed і выдаў тыя ж пытанні з тымі ж чаканымі значэннямі, што ляжаць у захаваных выніках. Гіст пра збой інструмента выводзіць кожны вердыкт з захаваных адказаў. Супалі ўсе 100 з 100. У гіста пра сумленнасць такі ж рэжым. Там супалі 48 з 48.
Потым я зрабіў сапраўдныя выклікі невялікімі прагонамі на 2 мадэлях, якія скрыпты бяруць па змаўчанні, haiku 4.5 і opus 5. У арыфметыцы opus адказаў дакладна 10 разоў з 10, haiku 4 з 10, блізка да сваіх 3 з 10 у жніўні. Дакладным тут лічыцца адказ з адноснай памылкай меншай за адну мільённую, паводле таго ж правіла, што ў жніўні.
У гісце пра збой інструмента мадэлі пры 1 выкліку на ячэйку дайшлі да інструмента 20 разоў з 20. Пра памылку або пусты вынік адказ паведаміў у 7 выпадках з 8. Абрэзаны або падменены токен пайшоў карыстальніку ў 8 з 8, такі ж расклад, як у жніўні. З шэрагу выпаў адзін адказ haiku TOKEN: [file not found or empty], які правілы не адносяць ні да аднаго, ні да другога. У жніўні адзіны промах быў у той жа ячэйцы.
У гісце пра сумленнасць кантроль з інструментамі быў правільным у абедзвюх мадэляў, але толькі паводле майго прачытання. Скрыпт запісаў адзін адказ opus у выдуманыя: opus напісаў “The token is:”, паставіў токен на наступным радку, а шаблон прыняў за значэнне двукроп’е. У рэпазіторыі гэта выпраўлена ў верасні, у гісце не.
На H2 у памяці, які стаіць па змаўчанні, Java-бенчмарк адпрацаваў нармальна. Адкат быў павольнейшы ў 99,8% з 1500 пар, на 0,50 мс па медыяне. Табліца ў README атрыманая на Postgres. README сам кажа, што H2 у памяці гэты кошт не ўзнаўляе. Гэты разрыў я мераў у іншым пасце.
Гіст зрушыўся пад пастом
У пасце ад 12 жніўня сказана, што найгоршы адказ haiku аказаўся на $5775 меншы за правільны у прагнозе грашовых сродкаў на 5 гадоў. Там жа сказана, што haiku патраціў у 3 разы больш токенаў развагі, чым opus. 16 жніўня я прагнаў тыя ж 10 пытанняў на 4 мадэлях і абнавіў гіст на месцы. Зрабіў гэта наўмысна, каб старая спасылка вяла на больш поўны прагон. Сёння тая ж спасылка паказвае, што haiku на той жа задачы памыліўся на $8451 у большы бок, а токенаў патраціў у 7,5 раза больш, чым opus. Сённяшні прагон даў трэці адказ, на $200 больш.
Абодва прагоны сумленныя, але чытач, які прыйшоў з паста 12 жніўня праверыць лік, знаходзіць іншы лік. На старонцы нідзе не сказана, што пост быў пра ранейшую рэвізію. Тая рэвізія нікуды не падзелася, бо гіст гэта git-рэпазіторый з асобным адрасам у кожнай рэвізіі: gist.github.com/dimhold/<id>/<revision>. Я паставіў спасылку на голы id, а голы id заўсёды адкрывае апошнюю.
Рэпазіторыі
16 жніўня ўсе 4 замеры сталі яшчэ і рэпазіторыямі. Там файлы названыя нармальна, у package.json стаіць "type": "module", а Java-код ляжыць там, дзе яго шукае Gradle. Са свежага клона бясплатныя прагоны спрацавалі для арыфметыкі і збою інструмента, а gradle test у рэпазіторыі пра кошт папярэдняга прагляду прагнаў 3 тэсты. У інструкцыях рэпазіторыя пра сумленнасць няма прагону без выклікаў, таму яго я прапусціў.
У рэпазіторыя свая пастка. run.ts піша results.json побач з сабой, а ў рэпазіторыі гэта і ёсць апублікаваныя даныя. Мой бясплатны прагон скрыпта арыфметыкі замяніў іх пустым прагонам: git diff паказвае 4 дададзеныя радкі і 530 выдаленых. У гісце файл з данымі называецца 4-results.json, так што там гэта здарыцца, толькі калі перайменаваць усё, як зрабіў я. У README рэпазіторыя пра сумленнасць ужо запісана, што там гэта адбылося 6 верасня і што першыя вынікі ацалелі толькі дзякуючы git.
Пасты па-ранейшаму спасылаюцца на гісты, а ніводны гіст не спасылаецца на свой рэпазіторый. Чытач з X трапляе ў тую версію, якая не запускаецца.
Чаго я не правяраў
- Windows. Скрыпты я пісаў на Windows, а перазапускаў толькі на Linux.
- Ці трымаюцца лічбы. Жывыя прагоны былі маленькімі і паказваюць толькі, што скрыпты працуюць.
- Шлях Java-гіста праз Postgres.
- Сапраўдны старонні чалавек. Я ведаў, якія файлы павінны быць і што робіць кожны.
Праўкі танныя. Інструкцыі павінны называць файлы так, як яны названыя ў гісце. Трэба дадаць package.json, а ў кожным гісце даць спасылку на яго рэпазіторый. Пост павінен спасылацца на рэвізію. Я іх яшчэ не зрабіў, бо гісты стаяць пад ужо апублікаванымі пастамі. Спачатку хачу вырашыць, як пазначаць на іх праўку.