Protokoll #12827
| ID | 12827 |
|---|---|
| Zeitstempel | 2025-12-24 10:53:00.240165 |
| Client | root |
| 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 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 1,691 (Input: 0, Output: 0) |
| Dauer | 80 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
}
}
}