Ворклог по задаче "Добавить ИИ агенту функции анализа проектной документации"
Отдельный крайне занятный кейс вот с такой инструкцией:
Прочитай файлы
storage/unpack/cmqv7yb0i00018hzwx2uttxcb/1782515133778-VKG_Ümberpuist hoone.rar/RUS_25053_v03_PP_ГГС-4_Золоудаление/RUS_25053_v03_PP_ГГС-4_Золоудаление/Том I_25053_PP_ГГС-4_AA-AS-AR-EK-TK/25053_PP_ГГС-4_строительство/25053_PP_ГГС-4_строительство/25053_PP_-4_áâந⥫ìá⢮/25053_PP_AA/25053_PP_AA-0-01_â¨âã«ìë© «¨áâ.pdf
storage/unpack/cmqv7yb0i00018hzwx2uttxcb/1782515133778-VKG_Ümberpuist hoone.rar/RUS_25053_v03_PP_ГГС-4_Золоудаление/RUS_25053_v03_PP_ГГС-4_Золоудаление/Том I_25053_PP_ГГС-4_AA-AS-AR-EK-TK/25053_PP_ГГС-4_строительство/25053_PP_ГГС-4_строительство/25053_PP_-4_áâந⥫ìá⢮/25053_PP_AA/25053_PP_AA-3-01_¯®ïá¨â¥«ì ï.pdf
Результаты запиши в ворклоги.
Что тут интересно в первую очередь? Это вот эти длинные пути с различными краказябрами. Напомню, что ЛЛМ как бы не имеют в себе механик переменных (это я еще только планирую в своей реализации сделать). По большому счету при формировании запросов ЛЛМ должна байт-в-байт повторить эти пути при передаче их параметрами в тулзы. И над отметить, что Gemini 2.5 Flash отлично с этим справился.
Далее интересные и неожиданные предположения имею сделать на основе ризонинга моделей при чтении файлов. Я сразу процитирую оба запроса.
[
{
"query": {
"reasoning": "Извлекаю текст из титульного листа для идентификации документа.",
"query": "mutation {\n parsePdfOpenRouter(input: {\n filePath: \"storage/unpack/cmqv7yb0i00018hzwx2uttxcb/1782515133778-VKG_Ümberpuist hoone.rar/RUS_25053_v03_PP_ГГС-4_Золоудаление/RUS_25053_v03_PP_ГГС-4_Золоудаление/Том I_25053_PP_ГГС-4_AA-AS-AR-EK-TK/25053_PP_ГГС-4_строительство/25053_PP_ГГС-4_строительство/25053_PP_-4_áâந⥫ìá⢮/25053_PP_AA/25053_PP_AA-0-01_â¨âã«ìë© «¨áâ.pdf\"\n pages: [1]\n }) {\n pages {\n text\n }\n }\n}",
"variables": "{}"
}
}
]
[
{
"query": {
"reasoning": "Извлекаю текст из пояснительной записки. Посмотрим, сколько страниц в документе, и прочитаем их (если их немного). Первый запрос показал 1 страницу, но лучше убедиться.",
"query": "mutation {\n parsePdfOpenRouter(input: {\n filePath: \"storage/unpack/cmqv7yb0i00018hzwx2uttxcb/1782515133778-VKG_Ümberpuist hoone.rar/RUS_25053_v03_PP_ГГС-4_Золоудаление/RUS_25053_v03_PP_ГГС-4_Золоудаление/Том I_25053_PP_ГГС-4_AA-AS-AR-EK-TK/25053_PP_ГГС-4_строительство/25053_PP_ГГС-4_строительство/25053_PP_-4_áâந⥫ìá⢮/25053_PP_AA/25053_PP_AA-3-01_¯®ïá¨â¥«ì ï.pdf\"\n }) {\n totalPages\n pages {\n pageNumber\n text\n }\n }\n}",
"variables": "{}"
}
}
]
Что тут интересного? В целом, он следовал логике, заложенной в скиле чтения документов, вот цитата:
Стратегия чтения документов
Рекомендуется сначала читать документ поверхностно — только первую страницу с запросом totalPages:
mutation {
parsePdfOpenRouter(input: {
filePath: "storage/unpack/tender-123/document.pdf"
pages: [1]
}) {
totalPages
pages {
text
}
}
}
Это позволяет:
- Узнать общее количество страниц в документе
- Понять содержание и релевантность документа
- Принять решение — нужно ли читать весь документ
Если документ важен и требуется полное содержание — читаем все страницы (без параметра pages).
А что же сделал наш агент? Он почти все правильно сделал, но ошибся в главном - кол-во страниц запросил на первом документе, а прочитал все уже на другом документе :-) При чем во втором запросе он даже уточнил: Первый запрос показал 1 страницу, но лучше убедиться.
При чем в первом запросе он даже не мог знать сколько на самом деле там страниц, потому что он только указал получить первую страницу, передав pages: [1], но в тело ответа он не включил параметр totalPages :-) Так что ответ он получил без информации сколько там страниц.
А вот во втором запросе он сделал иначе - указал totalPages (и эту информацию он получил), но не указал pages: [1] :-)
В общем, очень интересный и немного комичный пример того, как агент может логически отклониться от переданных ему инструкций, но в отдельных случаях с учетом требований к надежности выполнения задачи, результат может оказаться совсем не комичным.