Agentit kaipaavat vapautta, mutta tarvitsevat myös rajoja

Agenttisten tekoälyratkaisuiden yleistyessä eteen tulee uusi ja aika kiperä kysymys: kuinka paljon agentille voi antaa vapautta tehdä päätöksiä itsenäisesti, ja miten se vapaus rajataan teknisesti? Voiko agentti arvioida bugeja automaattisesti? Voiko se tehdä pull requesteja? Voiko se tehdä mergejä? Entä missä kohtaa ihmisen kannattaa puuttua peliin?

Kiinnostava kysymys ei ole enää osaako AI korjata bugeja, vaan se miten pitkälle prosessi voidaan automatisoida kuitenkin siten, että järjestelmä pysyy hallittuna.

Asiakasprojekteissa olemme rakentaneet usean agentin järjestelmiä muun muassa säänneltyyn terveysteknologiaan. Käytämme itse sisäisissä projekteissamme samoja teknologioita, joita tarjoamme asiakkaillemme, ja omalla tontilla voi kokeilla rohkeammin kuin asiakkaan tuotannossa.

Siksi rakensimme sisäisiin projekteihimme bugikorjausjärjestelmän, joka automatisoi git-issueiden käsittelyä ongelman arvioinnista koodikorjaukseen ja pull requestiin. Ratkaisussa yhdistyvät LLM:n kyky tulkita eri tavoin kirjoitettuja ja tuotettuja bugiraportteja, deterministiset työnkulut ja monenlaiset tekniset turvarajat.

Arviointi ennen korjausta

Kaikki issuet eivät ole tasavertaisia, sillä niitä syntyy hyvin eri tavoin. Joku kirjoittaa bugiraportin ohimennen ja ylimalkaisesti heti bugin osuessa kohdalle. Toinen kirjaa mukaan historian, selkeät askeleet virheen toistamiseen ja toiveen siitä miten järjestelmän pitäisi toimia. Joskus taas bugin kuvaus on pelkkä järjestelmän tuottama virheilmoitus logeissa.

Siksi testatun työnkulun ensimmäinen askel oli luonnollisesti luokitteluagentti. Sen tehtävä oli arvioida issuen laatua ja sitä, riittääkö bugiraportti luotettavan ratkaisun pohjaksi. Arvionsa perusteella agentti luokitteli issuen yhteen kolmesta tilasta:

  • Soveltuu automaattisesti korjattavaksi: Agentilla on riittävät tiedot tekoälypohjaisen ratkaisun aloittamiseksi, joten korjaus käynnistyy automaattisesti.
  • Vaatii lisätietoja: Agentti kaipaa vastauksia yksittäisiin kysymyksiin, jotta se pystyy esimerkiksi toistamaan virhetilanteen luotettavasti. Käyttäjän syöttäessä lisätietoja GitHubiin, käynnistyy arviointi uudelleen automaattisesti.
  • Ei sovellu tekoälyn ratkaistavaksi: Agentille oli asetettu turvarajoja, jotka estivät sitä korjaamasta esimerkiksi salaisuuksiin, GitHub-automaatioon tai sen omaan toimintaan liittyviä issueita. Lisäksi uusien toiminnallisuuksien rakentaminen rajattiin kokeilun ulkopuolelle.

Korjaus alkaa aina testistä

Kun luokittelija oli arvioinut, että ongelma voidaan korjata, korjausagentti pääsi töihin. Ensin agentti analysoi ongelman ja aiemman agentin syötteen. Sen pohjalta se kirjoitti epäonnistuvan testin, toteutti korjauksen, varmisti ettei sama testi enää epäonnistu ja avasi pull requestin.

Uuden, aluksi epäonnistuvan testin kirjoittaminen loi varmuutta siitä, että agentti oli tulkinnut bugin oikein. Jos agentti ei pystyisi luomaan testiä, joka toistaa sille annetun virheen, korjauskin olisi todennäköisesti virheellinen. Testi toimi myös regressiosuojana tulevaisuudelle.

Kun testit lopulta menivät läpi, agentti avasi pull requestin GitHubiin, ja tässä kokeilussa ihminen teki sille vielä koodikatselmoinnin. Katselmoinnissa ihminen pystyi varmistamaan, että automaattisesti luotu testi testasi oikeaa asiaa ja että agentin perustelut muutoksille olivat järkeviä. Agentti siis automatisoi suuren osan bugikorjauksen työstä, mutta lopullinen hyväksyntä jäi ihmiselle.

Vapautta ja rajoja

Vaikka agenteilla oli oikeus käynnistää korjaus automaattisesti, se ei tarkoittanut rajatonta päätösvaltaa. Lähtökohtana oli antaa agenteille juuri sen verran tilaa ja kykyä toimia, että kokonaisuus pystyi tekemään tehtävänsä, mutta ei yhtään enempää. Jokainen päätös antaa oikeuksia tuli olla perusteltu.

Lopulta luokitteleva agentti sai lukea issueita, kirjoittaa niihin vastauksia ja lisätä labeleita, joiden muutoksiin agenttikokonaisuus reagoi. Bugeja korjaava agentti sai sen jälkeen tutkia koodia, tehdä koodimuutoksia, kirjoittaa ja ajaa testejä sekä avata pull requestin. Järjestelmällä ei kuitenkaan ollut oikeutta esimerkiksi viedä muutoksia tuotantoon, muuttaa omaa koodiaan tai vaikkapa lukea ympäristömuuttujia.

Agenttien itsenäinen päätösvalta ei siis tarvitse olla joko päällä tai pois. Harva agentti on täysin itsenäinen tai täysin ihmisen ohjaama. Kyseessä on ennemmin monimutkainen verkko erilaisia oikeuksia ja kykyjä, ja agentti toteuttaa tehtäväänsä niiden rajoissa toivottuun pisteeseen asti.

Hard controls as code

Yksi tärkeimmistä asioista, joita halusimme projektissa puntaroida, oli agenttisen järjestelmän turvallisuus.

System promptiin voi kirjoittaa “älä koskaan mergeä omaa pull requestiasi”, ja ohjeena se on hyödyllinen. Paljon vahvemman kontrollin saa kuitenkin jo aiemmin rajaamalla yksinkertaisesti agentille annettuja käyttöoikeuksia. Silloin agentti ei pysty mergeämään, vaikka system prompt syystä tai toisesta ohitettaisiin.

Samaa ajattelua pyrimme noudattamaan koko järjestelmässä. Agenttien toimintaa rajoittivat muun muassa:

  • Repositoryn käyttöoikeudet
  • Agenteille tarjotut työkalut
  • Eri agenttien vastuut
  • CI-putki
  • Eri branchien suojatut tilat
  • Erilaiset kovat token- ja kustannusrajat
  • Aikaperustaiset katkaisut
Tärkeänä periaatteena oli siis luoda mahdollisimman paljon kovia rajoitteita suoraan koodiin (hard controls as code) sen sijaan, että agentille vain kerrotaan promptissa, miten sen tulisi käyttäytyä. Näiden kahden hallintatavan ero korostuu sitä enemmän, mitä enemmän vapautta agentti saa päättää omasta toiminnastaan.
Agenttipohjainen bugikorjausprosessi

Agentti vain kun se on hyödyllistä

Toinen tärkeä oppi liittyi kykyyn arvioida, missä agentista on aidosti hyötyä. 

Nykyisessä buumissa tekoälyä on helppo tarjota ratkaisuksi kaikkeen. Kielimalleja kannattaa kuitenkin käyttää vain siellä, missä niistä oikeasti on hyötyä. Meidän projektissamme niitä kohtia olivat:

  • Issueiden sisällön laadullinen arviointi ja rakenteettoman tiedon tulkinta
  • Koodipohjan tutkiminen
  • Ongelman paikallistaminen
  • Testin kirjoittaminen
  • Korjauksen suunnittelu ja koodaaminen
Näitä ympäröivä järjestelmä on suoraviivaisempi, ja hyvä niin. Mitä suurempi osa prosessista saadaan rakennettua deterministisiksi prosesseiksi, sitä helpompi kokonaisuutta on ymmärtää, valvoa ja kehittää.

Lopuksi

Kuinka paljon agentille siis kannattaa antaa vapautta tehdä päätöksiä itsenäisesti? Meidän tapauksessamme vastaus oli antaa agentille enemmän autonomiaa kuin pelkkä koodiapuri yleensä saa.

Selkeiden rajanvetojen ansiosta saimme aikaan paljon enemmän kuin yhden uuden kokeilun. Lopputuloksena syntyi agenttinen järjestelmä, joka osaa ratkaista sisäisten järjestelmiemme bugikorjauksia ja vapauttaa samalla kehittäjiemme kädet toteuttamaan suurempia kokonaisuuksia.

Ota yhteyttä niin jatketaan juttua!

Juho Arkkola