From 3f5b1a59a50b68c32c2ffe698a19e07ad0d01e07 Mon Sep 17 00:00:00 2001 From: Nora Date: Sat, 27 Jun 2026 13:59:29 +0000 Subject: [PATCH] docs: Agenten-Steckbriefe (Ist-Stand v0.1) + README-Status & Prototyp-Anleitung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/agent_specs.md: implementierte Agenten, Live/Mock-Pfade, Abweichungen vom Ziel-Design - README: Status-Tabelle aktualisiert, Prototyp-/Test-Befehle ergänzt Co-Authored-By: Claude Opus 4.8 --- README.md | 45 +++++-- docs/agent_specs.md | 98 ++++++++++++++ docs/architecture.md | 304 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 437 insertions(+), 10 deletions(-) create mode 100644 docs/agent_specs.md create mode 100644 docs/architecture.md diff --git a/README.md b/README.md index f979d17..2e83731 100644 --- a/README.md +++ b/README.md @@ -117,10 +117,29 @@ Der Spike demonstriert das Grundprinzip der Agenten-Orchestrierung mit reinem Py python3 spike/concept_spike.py ``` -### Vollständige App starten +### Photo-to-Listing-Prototyp (end-to-end) ```bash -python3 -m src.agents.orchestrator +# Vollständige Demo im deterministischen Mock-Modus (kein Netz nötig) +python3 spike/prototype.py --mock + +# Mit echtem Produktfoto über den authentifizierten claude-CLI +python3 spike/prototype.py --image /pfad/zum/foto.jpg --live + +# Nur maschinenlesbares JSON-Ergebnis +python3 spike/prototype.py --mock --json +``` + +### Orchestrator direkt aufrufen + +```bash +python3 -m src.agents.orchestrator --description "gebrauchte Bluetooth-Kopfhörer" +``` + +### Tests + +```bash +python3 -m unittest discover -s tests -v ``` --- @@ -129,14 +148,20 @@ python3 -m src.agents.orchestrator | Phase | Status | Beschreibung | |---|---|---| -| Grundgerüst | ✅ Fertig | Projektstruktur, Basisklassen, Dateigerüst | -| Concept Spike | ✅ Fertig | Orchestrator-Pattern ohne externe Abhängigkeiten | -| Bildanalyse-Agent | 🔄 In Arbeit | Integration eines Vision-Modells | -| Preis-Recherche-Agent | 📋 Geplant | eBay Sold Listings + Marktdaten | -| Listing-Erstellung-Agent | 📋 Geplant | LLM-basierte Textgenerierung | -| Chat-Moderation-Agent | 📋 Geplant | Automatische Antworten | -| eBay API-Integration | 📋 Geplant | Trading API / Listing-Upload | -| Tests & CI | 📋 Geplant | Pytest-Suite, GitHub Actions | +| Grundgerüst | ✅ Fertig | Projektstruktur, BMAD-Basisklasse, Datenmodelle | +| Concept Spike + Prototyp | ✅ Fertig | `spike/prototype.py` — Photo-to-Listing end-to-end | +| Bildanalyse-Agent | ✅ Fertig (v0.1) | Live über `claude -p` (Vision), deterministischer Mock-Fallback | +| Preis-Recherche-Agent | ✅ Fertig (v0.1) | Modell-Schätzung (Live) / Kategorie-Heuristik (Mock) | +| Listing-Erstellung-Agent | ✅ Fertig (v0.1) | Titel/Beschreibung/Kategorie/Attribute | +| Chat-Moderation-Agent | ✅ Fertig (v0.1) | FAQ-Antworten + Eskalation | +| Tests | ✅ Fertig | 28 `unittest`-Tests (Stdlib, offline deterministisch) | +| eBay API-Integration | 📋 Geplant | Trading API / Listing-Upload, echte Preisrecherche | +| CI | 📋 Geplant | GitHub Actions | + +> **v0.1-Hinweis:** Der Prototyp läuft Stdlib-only. LLM-Agenten nutzen den lokal +> authentifizierten `claude`-CLI (`claude -p`) statt eines API-Keys im Code; ohne +> CLI/Netz schalten alle Agenten automatisch auf einen deterministischen Mock um. +> Details: [`docs/agent_specs.md`](docs/agent_specs.md). --- diff --git a/docs/agent_specs.md b/docs/agent_specs.md new file mode 100644 index 0000000..a08e5c4 --- /dev/null +++ b/docs/agent_specs.md @@ -0,0 +1,98 @@ +# Agenten-Spezifikation — Implementierungsstand v0.1 + +Dieses Dokument beschreibt die **tatsächlich implementierten** Agenten des +Photo-to-Listing-Prototyps. Es ergänzt das Ziel-Design in +[`architecture.md`](architecture.md) um den konkreten Ist-Zustand. + +## Designentscheidungen v0.1 (Abweichungen vom Ziel-Design) + +| Thema | Ziel-Design (`architecture.md`) | Prototyp v0.1 | Begründung | +|---|---|---|---| +| Validierung | Pydantic v2 | `dataclasses` (Stdlib) | Spike/Agenten laufen **ohne** `pip install` (siehe `requirements.txt`) | +| LLM-Zugang | Anthropic API + `ANTHROPIC_API_KEY` | lokaler **`claude -p`** CLI | Kein Klartext-Key im Code (SOPS-Policy); CLI ist bereits authentifiziert | +| Preisdaten | eBay Finding API | Heuristik (Mock) bzw. Modell-Schätzung (Live) | Echtes Scraping = AGB-/Rechtsthema, bewusst nicht enthalten | +| Robustheit | Retry/Backoff | Mock-Fallback je Agent | Ein Agent darf die Pipeline nie reißen; Prototyp bleibt offline lauffähig | + +Jeder LLM-gestützte Agent hat zwei Pfade: +- **live** — ruft `claude -p` auf (wenn CLI vorhanden, sonst automatisch Fallback), +- **mock** — deterministische Logik, garantiert offline/in CI reproduzierbar. + +Der Betriebsmodus wird zentral über `ClaudeClient(mode="auto"|"live"|"mock")` +gesetzt und vom Orchestrator an alle Agenten durchgereicht. + +--- + +## Orchestrator — `src/agents/orchestrator.py` + +| Eigenschaft | Wert | +|---|---| +| Rolle | Zentraler Koordinator (BMAD-Orchestrator-Pattern) | +| Kein KI-Modell | reine Python-Orchestrierung | +| Kern-Methode | `photo_to_listing(image_path=None, description=None) -> ListingResult` | +| Chat-Methode | `answer_question(question, listing) -> ChatReply` | +| Ablauf | Vision → Market → Listing, danach optional Chat | + +--- + +## Vision — `ImageAnalysisAgent` (`image_analysis_agent.py`) + +| Eigenschaft | Wert | +|---|---| +| Rolle | Bildanalyse: Artikel, Zustand, Merkmale erkennen | +| Input | `{"image_path": str, "description": str}` (oder Pfad-String) | +| Output | `ItemAnalysis(title_guess, category, brand, condition, condition_score, features, defects, confidence, source)` | +| Live | `claude -p` liest die Bilddatei (Tool `Read`) und liefert JSON | +| Mock | Stichwort-Heuristik aus Dateiname/Beschreibung → plausibles Beispielobjekt | + +## Market — `PriceResearchAgent` (`price_research_agent.py`) + +| Eigenschaft | Wert | +|---|---| +| Rolle | Marktpreis vorschlagen | +| Input | `ItemAnalysis` | +| Output | `PriceSuggestion(suggested_price, price_min, price_max, currency, sample_size, rationale, source)` | +| Live | Modell schätzt Preisspanne (deutscher eBay-Markt) als JSON | +| Mock | Basispreis je Kategorie × Zustands-Faktor (0,5 … 1,0) | + +## Listing — `ListingAgent` (`listing_agent.py`) + +| Eigenschaft | Wert | +|---|---| +| Rolle | eBay-konformes Listing erzeugen | +| Input | `(ItemAnalysis, PriceSuggestion)` (oder dict) | +| Output | `Listing(title≤80, description, category_id, item_specifics, price, currency, source)` | +| Live | Modell erzeugt Titel/Text/Attribute als JSON | +| Mock | Template: Titel aus Marke+Artikel+Zustand, Beschreibung mit Stichpunkten, Kategorie-ID-Lookup | + +## Chat — `ChatModerationAgent` (`chat_moderation_agent.py`) + +| Eigenschaft | Wert | +|---|---| +| Rolle | Käuferfragen beantworten / eskalieren | +| Input | `{"question": str, "listing": Listing}` | +| Output | `ChatReply(question, answer, escalate, source)` | +| Live | Modell antwortet + setzt `escalate` bei Reklamation/Recht | +| Mock | FAQ-Intents (Versand, Preis, Zustand, Verfügbarkeit) + Eskalations-Stichwörter | + +--- + +## Datenfluss (implementiert) + +``` +Foto/Text + │ + ▼ ImageAnalysisAgent +ItemAnalysis + │ + ▼ PriceResearchAgent +PriceSuggestion + │ + ▼ ListingAgent +Listing ──► ListingResult (analysis + price + listing) + │ + ▼ ChatModerationAgent (auf Käuferfrage) +ChatReply +``` + +Alle Strukturen sind in `src/models.py` definiert und über `.to_dict()` / +`.to_json()` serialisierbar. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..961f450 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,304 @@ +# eBay-Auto-Lister — Systemarchitektur + +## 1. Überblick & Ziele + +Der **eBay-Auto-Lister** ist ein Python-basiertes Multi-Agent-System, das den vollständigen Prozess vom Produktfoto bis zur veröffentlichten eBay-Anzeige automatisiert. Durch den Einsatz spezialisierter KI-Agenten in einer koordinierten Pipeline wird jeder Schritt von der Bildanalyse über die Preisrecherche und Listing-Erstellung bis hin zur Chat-Moderation abgedeckt. + +### Kernziele + +- **Vollautomatisierung:** Minimaler manueller Aufwand nach dem Upload eines Fotos +- **Qualitätssicherung:** Jeder Agent liefert strukturierte, validierbare Outputs +- **Skalierbarkeit:** Agenten können unabhängig erweitert oder ersetzt werden +- **Compliance:** Einhaltung der eBay-API-Richtlinien und -Nutzungsbedingungen + +--- + +## 2. BMAD-Orchestrierungsmodell + +### Warum Orchestrierung statt monolithisch? + +Ein monolithischer Ansatz würde alle Aufgaben (Vision, Preisanalyse, Texterstellung, Moderation) in einem einzigen Prozess vermischen. Das erzeugt: + +- Enge Kopplung: Änderungen an einem Schritt gefährden alle anderen +- Keine Wiederverwendbarkeit: Einzelschritte können nicht isoliert getestet oder ausgetauscht werden +- Schwache Fehlerbehandlung: Ein Fehler stoppt die gesamte Pipeline + +Das BMAD-Prinzip (Business Method Agent Design) löst dies durch klare **Rollenverteilung**, **definierte Schnittstellen (Contracts)** und einen zentralen **Orchestrator**, der den Zustand hält und die Hand-offs steuert. + +### Rolle des Orchestrators + +Der Orchestrator ist der einzige Teilnehmer, der den vollständigen **Session-State** kennt. Er: + +1. Nimmt den initialen Job-Request entgegen (Foto-Pfad, Nutzerkonfiguration) +2. Übergibt Tasks sequenziell an die Fach-Agenten +3. Validiert den Output jedes Agenten gegen dessen Contract +4. Schreibt Zwischenergebnisse in das gemeinsame `ItemState`-Objekt +5. Behandelt Fehler und entscheidet über Retry oder Abbruch +6. Startet nach Veröffentlichung den Chat-Moderation-Agenten als parallelen Service + +### Hand-offs zwischen Agenten + +Jeder Hand-off ist ein expliziter Methodenaufruf mit typisiertem Input und Output: + +``` +Orchestrator → Bildanalyse-Agent : ImageAnalysisRequest → ItemData +Orchestrator → Preis-Recherche-Agent : PriceResearchRequest → PriceSuggestion +Orchestrator → Listing-Erstellung : ListingRequest → Listing +Orchestrator → eBay-API : Listing → PublishedListingId +Orchestrator → Chat-Moderation-Agent : ModerationServiceConfig (Fire-and-Forget) +``` + +### Nachrichten & State + +- **ItemState:** Zentrales Zustandsobjekt, das der Orchestrator durch die gesamte Pipeline mitführt +- **Messages:** Jeder Agenten-Aufruf ist eine strukturierte Nachricht (Dataclass); kein Shared-Memory zwischen Agenten +- **Zustandspersistenz:** Nach jedem erfolgreichen Schritt wird der State in eine JSON-Datei geschrieben (Resume-Fähigkeit bei Absturz) + +--- + +## 3. Pipeline-Diagramm + +```mermaid +flowchart TD + A([Foto-Upload]) --> B[Orchestrator] + + B -->|ImageAnalysisRequest| C[Bildanalyse-Agent] + C -->|ItemData| B + + B -->|PriceResearchRequest| D[Preis-Recherche-Agent] + D -->|PriceSuggestion| B + + B -->|ListingRequest| E[Listing-Erstellung-Agent] + E -->|Listing| B + + B -->|Listing via eBay-API| F[(eBay Marketplace)] + F -->|PublishedListingId| B + + B -->|ModerationServiceConfig| G[Chat-Moderation-Agent] + G <-->|Käufer-Nachrichten| F + + style A fill:#4a9eff,color:#fff + style B fill:#ff8c42,color:#fff + style C fill:#6bcb77,color:#fff + style D fill:#6bcb77,color:#fff + style E fill:#6bcb77,color:#fff + style F fill:#c9b8e8,color:#333 + style G fill:#ffd166,color:#333 +``` + +--- + +## 4. Agent-Steckbriefe + +### Orchestrator + +| Eigenschaft | Beschreibung | +|---|---| +| **Rolle** | Zentraler Koordinator der gesamten Pipeline | +| **Verantwortung** | Job-Verwaltung, State-Management, Fehlerbehandlung, Hand-offs | +| **Inputs** | Job-Request (Foto-Pfad, Nutzerkonfiguration) | +| **Outputs** | Finaler `ItemState` mit `published_listing_id` | +| **Tools/Modelle** | Kein KI-Modell; reine Python-Orchestrierungslogik | +| **Fehlerfälle** | Agent-Timeout → Retry (max. 3x); Contract-Verletzung → Abbruch mit Fehlermeldung; API-Fehler → Exponential Backoff | + +--- + +### Bildanalyse-Agent + +| Eigenschaft | Beschreibung | +|---|---| +| **Rolle** | Extrahiert strukturierte Produktdaten aus Fotos | +| **Verantwortung** | Objekterkennung, Zustandsbewertung, Kategorie-Klassifikation, Merkmalextraktion | +| **Inputs** | `ImageAnalysisRequest(image_path: str, language: str)` | +| **Outputs / Contract** | `ItemData(title: str, category: str, condition: str, features: list[str], brand: str \| None, confidence: float)` | +| **Tools/Modelle** | Vision-LLM (z. B. `claude-sonnet-4-6` mit Vision); optional lokales CLIP-Modell für Vorklassifikation | +| **Fehlerfälle** | Bild unlesbar → `ImageAnalysisError`; `confidence < 0.6` → Orchestrator fragt Nutzer zur Verifikation; Kein Objekt erkannt → Abbruch | + +--- + +### Preis-Recherche-Agent + +| Eigenschaft | Beschreibung | +|---|---| +| **Rolle** | Ermittelt marktgerechte Preisempfehlung | +| **Verantwortung** | Scraping abgeschlossener eBay-Verkäufe, Preisstatistik, Wettbewerbsanalyse | +| **Inputs** | `PriceResearchRequest(item: ItemData, max_results: int = 20)` | +| **Outputs / Contract** | `PriceSuggestion(suggested_price: Decimal, price_range: tuple[Decimal, Decimal], avg_sold_price: Decimal, sample_size: int, confidence: float)` | +| **Tools/Modelle** | eBay Finding API (abgeschlossene Listings); Scraper-Fallback für erweiterte Daten; statistisches Modul (`src/scrapers/price_analyzer.py`) | +| **Fehlerfälle** | Keine Vergleichsdaten → `PriceResearchWarning` + Schätzwert; API-Rate-Limit → Warten + Retry; `sample_size < 3` → Niedrige Konfidenz wird im Output markiert | + +--- + +### Listing-Erstellung-Agent + +| Eigenschaft | Beschreibung | +|---|---| +| **Rolle** | Generiert verkaufsfördernde eBay-Anzeigentexte | +| **Verantwortung** | Titel (max. 80 Zeichen), Beschreibungstext, eBay-Kategoriezuordnung, Versandoptionen vorschlagen | +| **Inputs** | `ListingRequest(item: ItemData, price: PriceSuggestion, language: str, seller_config: SellerConfig)` | +| **Outputs / Contract** | `Listing(title: str, description: str, category_id: str, price: Decimal, condition_id: str, shipping_options: list[ShippingOption], images: list[str])` | +| **Tools/Modelle** | Text-LLM (`claude-sonnet-4-6`); eBay-Kategorie-Lookup-Tabelle; Titel-Optimizer mit Keyword-Extraktion | +| **Fehlerfälle** | Titel > 80 Zeichen → automatisches Kürzen + Log; Ungültige Kategorie-ID → Fallback auf Elternkategorie; LLM-Timeout → Retry mit vereinfachtem Prompt | + +--- + +### Chat-Moderation-Agent + +| Eigenschaft | Beschreibung | +|---|---| +| **Rolle** | Begleitender Service für Käufer-Kommunikation nach Veröffentlichung | +| **Verantwortung** | Automatische Beantwortung häufiger Fragen, Spam-Filterung, Eskalation komplexer Anfragen | +| **Inputs** | `ModerationServiceConfig(listing_id: str, item: ItemData, auto_reply: bool, escalation_email: str)` | +| **Outputs / Contract** | Feuert Events: `MessageReplied`, `MessageEscalated`, `SpamDetected` | +| **Tools/Modelle** | Text-LLM (`claude-haiku-4-5-20251001` für niedrige Latenz); eBay Messaging API; Spam-Klassifikator | +| **Fehlerfälle** | Unbekannte Frage + `auto_reply=True` → Standardantwort + Eskalation; API-Fehler → Silent Retry; Modell-Timeout → Direkte Weiterleitung an Verkäufer | + +--- + +## 5. Datenmodelle + +```python +from dataclasses import dataclass, field +from decimal import Decimal + + +@dataclass +class ItemData: + title: str + category: str + condition: str # "new", "used_good", "used_fair", "defective" + features: list[str] = field(default_factory=list) + brand: str | None = None + confidence: float = 0.0 + + +@dataclass +class PriceSuggestion: + suggested_price: Decimal + price_range: tuple[Decimal, Decimal] + avg_sold_price: Decimal + sample_size: int + confidence: float + + +@dataclass +class ShippingOption: + service: str + cost: Decimal + estimated_days: int + + +@dataclass +class Listing: + title: str # max. 80 Zeichen + description: str + category_id: str + price: Decimal + condition_id: str + shipping_options: list[ShippingOption] + images: list[str] # lokale Dateipfade oder URLs + published_listing_id: str | None = None + + +@dataclass +class Message: + listing_id: str + sender_id: str + content: str + timestamp: str # ISO 8601 + reply: str | None = None + escalated: bool = False + + +@dataclass +class ItemState: + job_id: str + image_path: str + item_data: ItemData | None = None + price_suggestion: PriceSuggestion | None = None + listing: Listing | None = None + published_listing_id: str | None = None + status: str = "pending" # pending, analyzing, pricing, listing, publishing, live, error + error: str | None = None +``` + +--- + +## 6. Tech-Stack & Modulstruktur + +### Tech-Stack + +| Komponente | Technologie | +|---|---| +| Sprache | Python 3.12+ | +| KI-Modelle | Anthropic Claude API (`claude-sonnet-4-6`, `claude-haiku-4-5-20251001`) | +| eBay-Integration | eBay Trading API, eBay Finding API, eBay Messaging API | +| HTTP-Client | `httpx` (async) | +| Validierung | `pydantic` v2 | +| Secrets | SOPS + age | +| Tests | `pytest` + `pytest-asyncio` | +| Linting | `ruff` | + +### Modulstruktur + +``` +src/ +├── agents/ +│ ├── orchestrator.py # Pipeline-Koordination, State-Management +│ ├── image_analysis.py # Bildanalyse-Agent +│ ├── price_research.py # Preis-Recherche-Agent +│ ├── listing_creation.py # Listing-Erstellung-Agent +│ └── chat_moderation.py # Chat-Moderation-Agent (Service) +├── scrapers/ +│ ├── ebay_sold_listings.py # Scraper für abgeschlossene Verkäufe +│ └── price_analyzer.py # Statistische Preisauswertung +├── api/ +│ ├── ebay_trading.py # eBay Trading API Client +│ ├── ebay_finding.py # eBay Finding API Client +│ └── ebay_messaging.py # eBay Messaging API Client +├── models.py # Alle Dataclasses / Pydantic-Modelle +└── config.py # Konfiguration aus Umgebungsvariablen + +tests/ +├── agents/ +├── scrapers/ +└── api/ + +docs/ +└── architecture.md +``` + +--- + +## 7. Sicherheit & Compliance + +### eBay-API & Nutzungsbedingungen + +- **Rate Limits:** Alle API-Aufrufe laufen durch ein zentrales Rate-Limit-Modul mit Exponential Backoff +- **ToS-Compliance:** Automatisch generierte Texte werden auf verbotene Inhalte geprüft (Keyword-Blacklist + LLM-Validierung) +- **Kein Scraping produktiver Listings:** Preisrecherche ausschließlich über die offizielle Finding API oder explizit erlaubte Endpunkte +- **API-Credentials:** Niemals im Code hardcodiert — ausschließlich über Umgebungsvariablen + +### Secrets-Management (SOPS + age) + +Dieses Projekt folgt dem globalen Secrets-Standard des openclaw-Servers: + +- **Verschlüsselung:** Alle `.env`-Dateien werden mit SOPS + age verschlüsselt +- **age Public Key:** `age1vf04awvs2t0agylyz6yz2yrkngks3592d6s8agw3uu8hs8qks32qzpaldg` +- **Management:** `/opt/secrets/secrets.sh encrypt ebay-auto-lister` nach jeder Änderung +- **Berechtigungen:** `.env`-Dateien müssen `chmod 600` haben + +### .env-Regeln + +``` +# .env (NIEMALS committen) +EBAY_APP_ID=... +EBAY_CERT_ID=... +EBAY_DEV_ID=... +EBAY_AUTH_TOKEN=... +ANTHROPIC_API_KEY=... +``` + +- `.env` ist in `.gitignore` eingetragen — ein Commit schlägt fehl, wenn `.env` staged wird +- CI/CD erhält Secrets ausschließlich über verschlüsselte Umgebungsvariablen, nicht über Repository-Dateien +- Rotation von API-Keys erfolgt über `secrets.sh edit ebay-auto-lister` → Änderung → `secrets.sh encrypt ebay-auto-lister`