Protokoll #12827

ID12827
Zeitstempel2025-12-24 10:53:00.240165
Clientroot
IP
Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13

Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens1,691 (Input: 0, Output: 0)
Dauer80 ms
Request-Zeit
Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18
Response-Zeit-

Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22

Request

{
    "event": "PreToolUse",
    "tool_name": "Read",
    "tool_input": {
        "file_path": "\/var\/www\/scripts\/pipeline\/embed.py"
    }
}

Response

{
    "tool_response": {
        "type": "text",
        "file": {
            "filePath": "\/var\/www\/scripts\/pipeline\/chat.py",
            "content": "#!\/usr\/bin\/env python3\n\"\"\"\nRAG-Chat für KI-System\nSemantische Suche + LLM-Antwort mit Quellenangabe.\n\nUsage:\n    python chat.py \"Deine Frage hier\"\n    python chat.py  # Interaktiver Modus\n\"\"\"\n\nimport sys\n\nimport requests\n\nfrom config import ANTHROPIC_API_KEY, ANTHROPIC_MODEL, EMBEDDING_MODEL, OLLAMA_HOST, QDRANT_HOST, QDRANT_PORT\n\n\ndef get_embedding(text):\n    \"\"\"Get embedding from Ollama.\"\"\"\n    response = requests.post(\n        f\"{OLLAMA_HOST}\/api\/embeddings\", json={\"model\": EMBEDDING_MODEL, \"prompt\": text}, timeout=60\n    )\n    response.raise_for_status()\n    return response.json().get(\"embedding\")\n\n\ndef search_qdrant(query_embedding, limit=5):\n    \"\"\"Search for similar chunks in Qdrant.\"\"\"\n    response = requests.post(\n        f\"http:\/\/{QDRANT_HOST}:{QDRANT_PORT}\/collections\/documents\/points\/search\",\n        json={\"vector\": query_embedding, \"limit\": limit, \"with_payload\": True},\n        timeout=30,\n    )\n    response.raise_for_status()\n    return response.json().get(\"result\", [])\n\n\ndef build_context(results, max_tokens=3000):\n    \"\"\"Build context from search results.\"\"\"\n    context_parts = []\n    total_chars = 0\n    max_chars = max_tokens * 4  # Rough estimate\n\n    for i, result in enumerate(results):\n        content = result[\"payload\"].get(\"content\", \"\")\n        doc_title = result[\"payload\"].get(\"document_title\", \"Unbekannt\")\n\n        if total_chars + len(content) > max_chars:\n            break\n\n        context_parts.append(f\"[Quelle {i + 1}: {doc_title}]\\n{content}\")\n        total_chars += len(content)\n\n    return \"\\n\\n---\\n\\n\".join(context_parts)\n\n\ndef get_sources(results):\n    \"\"\"Extract source information from results.\"\"\"\n    sources = []\n    seen = set()\n\n    for result in results:\n        doc_title = result[\"payload\"].get(\"document_title\", \"\")\n        if doc_title and doc_title not in seen:\n            sources.append({\"title\": doc_title, \"score\": round(result[\"score\"], 3)})\n            seen.add(doc_title)\n\n    return sources\n\n\ndef ask_claude(question, context):\n    \"\"\"Get answer from Claude API.\"\"\"\n    import anthropic\n\n    system_prompt = \"\"\"Du bist ein hilfreicher Assistent für Fragen zu systemischem Teamcoaching und Teamentwicklung.\n\nBeantworte die Frage des Nutzers basierend auf dem bereitgestellten Kontext.\n- Antworte auf Deutsch\n- Sei präzise und hilfreich\n- Wenn der Kontext die Frage nicht beantwortet, sage das ehrlich\n- Verweise auf die Quellen wenn passend\"\"\"\n\n    user_prompt = f\"\"\"Kontext aus den Dokumenten:\n\n{context}\n\n---\n\nFrage: {question}\"\"\"\n\n    client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)\n\n    message = client.messages.create(\n        model=ANTHROPIC_MODEL,\n        max_tokens=1500,\n        system=system_prompt,\n        messages=[{\"role\": \"user\", \"content\": user_prompt}],\n    )\n\n    return message.content[0].text\n\n\ndef ask_ollama(question, context, model=\"gemma3:27b-it-qat\"):\n    \"\"\"Get answer from Ollama (local LLM).\"\"\"\n    prompt = f\"\"\"Du bist ein hilfreicher Assistent. Beantworte die Frage basierend auf dem Kontext.\n\nKontext:\n{context}\n\nFrage: {question}\n\nAntwort:\"\"\"\n\n    response = requests.post(\n        f\"{OLLAMA_HOST}\/api\/generate\", json={\"model\": model, \"prompt\": prompt, \"stream\": False}, timeout=120\n    )\n    response.raise_for_status()\n    return response.json().get(\"response\", \"\")\n\n\ndef chat(question, use_claude=True, top_k=5):\n    \"\"\"\n    Main RAG chat function.\n\n    Args:\n        question: User's question\n        use_claude: Use Claude API (True) or Ollama (False)\n        top_k: Number of chunks to retrieve\n\n    Returns:\n        dict with answer and sources\n    \"\"\"\n    # 1. Get embedding for question\n    query_embedding = get_embedding(question)\n    if not query_embedding:\n        return {\"error\": \"Embedding generation failed\"}\n\n    # 2. Search for relevant chunks\n    results = search_qdrant(query_embedding, limit=top_k)\n    if not results:\n        return {\"error\": \"No relevant documents found\"}\n\n    # 3. Build context\n    context = build_context(results)\n\n    # 4. Get answer from LLM\n    if use_claude and ANTHROPIC_API_KEY:\n        answer = ask_claude(question, context)\n    else:\n        answer = ask_ollama(question, context)\n\n    # 5. Get sources\n    sources = get_sources(results)\n\n    return {\"question\": question, \"answer\": answer, \"sources\": sources, \"chunks_used\": len(results)}\n\n\ndef interactive_mode():\n    \"\"\"Run interactive chat session.\"\"\"\n    print(\"=\" * 60)\n    print(\"RAG-Chat - Systemisches Teamcoaching\")\n    print(\"=\" * 60)\n    print(\"Frage stellen oder 'quit' zum Beenden\\n\")\n\n    while True:\n        try:\n            question = input(\"Du: \").strip()\n\n            if not question:\n                continue\n            if question.lower() in [\"quit\", \"exit\", \"q\"]:\n                print(\"Auf Wiedersehen!\")\n                break\n\n            print(\"\\nSuche relevante Dokumente...\")\n            result = chat(question)\n\n            if \"error\" in result:\n                print(f\"Fehler: {result['error']}\\n\")\n                continue\n\n            print(f\"\\nAssistent: {result['answer']}\\n\")\n\n            if result[\"sources\"]:\n                print(\"Quellen:\")\n                for src in result[\"sources\"]:\n                    print(f\"  - {src['title']} (Score: {src['score']})\")\n            print()\n\n        except KeyboardInterrupt:\n            print(\"\\n\\nAuf Wiedersehen!\")\n            break\n        except Exception as e:\n            print(f\"Fehler: {e}\\n\")\n\n\ndef main():\n    \"\"\"CLI entry point for interactive chat or single question mode.\"\"\"\n    if len(sys.argv) > 1:\n        # Single question mode\n        question = \" \".join(sys.argv[1:])\n        result = chat(question)\n\n        if \"error\" in result:\n            print(f\"Fehler: {result['error']}\")\n            return\n\n        print(f\"\\nAntwort: {result['answer']}\\n\")\n\n        if result[\"sources\"]:\n            print(\"Quellen:\")\n            for src in result[\"sources\"]:\n                print(f\"  - {src['title']} (Score: {src['score']})\")\n    else:\n        # Interactive mode\n        interactive_mode()\n\n\nif __name__ == \"__main__\":\n    main()\n",
            "numLines": 221,
            "startLine": 1,
            "totalLines": 221
        }
    }
}
← Vorheriger Zur Liste Nächster →