fix(bot): прогон 250 вопросов × 2 режима — 11 находок закрыто, все проверены перепрогоном
Владелец: «проверь их обоих на тех 250 вопросах» → «правь все». Разбор: docs/superpowers/findings/2026-07-14-bot-250-both-modes-run.md Цены оказались вылечены полностью (0 выдуманных цен на 500 ответов), но вылез другой пласт — бот путал гостя с вошедшим клиентом и импровизировал там, где правды нет в статьях. ЧТО ПОЧИНЕНО (было → стало на перепрогоне): - Гостю приписывали счёт и подарок («у вас уже есть 1000 ₽, они лежат на счёте») 2 → 0. У гостя нет ни счёта, ни подарка: он не зарегистрирован. - Вошедшему называли его баланс подарком портала 2 → 0 и подсовывали сценарий новичка («живите на подарок», «создайте первый проект») — подарок он потратил давно. - Вошедшему врали про состояние проектов («два работают», а работает один) 4 → 0 и про заявки («сегодня 12», а сегодня 0) 1 → 0. - «Сотая заявка уже дешевле» 2 → 0: ступень меняется по ОБЪЁМУ (первая — 500 заявок). - «1000 ₽ хватит на несколько десятков заявок» 1 → 0. По решению владельца число заявок на подарок НЕ называем вообще: сколько придёт, зависит от источника. - «Поднимите лимит — заявок будет больше» 1 → 0: лимит это ПОТОЛОК, а не источник. - «Такого не бывает» про списание без заявки 1 → 0: на проде фантомные списания БЫЛИ. - «Для Москвы — Московскую область» 1 → 0: Москва и СПб — самостоятельные субъекты. - Обрубки фраз после чистки сторожем («Они лежат…», «Нажмите её…») 3 → 0. ЗАМЕЧАНИЕ ВЛАДЕЛЬЦА ПО ЖИВОМУ ЛОГУ: «номера это и есть заявки, а он их делит». Фраза «мы не продаём номера поштучно» была ВЫДУМКОЙ бота — в статьях её нет. Теперь: номер = заявка = лид = контакт, продаём любой объём (хоть одну штуку), минимального заказа нет; спросили цену — бот называет цифру ПЕРВОЙ фразой. Живьём: «Сколько стоит один номер?» → «Заявка стоит от 55 ₽ до 25 ₽». ПРАВДА ПРО ВОЗВРАТ ДЕНЕГ вынесена в статью vozvrat-deneg.md — дословно из «Политики возврата» (/legal/refund): остаток по заявлению на почту, до 3 рабочих дней, за вычетом комиссий; стоимость переданных заявок не возвращается. Раньше бот придумывал процедуру. Плюс: сторож больше не считает выдумкой число, названное САМИМ клиентом («можно купить всего 5 номеров?»); демо-стенд перестал сам себе противоречить (счётчик проекта «сегодня» разошёлся с числом сделок); добавлен прогонщик bot:run-questions для таких проверок. Тесты: бот 258/258, весь бэкенд 2738/2744 (0 падений). Сторож не перестарался: из 250 старых одобренных ответов режет целиком 1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\KnowledgeChunk;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
/**
|
||||
* Прогонщик вопросов — наша проверка ИИ-фичи (массовый прогон + слепые судьи).
|
||||
* Продуктом не является: в бою не вызывается, но ломаться не должен, иначе прогон
|
||||
* молча соврёт нам самим.
|
||||
*/
|
||||
beforeEach(function () {
|
||||
config()->set('services.support.email', 'support@liderra.ru');
|
||||
config()->set('services.yandexgpt', [
|
||||
'api_key' => 'k', 'folder_id' => 'f', 'model' => 'yandexgpt-lite/latest',
|
||||
'endpoint' => 'https://llm.api.cloud.yandex.net/foundationModels/v1/completion',
|
||||
'timeout_seconds' => 8,
|
||||
]);
|
||||
KnowledgeChunk::create([
|
||||
'source_path' => 'help/b.md', 'title' => 'Как пополнить баланс', 'tour' => null,
|
||||
'topics' => 'пополнить, баланс', 'chunk_index' => 0,
|
||||
'content' => 'Пополнить баланс можно картой или по счёту.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('прогоняет вопросы и пишет ответы построчно', function () {
|
||||
Http::fake(['llm.api.cloud.yandex.net/*' => Http::response([
|
||||
'result' => ['alternatives' => [['message' => ['role' => 'assistant', 'text' => 'Пополнить баланс можно в разделе «Биллинг».']]]],
|
||||
])]);
|
||||
|
||||
$dir = sys_get_temp_dir().'/bot-run-'.uniqid();
|
||||
mkdir($dir);
|
||||
$file = $dir.'/q.json';
|
||||
$out = $dir.'/out.jsonl';
|
||||
file_put_contents($file, json_encode(['как пополнить баланс?', 'а картой можно?'], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$this->artisan('bot:run-questions', ['--file' => $file, '--out' => $out, '--as' => 'guest'])
|
||||
->assertExitCode(0);
|
||||
|
||||
$lines = array_filter(explode("\n", (string) file_get_contents($out)));
|
||||
expect($lines)->toHaveCount(2);
|
||||
|
||||
$first = json_decode((string) $lines[0], true);
|
||||
expect($first['n'])->toBe(1)
|
||||
->and($first['as'])->toBe('guest')
|
||||
->and($first['q'])->toBe('как пополнить баланс?')
|
||||
->and($first['a'])->toContain('Биллинг');
|
||||
});
|
||||
|
||||
it('без файла вопросов честно падает, а не делает вид, что прогнал', function () {
|
||||
$this->artisan('bot:run-questions', ['--file' => 'нет-такого.json', '--out' => 'x.jsonl'])
|
||||
->assertExitCode(1);
|
||||
});
|
||||
Reference in New Issue
Block a user