AI Engineering Academy · Lektion

Checkpointing og genoptagelse af opgaver

Gem agentens tilstand efter hvert gennemført trin, så en langvarig opgave kan genoptages fra det seneste vellykkede checkpoint i stedet for at blive startet forfra efter en fejl.

Lektion 3 af 413 trin

Checkpointing og genoptagelse af opgaver er en gratis AI Engineering Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i AI Engineering Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. AI Engineering Academy-kurset indeholder 4 lektioner i alt.

Problemet med langvarigt kørende agenter

En agent, der udfører en researchopgave på 50 trin, kan køre i 30 minutter. Hvis den fejler ved trin 47 på grund af en API-timeout eller en genstart af serveren, spildes alt det udførte arbejde ved en genstart fra begyndelsen, og det koster tokens. Kontrolpunkter gemmer agentens tilstand efter hvert gennemført trin, så opgaven kan genoptages fra det seneste vellykkede punkt i stedet for fra begyndelsen. Det er afgørende for alle agentopgaver, der varer længere end nogle få minutter.

Hvilken agenttilstand der skal bevares

En agents tilstand består af: opgavedefinitionen, de gennemførte trin med deres værktøjskald og observationer, indekset for det aktuelle trin, eventuelle akkumulerede resultater (skrevne filer og indsamlede data) samt metadata som starttidspunkt og samlet tokenforbrug. Gem alt dette, hver gang et trin er gennemført. Tilstanden skal kunne serialiseres — foretræk JSON frem for Python-objekter af hensyn til portabiliteten.

from dataclasses import dataclass, field
from typing import List, Any, Optional

@dataclass
class AgentStep:
    step_index: int
    thought: str
    tool_name: str
    tool_args: dict
    observation: str
    tokens_used: int
    completed_at: str

@dataclass
class AgentCheckpoint:
    task_id: str
    task_description: str
    status: str  # 'running', 'completed', 'failed'
    current_step: int
    completed_steps: List[AgentStep] = field(default_factory=list)
    accumulated_results: dict = field(default_factory=dict)
    total_tokens: int = 0
    final_answer: Optional[str] = None

Gem kontrolpunkter efter hvert trin

Efter hvert vellykket trin skal du serialisere kontrolpunktet og skrive det til et persistent lager. Brug en database eller objektlagring (S3, Redis) i stedet for en lokal disk, så kontrolpunktet overlever genstarter af serveren. Inkludér task_id i nøglen, så du kan hente et bestemt kontrolpunkt for en opgave. Skriv også en post i en trinlog for hvert trin, så du bevarer et revisionsspor, selv hvis kontrolpunktfilen bliver beskadiget.

import json
import redis
from dataclasses import asdict

redis_client = redis.Redis()

def save_checkpoint(checkpoint: AgentCheckpoint):
    key = f'agent:checkpoint:{checkpoint.task_id}'
    data = json.dumps(asdict(checkpoint), default=str)
    redis_client.set(key, data, ex=86400)  # 24h TTL
    # Also append to step log
    log_key = f'agent:log:{checkpoint.task_id}'
    if checkpoint.completed_steps:
        last = checkpoint.completed_steps[-1]
        redis_client.rpush(log_key, json.dumps(asdict(last), default=str))

def load_checkpoint(task_id: str) -> AgentCheckpoint | None:
    key = f'agent:checkpoint:{task_id}'
    data = redis_client.get(key)
    if data:
        return AgentCheckpoint(**json.loads(data))
    return None

Genoptagelse fra et kontrolpunkt

Når en opgave genoptages, skal du indlæse kontrolpunktet og genskabe agentens meddelelseshistorik ud fra de gennemførte trin. Start udførelsesløkken ved indekset for det næste trin, der ikke er gennemført. Modellen modtager sine tidligere tanker og observationer i meddelelseshistorikken, så den har fuld kontekst om det udførte arbejde og kan fortsætte uden at gentage det.

async def resume_or_start(task_id: str, task_description: str) -> str:
    checkpoint = load_checkpoint(task_id)
    if checkpoint and checkpoint.status == 'running':
        print(f'Resuming task {task_id} from step {checkpoint.current_step}')
        messages = rebuild_history(checkpoint)
        start_step = checkpoint.current_step
    else:
        print(f'Starting new task {task_id}')
        checkpoint = AgentCheckpoint(task_id=task_id, task_description=task_description, status='running', current_step=0)
        messages = [{'role': 'user', 'content': task_description}]
        start_step = 0
        save_checkpoint(checkpoint)
    return await run_agent_from(checkpoint, messages, start_step)

Genskab meddelelseshistorikken ud fra trin

Nøglen til genoptagelse er trofast at genskabe meddelelseshistorikken ud fra de gemte trin. Hvert gennemført trin svarer til en assistentmeddelelse (tanke + værktøjskald) og en værktøjsmeddelelse (observation). Afspil alle gennemførte trin som meddelelser, før du fortsætter, så modellen har den samme kontekst, som hvis den aldrig var blevet afbrudt.

def rebuild_history(checkpoint: AgentCheckpoint) -> list:
    messages = [{'role': 'user', 'content': checkpoint.task_description}]
    for step in checkpoint.completed_steps:
        # Reconstruct the agent's reasoning message
        messages.append({
            'role': 'assistant',
            'content': f'Thought: {step.thought}\nAction: {step.tool_name}({step.tool_args})'
        })
        # Reconstruct the tool observation
        messages.append({
            'role': 'user',
            'content': f'Observation: {step.observation}'
        })
    return messages

Idempotente værktøjskald

Hvis et trin kun blev delvist gennemført før et nedbrud (værktøjet blev kaldt, men observationen blev ikke gemt), kan genoptagelsen kalde værktøjet igen. Design værktøjer til at være idempotente: Når de kaldes to gange med de samme argumenter, skal resultatet være det samme som ved ét kald. Ved skrivehandlinger, f.eks. oprettelse af filer eller afsendelse af e-mails, skal du bruge deduplikeringsnøgler for at forhindre dublerede effekter, selv hvis værktøjet kaldes flere gange.

async def idempotent_write_file(content: str, path: str, task_id: str, step: int) -> str:
    dedup_key = f'{task_id}:step_{step}:write:{path}'
    if redis_client.exists(dedup_key):
        return f'File {path} already written (dedup key present)'
    with open(path, 'w') as f:
        f.write(content)
    redis_client.set(dedup_key, '1', ex=3600)
    return f'Successfully wrote {len(content)} chars to {path}'

Oprydning og opbevaring af kontrolpunkter

Kontrolpunkter bruger lagerplads og bør ikke ophobes ubegrænset. Fastlæg en opbevaringspolitik: Slet gennemførte kontrolpunkter efter 24 timer, slet fejlede kontrolpunkter efter 7 dage (til efterfølgende analyse), og slet aldrig kørende kontrolpunkter automatisk. Implementér et oprydningsjob i baggrunden, der kører hver time og fjerner udløbne kontrolpunkter i henhold til politikken.

from datetime import datetime, timedelta

RETENTION = {
    'completed': timedelta(hours=24),
    'failed': timedelta(days=7),
    'running': None  # never auto-delete
}

def cleanup_expired_checkpoints():
    now = datetime.utcnow()
    for key in redis_client.scan_iter('agent:checkpoint:*'):
        data = json.loads(redis_client.get(key))
        status = data.get('status', 'running')
        retention = RETENTION.get(status)
        if retention is None:
            continue
        started = datetime.fromisoformat(data.get('started_at', str(now)))
        if now - started > retention:
            redis_client.delete(key)

Kontrolpunkter i LangGraph

LangGraph har indbygget understøttelse af kontrolpunkter via klasserne MemorySaver og SqliteSaver. Tilknyt en kontrolpunktshåndtering til din graf, så hver nodeudførelse automatisk gemmes. Genoptag ved at kalde graph.invoke med det samme thread_id. LangGraph håndterer genskabelse af historikken og sporing af trin, så du ikke selv behøver at implementere logikken for kontrolpunkter.

from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.graph import StateGraph

# Create graph with persistent checkpointer
checkpointer = SqliteSaver.from_conn_string('/tmp/agent_state.db')
graph = StateGraph(AgentState)
graph.add_node('reason', reason_node)
graph.add_node('act', act_node)
# ... add edges ...
app = graph.compile(checkpointer=checkpointer)

# Run with thread_id - LangGraph auto-checkpoints
config = {'configurable': {'thread_id': 'task_abc123'}}
result = await app.ainvoke({'task': 'Research climate change'}, config)

# Resume same thread - LangGraph loads from checkpoint
result = await app.ainvoke({'task': 'Continue'}, config)

Distribuerede kontrolpunkter for parallelle agenter

Når flere agenter arbejder parallelt på delopgaver, skal hver agent have sit eget navnerum til kontrolpunkter. Brug en hierarkisk nøglestruktur: parent_task_id:sub_task_id. Den overordnede agents kontrolpunkt registrerer, hvilke delopgaver der er gennemført, og deres resultater. Når den overordnede agent genoptages, genbruger den resultaterne fra gennemførte delopgaver i kontrolpunktet i stedet for at køre dem igen.

async def parallel_with_checkpoints(parent_id: str, subtasks: list) -> list:
    results = []
    for i, subtask in enumerate(subtasks):
        sub_id = f'{parent_id}:sub_{i}'
        # Check if subtask already completed
        existing = load_checkpoint(sub_id)
        if existing and existing.status == 'completed':
            print(f'Sub-task {i} already done, using cached result')
            results.append(existing.final_answer)
        else:
            result = await run_agent(sub_id, subtask)
            results.append(result)
    return results

Test af genoptagelsesadfærd

Skriv integrationstests, der med vilje får agenten til at gå ned midt i en opgave, og verificér, at genoptagelsen giver det korrekte endelige resultat. Simulér et nedbrud ved at kaste en undtagelse ved et bestemt trinindeks. Efter genoptagelsen skal du kontrollere, at kun trinnene efter nedbruddet udføres igen, og ikke trinnene før det. Test også, at idempotente værktøjskald ikke skaber dublerede effekter, når et trin afspilles igen.

import pytest

@pytest.mark.asyncio
async def test_resumption_from_step_3():
    task_id = 'test_resume_001'
    # Run until step 3, then crash
    with pytest.raises(SimulatedCrash):
        await run_agent_crashing_at(task_id, 'Research AI trends', crash_at_step=3)

    checkpoint = load_checkpoint(task_id)
    assert checkpoint.current_step == 3
    assert len(checkpoint.completed_steps) == 3

    # Resume and complete
    result = await resume_or_start(task_id, 'Research AI trends')
    assert result is not None
    # Verify only steps 4+ were re-executed
    assert checkpoint_step_was_not_replayed(task_id, step=0)

Versionering af kontrolpunkter ved skemaændringer

Når du ændrer skemaet for AgentCheckpoint (ved at tilføje eller omdøbe felter), bliver gamle kontrolpunkter i lageret inkompatible. Håndtér dette med versionering af kontrolpunkter: Tilføj feltet checkpoint_version, og skriv migrationsfunktioner, der opgraderer gamle kontrolpunkter til det nye skema, når de indlæses. Det forhindrer nedbrud, når agenter genoptages efter en udrulning, der ændrede kontrolpunktformatet.

def load_and_migrate_checkpoint(task_id: str) -> AgentCheckpoint:
    raw = json.loads(redis_client.get(f'agent:checkpoint:{task_id}'))
    version = raw.get('checkpoint_version', '1.0')
    if version == '1.0':
        # Migrate: add new fields added in v2.0
        raw['checkpoint_version'] = '2.0'
        raw['accumulated_results'] = raw.get('accumulated_results', {})
        raw['total_tokens'] = raw.get('total_tokens', 0)
    return AgentCheckpoint(**raw)

Hurtig kontrol

Test din forståelse af kontrolpunkter og genoptagelse af opgaver i agenter.

Opsummering af lektionen

I denne lektion lærte du, at kontrolpunkter serialiserer agentens tilstand efter hvert trin, så langvarige opgaver kan overleve fejl uden at blive startet forfra, at genskabelse af meddelelseshistorikken ud fra gemte trin giver modellen fuld kontekst ved genoptagelse, og at idempotente værktøjer med deduplikeringsnøgler forhindrer dublerede effekter, når trin afspilles igen. Næste gang designer vi eskaleringstriggere til menneske-i-løkken.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “Checkpointing og genoptagelse af opgaver” gratis?

Ja — hele teksten til “Checkpointing og genoptagelse af opgaver” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af AI Engineering Academy-kurset, skal du opgradere til CoddyKit PRO. AI Engineering Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Checkpointing og genoptagelse af opgaver”?

Gem agentens tilstand efter hvert gennemført trin, så en langvarig opgave kan genoptages fra det seneste vellykkede checkpoint i stedet for at blive startet forfra efter en fejl. Du øver dig i AI Engineering Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på AI Engineering Academy?

Der kræves ingen tidligere erfaring. AI Engineering Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Checkpointing og genoptagelse af opgaver”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne AI Engineering Academy-lektion?

Ja. Alle AI Engineering Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Klassificering af agenters fejltilstande
  2. Selvkorrektion og refleksiv prompting
  3. Checkpointing og genoptagelse af opgaver
  4. Eskaleringsproces med mennesket i loopet
← Tilbage til AI Engineering Academy