Blog

CutomGPT: Luo Assets Discovery -mukautetut mallit automaattisesti

APR 9, 2024

Annoimme ChatGPT:lle Atlassianin C#-kirjaston osaamisen ja uudistimme Jira Assets Discoveryn koodin generoinnin. Lue lisää.

Max Hövelmann

Suurten kielimallien (LLM) ja generatiivisen tekoälyn yleistyminen on merkittävä edistysaskel koneoppimisessa. Se mahdollistaa laajan kirjon käyttötapoja sisällöntuotannosta asiakastukeen.

Atlassian integroi tätä kehittyvää teknologiaa aktiivisesti moniin tuotteisiinsa, kuten Jira Service Managementiin (JSM), Confluenceen ja Bitbucketiin "Atlassian Intelligence" -toiminnon avulla. Se on erittäin hyödyllinen esimerkiksi Confluence-sivujen luomisessa ja muokkaamisessa sekä Bitbucketin commit-viestien kirjoittamisessa, mutta näemme mahdollisuuksia myös erikoistuneemmille käyttötapauksille.

Arvioidaksemme tällaisten erikoistuneiden ratkaisujen toimivuutta kehitimme räätälöidyn Assistantin, joka voi luoda Custom Patterns -malleja Jira Assets Discoveryyn.

Mikä Jira Assets Discovery on?

Jiran Assets Discovery on Atlassianin Jira Service Managementia varten luoma maksuton Jira Marketplace -sovellus. Sen tarkoitus on auttaa organisaatioita hallitsemaan ja seuraamaan omaisuuttaan suoraan palvelunhallintatyökalussa. Näin kaikki organisaation laitteisto-, ohjelmisto- ja muut resurssit voidaan löytää, seurata ja hallita automaattisesti.

Prosessissa skannataan kaikki yrityksen verkkoon kuuluvat laitteet Scan Patterns -mallien avulla. Malli sisältää shell-komennon järjestelmätietojen hakemiseen sekä lyhyitä C#-koodiosuuksia, joilla komentorivin tuloste jäsennetään objekteiksi, jotka voidaan tuoda JSM:n Assetsiin.

Jos esimerkiksi tarvitaan tietoa viimeksi kirjautuneista käyttäjistä, malli suorittaa last-komennon. Komennon tuloste voi näyttää tältä:

mark     pts/0        10.10.0.7   Fri Feb 21 21:23   still logged inmark     pts/0        10.10.0.7   Tue Feb 18 22:34 - 00:05  (01:31)lisa     :0           :0          Thu Feb 13 09:19   gone - no logoutreboot   system boot  4.15.0-74-g Fri Jan 24 08:03 - 08:03  (00:00)

Seuraavaksi skripti jäsentää komentorivin tulosteesta jokaisen merkinnän ja luo Atlassianin HostInfo-objektista instansseja, joiden LastUser-kenttä on asetettu oikein, jotta ne voidaan tuoda JSM:ään.

Järjestelmä on erittäin joustava, sillä voit räätälöidä sitä kirjoittamalla malleja, jotka keräävät mitä tahansa shell-komennoilla saatavilla olevia järjestelmätietoja. Jos yritys esimerkiksi käyttää omia tietokantoja tiettyihin tallennustarpeisiin, voit luoda räätälöityjä malleja näiden tietokantojen tietojen automaattiseen hakemiseen.

Miten luon räätälöityjä malleja, jos en osaa C#:aa?

Vaikka ratkaisu tarjoaa erinomaisen tavan luoda asiakkaidemme tarpeisiin räätälöityjä ratkaisuja, siihen liittyy myös haasteita. Ne johtuvat pääasiassa C#-osaamisen, tarvittavien shell-komentojen sekä Assets Discoveryn C#-kirjaston tuntemuksen tarpeesta, kun kyseessä ovat epätyypilliset inventointitarpeet.

Tämän vuoksi asiakkaidemme on usein vaikea toteuttaa omia vaatimuksiaan ilman apua. Havaintomme mukaan asiakkaillamme on usein skriptauskokemusta, tavallisesti muista kielistä kuin C#:sta. Vaikka heillä olisi C#-osaamista, heiltä puuttuu aikaa opetella Atlassianin tarjoaman kirjaston käyttöä. He kuitenkin ymmärtävät hyvin järjestelmävaatimustensa yksityiskohdat, kuten sen, millaisia tietoja järjestelmistään tarvitaan.

Tarvitaan työkalu, joka muuntaa nämä vaatimukset valmiiksi malleiksi ilman, että se edellyttää laajaa C#- tai ohjelmointiosaamista yleisesti.

ChatGPT räätälöityjen mallien kirjoittamiseen

Shell-komentojen jäsentämiseen tarvittava C#-koodi on melko lyhyttä, joten pyysimme ChatGPT:tä kirjoittamaan sopivan toteutuksen määriteltyjen vaatimusten perusteella.

Tulokset olivat valitettavasti vähintäänkin epätyydyttäviä. Vaikka se pystyi tuottamaan tehokkaasti lyhyitä C#-koodikatkelmia, oli selvää, ettei GPT:tä ollut koulutettu riittävästi Atlassianin C#-kirjaston dokumentaatiolla.

Palataan aiempaan käyttäjäesimerkkiimme: GPT onnistui ilman lisäohjeita ymmärtämään, että last-komennolla voidaan hakea tiedot. Se ei kuitenkaan ymmärtänyt, mitä kenttiä mallin XML-tiedostossa tulisi olla, eikä malli sisältänyt lainkaan C#-koodia. Vaikka sille kerrottiin, että mallin on sisällettävä jäsentämiseen käytettävää C#-koodia, GPT4 ei pystynyt tuottamaan mitään mielekästä ratkaisua.

Esittelyssä: Discovery Custom Pattern Assistant

Ratkaistaksemme ongelman meidän piti toimittaa ChatGPT:lle tarvittava dokumentaatio. Onneksemme OpenAI julkaisi tuolloin CustomGPT:t, joiden avulla voidaan lisätä räätälöityjä tietotiedostoja ja suorittaa "Actions"-toimintoja.

Räätälöity tietämys

Kun käyttäjä esittää kysymyksen, ChatGPT tekee ensin tekstin samankaltaisuushaun annetusta tietopohjasta ja liittää hakutulokset huomaamattomasti käyttäjän kysymykseen. Näin chatbot voi hyödyntää sellaista tietoa, johon sitä ei ole erityisesti koulutettu, vastatakseen kysymyksiin.

ChatGPT tukee useiden tietotiedostojen lataamista, joten päätimme jakaa tietomme kolmeen tiedostoon:

  • Atlassianin dokumentaatioon perustuva yleinen dokumentaatio Assets Discoverysta ja Custom Patterns -malleista

  • Kattava dokumentaatiomme kirjaston varsinaisista C#-luokista

  • Luettelo kääntäjän virheistä ja niiden ratkaisuista ChatGPT:n aiheuttamiin yleisiin virheisiin

Tämän olennaisen tiedon tarjoamisen jälkeen havaittiin selkeä parannus: kun tekoäly ei aiemmin ymmärtänyt, miten kirjastoa käytetään, se osasi nyt hyödyntää luokkia oikein ja luoda täsmällisiä objekteja.

Vaikka tulokset olivat jo aiempaan verrattuna lupaavia, etenimme tekoälyn kanssa "luota mutta varmista" -periaatteella ja lisäsimme luodut mallit Assets Discoveryyn. Tulokset paranivat huomattavasti aiempaan verrattuna, mutta vaihtelivat edelleen. Useimmat mallien epäonnistumiset johtuivat pääosin vähäpätöisistä kääntäjävirheistä. Kääntäjää käytetään C#-lähdekoodin muuntamiseen koneen luettavaksi koodiksi, ja se tarkistaa samalla koodivirheet käännöksen aikana.

Kyseessä on siis automatisoitu prosessi, jonka tuloksena voi syntyä joko suoritettavaksi valmis käännetty ohjelma tai joukko virheitä sekä niiden sijainnit koodissa. Kun annamme räätälöidylle GPT:lle mahdollisuuden kääntää oma koodinsa, se voi tarkistaa tuloksensa automaattisesti. Jos käännös epäonnistuu, se voi korjata koodiaan havaittujen virheiden perusteella.

Räätälöidyt toiminnot

Toimintojen avulla CustomGPT:t voivat tehdä verkkopyyntöjä räätälöityyn taustajärjestelmään. Näin ne voivat joustavasti hyödyntää itse rakennettuja työkaluja esimerkiksi ajantasaisten säätietojen tarjoamiseen tai monimutkaisten fysiikkasimulaatioiden suorittamiseen.

Tarkistaaksemme luodun koodin automaattisesti kääntäjävirheiden varalta toteutimme oman taustajärjestelmän, joka tarjoaa päätepisteen C#-koodikatkelman vastaanottamiseen ja sen kääntämiseen. Vastauksena saadaan joko vahvistus onnistumisesta tai tieto virheestä tai virheistä.

Loimme ChatGPT-käyttöliittymään kaksi toimintoa, joiden avulla voi kommunikoida räätälöidyn taustajärjestelmämme kanssa: toinen C#-koodin kääntämiseen ja toinen C#-koodin sekä metatietokenttiä sisältävän XML-mallitiedoston validoimiseen.

Kun annoimme ChatGPT:lle mahdollisuuden sekä kääntää että tarkistaa oman koodinsa, arvioimme avustajamme uudelleen ja saavutimme lopulta odotuksemme ylittäviä tuloksia.

Kokonaisuuden viimeistely

Kun kaikki onnistuneen Custom Pattern -botin rakentamiseen tarvittavat osat olivat paikoillaan, viimeisenä vaiheena oli toteuttaa järjestelmäviestit. Ne tarjoavat taustatietoa sekä yleisen rakenteen, joka selittää, miten mallien luontiprosessi toimii.

Virtuaaliagentin suorituskyvyn arviointi

Linkitetyssä chat-keskustelussa omaksuimme Jira / JSM -käyttäjän roolin, jolla ei ollut aiempaa taustatietoa C#:sta tai asiakaskohtaisten mallien kirjoittamisesta.

Aloitimme keskustelun pyytämällä räätälöidyn mallin luomista annettujen vaatimusten perusteella:

User: I need a custom pattern to get the last logged in user on MacOS devices

CustonPatternGPT: To create a custom pattern for fetching the last logged-in user on MacOS devices, you can leverage the SSH protocol, as MacOS is Unix-based and supports SSH for remote command execution. The command to get the last logged-in user on a MacOS device is last -1 -t console. This command fetches the most recent login on the device, specifically on the console, which typically indicates a physical login.

Below is a template for creating such a pattern, including all necessary using directives and adhering to the specifications for .NET Framework 4.7 or below, as well as the requirements you've provided:

<?xml version="1.0" encoding="utf-8"?><ScanPattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <Version>1.0</Version>  <PatternID>MacOS-LastUserLogin</PatternID>  <OrderNr>0</OrderNr>  <ProcessType>SSHExecute</ProcessType>  <PatternType>Custom</PatternType>  <Command>    <![CDATA[    last -1 -t console    ]]>  </Command>  <Processing>    <![CDATA[    using System;    using Insight.Discovery.InfoClasses;    using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // For handling SSH command results    namespace Insight.Discovery {      public class PatternExec {        public void PerformAction(object[] parameters) {          HostInfo hostInfo = (HostInfo)parameters[2]; // Cast the third parameter to HostInfo          // Cast the first parameter to SSHExecuteResult and implicitly assign to string          string sshOutput = ((SSHExecuteResult)parameters[0]);          // Processing the SSH output to extract the last logged-in user          if (!string.IsNullOrEmpty(sshOutput)) {            var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);            if (lines.Length > 0) {              var lastLoginInfo = lines[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);              if (lastLoginInfo.Length > 0) {                string lastUser = lastLoginInfo[0];                // Setting the LastUser property of the HostInfo object                hostInfo.LastUser = lastUser;              }            }          }        }      }    }     ]]>  </Processing></ScanPattern>

This custom pattern XML defines a pattern for executing an SSH command on a MacOS device to retrieve the last logged-in user. The <Command> section contains the actual SSH command to be executed, and the <Processing> section contains C# code to parse the command's output and extract the last logged-in user's username, which is then assigned to the LastUser property of the HostInfo object. This pattern relies on the assumption that the device supports SSH access and that the executing account has the necessary permissions to execute the last command.Remember to test this pattern in a controlled environment before deploying it in a production setting to ensure it meets your specific requirements and works as expected across different MacOS versions.

GPT ymmärsi tehtävänsä ja aloitti selittämällä, millä shell-komennolla tiedot voidaan hakea kohdekoneelta. Se kertoi myös, mitä C#-versiota ja kieliominaisuuksia kannattaa käyttää.

Seuraavaksi pyysimme GPT:tä kääntämään C#-koodin syntaksi- ja kääntäjävirheiden tarkistamiseksi sekä validoimaan mallin XML-tiedoston, jotta kaikki tarvittavat määritysasetukset ovat mukana.

User: Cool. Now, can you compile the pattern and then validate the xml to check if there aren't any issues?

CustonPatternGPT:  Talked to custompatterngpt.hostname.com [compiling for errors]  Taked to custompatterngpt.hostname.com [validating the pattern] The pattern's C# code successfully compiled without any issues, indicating the code itself is syntactically correct and should work as intended. However, when validating the XML pattern, an error occurred: Invalid PatternType: Custom. The validation process indicates that "Custom" is not a recognized PatternType. Valid pattern types include Host, Deviceinfo, Network, CPU, OS, FileSystem, Application, Patch, ApplicationService, OSProductKey, ApplicationProductKey, User, Group, ConnectedPeripherie, SNMPExtendedValues, HostInfoList, and PostProcessing. To align with the recognized pattern types, you might consider categorizing this custom pattern under a valid type that closely matches the data it's designed to fetch. Since this pattern retrieves information about the last logged user, which is closely related to user information, a suitable PatternType might be User. If a more specific categorization is preferred and none of the listed types fit perfectly, consider using a general type like HostInfoList or PostProcessing, depending on the broader context of how you plan to use this data.Would you like to proceed with adjusting the PatternType, or do you need further assistance with another aspect of your pattern?

Käännös onnistui, mutta XML-tiedostossa mallin tyypiksi asetettiin virheellisesti Custom. Tämä vaikutti ensisilmäyksellä järkevältä, koska olimme kirjoittamassa räätälöityä mallia. Custom ei kuitenkaan ole kelvollinen mallityyppi. Tarkistuksen jälkeen GPT havaitsi ongelman nopeasti ja tarjosi useita kelvollisia mallityyppejä, jotka voisivat sopia nykyiseen malliin.

Pysyimme ei-teknisen käyttäjän roolissa ja pyysimme vain valitsemaan mallityypin, jonka GPT katsoi sopivimmaksi.

User: Just pick the one you see fit most and please validate the pattern again

CustonPatternGPT: Talked to custompatterngpt.hostname.com [pattern validation] The pattern has been successfully adjusted to use the PatternType "User", which is more appropriate for the data it's designed to fetch. The validation process did not return any errors this time, indicating that the XML structure and the pattern type are now correctly defined according to the system's expectations.

<?xml version= "1.0" encoding= "utf-8"?><ScanPattern xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd= "http://www.w3.org/2001/XMLSchema">" <Version>1.0</Version>" <PatternID>MacOS-LastUserLogin</PatternID>     <OrderNr>0</OrderNr>      <ProcessType>SSHExecute</ProcessType>      <PatternType>User</PatternType>     <Command>         <![CDATA[ last -1 -t console ]]>     </Command>     <Processing>         <![CDATA[             using System;            using Insight.Discovery.InfoClasses;            using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace            using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // For handling SSH command results            namespace Insight.Discovery {            public class PatternExec {                public void PerformAction(object[] parameters) {                HostInfo hostInfo = (HostInfo)parameters[2]; // Cast the third parameter to HostInfo                // Cast the first parameter to SSHExecuteResult and implicitly assign to string                string sshOutput = ((SSHExecuteResult)parameters[0]);                // Processing the SSH output to extract the last logged-in user                if (!string.IsNullOrEmpty(sshOutput)) {                    var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);                    if (lines.Length > 0) {                    var lastLoginInfo = lines[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);                    if (lastLoginInfo.Length > 0) {                        string lastUser = lastLoginInfo[0];                        // Setting the LastUser property of the HostInfo object                        hostInfo.LastUser = lastUser;                    }                    }                }            }        }        ]]>     </Processing></ScanPattern>

You should now be able to use this pattern for discovering the last logged-in user on MacOS devices via SSH commands. If you need further assistance or have any more requirements, feel free to ask!

GPT valitsi mallityypin ja validoi luodun mallin onnistuneesti uudelleen. Mallin suorittaminen MacBookilla vahvisti, että se tunnistaa oikein viimeksi sisäänkirjautuneen käyttäjän ja asettaa tämän HostInfo-tietoihin.

Tietoja tarkastellessamme huomasimme kuitenkin, että viimeiseksi käyttäjäksi oli asetettu “jiradiscovery, -”eli mallien suorittamiseen käytetty SSH-käyttäjä. Tämä oli täsmälleen se, mitä pyysimme: viimeksi sisäänkirjautunut käyttäjä. Se ei kuitenkaan selvästikään ollut se, mitä halusimme:

User: Great! I just tried the pattern and it's getting the last user, however because the pattern itself is executing with ssh, the last user is jiradiscovery. Can you instead get the last user that's not the jiradiscovery SSH user? Once you're done, please re-compile to see if it's still valid

CustonPatternGPT: Talked to custompatterngpt.hostname.com [pattern compilation] Talked to custompatterngpt.hostname.com [pattern validation]

The updated pattern, which now filters out the "jiradiscovery" user and targets the last logged-in user that's not associated with the SSH session, has been successfully re-compiled without any issues. This means the code is syntactically correct and aligns with the desired functionality.

Additionally, I've validated the pattern against the expected XML structure and pattern requirements. The process did not return any errors, indicating that the pattern is correctly defined and should work as intended for discovering the last logged-in user on MacOS devices, excluding the "jiradiscovery" SSH user.

Kun selitimme ongelman ChatGPT:lle, se ymmärsi virheen ja ehdotti, käänsi ja validoi ratkaisun. Uuden, tarkennetun mallin käyttäminen Discoveryssä vahvisti, että se kerää nyt tiedot oikein.

Viimeisenä vaiheena pyysimme avustajaa lisäämään lokituksen virheenkorjausta varten sekä dokumentaation, joka on suunnattu aloitteleville ohjelmoijille. Näin tulevaisuudessa mallin ylläpidosta vastaavan henkilön on huomattavasti helpompi ymmärtää, mitä malli tekee:

User: Perfect, now it's working flawlessly. Finally, can you add some documentation and logging to the pattern, especially with focus on making the code understandable to a maintainer that might not know c# well?

CustonPatternGPT: To enhance the custom pattern with documentation and logging, aimed at making the code more understandable for maintainers with varying levels of C# knowledge, I've incorporated comments throughout the pattern's processing section. These comments explain the purpose of each code block and the logic behind it, along with adding logging statements to help with debugging and understanding the flow of execution:

<?xml version="1.0" encoding="utf-8"?>
<ScanPattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Version>1.0</Version>
  <PatternID>MacOS-LastUserLogin</PatternID>
  <OrderNr>0</OrderNr>
  <ProcessType>SSHExecute</ProcessType>
  <PatternType>User</PatternType>
  <Command>
    <![CDATA[
    last -1 -t console
    ]]>
  </Command>
  <Processing>
    <![CDATA[
    using System;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.ProviderClasses; // Needed for executing commands on the host
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // To handle the results from SSH commands
    using Insight.Discovery.Tools; // To use logging services
    namespace Insight.Discovery {
      public class PatternExec {
        public void PerformAction(object[] parameters) {
          // Obtain the HostInfo object from the parameters array. This object represents the host we are currently scanning.
          HostInfo hostInfo = (HostInfo)parameters[2];
          // The SSH command's output is obtained from the parameters array and implicitly converted to a string.
          string sshOutput = ((SSHExecuteResult)parameters[0]);
          // Log the obtained SSH output for debugging purposes.
          LogService.Instance.LogDebug($"SSH Output: {sshOutput}");
          // Check if the SSH output is not empty or null.
          if (!string.IsNullOrEmpty(sshOutput)) {
            // Split the output into lines for processing.
            var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            // Iterate through each line in the SSH output.
            foreach (var line in lines) {
              // Split each line into parts to analyze the login information.
              var loginInfo = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
              // Check if the line has content and the user is not 'jiradiscovery'.
              if (loginInfo.Length > 0 && loginInfo[0] != "jiradiscovery") {
                string lastUser = loginInfo[0]; // The first part is assumed to be the username.
                // Log the found user for verification.
                LogService.Instance.LogDebug($"Last logged-in user found: {lastUser}");
                // Assign the found username to the LastUser property of the HostInfo object.
                hostInfo.LastUser = lastUser;
                // Stop processing after the first matching user is found.
                break;
              }
            }
          } else {
            // Log a warning if the SSH command did not return any output.
            LogService.Instance.LogWarning("SSH command did not return any output.");
          }
        }
      }
    }
    ]]>
  </Processing>
</ScanPattern>

This updated version of the pattern now includes detailed comments explaining the functionality of each segment of the code, making it easier for someone who may not be familiar with C# to understand the pattern's purpose and how it works. Logging statements have been added to aid in debugging and to provide insight into the pattern's operation during execution.This documentation and logging strategy is designed to make the code more accessible and maintainable, helping future maintainers to quickly grasp the logic and purpose behind each operation.

User: Thank you, you're awesome!

CustonPatternGPT: You're welcome! I'm glad I could help. If you have any more questions or need further assistance in the future, feel free to reach out. Have a great day!

Custom GPT:n tulevat parannukset

Nykyinen versio on hyötynyt merkittävästi mahdollisuudesta kääntää koodia ja tunnistaa virheitä, mutta kaikkia bugeja ei voi havaita tällä tavalla. Tällaisia bugeja kutsutaan "ajonaikaisiksi virheiksi", koska ne ilmenevät vasta ohjelman suorituksen aikana.

Onneksi tällaiset bugit voidaan havaita automaattisella testauksella. Tulevaisuudessa CustomGPT pystyy varmistamaan, tuottaako malli oikeita tuloksia ilman, että sitä tarvitsee ottaa käyttöön ja testata kohdekoneella.

Kun malli on käännetty onnistuneesti, räätälöity GPT antaa shell-komennon, joka suoritetaan yhdellä kohdepalvelimista. Komennon suorittamisen jälkeen kyseisen koneen tuottama tuloste tulee liittää takaisin chat-ikkunaan. Tämän jälkeen GPT suorittaa automaattiset testit varmistaakseen, että luotu koodi käsittelee annetun tulosteen oikein, ja tekee tarvittavat muutokset, jos testi epäonnistuu.

  • Atlassian

Subscribe to our newsletter