-
Notifications
You must be signed in to change notification settings - Fork 5
Agentic RAG
Режим, в котором LLM сам решает, когда и что искать в базе знаний. Вместо одноразовой инжекции контекста перед запросом, LLM получает инструмент knowledge_search и вызывает его по мере необходимости — может искать несколько раз с разными запросами в рамках одного ответа.
1. Пользователь: "Какие тарифы на подключение?"
2. Система: retrieve("тарифы подключение") → контекст
3. Контекст → system prompt
4. LLM: ответ на основе найденного контекста
LLM не может запросить дополнительный поиск. Если первый запрос не попал — информация потеряна.
1. Пользователь: "Сравни тарифы для бизнеса и для частных лиц"
2. LLM получает tool knowledge_search в системном промпте
3. LLM вызывает: knowledge_search("тарифы для бизнеса")
→ Система ищет, возвращает результат
4. LLM вызывает: knowledge_search("тарифы для частных лиц")
→ Система ищет, возвращает результат
5. LLM: сравнительный ответ на основе обоих результатов
LLM сам формулирует поисковые запросы, может уточнять и переформулировать.
Agentic цикл выполняется на сервере. Фронтенд получает обычные текстовые чанки + события tool_start/tool_end для индикации поиска.
┌─────────┐ SSE chunks ┌──────────┐
│ Frontend │◄───────────────────│ Server │
│ ChatView │ tool_start/end │ Router │
└─────────┘ └────┬─────┘
│ loop (max 5)
▼
┌──────────┐
│ LLM │
│ Provider │
└────┬─────┘
│ tool_call?
▼
┌──────────┐
│ Wiki RAG │
│ retrieve │
└──────────┘
{
"type": "function",
"function": {
"name": "knowledge_search",
"description": "Search the knowledge base for relevant information.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query. Be specific."
}
},
"required": ["query"]
}
}
}for iteration in range(MAX_TOOL_ITERATIONS): # max 5
# 1. Отправляем messages в LLM с tools=[knowledge_search]
for event in llm.generate(messages, stream=True, tools=tools):
if event.type == "content":
yield SSE chunk # текст пользователю
elif event.type == "tool_calls":
tool_calls = event.tool_calls
if not tool_calls:
break # LLM ответил текстом — готово
# 2. Выполняем поиск
for tc in tool_calls:
yield SSE tool_start(query)
result = wiki_rag.retrieve(query, collection_ids)
yield SSE tool_end(found)
messages.append(tool_result)
# 3. Повторяем цикл с обогащёнными messages| Параметр | Значение | Описание |
|---|---|---|
MAX_TOOL_ITERATIONS |
5 | Максимум итераций цикла (защита от бесконечного поиска) |
top_k |
5 | Результатов на один поисковый запрос |
max_chars |
3000 | Макс. символов контекста за один поиск |
Только финальный текстовый ответ. Промежуточные tool_call и tool_result сообщения — эфемерные, существуют только на время цикла. Это сохраняет историю чата чистой и экономит контекстное окно.
Agentic RAG работает только с провайдерами, поддерживающими OpenAI-совместимый tool calling API.
| Провайдер | supports_tools |
Режим RAG |
|---|---|---|
| OpenAI | true |
Agentic |
| Anthropic (Claude) | true |
Agentic |
| DeepSeek | true |
Agentic |
| OpenRouter | true |
Agentic |
| Kimi (Moonshot) | true |
Agentic |
| Claude Bridge | true |
Agentic |
| vLLM (Qwen2.5) | true |
Agentic |
| Google Gemini SDK | false |
One-shot (fallback) |
| Custom | true |
Agentic |
Если провайдер не поддерживает tools (supports_tools = False), автоматически используется прежний one-shot режим: поиск перед LLM-запросом, инжекция в system prompt. Переключение прозрачно — пользователь видит одинаковый результат.
Во время agentic RAG поиска в ChatView отображается inline-индикатор:
🔍 Поиск по базе знаний: «тарифы для бизнеса»
| Тип | Поля | Описание |
|---|---|---|
tool_start |
name, query
|
LLM запросил поиск. Показать индикатор |
tool_end |
name, found
|
Поиск завершён. Скрыть индикатор |
chunk |
content |
Текстовый чанк (как обычно) |
- Нет текста + поиск — вместо bounce-анимации показывается "Поиск по базе знаний: «запрос»"
- Есть текст + поиск — индикатор под текстом ответа
- Поиск завершён — индикатор исчезает, LLM продолжает генерацию
| Язык | Ключ chatView.searchingKnowledge
|
|---|---|
| RU | Поиск по базе знаний: «{query}» |
| EN | Searching knowledge base: "{query}" |
| KK | Білім базасынан іздеу: «{query}» |
Agentic RAG поддерживается во всех четырёх endpoint'ах чата:
| Endpoint | Тип | Agentic RAG |
|---|---|---|
POST /admin/chat/sessions/{id}/stream |
Streaming | SSE loop с tool_start/tool_end
|
POST /admin/chat/sessions/{id}/messages |
Non-streaming | Серверный цикл, возвращает финальный текст |
PUT /admin/chat/sessions/{id}/messages/{msg_id} |
Edit | При редактировании user-сообщения |
POST /admin/chat/sessions/{id}/messages/{msg_id}/regenerate |
Regenerate | При регенерации ответа |
К system prompt добавляется суффикс:
У тебя есть инструмент knowledge_search для поиска по базе знаний.
Используй его когда вопрос связан с документацией или требует фактических данных.
Можешь вызвать несколько раз с разными запросами.
Не выдумывай — если не нашёл информацию, честно скажи.
К system prompt добавляется anti-hallucination суффикс:
ВАЖНО: Ты — чат-бот без доступа к инструментам, файлам и командам.
НИКОГДА не генерируй вызовы функций, tool_use, function_calls...
Выбор суффикса определяется функцией _finalize_prompt(prompt, agentic_rag=True/False).
Agentic RAG активируется когда все условия выполнены:
-
rag_mode != "none"— RAG не отключён -
collection_idsне пустой — есть коллекции для поиска -
wiki_ragинициализирован — сервис базы знаний доступен - Провайдер поддерживает tools —
supports_tools = True
Проверяется функцией _should_use_agentic_rag() в modules/chat/router.py.
| Файл | Изменения |
|---|---|
cloud_llm_service.py |
BaseLLMProvider.supports_tools, generate_with_tools() в OpenAICompatibleProvider
|
vllm_llm_service.py |
VLLMLLMService.supports_tools, generate_with_tools()
|
modules/chat/router.py |
KNOWLEDGE_SEARCH_TOOL, agentic loop, _should_use_agentic_rag(), _execute_knowledge_search()
|
admin/src/views/ChatView.vue |
searchingQuery ref, обработка tool_start/tool_end, inline индикатор |
admin/src/api/chat.ts |
Расширение типа stream callback (query, name, found) |
admin/src/plugins/i18n.ts |
Ключ chatView.searchingKnowledge (ru/en/kk) |