Tekoälyagentit · Oppitunti

Asynkroninen Python agenttikehittäjille

asyncion perusteet, async def, await ja tapahtumasilmukka – asynkronisen toiminnan malli.

Oppitunti 1/413 vaihetta

Asynkroninen Python agenttikehittäjille on ilmainen Tekoälyagentit-oppitunti CoddyKitissä. Tämä on oppitunti 1/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.

Miksi asynkronisuutta agenteille?

Agentit tekevät paljon I/O-sidonnaisia kutsuja: LLM-rajapintakutsuja, verkkopyyntöjä ja tietokantakyselyjä. Synkroninen koodi odottaa joutilaana näiden kutsujen valmistumista. Asynkroninen koodi suorittaa muuta työtä odotusten aikana, mikä parantaa suorituskykyä huomattavasti.

Asynkronian perusteet: async def ja await

async def määrittelee korutiinifunktion. await keskeyttää suorituksen, kunnes odotettu toiminto valmistuu, jolloin tapahtumasilmukka voi sillä välin suorittaa muita korutiineja.

import asyncio

async def fetch_data(source: str) -> str:
    print(f'Starting fetch from {source}')
    await asyncio.sleep(1)  # Simulates a network call
    print(f'Finished fetch from {source}')
    return f'Data from {source}'

async def main():
    # Sequential: takes 2 seconds total
    result1 = await fetch_data('source-A')
    result2 = await fetch_data('source-B')
    print('Sequential results:', result1, result2)

asyncio.run(main())

# asyncio.run() starts the event loop and runs main()
# It is the entry point for async programs

Tapahtumasilmukka

tapahtumasilmukka on asyncio-kirjaston ydin. Se hallinnoi korutiinien ja I/O-takaisinkutsujen jonoa ja suorittaa niitä, kun ne ovat valmiita. Kaikki asynkroninen koodi suoritetaan tapahtumasilmukan sisällä yhdessä säikeessä.

import asyncio

async def task_a():
    print('Task A: start')
    await asyncio.sleep(2)
    print('Task A: done')

async def task_b():
    print('Task B: start')
    await asyncio.sleep(1)
    print('Task B: done')

async def main():
    # asyncio.gather runs both tasks concurrently
    # Total time: ~2 seconds (not 3)
    await asyncio.gather(task_a(), task_b())
    print('Both tasks complete')

# Expected output order:
# Task A: start
# Task B: start
# Task B: done   <- after 1s
# Task A: done   <- after 2s
# Both tasks complete
asyncio.run(main())

Korutiinit ja säikeet

Korutiinit toimivat yhteistyöhön perustuvasti: ne luovuttavat hallinnan eksplisiittisesti komennolla await. Säikeet toimivat ennakoivasti: käyttöjärjestelmä voi vaihtaa niiden välillä milloin tahansa. Korutiinit ovat kevyempiä, I/O-toiminnoissa ei esiinny GIL-ongelmia ja niiden toimintaa on helpompi hahmottaa.

import asyncio
import threading
import time

# Thread approach: multiple OS threads
def thread_worker(name):
    print(f'Thread {name}: start')
    time.sleep(1)  # Blocks the thread
    print(f'Thread {name}: done')

threads = [threading.Thread(target=thread_worker, args=(i,)) for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print('---')

# Coroutine approach: single-threaded event loop
async def coro_worker(name):
    print(f'Coro {name}: start')
    await asyncio.sleep(1)  # Suspends, does NOT block other coroutines
    print(f'Coro {name}: done')

async def main():
    await asyncio.gather(*[coro_worker(i) for i in range(3)])

asyncio.run(main())
# Both approaches run 3 tasks in ~1 second total, but coroutines use one thread

asyncio.run()-aloituskohta

asyncio.run() luo uuden tapahtumasilmukan, suorittaa annetun korutiinin loppuun ja sulkee silmukan. Se on asynkronisten Python-ohjelmien vakiomuotoinen aloituskohta Pythonin versiossa 3.7 ja sitä uudemmissa versioissa.

import asyncio

async def agent_main():
    print('Agent starting')
    # All agent async work goes here
    results = await asyncio.gather(
        asyncio.sleep(0.1),  # Simulated LLM call
        asyncio.sleep(0.1),  # Simulated DB query
    )
    print('Agent done')
    return 'complete'

# Run the agent
result = asyncio.run(agent_main())
print('Result:', result)

# WRONG: calling asyncio.run() inside an already-running event loop
# In Jupyter notebooks, use: await agent_main() directly
# Or: nest_asyncio.apply() then asyncio.run()

Yleinen virhe: estävä toiminto asynkronisessa kontekstissa

Älkää koskaan kutsuko estäviä toimintoja (time.sleep, requests.get, synkroninen tiedostojen I/O) asynkronisen koodin sisällä. Tämä estää koko tapahtumasilmukan toiminnan ja poistaa kaiken samanaikaisuuden.

import asyncio
import time
import httpx

# WRONG: blocks the event loop
async def bad_agent_step():
    time.sleep(2)          # Blocks all other coroutines
    # requests.get(url)    # Also blocks - do NOT use requests in async code
    return 'done'

# RIGHT: use async equivalents
async def good_agent_step():
    await asyncio.sleep(2)  # Suspends, other coroutines can run
    
    async with httpx.AsyncClient() as client:
        response = await client.get('https://api.example.com/data')
    return response.text

# For CPU-intensive work: use run_in_executor
import concurrent.futures

async def cpu_intensive_step(data: str):
    loop = asyncio.get_event_loop()
    with concurrent.futures.ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, expensive_cpu_fn, data)
    return result

def expensive_cpu_fn(data):
    # CPU-bound work runs in separate process
    return data.upper()

print('Blocking vs non-blocking patterns demonstrated')

await unohtui: hiljainen virhe

await-komennon unohtaminen ei aiheuta virhettä – sen sijaan palautetaan korutiiniobjekti tuloksen sijaan. Tämä on hiljainen virhe, joka aiheuttaa myöhemmin virheitä tai tyhjiä tuloksia.

import asyncio

async def get_answer() -> str:
    await asyncio.sleep(0.1)
    return 'The answer is 42'

async def bad_call():
    result = get_answer()   # WRONG: forgot await
    print(type(result))     # <class 'coroutine'> - not a string!
    # Using result as a string here causes AttributeError or wrong behavior
    return result

async def good_call():
    result = await get_answer()  # CORRECT
    print(type(result))           # <class 'str'>
    return result

async def main():
    bad = await bad_call()
    print('Bad result:', bad)    # coroutine object, not the string
    
    good = await good_call()
    print('Good result:', good)  # 'The answer is 42'
    
    # Clean up the uncollected coroutine
    if asyncio.iscoroutine(bad):
        bad.close()

asyncio.run(main())

Sisäkkäisten tapahtumasilmukoiden ongelma

asyncio.run()-funktion kutsuminen jo käynnissä olevan tapahtumasilmukan sisällä (esimerkiksi Jupyterissä tai FastAPI:ssa) aiheuttaa RuntimeError-virheen. Ratkaisuja ovat await-komennon käyttäminen suoraan tai nest_asyncio-kirjaston käyttäminen muistikirjoissa.

import asyncio

async def my_agent_coroutine():
    await asyncio.sleep(0.1)
    return 'done'

# In FastAPI or other async frameworks, the event loop is already running
# Use await directly in async endpoints:
async def fastapi_endpoint():
    # WRONG inside async context:
    # result = asyncio.run(my_agent_coroutine())  # RuntimeError!
    
    # CORRECT: just await
    result = await my_agent_coroutine()
    return result

# In Jupyter notebooks: install nest_asyncio
# import nest_asyncio
# nest_asyncio.apply()
# Then asyncio.run() works

# Detect if running in event loop:
def run_agent(coro):
    try:
        loop = asyncio.get_running_loop()
        # Already in async context
        import concurrent.futures
        with concurrent.futures.ThreadPoolExecutor() as pool:
            future = pool.submit(asyncio.run, coro)
            return future.result()
    except RuntimeError:
        # No running loop
        return asyncio.run(coro)

print('Nested event loop solution defined')

asyncio.create_task

Käyttäkää asyncio.create_task()-funktiota ajoittamaan korutiini suoritettavaksi ilman, että sen valmistumista odotetaan heti. Näin voitte käynnistää useita tehtäviä ja odottaa niiden valmistumista myöhemmin.

import asyncio

async def background_job(job_id: int) -> str:
    await asyncio.sleep(0.5)
    return f'Job {job_id} completed'

async def main():
    # Start all tasks without waiting
    task1 = asyncio.create_task(background_job(1))
    task2 = asyncio.create_task(background_job(2))
    task3 = asyncio.create_task(background_job(3))
    
    # Do other work while tasks run
    print('Tasks started, doing other work...')
    await asyncio.sleep(0.1)
    print('Other work done')
    
    # Now wait for all tasks
    results = await asyncio.gather(task1, task2, task3)
    print('All results:', results)
    
    # Or wait for the first to complete
    task_a = asyncio.create_task(background_job(4))
    task_b = asyncio.create_task(background_job(5))
    done, pending = await asyncio.wait([task_a, task_b], return_when=asyncio.FIRST_COMPLETED)
    for t in pending:
        t.cancel()  # Cancel remaining tasks
    print('First result:', done.pop().result())

asyncio.run(main())

Asynkroniset kontekstinhallintaohjelmat

Monet asynkroniset kirjastot käyttävät asynkronisia kontekstinhallintaohjelmia yhdessä komennon async with kanssa. Näin varmistetaan yhteyksien ja resurssien asianmukainen alustaminen ja vapauttaminen asynkronisessa koodissa.

import asyncio
import httpx

async def fetch_multiple_urls(urls: list) -> list:
    # async with ensures the client is properly closed
    async with httpx.AsyncClient(timeout=10.0) as client:
        # Fetch all URLs concurrently
        tasks = [client.get(url) for url in urls]
        responses = await asyncio.gather(*tasks, return_exceptions=True)
        
        results = []
        for url, response in zip(urls, responses):
            if isinstance(response, Exception):
                results.append({'url': url, 'error': str(response)})
            else:
                results.append({'url': url, 'status': response.status_code})
        return results

# Async generators for streaming
async def stream_agent_events():
    events = ['thinking', 'searching', 'generating', 'done']
    for event in events:
        await asyncio.sleep(0.2)  # Simulate event arrival
        yield event

async def consume_stream():
    async for event in stream_agent_events():
        print(f'Event: {event}')

asyncio.run(consume_stream())

Virheenkäsittely asynkronisessa koodissa

Käyttäkää komentoa asyncio.gather(..., return_exceptions=True) yksittäisten tehtävien virheiden käsittelemiseen ilman koko erän keskeyttämistä. Tarkistakaa jokaisesta tuloksesta, onko kyseessä poikkeustyyppi.

import asyncio

async def might_fail(task_id: int) -> str:
    await asyncio.sleep(0.1)
    if task_id == 2:
        raise ValueError(f'Task {task_id} failed')
    return f'Task {task_id} succeeded'

async def robust_gather():
    tasks = [might_fail(i) for i in range(1, 5)]
    
    # return_exceptions=True: exceptions are returned as values, not raised
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    successes = []
    failures = []
    for i, result in enumerate(results):
        if isinstance(result, Exception):
            failures.append({'task': i + 1, 'error': str(result)})
        else:
            successes.append(result)
    
    print(f'Succeeded: {len(successes)}, Failed: {len(failures)}')
    print('Failures:', failures)
    return successes, failures

asyncio.run(robust_gather())

Tietotesti: asynkroninen Python

Testatkaa ymmärrystänne asynkronisesta Pythonista agenttien kehityksessä.

Asynkronisen Pythonin yhteenveto

Agenttien kehittäjien asynkronisen Pythonin tärkeimmät säännöt ovat seuraavat: käyttäkää async def- ja await-rakenteita kaikissa I/O-sidonnaisissa toiminnoissa; älkää koskaan kutsuko estäviä toimintoja asynkronisessa kontekstissa; käyttäkää asyncio.gather()-funktiota rinnakkaiseen suoritukseen; käyttäkää return_exceptions=True-asetusta vikasietoisiin rinnakkaisiin kutsuihin; käyttäkää async with-rakennetta resurssien hallintaan; suorittakaa suorittimesta paljon kuormittava työ prosessijoukon suorittimessa.

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 ”Asynkroninen Python agenttikehittäjille” ilmainen?

Kyllä – oppitunnin ”Asynkroninen Python agenttikehittäjille” 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 ”Asynkroninen Python agenttikehittäjille”?

asyncion perusteet, async def, await ja tapahtumasilmukka – asynkronisen toiminnan malli. 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 1/4.

Kuinka kauan ”Asynkroninen Python agenttikehittäjille”-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. Asynkroninen Python agenttikehittäjille
  2. Tapahtumajonot ja viestinvälittäjät
  3. Työkalujen rinnakkainen suoritus ilman estävää odotusta
  4. Asynkroniset agenttikehykset: LangChain ja muut
← Takaisin: Tekoälyagentit