Tekoälyagenttien suunnittelu ja rakentaminen
Olen viime kuukausina päässyt suunnittelemaan ja rakentamaan suurehkoa tekoälyagentteihin pohjautuvaa järjestelmää. Tässä prosessissa olen oppinut jonkin verran siitä, millaiset ratkaisut tekoälyagenttien suunnittelussa ja toteutuksessa toimivat parhaiten. Koitin tiivistää tähän artikkeliin keskeisimmät opit ja jonkinlaisen kuvauksen filosofiasta, jota pyrin noudattamaan tekoälyagentteja rakentaessani.
Miten agenttipohjaiset järjestelmät toimivat?
Agenttipohjaisissa järjestelmissä on yleensä useita itsenäisiä agentteja, joilla on omat roolinsa ja tehtävänsä. ”Agentti” on varmasti monelle tuttu termi erilaisista tekoälyavustajista, mutta tässä yhteydessä agentilla tarkoitetaan käytännössä itsenäisesti toimivaa yksikköä, joka toimii suuren kielimallin päällä. Kullakin agentilla on oma kontekstinsa kielimallin suhteen, joten ne voidaan alustaa keskenään täysin erilaisilla tiedoilla (kuten: ”olet C-koodari” tai ”olet puutarhuri”) ja niille voidaan määritellä täysin yksilölliset tavoitteet ja keinot niiden saavuttamiseen.
Nämä agentit kommunikoivat keskenään ja tekevät yhteistyötä saavuttaakseen yhteisen tavoitteen. Agentit ovat yleensä erikoistuneita tiettyihin tehtäviin, kuten tiedonhakuun, analysointiin tai päätöksentekoon. Yksi agentti voi esimerkiksi olla vastuussa käyttäjän syötteen käsittelystä, toinen agentti voi hakea tarvittavat tiedot, ja kolmas agentti voi analysoida tiedot ja tehdä suosituksia käyttäjälle.
Agenteilla on käytössään erilaisia työkaluja ja resursseja, joita ne voivat hyödyntää tehtäviensä suorittamisessa. Ne voivat esimerkiksi käyttää ulkoisia rajapintoja, tietokantoja tai muita järjestelmiä saadakseen tarvitsemansa tiedot tai suorittaakseen toimintoja. Ajatuksena on, että agentit toimivat hyvin itsenäisesti, mutta samalla ne pystyvät tekemään yhteistyötä ja jakamaan tietoa keskenään.
Yksittäisen agentin suorittama yksittäinen tehtävä on keskustelu kielimallin (LLM) kanssa. Agentti antaa LLM:lle syötteen, joka sisältää sekä itse kulloinkin suoritettavan agentin että tehtävän kuvauksen ja mahdollisesti muita ohjeita tai kontekstia. LLM käsittelee syötteen ja palauttaa vastauksen, jolla agentti sitten jatkaa tehtävän suorittamista. Tämä prosessi toistuu, kunnes agentti on suorittanut koko tehtävänsä. Lue myös blogiartikkelimme miten LLMs.txt voi tarjota uuden tavan tehdä verkkosivuista AI-ystävällisemmät.
Millaisia ongelmia agenttipohjaisissa järjestelmissä on?
Agenttipohjaisen järjestelmän suunnittelussa ja toteutuksessa on melko uniikkeja haasteita, joiden ratkaiseminen vaatii erityistä huomiota. Yksi keskeisimmistä ongelmista on agenttien välinen kommunikaatio ja yhteistyö. Koska agentit toimivat itsenäisesti, niiden on pystyttävä jakamaan tietoa ja tekemään yhteistyötä tehokkaasti. Tämä vaatii selkeät rajapinnat ja protokollat, joiden avulla agentit voivat kommunikoida keskenään.
Toinen merkittävä ongelma on agenttien suorituskyky ja kokonaisjärjestelmän skaalautuvuus. LLM-keskusteluiden käyminen ei lähtökohtaisesti ole kovin nopeaa, eikä niiden lisääminen ainakaan paranna järjestelmän suorituskykyä.
Kolmas – ja ehkä hankalin – ongelma on agenttien non-deterministinen luonne. Koska LLM-mallien toiminnan ennustettavuus ei ole kovinkaan hyvä, agenttien käyttäytyminen voi vaihdella merkittävästi eri suorituskertojen välillä. Tämä tekee järjestelmän testaamisesta ja virheiden korjaamisesta haastavaa, koska samat syötteet johtavat erilaisiin lopputuloksiin eri aikoina.
Näiden lisäksi ongelmia on helposti myös virheiden käsittelyssä, tilanhallinnassa sekä järjestelmän yleisessä ylläpidettävyydessä. Agenttipohjaiset järjestelmät voivat nopeasti kasvaa monimutkaisiksi, mikä tekee niiden hallinnasta ja päivittämisestä haastavaa. Ja kuten LLM:ien kanssa yleensäkin, myös agenttipohjaisissa järjestelmissä kontekstin hallinta on kriittinen osa onnistunutta toteutusta.
Mikä on hyvä lähestymistapa agenttipohjaisten järjestelmien suunnitteluun?
Varsin hyvän lähestymistavan agenttipohjaisten järjestelmien suunnitteluun tarjoaa Unix-filosofia. Unix-filosofian tarkennettu ja virtaviivaistettu muoto kuuluu näin:
Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.
— Doug McIlroy
Tämä filosofia istuu agenttipohjaisten järjestelmien suunnitteluun kuin nenä päähän! Jokainen agentti on kuin pieni ohjelma, joka tekee yhden asian hyvin. Agentit on suunniteltu toimimaan yhdessä, jakamaan tietoa ja tekemään yhteistyötä. Ja koska agentit kommunikoivat keskenään tekstipohjaisen rajapinnan kautta (kuten LLM-keskustelut), ne noudattavat myös tekstivirtojen käsittelyn periaatetta.
Yksi Unix-mantra on myös ”Everything is a file.” Tiedostojen merkitystä myöskään agenttipohjaisissa järjestelmissä ei kannata aliarvioida, sillä agentit voivat itse tallentaa tilansa ja tietonsa tiedostoihin tai tietokantoihin, joita muut agentit voivat lukea ja kirjoittaa. Tämä tekee agenttien välisestä kommunikaatiosta ja yhteistyöstä entistä helpompaa ja tehokkaampaa.
Suorituskyvyn, skaalautuvuuden ja ennustettavuuden parantamiseksi kannattaa ehdottomasti pyrkiä siihen, että agenttien tehtävät ovat mahdollisimman pieniä ja yksinkertaisia. Mitä vähemmän kukin agentti joutuu tekemään, sitä nopeammin se pystyy suorittamaan tehtävänsä ja sitä helpommin sen käyttäytymistä voi ennustaa. Usein tämä tarkoittaa sitä, että monimutkaisuus työnnetään agenteista eteenpäin, esimerkiksi niiden käyttämiin työkaluihin tai ulkoisiin järjestelmiin. Nämä voivat olla esimerkiksi erillisiä mikropalveluita, jotka hoitavat monimutkaiset toiminnot agenttien puolesta.
AI ja kielimallit: Lue lisää
Myös kontekstin hallinnassa iso vastuu on työkaluilla ja ulkoisilla järjestelmillä. Agenttien konteksti-ikkunaan kannattaa pyrkiä tunkemaan mahdollisimman vähän tietoa. Tämä tarkoittaa, että työkalujen ja ulkoisten järjestelmien olisi hyvä pystyä pureskelemaan tietoa mahdollisimman paljon valmiiksi ja tarjoamaan agentille vain se, mitä se tarvitsee tehtävänsä suorittamiseen. LLM:t kärsivät yleisesti ns. ”lost in the middle”-ongelmasta, jossa konteksti-ikkunan keskiosalla on merkittävästi vähemmän painoarvoa kuin alussa ja lopussa olevilla tiedoilla. Mitä vähemmän tietoa kontekstissa on, sitä vähemmän tämä ongelma korostuu.
Lopputulosten heikon ennustettavuuden vuoksi virheenkäsittelyyn kannattaa panostaa agenttipohjaisissa järjestelmissä poikkeuksellisen paljon. Jokainen agentti kannattaa lähtökohtaisesti suunnitella käsittelemään yleisimmät virheensä, mutta lisäksi erillisten tarkistusagenttien lisääminen järjestelmään on monissa tapauksissa hyvä ajatus. Usein on tarpeen tarjota agenteille myös jonkinlainen uudelleenkokeilumekanismi, joka yrittää suorittaa epäonnistuneen tehtävän uudelleen tietyn määrän kertoja ennen kuin luovuttaa.
Miksi agenttipohjaisia järjestelmiä sitten kannattaa rakentaa?
Agenttipohjaisten järjestelmien haasteista huolimatta ne tarjoavat merkittäviä etuja monissa sovelluksissa. Yksi keskeisimmistä eduista on juurikin se, että ne pakottavat miettimään järjestelmän rakennetta ja toimintaa modulaarisella tavalla. Hyvin suunniteltuna järjestelmästä tulee erittäin vikasietoinen ja helposti laajennettava. Koska agentit ovat itsenäisiä, uusia agentteja voidaan lisätä järjestelmään ilman, että se vaikuttaa merkittävästi olemassa oleviin agentteihin. Tämä tekee järjestelmän päivittämisestä ja laajentamisesta helppoa ja joustavaa.
Agenttipohjaisilla järjestelmillä myös pystytään tekemään asioita, joita perinteisillä järjestelmillä olisi vaikea toteuttaa. Esimerkiksi monimutkaiset päätöksentekoprosessit, jotka vaativat useiden eri tietolähteiden ja analyysien yhdistämistä, voidaan jakaa useiden agenttien kesken. Jokainen agentti voi keskittyä tiettyyn osa-alueeseen, ja lopullinen päätös voidaan tehdä yhdistämällä kaikkien agenttien tuottamat tulokset. Agentit voivat myös varmistaa toistensa toimintaa ja korjata virheitä, mikä parantaa järjestelmän luotettavuutta ja tarkkuutta.
Parhaimmillaan agenttipohjaisten järjestelmien tominta tuntuu maagiselta. Kun agentit toimivat saumattomasti yhdessä, ne voivat suorittaa hämmästyttävän monimutkaisia tehtäviä ilman, että koodipohjan monimutkaisuus nousee kohtuuttomaksi. Agenttipohjaisista järjestelmistä – kuten Unixista – tulee usein suurempia kuin osiensa summa.