Files
marketing-parser/Техническое Задание на реализацию AI-агента для синтеза отчётов с использованием Ollama.md
2025-10-05 16:40:36 +05:00

136 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Проект: Доработка модуля генерации отчётов в существующем Java/Spring Boot бэкенде.
1. Общее описание
Целью является создание "Агента-синтезатора" внутри бэкенда. Этот агент будет использовать существующий сервис OllamaAnalyticsService для взаимодействия с локально развёрнутой языковой моделью Ollama. Задача агента — принять "сырые" тезисы (learnings) от сервиса deep-research и с помощью Ollama сгенерировать из них связный, структурированный и стилистически выверенный текстовый отчёт в формате Markdown.
2. Требования к реализации
2.1. Создание нового сервиса: ReportSynthesisService
Необходимо создать новый Spring-сервис (@Service).
Этот сервис будет зависеть от уже существующего OllamaAnalyticsService и должен инжектировать его (@Autowired).
Сервис должен иметь один публичный метод:
Java
public Mono<String> synthesizeReport(String originalQuery, List<String> learnings, String lang)
Вход:
originalQuery: Исходная тема исследования.
learnings: Список "сырых" тезисов от deep-research.
lang: Целевой язык отчёта.
Выход: Mono<String>, содержащий готовый отчёт в формате Markdown.
2.2. Логика работы ReportSynthesisService
Метод synthesizeReport получает на вход данные.
Он объединяет список learnings в единый блок текста, где каждый тезис начинается с новой строки (например, с помощью String.join("\n- ", learnings)).
Он формирует промпт (инструкцию) для модели Ollama (см. п. 2.3).
Ключевой шаг: Он вызывает метод generateWithInstruction из вашего существующего OllamaAnalyticsService:
Java
// Преобразуем асинхронный вызов в Mono
Mono<String> synthesizedReportMono = Mono.fromCallable(() ->
ollamaAnalyticsService.generateWithInstruction(aggregatedLearnings, prompt)
);
Метод возвращает synthesizedReportMono.
2.3. Разработка промпта для Ollama
Промпт — это сердце качественного результата. Он должен быть чётким и структурированным. Этот промпт будет реализован как форматированная строка внутри ReportSynthesisService.
Пример промпта для Ollama (модели типа Llama3, Gemma):
Ты — профессиональный AI-аналитик. Твоя задача — написать подробный и структурированный отчёт на основе предоставленных данных. Не добавляй никаких предисловий или комментариев от себя, просто верни готовый отчёт.
### Тема исследования:
${originalQuery}
### Собранные данные (тезисы):
- ${learnings_as_string}
### Твоя задача:
1. **Язык:** Напиши отчёт полностью на ${lang} языке.
2. **Структура:** Отчёт должен иметь чёткую структуру: введение, основная часть с несколькими разделами и подразделами, и заключение.
3. **Форматирование:** Используй Markdown. Для главных заголовков разделов используй `##`, для подзаголовков — `###`. Для списков используй `-`.
4. **Стиль:** Преврати разрозненные тезисы в единую, связную и хорошо написанную статью. Не просто перечисляй факты, а анализируй и обобщай их.
5. **Ограничение:** Используй только ту информацию, которая дана в собранных данных. Не придумывай ничего от себя.
Начинай отчёт с главного заголовка.
2.4. Интеграция в существующий асинхронный процесс
Необходимо модифицировать ваш существующий метод в контроллере, который запускает весь процесс. Вместо вызова OpenAI, теперь будет вызываться ваш новый ReportSynthesisService.
Примерная схема интеграции (на основе вашего кода):
Java
// ...
// Инжектируем новый сервис
@Autowired
private ReportSynthesisService reportSynthesisService;
// ... в вашем методе generateResearchReport
deepResearchService.generateReportAsync(deepRequest)
.publishOn(Schedulers.boundedElastic())
.flatMap(researchResponse -> { // Используем flatMap для асинхронной цепочки
if (researchResponse == null || researchResponse.getLearnings() == null || researchResponse.getLearnings().isEmpty()) {
return Mono.error(new RuntimeException("Empty research response content"));
}
// НОВЫЙ ШАГ: Вызываем наш сервис синтеза с Ollama
return reportSynthesisService.synthesizeReport(
request.getQuery(),
researchResponse.getLearnings(),
request.getLang()
).map(synthesizedText -> new SynthesizedReport(researchResponse, synthesizedText)); // Объединяем результаты
})
.map(synthesizedReport -> {
// Здесь мы используем synthesizedText для генерации PDF
// Этот код остаётся почти без изменений
byte[] pdfBytes = researchPdfService.generatePdfReport(
request.getQuery(),
synthesizedReport.getOriginalResponse(),
synthesizedReport.getSynthesizedMarkdown() // Передаем новый красивый текст от Ollama
);
String filename = "research*report*" + System.currentTimeMillis() + ".pdf";
saveResearchReportToHistory(request, filename, pdfBytes, synthesizedReport.getOriginalResponse());
return true;
})
.doOnError(e -> {
System.err.println("Error in full research chain: " + e.getMessage());
})
.subscribe();
// ...
Вам также понадобится немного изменить researchPdfService.generatePdfReport, чтобы он принимал новый синтезированный Markdown-текст в качестве основного контента.
3. Конфигурация
Вся конфигурация для Ollama уже есть в вашем OllamaAnalyticsService. Новых настроек добавлять не нужно.
Важная рекомендация: Убедитесь, что в вашем application.properties (или yml) для ollama.model указана достаточно мощная модель, способная следовать сложным инструкциям. Модель gemma3:1b слишком слабая для такой задачи. Рекомендуется использовать:
llama3:8b-instruct (хороший баланс)
gemma:7b-it
mistral или mixtral
Пример:
Properties
ollama.host=http://185.35.223.45:11434
ollama.model=llama3:8b-instruct
ollama.timeoutMs=180000 # Увеличьте таймаут до 3 минут, т.к. генерация отчёта - долгая задача 4. Ожидаемый результат
После реализации бэкенд будет использовать ваш собственный, локально развёрнутый Ollama для создания высококачественных, структурированных PDF-отчётов, полностью контролируя весь процесс и не завися от внешних платных API для синтеза текста.