Tool típusok és mikor melyiket
A platform öt interfészt és számos abstract alaposztályt biztosít. Ez a fejezet segít eldönteni, melyikből érdemes kiindulni.
4.1 Döntési útmutató
Az első kérdés mindig az: ki aktiválja a tool-t?
| Aktiváló | Interfész | Tipikus use case |
|---|---|---|
| Az LLM dönti el a felhasználói kérdés alapján | IChatbotTool |
Külső API, adatbázis-lekérdezés, egyedi logika, PDF, web keresés |
| Orchestrátor aktiválja – explicit prioritás szerint | IOrchestratorActivatedTool |
Oldalanalízis, összefoglalás, RAG retrieval, interaktív Q&A |
| A platform – domain match alapján, minden kérésre | IOrchestratorTool (→ AbstractOrchestratorTool) |
Domain-specifikus, összetett koordinációs logika |
| Nem a chat pipeline – offline batch indítás | IIngestionTool |
Tudásbázis feltöltés, NER annotáció, gráf építés |
| Nem a chat pipeline – külső hívó indítja explicit módon, feladat-azonosítóval | IAsyncTaskTool |
Hosszú futású, chat-től független backfill/batch feladat, lekérdezhető állapottal |
Ha a tool-nak hiányos információ esetén vissza kell kérdezni a felhasználóhoz,
az IClarifiableTool-t kell implementálni – ez az IChatbotTool
és az IOrchestratorActivatedTool kombinációja, és az orchestrátor aktiválja.
4.2 IChatbotTool – LLM routing aktiválja
A platform a felhasználói kérdés alapján LLM-mel dönti el, hogy ezt a tool-t
kell-e aktiválni. A döntés a getExecutableInstruction() tartalmán
alapul. Az isEligible() metódus az LLM döntése előtt fut,
és nem-funkcionális feltételeket (jogosultság, domain) ellenőriz.
IOrchestratorActivatedTool-t implementáló osztályok ki vannak
zárva az LLM routing-ból – a platform sosem irányítja hozzájuk a kéréseket
az automatikus tool-választáson keresztül.
Platform abstract osztályok – IChatbotTool alapon
| Osztály | Mire való | Visszatérési mód |
|---|---|---|
AbstractWebSearchTool |
Valós idejű web keresés; az eredmény kontextusba vagy kész válaszba kerülhet | CONTEXT vagy ANSWERED |
| Közvetlen IChatbotTool impl. | Egyedi logika (pl. időjárás, menetrend, intézményi adatbázis) | bármelyik |
4.3 IOrchestratorActivatedTool – csak orchestrátor aktiválja
Ezeket a tool-okat az LLM routing sosem aktiválja – az
isEligible() sem fut le rajtuk. Kizárólag egy futó orchestrátor
dönthet arról, mikor és milyen prioritással indítja el őket.
A prioritásrendszer
Minden IOrchestratorActivatedTool implementáláshoz kötelező a
getPriority() metódus. A kisebb szám korábban fut:
- 0 – legkorábban fut (pl.
IClarifiableTool,AbstractPageAnalysisToolleszármazottak) - Azonos prioritás → párhuzamos futás (CompletableFuture)
- Különböző prioritás → kisebbtől a nagyobb felé, sorban
- Integer.MAX_VALUE → mindig utoljára fut
(pl.
AbstractRAGRetrievalTool– fallback)
@Override
public int getPriority() {
return 0; // az orchestrátor elsőként futtatja
}
Platform abstract osztályok – IOrchestratorActivatedTool alapon
| Osztály | Mire való | Priority |
|---|---|---|
AbstractPageAnalysisTool |
Oldalanalízis alapja – ebből örökölnek a specializált tool-ok | 0 |
AbstractSummaryTool |
Gráf-alapú összefoglalás generálás | 0 |
AbstractEntityAnalysisTool |
Entitás elemzés és kinyerés a tudásgráfból; a getExecutableInstruction() igen/nem kérdése írja le, mikor alkalmas a kérdés kiszolgálására |
0 |
AbstractContextSearchTool |
Kontextus-előállítás deep fallback esetén; a mélykereső koordinátor kereső tool-ja | 0 |
AbstractNeighborPageSearchTool |
Opcionális környezet-kereső a mélykereső koordinátorhoz (→ 6.10) | 0 |
AbstractDeepSearchCoordinatorTool |
Mélykereső koordinátor deep fallback tool-ként (→ 6.10) | 0 |
AbstractRAGRetrievalTool |
Domain-specifikus RAG retrieval; az orchestrátor fallback-ként mindig aktiválja | Integer.MAX_VALUE |
AbstractMcpTool |
Adatbeszerzés MCP szerverről, platform által kezelt tisztázó körrel, megerősítéssel és kiszivárgás-ellenőrzéssel (→ 14. fejezet) | tetszőleges |
Konstruktor és bekötés – no-arg + @PostConstruct
A plugin-aktiválási mechanizmus (Java ServiceLoader, orchestrátoroknál
emellett a PluginLoader reflection-alapú példányosítása is) miatt
minden plugin tool osztálynak – nem csak az orchestrátoroknak,
hanem a fenti platform abstract osztályok (AbstractPageAnalysisTool és
leszármazottai, AbstractNERIngestionTool, AbstractRAGRetrievalTool
stb.) leszármazottainak is – publikus, paraméter nélküli konstruktorral kell
rendelkeznie. A domain-specifikus függőségeket (NER ingestion tool, saját LLM
asszisztens stb.) ezért nem lehet konstruktor-paraméterként átadni; a bevett minta:
- a függőségeket
@Autowiredmezőként veszed fel - egy
@PostConstruct-tal jelöltinit()metódusban regisztrálod őket az alaposztály védett settereén keresztül – ez már azután fut le, hogy a platformautowireBean()-nel feltöltötte a mezőket
@Component
public class MyCharacterTool extends AbstractEntityAnalysisTool {
@Autowired
private MyNERIngestionTool nerTool;
@Autowired
private MyCharacterAssistant characterAssistant;
public MyCharacterTool() {
super();
}
@PostConstruct
@Override
public void init() {
setAbstractNERIngestionTool(nerTool);
setToolAssistant(characterAssistant);
}
@Override
public int getPriority() {
return 0;
}
}
Referencia implementáció a kódbázisban: EgriCsillagokCharacterTool
(AbstractEntityAnalysisTool leszármazott) és testvérei,
EgriCsillagokSummaryTool, EgriCsillagokContextSearchTool
– mindegyik ugyanezt a no-arg konstruktor + @PostConstruct init()
mintát követi, csak a bekötött setterek térnek el az adott alaposztály szerint.
4.4 IClarifiableTool – interaktív Q&A
Az IClarifiableTool az IChatbotTool és az
IOrchestratorActivatedTool kombinációja. Ha a tool hiányos
paraméterezetést észlel, kérdést tesz fel a felhasználónak; a kapott
válasszal folytatódik a feldolgozás.
Mivel IOrchestratorActivatedTool-t is implementál, kizárólag
orchestrátor aktiválhatja – az LLM routing nem irányítja hozzá a kéréseket.
A getPriority() értéke tipikusan 0 (az orchestrátor elsőként kérdez),
a domain megadható (null = domain-független).
A részletes megvalósítási útmutató a 7. fejezetben olvasható.
4.5 IOrchestratorTool – orchestrátor implementáció
Az IOrchestratorTool marker interfész: jelöli, hogy egy osztály
orchestrátort valósít meg. A platform domain-egyezés alapján, minden kérésre
automatikusan aktiválja – az LLM routing nem vesz részt benne.
Plugin fejlesztőként az AbstractOrchestratorTool abstract osztályból
kell örökölni, amely implementálja az IChatbotTool-t és az
IOrchestratorTool-t egyaránt. Kötelező feltételek:
@Scope("prototype")kötelező – az orchestrátor per-request mutable állapotot tárol (LLM hívás eredmények, sub-query lista, clarification session stb.)- Domainen belül több orchestrátor is regisztrálható (jellemzően
system-enként egy-egy,
getEligibleSystem()alapján megkülönböztetve), de kérésenként pontosan egy aktiválódik - Plugin orchestrátorokhoz no-arg konstruktor szükséges
(a
PluginLoaderreflection-nel példányosít)
A részletes implementálási útmutató az 5. fejezetben olvasható.
4.6 IIngestionTool – offline tudásbázis feltöltés
Az IIngestionTool kiterjeszti az IChatbotTool-t, de
ki van zárva a chat pipeline-ból – a platform soha nem aktiválja
felhasználói kérés hatására. Kizárólag az ingestion pipeline hívja meg az
executeIngestion() metódust, jellemzően REST API-on keresztül
indított batch feldolgozás részeként.
Főbb szabályok:
- Az implementáció felelős az idempotenciáért (pl.
_SUCCESSmarker ellenőrzés) - Nem dob kivételt, amely a pipeline-t leállítaná – hibát naplóz és visszatér
- Az
IChatbotToolmetódusokat (pl.executeWithResult()) nem szükséges implementálni –null-lal visszatérő csonk elegendő
A platform AbstractNERIngestionTool abstract osztályt biztosít,
amely a Spark-alapú NER pipeline-t (entitáskinyerés, gráf építés) tartalmazza;
a fejlesztőnek a domain-specifikus részt kell implementálnia.
Részletek a 10. fejezetben.
4.7 Teljes áttekintő táblázat
| Interfész / osztály | LLM routing | Orchestrátor aktiválja | Chat pipeline | Ingestion | Async Task Service |
|---|---|---|---|---|---|
IChatbotTool |
✅ | — | ✅ | — | — |
AbstractWebSearchTool |
✅ | — | ✅ | — | — |
IOrchestratorActivatedTool |
❌ | ✅ | — | — | — |
AbstractPageAnalysisTool (+ leszármazottak) |
❌ | ✅ | — | — | — |
AbstractRAGRetrievalTool |
❌ | ✅ (fallback) | — | — | — |
IClarifiableTool |
❌ | ✅ | ✅ (clarify endpoint) | — | — |
AbstractMcpTool |
❌ | ✅ | ✅ (clarify endpoint) | — | — |
IOrchestratorTool / AbstractOrchestratorTool |
❌ | — | ✅ (domain match) | — | — |
IIngestionTool / AbstractNERIngestionTool |
❌ | — | ❌ | ✅ | — |
IAsyncTaskTool / AbstractGraphEnrichmentTask |
❌ | — | ❌ | — | ✅ |
4.8 Tool-ok együttműködése
Egy IOrchestratorActivatedTool építhet egy másik, ugyanabban a
prioritáscsoport-futtatásban részt vevő tool kimenetére. A platform két, egymást
kiegészítő mechanizmust kínál erre, attól függően, hogy a kapcsolat kiegészítő
jellegű-e, vagy a működés szempontjából elengedhetetlen.
| Interfész | Mikor használd | Aktiválás garantált? |
|---|---|---|
IContextConsumerTool |
A másik tool kimenete csak pontosítja/kiegészíti az eredményt – hiányában is értelmes, csak esetleg általánosabb választ ad | Nem – csak akkor kap adatot, ha a másik tool egyébként is lefutott |
IToolDependent |
A másik tool kimenete nélkül a működés értelmezhetetlen | Igen – az orchestrátor kikényszeríti a megjelölt tool-ok lefutását |
IAgentCoordinator |
A szükséges tool-ok köre és sorrendje a feladat tartalmától függ – a coordinator futásidőben, dinamikusan hozza létre a rész-lépéseket | Rész-lépésenként igen – a rész-lépés saját requiredToolNames
mezője kényszeríti ki |
IAgentCoordinator – dinamikus feladat-szétbontás
A fenti két mechanizmus egy már létező, statikus tool-halmazra épít. Ha a
szükséges tool-ok köre és sorrendje csak a feladat tényleges tartalmából
derül ki - futásidőben, esetenként eltérő módon -, az
IAgentCoordinator interfész ad erre megoldást: egy tool a saját
algoritmusa szerint bonthatja rész-lépésekre a feladatot, rész-lépésenként
pontosan megjelölve, melyik tool-nak kell rajta aktiválódnia. A teljes
szerződést, a rész-lépés-fa végrehajtási szabályait és a tool-ok
együttműködésének egy negyedik, orchestrátort teljesen megkerülő csatornáját
(közvetlen, kódbeli metódushívás két tool között) a
6. fejezet tárgyalja.
IContextConsumerTool – opcionális kiegészítés
Az orchestrátor egy implementáló tool-t mindig az
executeWithPriorContext(...) metódusán keresztül hajt végre, és
paraméterként átadja az addig lefutott tool-ok összesített kontextus-pufferének
pillanatképét (kulcs: taskNo:toolName alakú completion-kulcs; a map
soha nem null). A tool-ok singleton példányok, amelyek párhuzamos kéréseket
szolgálnak ki, ezért a kapott kontextust nem szabad példánymezőben tárolni - csak
az adott hívás idejére, paraméterként vagy helyi változóként használható. A
kontextus nélküli executeWithResult(...) meghívása egy ilyen tool-on
hiba: az interfész alapértelmezése UnsupportedOperationException-t dob,
így azt nem kell implementálni.
public class SuggestionTool implements IOrchestratorActivatedTool, IContextConsumerTool<Object> {
@Override
public ToolExecutionResult executeWithPriorContext(List<String> systems, String userPrompt,
String userLang, List<String> importantWords,
Map<String, List<PromptAndContext>> priorToolContexts,
IResponseEmitter responseEmitter,
CallbackWithErrorHandler<OpenAIResponseVO, Exception> finalCallback) {
// lehet null – nem hibaeset, ilyenkor általános javaslatokra esünk vissza
List<PromptAndContext> extractedEntities = priorToolContexts.get("1:entity_extraction");
...
}
@Override
public int getPriority() { return 10; } // magasabb szám = később fut
}
Ha a tool tisztázó kérdést is feltehet, az IClarifiableContextConsumerTool-t
implementálja: a tisztázó kör folytatásakor az orchestrátor az
executeWithClarificationAndPriorContext(session, priorToolContexts, ...)
metódust hívja, a kontextus nélküli executeWithClarification(...)
alapértelmezése itt is kivételt dob.
IToolDependent a megfelelő eszköz.
IToolDependent – garantált függőség
A getRequiredTools() konkrét, típusos tool-példányokat sorol fel – nem
neveket –, amelyekre a működés épül. Az orchestrátor ezeket a saját prioritáscsoportjuk
előtt garantáltan lefuttatja, akkor is, ha az LLM suitability teszt önmagában nem
aktiválta volna őket. Minden megjelölt tool-nak szigorúan kisebb prioritással kell
futnia, mint a rá támaszkodó tool-nak – induláskor a platform ellenőrzi ezt, és hibát
naplóz, ha a sorrend rossz.
A lefutott függőségek kontextusát az executeWithRequiredContext(...)
egyetlen hívása kapja meg paraméterként (nem egy korábbi, elkülönült hívással beállított
mezőből) – ez singleton scope-ú tool-ok esetén is szálbiztos marad, mert nincs
hívások közötti megosztott állapot.
@Component
public class RiskAssessmentTool implements IOrchestratorActivatedTool, IToolDependent {
@Autowired
private PatientLookupTool upstreamPatientTool;
@Override
public Set<IChatbotTool<?>> getRequiredTools() {
return Set.of(upstreamPatientTool);
}
@Override
public int getPriority() { return 10; } // az upstreamPatientTool.getPriority()-nál nagyobb!
@Override
public ToolExecutionResult executeWithRequiredContext(
List<String> systems, String userPrompt, String userLang, List<String> importantWords,
Map<String, List<PromptAndContext>> requiredToolContexts,
FluxSink<TextGenerationResponse> progressEmitter,
CallbackWithErrorHandler<OpenAIResponseVO, Exception> finalCallback) {
List<PromptAndContext> patientData = requiredToolContexts.get(upstreamPatientTool.getName());
if (patientData == null || patientData.isEmpty()) {
return null; // az upstream tool nem adott adatot – nincs miből dolgozni
}
// ... kockázatértékelés a patientData alapján
return ToolExecutionResult.asGuaranteedContext(getName(), resultDocs);
}
@Override
public ToolExecutionResult executeWithResult(List<String> systems, String userPrompt, String userLang,
List<String> importantWords, FluxSink<TextGenerationResponse> progressEmitter,
CallbackWithErrorHandler<OpenAIResponseVO, Exception> finalCallback) {
// Csak akkor hívódik, ha a tool nem az orchestrátor prioritáscsoport-motorján
// keresztül aktiválódott (pl. explicit toolName aktiválás) – ilyenkor a
// requiredToolContexts üres lesz, a tool a saját fallback-jét futtathatja
// (pl. az upstream tool közvetlen meghívásával).
return executeWithRequiredContext(systems, userPrompt, userLang, importantWords, Map.of(),
progressEmitter, finalCallback);
}
}
requiredToolContexts map kulcsa a függő tool egyszerű neve
(getName()), nem a belső taskNo:toolName completion-kulcs –
ezt az orchestrátor már leképezve adja át.
Ha egy tool olyan tartalmat ad tovább egy másik tool-nak, ami kizárólag a fogadó
tool-nak szól – akár IContextConsumerTool, akár
IToolDependent csatornán –, és nem szabad, hogy bekerüljön a végső
LLM-válasz vagy a RAG pipeline kontextusába, a dokumentumot
InternalContextDocument-ként érdemes becsomagolni a szokásos
TextAnswer helyett. Az orchestrátor a feldolgozás összegzésekor
minden InternalContextDocument példányt kiszűr, mielőtt a kontextus
a következő lépéshez (RAG, végső LLM hívás) kerülne – függetlenül attól, hogy a
tartalma strukturált adat (pl. JSON-serializált bean) vagy egy tool által
LLM-mel szintetizált leírás. A megkülönböztetés nem a tartalom jellegén, hanem a
címzetten múlik: kizárólag tool-nak szól, vagy a végfelhasználói válasznak is.
HashSet<UniqueTextDocument> docs = new HashSet<>();
docs.addAll(TextAnswer.asSet(normalizedSummary)); // a végső válaszba is bekerülhet
docs.addAll(InternalContextDocument.asSet(toJson(data))); // csak a következő tool-nak szól
return ToolExecutionResult.asGuaranteedContext(getName(), docs);
for (UniqueTextDocument doc : patientData) {
if (doc instanceof InternalContextDocument && doc.getText() != null) {
PatientCaseData data = objectMapper.readValue(doc.getText(), PatientCaseData.class);
// ...
}
}
4.9 IAsyncTaskTool – külső hívó indítja explicit módon
Az IAsyncTaskTool sem a chat pipeline-nak, sem az ingestion
pipeline-nak nem része – egy külső hívó a Platform API-n keresztül, a feladat
típusazonosítójának megnevezésével indítja el, strukturáltan megadott bemeneti
paraméterekkel. A végrehajtás a háttérben zajlik, állapota egy visszaadott
feladat-azonosítóval, a végrehajtástól függetlenül kérdezhető le.
A részletes implementálási útmutató a 12. fejezetben, a hozzá tartozó végpontok pedig a 13. fejezetben olvashatók.