Preise

Architektur im Überblick

Quelldateien

Diese Seite wurde aus den folgenden Quelldateien erstellt:

JoyAgent-JDGenie ist ein Multi-Agenten-System, das auf einer hierarchischen Agentenarchitektur basiert und das ReAct-Muster (Reasoning and Acting) zur intelligenten Aufgabenverarbeitung einsetzt. Das System besteht aus einem Java-basierten Backend mit verschiedenen spezialisierten Agenten, einem Python-basierten Tool-Server für die Werkzeugausführung, einem MCP-Client für die externe Kommunikation sowie einer React-basierten Frontend-Komponentenbibliothek.

Systemarchitektur-Überblick

Die Architektur von JoyAgent-JDGenie folgt einem modularen Design mit klarer Trennung zwischen Agentenlogik, Tool-Ausführung und Benutzeroberfläche. Das System implementiert eine Multi-Tier-Architektur, bei der die Agenten im Java-Backend die zentrale Steuerung übernehmen, während Python-Services für die Tool-Ausführung zuständig sind.

正在加载图表渲染器...

Architektur-Erklärung:

  1. Frontend Layer: Die React-basierte Benutzeroberfläche besteht aus drei Hauptkomponenten - ChatView für die Benutzerinteraktion, PlanView für die Visualisierung von Aufgabenplänen und ActionPanel für die Darstellung von Ausführungsergebnissen (ui/src/components/index.ts:1-21).

  2. Backend Agent Layer: Vier spezialisierte Agenten arbeiten zusammen - PlanningAgent erstellt Aufgabenpläne, ExecutorAgent führt Tools aus, ReactImplAgent bietet eine alternative ReAct-Implementierung und SummaryAgent fasst Ergebnisse zusammen (genie-backend/src/main/java/com/jd/genie/agent/agent/PlanningAgent.java:32-88).

  3. Core Infrastructure: Die abstrakte BaseAgent-Klasse definiert die Grundstruktur, ReActAgent implementiert das Think-Act-Muster, AgentContext verwaltet Anfragekontexte und GenieConfig steuert die Konfiguration (genie-backend/src/main/java/com/jd/genie/agent/agent/BaseAgent.java:30-103).

  4. Tool Services: Der Python-basierte Genie-Tool Server stellt Werkzeugfunktionalität über FastAPI bereit, während der Genie-Client die MCP-Kommunikation mit externen Servern handhabt (genie-tool/server.py:1-80).

Agent-Hierarchie und Basisklassen

BaseAgent - Abstrakte Fundamentalklasse

Die BaseAgent-Klasse bildet das Fundament der gesamten Agentenarchitektur. Diese abstrakte Klasse definiert die Kernattribute und Verhaltensmuster, die alle spezialisierten Agenten gemeinsam haben.

Kernattribute und Zustandsverwaltung:

java
1// Kernattribute (Zeile 32-40)
2private String name;
3private String description;
4private String systemPrompt;
5private String nextStepPrompt;
6public ToolCollection availableTools = new ToolCollection();
7private Memory memory = new Memory();
8protected LLM llm;
9protected AgentContext context;
10
11// Ausführungskontrolle (Zeile 42-46)
12private AgentState state = AgentState.IDLE;
13private int maxSteps = 10;
14private int currentStep = 0;
15private int duplicateThreshold = 2;

Verantwortlichkeiten:

  • Zustandsverwaltung: Verwaltung des Agentenzustands (IDLE, FINISHED, ERROR) mit automatischer Rücksetzung bei Erreichen der maximalen Schritte (BaseAgent.java:71-82)
  • Hauptschleife: Die run()-Methode implementiert die zentrale Ausführungsschleife, die step() wiederholt aufruft, bis der Agent fertig ist oder die maximale Schrittzahl erreicht (BaseAgent.java:62-89)
  • Speicherverwaltung: Aktualisierung des Agentenspeichers mit verschiedenen Rollentypen (USER, SYSTEM, ASSISTANT) durch die updateMemory()-Methode (BaseAgent.java:94-103)

Fehlerbehandlung:

Die Klasse implementiert eine robuste Fehlerbehandlung, die bei Ausnahmen den Zustand auf ERROR setzt und die Ausnahme weiterleitet. Bei Erreichen der maximalen Schrittzahl wird der Zustand auf IDLE zurückgesetzt und eine Terminierungsnachricht hinzugefügt.

ReActAgent - Reasoning and Acting Pattern

Der ReActAgent erweitert BaseAgent und implementiert das ReAct-Muster, das Denken (Reasoning) und Handeln (Acting) in einem strukturierten Prozess kombiniert.

Kernabstraktionen:

java
1// Abstrakte Methoden für das ReAct-Muster
2public abstract boolean think();  // Zeile 28
3public abstract String act();     // Zeile 33
4
5// Schritt-Implementierung (Zeile 38-45)
6@Override
7public String step() {
8    boolean shouldAct = think();
9    if (!shouldAct) {
10        return "Thinking complete - no action needed";
11    }
12    return act();
13}

Design-Entscheidungen:

  1. Trennung von Denken und Handeln: Die think()-Methode entscheidet, ob eine Aktion erforderlich ist, während act() die tatsächliche Ausführung übernimmt. Diese Trennung ermöglicht flexiblere Kontrollflüsse.

  2. Digital Employee Integration: Die generateDigitalEmployee()-Methode ermöglicht die dynamische Erstellung von spezialisierten "digitalen Mitarbeitern" basierend auf Aufgabenbeschreibungen (ReActAgent.java:47-80).

  3. LLM-Integration: Die Methode nutzt CompletableFuture für asynchrone LLM-Aufrufe mit niedriger Temperatur (0.01) für konsistente Ergebnisse.

Spezialisierte Agenten-Implementierungen

PlanningAgent - Strategische Planung

Der PlanningAgent ist für die Erstellung und Verwaltung von Aufgabenplänen zuständig. Er analysiert Benutzeranfragen und generiert strukturierte Ausführungspläne.

Initialisierung und Konfiguration:

java
1public PlanningAgent(AgentContext context) {
2    setName("planning");
3    setDescription("An agent that creates and manages plans to solve tasks");
4    
5    // Tool-Prompt aus verfügbaren Tools generieren (Zeile 48-51)
6    StringBuilder toolPrompt = new StringBuilder();
7    for (BaseTool tool : context.getToolCollection().getToolMap().values()) {
8        toolPrompt.append(String.format("工具名:%s 工具描述:%s\n", 
9            tool.getName(), tool.getDescription()));
10    }
11    
12    // System-Prompt mit Platzhaltern konfigurieren (Zeile 55-64)
13    setSystemPrompt(genieConfig.getPlannerSystemPromptMap()
14        .getOrDefault(promptKey, PlanningPrompt.SYSTEM_PROMPT)
15        .replace("{{tools}}", toolPrompt.toString())
16        .replace("{{query}}", context.getQuery())
17        .replace("{{date}}", context.getDateInfo())
18        .replace("{{sopPrompt}}", context.getSopPrompt()));
19}

Schlüsselfunktionalitäten:

  1. Dynamische Prompt-Erstellung: Der Agent ersetzt Platzhalter in Prompt-Templates mit aktuellen Kontextinformationen wie Werkzeugbeschreibungen, Benutzeranfragen und Datumsinformationen (PlanningAgent.java:55-64).

  2. PlanningTool-Integration: Ein spezielles PlanningTool wird initialisiert und dem Agenten zur Verfügung gestellt (PlanningAgent.java:76-78).

  3. Snapshot-Mechanismus: System-Prompts werden als Snapshots gespeichert, um dynamische Aktualisierungen während der Ausführung zu ermöglichen (PlanningAgent.java:66-67).

ExecutorAgent - Werkzeugausführung

Der ExecutorAgent führt die vom PlanningAgent erstellten Pläne durch Aufruf spezifischer Werkzeuge aus.

Konfigurationsstruktur:

java
1public ExecutorAgent(AgentContext context) {
2    setName("executor");
3    setDescription("an agent that can execute tool calls.");
4    
5    // Tool-Prompt generieren (Zeile 45-48)
6    StringBuilder toolPrompt = new StringBuilder();
7    for (BaseTool tool : context.getToolCollection().getToolMap().values()) {
8        toolPrompt.append(String.format("工具名:%s 工具描述:%s\n", 
9            tool.getName(), tool.getDescription()));
10    }
11    
12    // Executor-spezifische SOP-Prompts integrieren (Zeile 53-64)
13    setSystemPrompt(genieConfig.getExecutorSystemPromptMap()
14        .getOrDefault(promptKey, ToolCallPrompt.SYSTEM_PROMPT)
15        .replace("{{tools}}", toolPrompt.toString())
16        .replace("{{query}}", context.getQuery())
17        .replace("{{date}}", context.getDateInfo())
18        .replace("{{sopPrompt}}", context.getSopPrompt())
19        .replace("{{executorSopPrompt}}", 
20            genieConfig.getExecutorSopPromptMap().getOrDefault(sopPromptKey, "")));
21    
22    // Tool-Collection übernehmen (Zeile 77)
23    availableTools = context.getToolCollection();
24}

Unterschiede zum PlanningAgent:

  • Zusätzliche SOP-Prompts: Der ExecutorAgent integriert executor-spezifische Standard Operating Procedure-Prompts für detailliertere Ausführungsanweisungen (ExecutorAgent.java:57-58).
  • MaxObserve-Konfiguration: Konfigurierbare Beobachtungsgrenze für Tool-Ausgaben (ExecutorAgent.java:74).
  • TaskId-Verwaltung: Jede Ausführung erhält eine eindeutige TaskId für Tracking-Zwecke (ExecutorAgent.java:80).

ReactImplAgent - Alternative ReAct-Implementierung

Der ReactImplAgent bietet eine eigenständige Implementierung des ReAct-Musters mit eigener Konfiguration und Prompt-Struktur.

Charakteristische Merkmale:

java
1public ReactImplAgent(AgentContext context) {
2    setName("react");
3    setDescription("an agent that can execute tool calls.");
4    
5    // BasePrompt anstelle von SOP-Prompt (Zeile 51-60)
6    setSystemPrompt(genieConfig.getReactSystemPromptMap()
7        .getOrDefault(promptKey, ToolCallPrompt.SYSTEM_PROMPT)
8        .replace("{{tools}}", toolPrompt.toString())
9        .replace("{{query}}", context.getQuery())
10        .replace("{{date}}", context.getDateInfo())
11        .replace("{{basePrompt}}", context.getBasePrompt()));
12    
13    // Eigene maxSteps-Konfiguration (Zeile 66)
14    setMaxSteps(genieConfig.getReactMaxSteps());
15}

Design-Unterschiede:

  • BasePrompt statt SOP: Verwendet einen generischen BasePrompt anstelle spezifischer SOP-Prompts, was flexiblere Einsatzmöglichkeiten ermöglicht (ReactImplAgent.java:54-55).
  • Unabhängige Konfiguration: Nutzt separate Konfigurationsschlüssel für React-spezifische Einstellungen (ReactImplAgent.java:66-67).

SummaryAgent - Ergebniszusammenfassung

Der SummaryAgent ist für die Aufbereitung und Zusammenfassung der Ausführungsergebnisse zuständig.

Kernfunktionalitäten:

java
1// Dateiinformationen erstellen (Zeile 49-63)
2private String createFileInfo() {
3    List<File> files = context.getProductFiles();
4    if (CollectionUtils.isEmpty(files)) {
5        log.info("requestId: {} no files found in context", requestId);
6        return "";
7    }
8    
9    String result = files.stream()
10        .filter(file -> !file.getIsInternalFile()) // Interne Dateien filtern
11        .map(file -> file.getFileName() + " : " + file.getDescription())
12        .collect(Collectors.joining("\n"));
13    
14    return result;
15}
16
17// System-Prompt formatieren (Zeile 66-78)
18private String formatSystemPrompt(String taskHistory, String query) {
19    return systemPrompt
20        .replace("{{taskHistory}}", taskHistory)
21        .replace("{{fileNameDesc}}", createFileInfo())
22        .replace("{{query}}", query);
23}

Verantwortlichkeiten:

  1. Dateifilterung: Filtert interne Dateien aus den Ergebnissen, um nur benutzerrelevante Dateien anzuzeigen (SummaryAgent.java:57).
  2. Prompt-Formatierung: Integriert Aufgabenhistorie, Dateiinformationen und ursprüngliche Anfrage in den Zusammenfassungs-Prompt (SummaryAgent.java:74-77).
  3. Modellauswahl: Wählt dynamisch das LLM basierend auf dem Agententyp (Planner vs. React) (SummaryAgent.java:37).

Datenfluss und Aufrufsequenz

正在加载图表渲染器...

Datenfluss-Erklärung:

  1. Anfrageeingabe: Der Benutzer gibt eine Anfrage in die ChatView-Komponente ein, die diese an den PlanningAgent weiterleitet (BaseAgent.java:62-67).

  2. Planungsphase: Der PlanningAgent führt wiederholt think()- und act()-Zyklen durch, um einen strukturierten Ausführungsplan zu erstellen. Dabei nutzt er das PlanningTool zur Planverwaltung (PlanningAgent.java:76-78).

  3. Ausführungsphase: Der ExecutorAgent übernimmt den erstellten Plan und führt die einzelnen Werkzeugaufrufe durch. Die think()-Methode entscheidet über den nächsten Schritt, act() führt ihn aus (ReActAgent.java:38-45).

  4. Tool-Kommunikation: Werkzeugaufrufe werden an den Genie-Tool Server weitergeleitet, der über den MCP-Client mit externen Servern kommuniziert (genie-client/server.py:86-115).

  5. Zusammenfassung: Der SummaryAgent filtert und formatiert die Ergebnisse, einschließlich der erstellten Dateien, und generiert eine benutzerfreundliche Zusammenfassung (SummaryAgent.java:49-78).

Kontextverwaltung und Konfiguration

AgentContext - Zentraler Datenspeicher

Der AgentContext dient als zentraler Datenspeicher für alle Request-spezifischen Informationen, die während der Agentenausführung benötigt werden.

Datenstruktur:

java
1public class AgentContext {
2    String requestId;           // Eindeutige Anfrage-ID
3    String sessionId;           // Sitzungs-ID für Konversationskontext
4    String query;               // Ursprüngliche Benutzeranfrage
5    String task;                // Aktuelle Aufgabe
6    Printer printer;            // Ausgabesteuerung
7    ToolCollection toolCollection;  // Verfügbare Werkzeuge
8    String dateInfo;            // Datumsinformationen
9    List<File> productFiles;    // Erstellte Dateien
10    Boolean isStream;           // Streaming-Modus
11    String streamMessageType;   // Art der Stream-Nachricht
12    String sopPrompt;           // Standard Operating Procedure Prompt
13    String basePrompt;          // Basis-Prompt
14    Integer agentType;          // Agententyp (1=Plan, 2=React, 3=Summary)
15    List<File> taskProductFiles; // Aufgaben-spezifische Dateien
16    String templateType;        // Vorlagentyp
17}

Verwendungszweck:

  • Request-Tracking: Die requestId ermöglicht durchgängiges Logging und Debugging über alle Agenten hinweg (AgentContext.java:22).
  • Tool-Verwaltung: Die ToolCollection wird zwischen Agenten geteilt und ermöglicht Zugriff auf alle verfügbaren Werkzeuge (AgentContext.java:27).
  • Dateiverwaltung: Produktdateien werden zentral verwaltet und können vom SummaryAgent gefiltert werden (AgentContext.java:29).

GenieConfig - Flexible Konfiguration

Die GenieConfig-Klasse verwaltet alle konfigurierbaren Aspekte des Systems durch Map-basierte Prompt-Templates und Modelleinstellungen.

Konfigurationsstruktur:

java
1// Prompt-Maps für verschiedene Agenten
2private Map<String, String> plannerSystemPromptMap = new HashMap<>();
3private Map<String, String> plannerNextStepPromptMap = new HashMap<>();
4private Map<String, String> executorSystemPromptMap = new HashMap<>();
5private Map<String, String> executorNextStepPromptMap = new HashMap<>();
6private Map<String, String> executorSopPromptMap = new HashMap<>();
7private Map<String, String> reactSystemPromptMap = new HashMap<>();
8private Map<String, String> reactNextStepPromptMap = new HashMap<>();
9
10// Konfiguration via Spring @Value Annotation (Zeile 22-26)
11@Value("${autobots.autoagent.planner.system_prompt:{}}")
12public void setPlannerSystemPromptMap(String list) {
13    plannerSystemPromptMap = JSONObject.parseObject(list, 
14        new TypeReference<Map<String, String>>() {});
15}

Konfigurationsbereiche:

  1. Planner-Prompts: System- und NextStep-Prompts für den PlanningAgent (GenieConfig.java:21-33).
  2. Executor-Prompts: System-, NextStep- und SOP-Prompts für den ExecutorAgent (GenieConfig.java:35-54).
  3. React-Prompts: Separate Prompt-Maps für den ReactImplAgent (GenieConfig.java:56-68).

Design-Vorteile:

  • Hot-Reload: Konfigurationsänderungen können ohne Neustart durch Spring's Refresh-Mechanismus übernommen werden.
  • Multi-Tenancy: Verschiedene Prompt-Versionen können für unterschiedliche Einsatzszenarien konfiguriert werden.
  • Fallback-Mechanismus: getOrDefault() stellt sicher, dass immer ein Standard-Prompt verfügbar ist (PlanningAgent.java:55).

Tool-Server und Client-Architektur

Genie-Tool Server - FastAPI Backend

Der Genie-Tool Server ist ein Python-basierter FastAPI-Service, der Werkzeugfunktionalität über HTTP-Endpunkte bereitstellt.

Anwendungsinitialisierung:

python
1def create_app() -> FastAPI:
2    _app = FastAPI(
3        on_startup=[log_setting, print_logo]
4    )
5    
6    register_middleware(_app)
7    register_router(_app)
8    
9    return _app
10
11def register_middleware(app: FastAPI):
12    app.add_middleware(UnknownException)
13    app.add_middleware(
14        CORSMiddleware,
15        allow_origins=["*"],
16        allow_methods=["*"],
17        allow_headers=["*"],
18        allow_credentials=True,
19    )
20    app.add_middleware(HTTPProcessTimeMiddleware)

Middleware-Konfiguration:

  1. CORS-Support: Erlaubt Cross-Origin-Requests von beliebigen Quellen für Entwicklung und Deployment (server.py:47-53).
  2. Fehlerbehandlung: UnknownException-Middleware fängt unbehandelte Ausnahmen ab und konvertiert sie in strukturierte Fehlerantworten (server.py:46).
  3. Performance-Monitoring: HTTPProcessTimeMiddleware misst die Verarbeitungszeit jeder Anfrage (server.py:54).

Server-Konfiguration:

python
1if __name__ == "__main__":
2    parser = OptionParser()
3    parser.add_option("--host", dest="host", type="string", default="0.0.0.0")
4    parser.add_option("--port", dest="port", type="int", default=1601)
5    parser.add_option("--workers", dest="workers", type="int", default=10)
6    (options, args) = parser.parse_args()
7    
8    uvicorn.run(
9        app="server:app",
10        host=options.host,
11        port=options.port,
12        workers=options.workers,
13        reload=os.getenv("ENV", "local") == "local",
14    )

Genie-Client - MCP Kommunikation

Der Genie-Client implementiert einen MCP-Client (Model Context Protocol) für die Kommunikation mit externen Tool-Servern.

API-Endpunkte:

python
1@app.post("/v1/tool/list")
2async def list_tools(
3        request: Request,
4        server_url: str = Body(..., embed=True, description="mcp server url", alias="server_url"),
5):
6    """Werkzeugliste von einem MCP-Server abrufen"""
7    mcp_client = SseClient(server_url=server_url, entity=HeaderEntity(request.headers))
8    try:
9        tools = await mcp_client.list_tools()
10        return {"code": 200, "message": "success", "data": tools}
11    except Exception as e:
12        return {"code": 500, "message": f"Error: {str(e)}", "data": None}
13
14@app.post("/v1/tool/call")
15async def call_tool(
16        request: Request,
17        server_url: str = Body(..., description="mcp server url", alias="server_url"),
18        name: str = Body(..., description="tool name to call", alias="name"),
19        arguments: dict = Body(..., description="tool parameters", alias="arguments"),
20):
21    """Ein spezifisches Werkzeug aufrufen"""
22    mcp_client = SseClient(server_url=server_url, entity=entity)
23    result = await mcp_client.call_tool(name, arguments)
24    return {"code": 200, "message": "success", "data": result}

Funktionalitäten:

  1. Server-Discovery: Der /v1/serv/pong-Endpunkt testet die Erreichbarkeit eines MCP-Servers (server.py:34-57).
  2. Tool-Listing: Der /v1/tool/list-Endpunkt ruft alle verfügbaren Werkzeuge von einem Server ab (server.py:60-83).
  3. Tool-Ausführung: Der /v1/tool/call-Endpunkt führt ein spezifisches Werkzeug mit den angegebenen Parametern aus (server.py:86-115).

Header-Propagation:

Der Client propagiert Request-Header (einschließlich Cookies) an den MCP-Server, was Authentifizierung und Session-Management ermöglicht (server.py:98-100).

Kontext-Modell für Request-Tracking

Das Kontext-Modell implementiert Request-ID-Tracking und LLM-Modellinformationen für die Python-Komponenten.

Request-ID-Kontext:

python
1class _RequestIdCtx(object):
2    def __init__(self):
3        self._request_id = contextvars.ContextVar("request_id", default="default-request-id")
4    
5    @property
6    def request_id(self):
7        return self._request_id.get()
8    
9    @request_id.setter
10    def request_id(self, value):
11        self._request_id.set(value)

LLM-Modellinformationen:

python
1class LLMModelInfo(BaseModel):
2    model: str
3    context_length: int
4    max_output: int
5
6class _LLMModelInfoFactory:
7    def get_context_length(self, model: str, default: int = 128000) -> int:
8        if info := self._factory.get(model):
9            return info.context_length
10        else:
11            return default
12    
13    def get_max_output(self, model: str, default: int = 32000) -> int:
14        if info := self._factory.get(model):
15            return info.max_output
16        else:
17            return default

Frontend-Komponentenstruktur

Modulare Komponentenarchitektur

Das Frontend basiert auf einer modularen Komponentenstruktur, die Wiederverwendbarkeit und Separation of Concerns fördert. Die Komponenten-Exporte zeigen die zentralen UI-Elemente.

Hauptkomponenten:

typescript
1// Core-Komponenten (ui/src/components/index.ts)
2export { default as ChatView } from './ChatView';
3export { default as LoadingSpinner } from './LoadingSpinner';
4export { default as Slogn } from './Slogn';
5export { default as AttachmentList } from './AttachmentList';
6export { GeneralInput, LoadingDot, Logo };
7
8// PlanView-Komponenten (ui/src/components/PlanView/index.ts)
9export { PlanView, Dot, PlanItem };
10export type { PlanViewAction };
11
12// ActionPanel-Komponenten (ui/src/components/ActionPanel/index.ts)
13export { ActionPanel, useMsgTypes, Loading, FileRenderer, 
14         HTMLRenderer, TableRenderer, MarkdownRenderer, PanelProvider };
15export type { PanelItemType };

Komponentenkategorien:

  1. ChatView: Hauptkomponente für die Benutzerinteraktion und Nachrichtenverwaltung (index.ts:7).
  2. PlanView: Visualisierung von Aufgabenplänen mit PlanItem-Unterklomponenten für einzelne Schritte (PlanView/index.ts:1-8).
  3. ActionPanel: Container für verschiedene Renderer (Markdown, Tabelle, HTML, Dateien) zur Darstellung von Ausführungsergebnissen (ActionPanel/index.ts:1-19).

Service-Layer für API-Kommunikation

Die Service-Schicht definiert typisierte HTTP-Methoden für die Kommunikation mit dem Backend.

API-Struktur:

typescript
1interface ApiResponse&lt;T&gt; {
2  code: number
3  data: T
4  message: string
5}
6
7export const api = {
8  get: &lt;T&gt;(url: string, params?: any) =>
9    request.get<ApiResponse&lt;T&gt;>(url, { params }),
10  
11  post: &lt;T&gt;(url: string, data?: any) =>
12    request.post<ApiResponse&lt;T&gt;>(url, data),
13  
14  put: &lt;T&gt;(url: string, data?: any) =>
15    request.put<ApiResponse&lt;T&gt;>(url, data),
16  
17  delete: &lt;T&gt;(url: string, params?: any) =>
18    request.delete<ApiResponse&lt;T&gt;>(url, { params }),
19};

Design-Merkmale:

  • Generische Typisierung: Alle API-Methoden sind generisch typisiert, was Compile-Time-Typsicherheit gewährleistet (index.ts:10-20).
  • Einheitliche Response-Struktur: Die ApiResponse-Schnittstelle standardisiert alle Backend-Antworten mit Code, Data und Message-Feldern (index.ts:3-7).

SimpleTable-Komponente für Datenvisualisierung

Die SimpleTable-Komponente demonstriert die Datenvisualisierungsstrategie des Frontends.

typescript
1interface SimpleTableProps {
2  data: {
3    columnList?: TableColumn[];
4    dataList?: Record<string, any>[];
5  };
6}
7
8const SimpleTable: GenieType.FC<SimpleTableProps> = ({ data }) => {
9  const { columnList = [], dataList = [] } = data || {};
10  return (
11    <Table 
12      dataSource={dataList} 
13      columns={columnList} 
14      size="middle" 
15      className="w-full" 
16      scroll={{ y: 400 }} 
17    />
18  );
19};

Sicherheitsmerkmale:

  • Null-Safety: Standardwerte für columnList und dataList verhindern Runtime-Fehler bei fehlenden Daten (SimpleTable.tsx:20).
  • Scroll-Unterstützung: Feste Höhe von 400px mit Scroll ermöglicht die Anzeige großer Datensätze (SimpleTable.tsx:21).

Modulabhängigkeiten und Beziehungen

正在加载图表渲染器...

Abhängigkeitsanalyse:

  1. Vererbungshierarchie: BaseAgent → ReActAgent → (PlanningAgent, ExecutorAgent, ReactImplAgent) bildet die Kernvererbungskette (BaseAgent.java:30, ReActAgent.java:23).

  2. Komposition: Alle Agenten halten Referenzen auf AgentContext, GenieConfig, LLM und Memory, was eine lose Kopplung ermöglicht.

  3. Tool-Integration: PlanningTool ist spezifisch für PlanningAgent, während ToolCollection von ExecutorAgent und ReactImplAgent geteilt wird (PlanningAgent.java:76-77, ExecutorAgent.java:77).

  4. Frontend-Backend-Trennung: UI-Komponenten kommunizieren ausschließlich über die Service-Schicht mit dem Backend, was Testbarkeit und Austauschbarkeit verbessert (services/index.ts:9-21).

Kern-Designentscheidungen und Architekturmuster

1. ReAct-Pattern als Fundament

Entscheidung: Das System verwendet das ReAct-Muster (Reasoning and Acting) als zentrales Ausführungsmodell.

Begründung: Die Trennung von think() und act() ermöglicht eine klare Unterscheidung zwischen Entscheidungsfindung und Ausführung. Dies verbessert die Debuggbarkeit und ermöglicht differenzierte Fehlerbehandlung für beide Phasen (ReActAgent.java:28-45).

Trade-offs: Die zusätzliche Abstraktionsschicht erhöht die Komplexität, bietet aber bessere Kontrolle über den Ausführungsfluss.

2. Template-basierte Prompt-Verwaltung

Entscheidung: Verwendung von Map-basierten Prompt-Templates mit Platzhaltern.

Begründung: Dies ermöglicht dynamische Prompt-Anpassung ohne Code-Änderungen und unterstützt Multi-Tenancy-Szenarien. Die getOrDefault()-Strategie stellt sicher, dass immer ein Fallback verfügbar ist (GenieConfig.java:21-68).

Implementierung: Platzhalter wie {{tools}}, {{query}}, {{date}} werden zur Laufzeit durch Kontextinformationen ersetzt (PlanningAgent.java:55-64).

3. Hybride Java-Python-Architektur

Entscheidung: Java-Backend für Agentenlogik, Python-Services für Tool-Ausführung.

Begründung: Java bietet robuste Enterprise-Funktionalität und Typsicherheit für komplexe Agentenlogik, während Python flexible Tool-Integration und schnelle Entwicklung ermöglicht.

Kommunikation: HTTP-basierte Kommunikation zwischen Java und Python über standardisierte API-Endpunkte (genie-tool/server.py:35-43).

4. Kontext-Propagation für Request-Tracking

Entscheidung: Durchgängige Request-ID über alle Systemkomponenten.

Begründung: Ermöglicht verteiltes Logging und Debugging über Java- und Python-Komponenten hinweg. Die Verwendung von contextvars in Python stellt Thread-Sicherheit sicher (context.py:16-26).

5. Snapshot-Mechanismus für dynamische Prompts

Entscheidung: Speicherung von Prompt-Snapshots zur Laufzeitaktualisierung.

Begründung: Ermöglicht die Aktualisierung von Prompts während der Ausführung (z.B. Hinzufügen von Dateiinformationen) ohne Verlust der ursprünglichen Template-Struktur (PlanningAgent.java:66-67).

6. Modulare Frontend-Architektur

Entscheidung: Komponentenbasierte UI mit separaten Renderern für verschiedene Inhaltstypen.

Begründung: Ermöglicht Wiederverwendung von Komponenten und einfache Erweiterung um neue Darstellungsformate. Die Trennung von ActionPanel und spezifischen Renderern folgt dem Single Responsibility Principle (ActionPanel/index.ts:1-19).

Technologie-Stack und Auswahlkriterien

TechnologieVerwendungszweckAuswahlkriterienAlternativen
Java 17+Backend Agent FrameworkTypsicherheit, Enterprise-Funktionalität, Spring-IntegrationKotlin, Scala
Spring BootDependency Injection, KonfigurationReife, Community-Support, ProduktionsbereitQuarkus, Micronaut
Python 3.8+Tool Server, MCP ClientFlexibilität, umfangreiche Tool-BibliothekenNode.js, Go
FastAPIPython Web FrameworkAsynchrone Unterstützung, automatische API-DokumentationFlask, Django
ReactFrontend FrameworkKomponentenwiederverwendung, große CommunityVue.js, Angular
TypeScriptFrontend TypisierungCompile-Time-Fehlererkennung, IDE-SupportJavaScript (ohne Typen)
MermaidDiagramm-GenerierungTextbasierte Diagramme, Markdown-IntegrationPlantUML, Draw.io
UvicornASGI ServerPerformance, WebSocket-SupportGunicorn, Daphne
PydanticDatenvalidierungTypsicherheit, automatische ValidierungMarshmallow, Cerberus
ContextvarsRequest-KontextThread-sichere KontextspeicherungThread-locals

Technologie-Entscheidungen im Detail:

  1. FastAPI vs. Flask: FastAPI wurde aufgrund der nativen asynchronen Unterstützung und der automatischen OpenAPI-Dokumentation gewählt, was für Tool-Integrationen kritisch ist (server.py:14).

  2. TypeScript für Frontend: Die typisierte API-Schicht verhindert Runtime-Fehler bei der Kommunikation mit dem Backend und verbessert die Entwicklererfahrung durch IDE-Autovervollständigung (services/index.ts:3-7).

  3. Spring Boot für Backend: Die Integration mit GenieConfig ermöglicht externe Konfiguration ohne Neustart, was für Produktionsumgebungen essentiell ist (GenieConfig.java:22-26).

Bekannte Einschränkungen und zukünftige Erweiterungen

Aktuelle Einschränkungen

  1. Feste Max-Steps: Die maximale Schrittzahl ist statisch konfiguriert und kann sich nicht dynamisch an die Aufgabenkomplexität anpassen (BaseAgent.java:44).

  2. Synchrones LLM-Warten: Obwohl CompletableFuture verwendet wird, wartet der Code synchron auf Ergebnisse (summaryFuture.get()), was bei langen LLM-Antworten zu Blockierungen führen kann (ReActAgent.java:66).

  3. CORS-Wildcard: Die aktuelle CORS-Konfiguration erlaubt alle Origins (allow_origins=["*"]), was für Produktionsumgebungen eingeschränkt werden sollte (server.py:49).

  4. Fehlende Circuit Breaker: Bei Tool-Server-Ausfällen gibt es keine automatische Unterbrechung, was zu Kaskadenfehlern führen kann.

Potenzielle Erweiterungen

  1. Dynamische Schrittanzahl: Implementierung eines adaptiven Algorithmus, der die maximale Schrittzahl basierend auf Aufgabenkomplexität anpasst.

  2. Vollständig asynchrone Verarbeitung: Umstellung auf nicht-blockierende LLM-Aufrufe mit Reactive Streams.

  3. Distributed Tracing: Integration von OpenTelemetry für verteiltes Tracing über Java- und Python-Komponenten.

  4. Caching-Layer: Einführung eines Caching-Mechanismus für häufige Tool-Aufrufe zur Performance-Verbesserung.