Feedback erfassen und speichern
Explizite Bewertungen und implizite Verhaltenssignale aus Agenteninteraktionen erfassen.
Feedback erfassen und speichern ist eine kostenlose AI Agents-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Agents-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.
Warum Agenten Feedback benötigen
Ein Agent, der nie Feedback erhält, bleibt auf dem Stand seiner ursprünglichen Schulung — er kann sich nicht weiter verbessern. Feedback schließt die Lücke zwischen dem, was der Agent tut, und dem, was Benutzer tatsächlich möchten.
Zwei Kategorien sind besonders wichtig: explizites Feedback (der Benutzer bewertet die Ausgabe bewusst) und implizites Feedback (das Verhalten des Benutzers signalisiert die Qualität, ohne dass er dies ausdrücklich sagt).
Explizites Feedback: Daumen hoch/runter
Die einfachste Form: ein binäres Signal nach jeder Antwort. Es ist leicht zu erfassen und zu speichern, enthält aber nur wenige Informationen.
Implementierungsmuster: Bieten Sie nach der Antwort des Agenten eine Feedbackabfrage an und speichern Sie das Ergebnis zusammen mit der ID des Konversationsabschnitts.
import uuid
from datetime import datetime
def collect_thumbs_feedback(turn_id: str, rating: str) -> dict:
"""rating: 'up' or 'down'"""
assert rating in ('up', 'down'), 'Invalid rating'
record = {
'feedback_id': str(uuid.uuid4()),
'turn_id': turn_id,
'type': 'thumbs',
'value': 1 if rating == 'up' else -1,
'created_at': datetime.utcnow().isoformat()
}
return record
feedback = collect_thumbs_feedback('turn_abc123', 'up')
print(feedback)Explizites Feedback: Sternebewertungen
Eine Bewertung mit 1 bis 5 Sternen bietet eine feinere Abstufung als eine Daumenbewertung. Sie ermöglicht die Unterscheidung zwischen gerade noch akzeptabel (2 Sterne) und hervorragend (5 Sterne), was für eine präzise Qualität des Trainingssignals nützlich ist.
Normalisieren Sie den Wert auf 0 bis 1, bevor Sie ihn in Trainingspipelines verwenden.
def collect_star_feedback(turn_id: str, stars: int) -> dict:
if not 1 <= stars <= 5:
raise ValueError('Stars must be between 1 and 5')
return {
'turn_id': turn_id,
'type': 'star',
'raw_value': stars,
'normalized': (stars - 1) / 4.0 # maps 1->0.0, 5->1.0
}
fb = collect_star_feedback('turn_xyz456', 4)
print(fb)
# {'turn_id': 'turn_xyz456', 'type': 'star', 'raw_value': 4, 'normalized': 0.75}Explizites Feedback: Korrekturen im Freitext
Freitext-Feedback ist das aussagekräftigste Signal. Der Benutzer schreibt genau, was er wollte: „Die Zusammenfassung war zu lang“, „Sie haben den Hauptpunkt übersehen“, „Falsche Währung — ich habe nach EUR gefragt“.
Speichern Sie Korrekturen zusammen mit der ursprünglichen Ausgabe, damit Sie später Paare aus (fehlerhafte Ausgabe → korrigierte Ausgabe) für überwachtes Fine-Tuning bilden können.
def collect_correction_feedback(
turn_id: str,
original_output: str,
corrected_output: str,
user_note: str = ''
) -> dict:
return {
'turn_id': turn_id,
'type': 'correction',
'original': original_output,
'corrected': corrected_output,
'user_note': user_note
}
fb = collect_correction_feedback(
'turn_789',
'The capital of Australia is Sydney.',
'The capital of Australia is Canberra.',
'Sydney is the largest city but not the capital.'
)
print(fb)Implizites Feedback: Signal durch erneute Fragen
Wenn ein Benutzer unmittelbar dieselbe Frage mit anderen Worten erneut stellt, ist dies ein starkes implizites Signal dafür, dass die vorherige Antwort falsch oder unzureichend war. Der Benutzer muss nichts anklicken — sein Verhalten selbst ist das Signal.
from datetime import datetime, timedelta
def detect_re_ask(
current_msg: str,
conversation_history: list,
similarity_threshold: float = 0.7,
window_seconds: int = 120
) -> bool:
"""
Returns True if the current message is semantically similar
to a recent message, suggesting dissatisfaction.
"""
now = datetime.utcnow()
for turn in conversation_history[-5:]:
age = (now - turn['timestamp']).seconds
if age <= window_seconds and turn['role'] == 'user':
# In production: use embedding cosine similarity
if simple_similarity(current_msg, turn['content']) >= similarity_threshold:
return True
return False
def simple_similarity(a: str, b: str) -> float:
words_a = set(a.lower().split())
words_b = set(b.lower().split())
if not words_a or not words_b:
return 0.0
return len(words_a & words_b) / len(words_a | words_b)
if __name__ == '__main__':
now = datetime.utcnow()
history = [
{'role': 'user', 'content': 'How do I reset my password', 'timestamp': now - timedelta(seconds=30)},
]
result = detect_re_ask('How do I reset my password please', history)
print('Re-ask detected:', result)
Implizites Feedback: Signal durch Bearbeitung der Ausgabe
Wenn der Agent Text erzeugt und der Benutzer ihn vor der Verwendung bearbeitet, ist die Differenz zwischen dem Original und der bearbeiteten Version implizites Feedback. Die bearbeitete Version entspricht dem, was der Benutzer tatsächlich wollte.
Dies ist bei Schreibassistenten, Codegeneratoren und E-Mail-Entwürfen üblich.
import difflib
def extract_edit_feedback(original: str, edited: str) -> dict:
differ = difflib.unified_diff(
original.splitlines(),
edited.splitlines(),
lineterm=''
)
diff_lines = list(differ)
edit_ratio = difflib.SequenceMatcher(None, original, edited).ratio()
return {
'type': 'edit',
'original': original,
'edited': edited,
'edit_distance': 1.0 - edit_ratio, # 0=unchanged, 1=fully rewritten
'diff': '\n'.join(diff_lines)
}
fb = extract_edit_feedback(
'Dear John, I am writing to inform you...',
'Hi John, Just a quick note...'
)
print(f"Edit distance: {fb['edit_distance']:.2f}")Schema zur Speicherung von Feedback
Alle Feedbacktypen verwenden ein gemeinsames Schema mit typspezifischen Nutzdatenfeldern. Eine einzelne Tabelle mit einem type-Diskriminator und einer payload-JSON-Spalte hält Abfragen einfach und unterstützt zugleich jeden Feedbacktyp.
# SQL schema for feedback storage
CREATE_TABLE_SQL = '''
CREATE TABLE agent_feedback (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id TEXT NOT NULL,
turn_id TEXT NOT NULL,
agent_id TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN ('thumbs','star','correction','re_ask','edit')),
value FLOAT, -- numeric signal: +1/-1, 0-1, edit distance
payload JSONB, -- type-specific data
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX ON agent_feedback (agent_id, created_at);
CREATE INDEX ON agent_feedback (type);
'''
# Example insert
INSERT_SQL = '''
INSERT INTO agent_feedback (session_id, turn_id, agent_id, type, value, payload)
VALUES ($1, $2, $3, $4, $5, $6)
'''
if __name__ == '__main__':
print('Feedback table schema:')
print(CREATE_TABLE_SQL)
print('Insert statement:')
print(INSERT_SQL)
Eine FeedbackCollector-Klasse schreiben
Wenn die gesamte Feedbackerfassung hinter einer einzigen Klasse zentralisiert wird, bleibt der übrige Codebestand übersichtlich. Der Collector übernimmt Deduplizierung, Bündelung und asynchrone Schreibvorgänge, sodass Feedback niemals die Hauptschleife des Agenten blockiert.
import asyncio
from collections import deque
from datetime import datetime
class FeedbackCollector:
def __init__(self, agent_id: str, flush_interval: int = 30):
self.agent_id = agent_id
self.buffer: deque = deque(maxlen=1000)
self.flush_interval = flush_interval
def record(self, turn_id: str, fb_type: str, value: float, payload: dict):
self.buffer.append({
'turn_id': turn_id,
'agent_id': self.agent_id,
'type': fb_type,
'value': value,
'payload': payload,
'created_at': datetime.utcnow().isoformat()
})
async def flush(self, db_client):
while self.buffer:
record = self.buffer.popleft()
await db_client.insert('agent_feedback', record)
async def start_auto_flush(self, db_client):
while True:
await asyncio.sleep(self.flush_interval)
await self.flush(db_client)
if __name__ == '__main__':
fc = FeedbackCollector(agent_id='agent-1')
fc.record('turn-1', 'thumbs', 1.0, {'comment': 'Great answer'})
fc.record('turn-2', 'thumbs', -1.0, {'comment': 'Wrong ticker'})
print(f'Buffered {len(fc.buffer)} feedback records:')
for rec in fc.buffer:
print(' -', rec['type'], rec['value'], rec['payload'])
Feedback zur Analyse aggregieren
Unbearbeitete Feedbackdatensätze müssen aggregiert werden, bevor sie für Verbesserungsentscheidungen nützlich sind. Häufige Aggregationen sind die Genehmigungsrate pro Intent-Typ, die Korrekturrate im Zeitverlauf und die Kategorien der am häufigsten bearbeiteten Ausgaben.
from collections import defaultdict
from statistics import mean
def aggregate_feedback(records: list) -> dict:
by_type = defaultdict(list)
for r in records:
by_type[r['type']].append(r['value'])
summary = {}
if 'thumbs' in by_type:
values = by_type['thumbs']
summary['approval_rate'] = (values.count(1) / len(values)) * 100
if 'star' in by_type:
summary['avg_star'] = mean(by_type['star']) * 4 + 1 # denormalize
if 'edit' in by_type:
summary['avg_edit_distance'] = mean(by_type['edit'])
if 'correction' in by_type:
summary['correction_count'] = len(by_type['correction'])
return summary
records = [
{'type': 'thumbs', 'value': 1},
{'type': 'thumbs', 'value': -1},
{'type': 'star', 'value': 0.75},
{'type': 'edit', 'value': 0.3}
]
print(aggregate_feedback(records))Datenschutz und Einwilligung bei der Feedbackerfassung
Feedback enthält häufig sensible Benutzerdaten. Bewährte Vorgehensweisen: Holen Sie vor der Aufzeichnung von Freitextkorrekturen eine ausdrückliche Einwilligung ein, anonymisieren Sie Sitzungs-IDs vor der Analyse, legen Sie Aufbewahrungsfristen fest (z. B. Löschung nach 90 Tagen) und protokollieren Sie niemals PII in Feedbacknutzdaten.
import hashlib
import re
def anonymise_feedback(record: dict) -> dict:
"""Anonymise feedback record before storing for training."""
safe = record.copy()
# Hash the session_id so it can't be traced back to a user
if 'session_id' in safe:
safe['session_id'] = hashlib.sha256(
safe['session_id'].encode()
).hexdigest()[:16]
# Strip emails and phone numbers from correction text
if 'payload' in safe and 'corrected' in safe['payload']:
text = safe['payload']['corrected']
text = re.sub(r'[\w.+-]+@[\w-]+\.[\w.]+', '[EMAIL]', text)
text = re.sub(r'\+?[0-9][\s\-().]{7,}[0-9]', '[PHONE]', text)
safe['payload'] = dict(safe['payload'], corrected=text)
return safe
if __name__ == '__main__':
record = {
'session_id': 'sess-abc123',
'payload': {'corrected': 'Contact me at jane@example.com or 555-123-4567'}
}
print('Anonymised record:', anonymise_feedback(record))
End-to-End-Feedbackpipeline
Alles zusammengeführt: erfassen → anonymisieren → puffern → leeren → aggregieren → berichten. Die Pipeline läuft in der Produktion neben dem Agenten und erstellt wöchentlich einen Verbesserungsbericht, der zeigt, für welche Intents die Genehmigungsraten am niedrigsten sind.
# Simplified end-to-end feedback pipeline sketch
class FeedbackPipeline:
def __init__(self, agent_id: str):
self.collector = FeedbackCollector(agent_id)
self.records = []
def on_thumbs(self, turn_id: str, rating: str):
value = 1.0 if rating == 'up' else -1.0
record = self.collector.record(turn_id, 'thumbs', value, {})
self.records.append(record)
def on_edit(self, turn_id: str, original: str, edited: str):
fb = extract_edit_feedback(original, edited)
record = self.collector.record(
turn_id, 'edit', fb['edit_distance'], fb
)
self.records.append(record)
def weekly_report(self) -> dict:
return aggregate_feedback(
[r for r in self.records]
)Wissenscheck
Welches Feedbacksignal erfordert keine bewusste Handlung des Benutzers?
Zusammenfassung: Feedback erfassen und speichern
Großartige Arbeit! Das haben Sie in dieser Lektion gelernt:
- Explizites Feedback: Daumenbewertungen (binär), Sterne (abgestuft), Korrekturen (gepaarte Trainingsdaten)
- Implizites Feedback: Erkennung erneuter Fragen und Signale aus der Bearbeitungsdistanz von Ausgaben messen die Qualität ohne Aufwand für den Benutzer
- Speicherschema: eine einzelne Tabelle mit Typ-Diskriminator und JSONB-Nutzdaten
- Pipeline: erfassen → anonymisieren → puffern → leeren → aggregieren
- Datenschutz: Sitzungs-IDs hashen, PII entfernen, Aufbewahrungsfristen festlegen
In der nächsten Lektion lernen Sie, wie Agenten über ihre eigene Leistung reflektieren und diese Reflexionen als episodisches Gedächtnis speichern können.
Lerne AI Agents mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 60
- Lektionen
- 239
Häufig gestellte Fragen
Ist die Lektion „Feedback erfassen und speichern“ kostenlos?
Ja — der vollständige Text von „Feedback erfassen und speichern“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Agents-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Feedback erfassen und speichern“?
Explizite Bewertungen und implizite Verhaltenssignale aus Agenteninteraktionen erfassen. Du übst AI Agents mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um AI Agents zu starten?
Keine Vorkenntnisse erforderlich. AI Agents auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Feedback erfassen und speichern“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser AI Agents-Lektion Code schreiben und ausführen?
Ja. Jede AI Agents-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Feedback erfassen und speichern
- Reflexions- und Selbstkritikschleifen
- Trajektorienbasiertes Selbstverbessern
- Wenn Selbstverbesserung schiefgeht