Tekoälyagentit · Oppitunti

Reflektio- ja itsekritiikkisyklit

Agentit, jotka arvioivat omia tuotoksiaan ja muodostavat parannusehdotuksia.

Oppitunti 2/413 vaihetta

Reflektio- ja itsekritiikkisyklit on ilmainen Tekoälyagentit-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Tekoälyagentit-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Tekoälyagentit-kurssilla on yhteensä 4 oppituntia.

Mitä on agentin itsereflektio?

Itsereflektio tarkoittaa käytäntöä, jossa agenttia pyydetään arvioimaan juuri valmistunutta tuotostaan ennen sen palauttamista käyttäjälle tai välittömästi sen jälkeen. Agentti toimii omana kriitikkonaan.

Tämä muistuttaa tapaa, jolla asiantuntijat tarkistavat työnsä: luonnostelu → kritiikki → korjaaminen. Tämän silmukan lisääminen agentteihin parantaa usein tuotosten laatua ilman muutoksia taustalla olevaan malliin.

Reflektiokehotteen malli

Kun agentti on tuottanut vastauksen, syöttäkää vastaus takaisin mallille rakenteisen reflektiokehotteen avulla. Malli tunnistaa tällöin heikkoudet ja ehdottaa parannuksia.

import anthropic

client = anthropic.Anthropic(api_key='YOUR_API_KEY')

def reflect_on_response(task: str, response: str) -> str:
    reflection_prompt = (
        'You just completed the following task:\n\n'
        f'TASK: {task}\n\n'
        f'YOUR RESPONSE:\n{response}\n\n'
        'Please reflect on your performance by answering:\n'
        '1. What did you do well?\n'
        '2. What could be improved?\n'
        '3. What would you do differently if you had to redo this?\n'
        'Be specific and honest.'
    )
    result = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=512,
        messages=[{'role': 'user', 'content': reflection_prompt}]
    )
    return result.content[0].text

Rakenteinen reflektiotulos

Rakenteista muotoa vailla olevaa reflektiotekstiä on vaikea käsitellä ohjelmallisesti. Pyytäkää mallia tuottamaan rakenteinen JSON-reflektio, jotta voitte poimia pisteet ja toimenpiteet luotettavasti.

STRUCTURED_REFLECTION_PROMPT = '''
Reflect on the task and response above. Return ONLY valid JSON:
{
  "strengths": ["..."],
  "weaknesses": ["..."],
  "alternative_approach": "...",
  "quality_score": 0.0,
  "retry_recommended": false
}
quality_score: 0.0 (terrible) to 1.0 (excellent).
retry_recommended: true if quality_score < 0.6.
'''

import json

def structured_reflect(task: str, response: str, client) -> dict:
    prompt = f'TASK: {task}\n\nRESPONSE: {response}\n\n{STRUCTURED_REFLECTION_PROMPT}'
    result = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=512,
        messages=[{'role': 'user', 'content': prompt}]
    )
    text = result.content[0].text.strip()
    # strip markdown code fences if present
    if text.startswith('```'):
        text = text.split('```')[1].lstrip('json').strip()
    return json.loads(text)

if __name__ == '__main__':
    class FakeContent:
        def __init__(self, text):
            self.text = text

    class FakeResponse:
        def __init__(self, text):
            self.content = [FakeContent(text)]

    class FakeMessages:
        def create(self, **kwargs):
            return FakeResponse(
                '{"strengths": ["clear"], "weaknesses": ["too long"], '
                '"alternative_approach": "be more concise", '
                '"quality_score": 0.7, "retry_recommended": false}'
            )

    class FakeClient:
        def __init__(self):
            self.messages = FakeMessages()

    result = structured_reflect('Summarize the article', 'A very long response...', FakeClient())
    print('quality_score:', result['quality_score'])
    print('weaknesses:', result['weaknesses'])

Itsekritiikkisilmukka: uusi yritys matalalla pistemäärällä

Kun reflektion pistemäärä jää kynnysarvon alle, tehtävä yritetään automaattisesti uudelleen käyttämällä reflektion heikkouksia ja vaihtoehtoista lähestymistapaa lisäkontekstina. Näin agentin yhden suorituksen sisälle muodostuu palautteeseen perustuva kehityssilmukka.

def agent_with_self_critique(task: str, client, max_retries: int = 2) -> str:
    response = run_agent(task, client)

    for attempt in range(max_retries):
        reflection = structured_reflect(task, response, client)
        print(f'Attempt {attempt+1} quality: {reflection["quality_score"]:.2f}')

        if not reflection['retry_recommended']:
            break

        # Enrich the task with reflection insights
        improved_task = (
            f'{task}\n\n'
            'Previous attempt weaknesses:\n'
            + '\n'.join(f'- {w}' for w in reflection['weaknesses'])
            + f'\n\nSuggested approach: {reflection["alternative_approach"]}'
        )
        response = run_agent(improved_task, client)

    return response

def run_agent(task: str, client) -> str:
    result = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=1024,
        messages=[{'role': 'user', 'content': task}]
    )
    return result.content[0].text

Reflektioiden episodinen muisti

Yksittäisestä reflektiosta on hyötyä kerran; tallennetut reflektiot muodostavat episodisen muistin, joka auttaa agenttia oppimaan istuntojen välillä. Jokainen reflektio on episodi: tehtävän konteksti + tapahtunut + agentin oppima asia.

from datetime import datetime
from dataclasses import dataclass, asdict
from typing import Optional

@dataclass
class ReflectionEpisode:
    episode_id: str
    task_type: str          # e.g. 'summarize', 'code_review', 'translate'
    task_summary: str       # short description (not full text)
    quality_score: float
    strengths: list
    weaknesses: list
    alternative_approach: str
    timestamp: str = ''

    def __post_init__(self):
        if not self.timestamp:
            self.timestamp = datetime.utcnow().isoformat()

    def to_dict(self) -> dict:
        return asdict(self)

# Example
episode = ReflectionEpisode(
    episode_id='ep_001',
    task_type='summarize',
    task_summary='Summarize a 5-page financial report',
    quality_score=0.55,
    strengths=['Identified key figures'],
    weaknesses=['Too verbose', 'Missed conclusion'],
    alternative_approach='Lead with the executive summary first'
)
print(episode.to_dict())

Reflektioiden pysyvä tallentaminen

Tallentakaa reflektioepisodit pysyvästi JSON-tiedostoon tai tietokantaan. Ladatkaa käynnistyksen yhteydessä viimeisimmät saman tehtävätyypin episodit ja lisätkää ne kontekstiksi — agentti oppii omasta aiemmasta suoriutumisestaan.

import json
import os

MEMORY_FILE = 'agent_episodic_memory.json'

def save_episode(episode: ReflectionEpisode):
    episodes = load_all_episodes()
    episodes.append(episode.to_dict())
    with open(MEMORY_FILE, 'w') as f:
        json.dump(episodes, f, indent=2)

def load_all_episodes() -> list:
    if not os.path.exists(MEMORY_FILE):
        return []
    with open(MEMORY_FILE) as f:
        return json.load(f)

def load_recent_episodes(task_type: str, n: int = 3) -> list:
    all_ep = load_all_episodes()
    matching = [e for e in all_ep if e['task_type'] == task_type]
    # Sort by timestamp descending, take most recent n
    matching.sort(key=lambda e: e['timestamp'], reverse=True)
    return matching[:n]

Aiemman reflektion lisääminen kontekstiksi

Ennen tehtävän aloittamista hakekaa viimeisimmät kyseisen tehtävätyypin episodiset reflektiot ja sisällyttäkää ne järjestelmäkehotteeseen. Agentti tietää nyt, mitä virheitä se teki viimeksi, ja voi välttää niitä ennakoivasti.

def build_system_prompt_with_memory(task_type: str) -> str:
    base = 'You are a helpful AI assistant. Complete the task carefully.'
    episodes = load_recent_episodes(task_type, n=3)

    if not episodes:
        return base

    memory_block = '\n\nYour recent performance on similar tasks:\n'
    for ep in episodes:
        memory_block += (
            f'- Score {ep["quality_score"]:.2f}: '
            f'Weaknesses: {ep["weaknesses"]}. '
            f'Better approach: {ep["alternative_approach"]}\n'
        )
    memory_block += '\nApply these lessons to your current response.'
    return base + memory_block

# Before each task:
system_prompt = build_system_prompt_with_memory('summarize')
print(system_prompt[:300])

Työkalujen käytön reflektointi

Reflektioista on vielä enemmän hyötyä työkaluja käyttävillä agenteilla, jotka voivat arvioida työkalukutsustrategiaansa: käyttikö agentti oikeita työkaluja oikeassa järjestyksessä ja oikeilla parametreilla?

TOOL_REFLECTION_PROMPT = '''
You completed a multi-step task using tools. Reflect on your tool usage:

Tool call log:
{tool_log}

Final result: {result}

Answer:
1. Were all tool calls necessary?
2. Were there redundant or incorrect calls?
3. What is the optimal tool sequence for this task type?

Return JSON:
{{
  "redundant_calls": [],
  "incorrect_calls": [],
  "optimal_sequence": [],
  "efficiency_score": 0.0
}}
'''

def reflect_on_tool_use(tool_log: list, result: str, client) -> dict:
    import json
    log_str = json.dumps(tool_log, indent=2)
    prompt = TOOL_REFLECTION_PROMPT.format(
        tool_log=log_str, result=result
    )
    response = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=512,
        messages=[{'role': 'user', 'content': prompt}]
    )
    return json.loads(response.content[0].text)

if __name__ == '__main__':
    class FakeContent:
        def __init__(self, text):
            self.text = text

    class FakeResponse:
        def __init__(self, text):
            self.content = [FakeContent(text)]

    class FakeMessages:
        def create(self, **kwargs):
            return FakeResponse(
                '{"redundant_calls": ["search(x)"], "incorrect_calls": [], '
                '"optimal_sequence": ["search", "summarize"], "efficiency_score": 0.8}'
            )

    class FakeClient:
        def __init__(self):
            self.messages = FakeMessages()

    tool_log = [{'tool': 'search', 'args': {'q': 'x'}}, {'tool': 'search', 'args': {'q': 'x'}}]
    reflection = reflect_on_tool_use(tool_log, 'Found the answer', FakeClient())
    print('Efficiency score:', reflection['efficiency_score'])
    print('Redundant calls:', reflection['redundant_calls'])

Episodisen muistin vanheneminen ja karsiminen

Vanhat reflektiot vanhenevat, jos maailma muuttuu tai malli päivitetään. Toteuttakaa vanheneminen painottamalla viimeisimpiä episodeja enemmän ja karsimalla kynnysarvoa vanhemmat tai erittäin heikon laatupistemäärän saaneet episodit, sillä ne ovat voineet olla poikkeamia.

from datetime import datetime, timedelta

def prune_old_episodes(
    episodes: list,
    max_age_days: int = 30,
    min_quality: float = 0.0
) -> list:
    cutoff = datetime.utcnow() - timedelta(days=max_age_days)
    kept = []
    for ep in episodes:
        ep_time = datetime.fromisoformat(ep['timestamp'])
        if ep_time >= cutoff and ep['quality_score'] >= min_quality:
            kept.append(ep)
    return kept

def weighted_episodes(episodes: list) -> list:
    now = datetime.utcnow()
    for ep in episodes:
        age_days = (now - datetime.fromisoformat(ep['timestamp'])).days
        # Recency weight: 1.0 today, halves every 7 days
        ep['weight'] = 0.5 ** (age_days / 7)
    return sorted(episodes, key=lambda e: e['weight'], reverse=True)

if __name__ == '__main__':
    now = datetime.utcnow()
    episodes = [
        {'timestamp': (now - timedelta(days=2)).isoformat(), 'quality_score': 0.9, 'content': 'recent good episode'},
        {'timestamp': (now - timedelta(days=45)).isoformat(), 'quality_score': 0.8, 'content': 'old episode'},
        {'timestamp': (now - timedelta(days=10)).isoformat(), 'quality_score': 0.3, 'content': 'low quality episode'},
    ]
    kept = prune_old_episodes(episodes, max_age_days=30, min_quality=0.5)
    print(f'Kept {len(kept)} of {len(episodes)} episodes after pruning')
    for ep in weighted_episodes(kept):
        print(f"  weight={ep['weight']:.3f} content={ep['content']}")

Reflektion tehokkuuden mittaaminen

Seuratkaa, parantaako itsekritiikki todella tuloksia, vertaamalla ensimmäisten yritysten ja lopullisten, reflektion jälkeisten yritysten laatupisteitä. Jos parannus on vähäinen tai tulokset heikkenevät, reflektiokehote saattaa tarvita säätämistä.

def measure_reflection_gain(run_log: list) -> dict:
    """
    run_log: list of dicts with keys 'attempt', 'quality_score'
    e.g. [{'attempt': 1, 'quality_score': 0.55}, {'attempt': 2, 'quality_score': 0.78}]
    """
    if not run_log:
        return {}

    first_score = run_log[0]['quality_score']
    best_score = max(r['quality_score'] for r in run_log)
    final_score = run_log[-1]['quality_score']

    return {
        'first_attempt_score': first_score,
        'final_score': final_score,
        'best_score': best_score,
        'absolute_gain': final_score - first_score,
        'relative_gain_pct': ((final_score - first_score) / max(first_score, 0.001)) * 100,
        'retries': len(run_log) - 1
    }

log = [
    {'attempt': 1, 'quality_score': 0.55},
    {'attempt': 2, 'quality_score': 0.78}
]
print(measure_reflection_gain(log))

Reflektiosilmukan suojatoimet

Ilman rajoituksia reflektiosilmukka voi jatkua loputtomiin. Asettakaa aina enimmäismäärä uudelleenyrityksille, vähimmäispistekynnys aikaiselle lopetukselle ja aikabudjetti. Lokittakaa kaikki reflektiot, jotta voitte tarkastaa silmukan toiminnan.

import time

def safe_reflection_loop(
    task: str,
    client,
    max_retries: int = 3,
    quality_target: float = 0.75,
    time_budget_seconds: float = 30.0
) -> dict:
    start = time.time()
    response = run_agent(task, client)
    run_log = []

    for attempt in range(max_retries + 1):
        if time.time() - start > time_budget_seconds:
            print('Time budget exceeded, returning best result')
            break
        reflection = structured_reflect(task, response, client)
        run_log.append({'attempt': attempt + 1,
                        'quality_score': reflection['quality_score']})

        if reflection['quality_score'] >= quality_target:
            print(f'Quality target reached at attempt {attempt + 1}')
            break
        if attempt < max_retries:
            response = run_agent(task + '\n' + reflection['alternative_approach'], client)

    return {'response': response, 'run_log': run_log,
            'gain': measure_reflection_gain(run_log)}

Tietotesti

Mikä on reflektioepisodien episodiseksi muistiksi tallentamisen tärkein hyöty?

Kertaus: reflektio- ja itsekritiikkisilmukat

Erinomaista! Tässä on yhteenveto tämän oppitunnin asioista:

  • Reflektiokehote: rakenteinen JSON, joka sisältää vahvuudet, heikkoudet, laatupisteet ja uudelleenyrityksen lipun
  • Itsekritiikkisilmukka: uusi yritys matalalla pistemäärällä, jolloin tehtävää täydennetään reflektion havainnoilla
  • Episodinen muisti: reflektioiden tallentaminen aikaleimatuiksi episodeiksi tehtävätyypin mukaan
  • Muistin lisääminen kontekstiin: viimeisimpien episodien lataaminen järjestelmäkehotteeseen ennen jokaista suoritusta
  • Suojatoimet: enimmäismäärä uudelleenyrityksiä, aikabudjetti ja aikainen lopetus laatutavoitteen täyttyessä

Seuraavaksi käsitellään sitä, miten onnistuneita ja epäonnistuneita suorituspolkuja voidaan hyödyntää syvempään itsekehitykseen.

Aloita maksutta

Opi Tekoälyagentit tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
60
Oppitunnit
239

Usein kysytyt kysymykset

Onko oppitunti ”Reflektio- ja itsekritiikkisyklit” ilmainen?

Kyllä – oppitunnin ”Reflektio- ja itsekritiikkisyklit” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Tekoälyagentit-kurssin, päivitä CoddyKit PROhon. Tekoälyagentit-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Reflektio- ja itsekritiikkisyklit”?

Agentit, jotka arvioivat omia tuotoksiaan ja muodostavat parannusehdotuksia. Harjoittelet Tekoälyagentit-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Tekoälyagentit-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Tekoälyagentit-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Reflektio- ja itsekritiikkisyklit”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Tekoälyagentit-oppitunnilla?

Kyllä. Jokainen Tekoälyagentit-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Palautteen kerääminen ja tallentaminen
  2. Reflektio- ja itsekritiikkisyklit
  3. Toimintoratoihin perustuva itsensä kehittäminen
  4. Kun itsensä kehittäminen menee pieleen
← Takaisin: Tekoälyagentit