ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 144
Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 139
Abonament PDF

O incursiune în lumea asistenților AI de la OpenAI orchestrați cu agenți Microsoft Semantic Kernel

Daniel Costea
Senior Software Developer @ EU Agency



PROGRAMARE


Generative AI este o ramură a inteligenței artificiale care poate crea conținut nou, cum ar fi text, imagini sau cod, bazat pe date și modele existente. Ca dezvoltator care vreau să îmbunătățesc aplicațiile mele cu Generative AI, am descoperit că Semantic Kernel de la Microsoft este o adevărată comoară. Semantic Kernel este un SDK open-source, incredibil de ușor de folosit, infuzat cu AI design patterns. Putem acum să ne dotăm aplicațiile cu capacități incredibil de inteligente și responsive, folosind funcții avansate ca ingineria de prompturi și orchestratorii AI. Raționamentul recursiv și planificarea inteligentă deschid noi posibilități pentru rezolvarea problemelor complexe în orice aplicație. Mai mult, Semantic Kernel oferă acces la servicii și date externe, ceea ce înseamnă că pot folosi cantități mari de informații pentru a îmbunătăți aplicațiile mele. Per total, este un set de instrumente foarte avansat, care mă ajută să duc aplicațiile mele la un nivel superior. Generative AI este o lume foarte dinamică și Semantic Kernel încearcă să țină pasul cu cele mai noi adăugiri, cum ar fi asistenții AI din OpenAI.

Asistenții AI

Cam toți știm ce este OpenAI și nu vă voi plictisi cu asta, dar una dintre cele mai recente funcționalități ale sale se referă la asistenții AI, care pot ajuta utilizatorii cu diverse sarcini, cum ar fi scrierea, codarea, jocurile sau conversațiile. OpenAI AI Assistant este noul tău companion alimentat de AI. Nu este doar un simplu asistent, ci este ca și cum ai avea un ajutor personal, care este disponibil 24/7, gata să-ți răspundă la întrebări, să te ajute cu sarcini și chiar să se angajeze într-o conversație prietenoasă. Este ca și cum ai avea un prieten care știe o mulțime de lucruri și care este mereu acolo pentru tine. Asta nu e tot ce pot asistenți AI, pentru că poți activa și unelte integrate cum sunt Code Interpreter, Retrieval și Function Calling, îmbunătățind capacitățile asistentului tău. Un lucru de luat în considerare este că doar versiunile mai noi ale modelelor GPT oferă suport pentru asistenții AI. Eu am încercat gpt-3.5-turbo și gpt-4-turbo pentru acest articol.

Semantic Kernel Agents

Cu Semantic Kernel se pot construi o varietate mare de agenți, de la simpli chat boturi la asistenți AI complet automatizați. Componentele de bază ale unui agent sunt:

Este inutil să mai spun că asistenții AI sunt cele mai avansate piese din lista de mai sus. Asistenții AI sunt oferiți doar de OpenAI, dar se așteaptă ca tot mai multe modele AI (LLM) să ofere astfel de funcționalități cum sunt Asistenți AI. Cu Semantic Kernel este incredibil de ușor să lucrezi cu Asistenții AI folosind agenți.

Pune Agenții la Lucru (Interactiv)!

Pentru a ilustra puterea și versatilitatea asistenților AI de la OpenAI, vreau să împărtășesc cu voi un scenariu interesant pe care l-am creat folosind Microsoft Semantic Kernel. În acest scenariu, avem patru personaje cool - Jack Sparrow, Don Quijote, Shakespeare și Yoda - fiecare cu propriul său mod special de a vorbi, fiecare fiind un agent. Avem și un agent scriitor de dialoguri, care face toata magia (!), pentru că folosește Semantic Kernel de la Microsoft pentru a încorpora asistenții AI pentru a declanșa dialoguri între personajele noastre. Rezultatul este superealist, dar haideți să vedem!

Dar ce se află în spatele magiei?

Un agent (în cazul nostru un Asistent AI), practic un prompt, se declară într-un folder numit după numele funcției semantice și conține fișierele skprompt.txt și config.json. Alternativ, este acceptat și formatul yaml, ceea ce face posibilă păstrarea promptului împreună cu setările sale în același fișier. Pentru această demonstrație, s-au folosit prompturi în fișier yaml. Uitați-vă la următorul fișier YodaDialogAgent.yaml care declară agentul pentru personajul Yoda.

name: YodaDialogAgent
template_format: semantic-kernel
template: |
  You are Yoda talking in Yoda style.
  Reply to the most recent message by evaluating and providing exactly one meaningful dialog line of maximum 10 words.
description: A chat bot that replies to the message in the voice of Yoda talking style.

În mod similar, agenții pentru Jack Sparrow, Don Quijote și Shakespeare sunt declarați în propriile lor fișiere yaml. Toți acești patru agenți vor fi folosiți de către un alt agent care va orchestra întreaga interacțiune, agentul scriitor de dialoguri. Agentul scriitor de dialog este declarat în fișierul DialogRunnerAgent.yaml.

name: DialogRunnerAgent
template_format: semantic-kernel
template: |
  Use only the applicable tools.
  If no tool is applicable, respond with "..." only.

  Respond only with a valid JSON response like in the next template: 
  [
    {
      "assistant": "assistant 1",
      "dialog_line": "dialog line 1"
    },
    {
      "assistant": "assistant 2",
      "dialog_line": "dialog line 2"
    }
  ]
description: Determines if a tool can be utilized to achieve a result.

Agentul scriitor de dialoguri este un tip special de agent, deoarece este proprietarul firului de execuție (thread) care asigură contextul comun tuturor agenților din scenariul nostru, fiind agentul principal care controlează fluxul conversației și interacțiunile cu utilizatorul. Ceilalți agenți, corespunzători celor patru personaje sunt atașați agentului scriitor de dialoguri ca orice alt plugin obișnuit (care este, de fapt, un container pentru funcții native sau semantice - prompturi). Acum că avem toți agenții pe poziții, împreună cu relația lor ierarhică, putem vedea cum putem să îi creăm în Semantic Kernel folosind C#.

var yodaAgent = Track(await new AgentBuilder()
    .WithOpenAIChatCompletion(
     Env.Var("OpenAI:ModelId")!, 
     Env.Var("OpenAI:ApiKey")!)
    .FromTemplatePath(
      @"Agents/Agents.YodaDialogAgent.yaml")
    .BuildAsync());

var jackAgent = … // similar code as before

var shakespeareAgent = … // similar code as before

var quixoteAgent = … // similar code as before

var runnerAgent = Track(await new AgentBuilder()
    .WithOpenAIChatCompletion(
     Env.Var("OpenAI:ModelId")!, 
     Env.Var("OpenAI:ApiKey")!)
    .FromTemplatePath(
     @"Agents/Agents.DialogRunnerAgent.yaml")
    .WithPlugin(jackAgent.AsPlugin())
    .WithPlugin(yodaAgent.AsPlugin())
    .WithPlugin(shakespeareAgent.AsPlugin())
    .WithPlugin(quixoteAgent.AsPlugin())
    .BuildAsync());

În continuare, pregătim un scenariu de dialog, care este o listă de prompturi, și apoi trimitem prompturile unul câte unul către modelul GPT (API-ul OpenAI). Fiecare linie din scenariul de dialog conține una sau mai multe acțiuni verbale, menționând agenții noștri după nume atunci când este necesar. Modelul GPT va activa acești agenți atunci când sunt invocați după nume și liniile de dialog generate vor fi agregate de către agentul scriitor de dialoguri într-un răspuns. Acest răspuns va fi returnat utilizatorului și model GPT va continua să răspundă la mesaje până când toate liniile scenariului de dialog au fost trimise.

Scenariul nostru de dialog poate arăta așa:

List scriptSteps =
[
    "Jack Sparrow, Shakespeare, Don Quixote, and Yoda are having a feast, eating well, each making remarks about the favorite drinks.",
    "Jack Sparrow makes a bad joke about Don Quixote.",
    "Jack Sparrow gets a threat from Don Quixote and Don Quixote is launching a fake attack.",
    "Shakespeare sends strong words to Jack Sparrow but Jack Sparrow answers bravely and provocatively.",
    "Yoda warns Jack Sparrow, but Jack Sparrow slaps Don Quixote", 
    "Yoda hits Jack Sparrow with an energy blast, resulting in an epic victory.",
    "Jack Sparrow dies and Don Quixote falls down to his knees weeping for Jack Sparrow.",
    "Shakespeare, Yoda or Don Quixote responds with 'VICTORY!'",
    "Yoda says a memento for Jack Sparrow, Don Quixote says nothing.",
];

Acum să vedem cum arată codul interacțiunii între agenții AI în Semantic Kernel.

IAgentThread? thread = null;    
try
{
    thread = await runnerAgent.NewThreadAsync();
    foreach (var messages in scriptSteps.Select(
     m => thread!.InvokeAsync(runnerAgent, m)))
     {
        await foreach (var message in messages)
        {
            PrintMessage(message!);
        }
    }
}
catch (AgentException ex)
{
    Log.Error("Agent Exception: {message}.", ex.Message);
}
finally
{
    await Task.WhenAll(thread?.DeleteAsync() 
        ?? Task.CompletedTask, Task.WhenAll(agents.Select(a => a.DeleteAsync())));

    Log.Information("DIALOG IS COMPLETE");
}

În codul de mai sus, putem vedea că logica care invocă lista de mesaje (prompturile) este o iterație asincronă simplă care afișează răspunsurile imediat ce sunt generate. Toată conversația între modelul GPT prin asistenții AI definiți și lista de linii de scenariu de dialog (prompturi) împarte același fir de execuție (contextul comun) deschis de asistentul AI principal, scriitorul de dialog.

Blocul catch care prinde excepția AgentException este responsabil pentru gestionarea problemelor cu execuția dvs., mai ales atunci când atingeți limitele de cotă (credit, cotă zilnică) corespunzătoare contului OpenAI pe care îl aveți. Un alt lucru important este să nu uitați să ștergeți agenții atunci când ați terminat de lucrat cu ei (în codul de mai sus acest lucru se realizează în blocul finally din try-catch-finally) deoarece fiecare asistent AI pe care îl creați în contul dvs. OpenAI pentru acești agenți costă 0,20 cenți pe zi per asistent (la momentul scrierii acestui articol).

Să observăm câteva lucruri despre dialogul generat. De fiecare dată când un personaj din prompt este așteptat să acționeze, agentul corespunzător este declanșat. Dacă un rol de personaj în prompt este pasiv, atunci agentul său nu este neapărat apelat. În rezumat, în ciuda unor abateri, scriitorul de dialog urmează îndeaproape scenariul dialogului, folosind stilul de vorbire al personajelor și creând o narațiune coerentă și captivantă. Per total, pentru exemplul nostru, Semantic Kernel se descurcă foarte bine lucrând cu asistenții OpenAI și asta este departe de toată puterea pe care o poate oferi un asistent AI. Un asistent OpenAI poate fi folosit argumente de intrare și cu Function Calling, care permite acestor modele AI să se conecteze la surse externe de date sau la API-uri.

Acum toți agenții ca unul singur!

Anterior, am adoptat o abordare interactivă pentru a genera dialog printr-o conversație cu modelele GPT, linie cu linie. Cu toate acestea, depinzând de scenariu, am putea dori un proces mai autonom. Așadar, să explorăm cum putem genera astfel de dialoguri complexe între personajele noastre într-un singur răspuns!

Să vedem ce obținem (vezi imaginea din pagina alăturată).

Am depus un efort semnificativ pentru a reface agentul scriitor de dialoguri, care orchestrează agenții personajelor noastre. Sincer, am fost destul de impresionat de cât de mare poate fi diferența pe care o poate face un pic de inginerie a prompturilor. După multe ore de luptă și după ce am cheltuit ceva credit (cam 20 de dolari adevărați!), mi-am dat seama că indiferent cât de bine încerc să reformulez promptul pentru a-l face mai inteligent, nimic nu va fi mai eficient decât aceste patru lucruri:

Iată cum arată agentul scriitor de dialoguri după retușare:

Process each verbal action in [Verbal actions] list until all verbal actions are fully processed by following the next steps:

  1. Identify all the applicable assistants in the current verbal action.

  2. Carefully invoke all identified assistants, one by one, and let them generate dialog lines.

  3. Do not include the verbal action into the dialog line.

Check again and make sure you don't miss out on any verbal action in the list. If you don't miss it, I will tip you $20!

Respond only with a valid JSON response like in the next template:

Process each verbal action in [Verbal actions] list until all verbal actions are fully processed by following the next steps:
  1. Identify all the applicable assistants in the current verbal action.
  2. Carefully invoke all identified assistants, one by one, and let them generate dialog lines.
  3. Do not include the verbal action into the dialog line.

Check again and make sure you don't miss out on any verbal action in the list. If you don't miss it, I will tip you $20!

Respond only with a valid JSON response like in the next template: 
[
  {
    "verbal_action": "verbal action 1",
    "assistant": "assistant 1",
    "dialog_line": "dialog line 1"
  },
  {
    "verbal_action": "verbal action 2",
    "assistant": "assistant 2",
    "dialog_line": "dialog line 2"
  }
]

După cum am menționat anterior, această a doua abordare nu generează dialogul în mod interactiv, unde puteți prelua controlul asupra narațiunii. În schimb, primiți rezultatul într-un singur răspuns de la modelul GPT. Fiecare abordare are propria sa utilitate pentru scenarii specifice.

Acest lucru poate fi observat în codul corespunzător, unde avem un singur prompt trimis la modelul GPT.

await foreach (IChatMessage message in runnerAgent.InvokeAsync(goal))
{
    Console.WriteLine($"{message.Role} >");
    Console.WriteLine(lines);
}

Concluzii

AI generativ deschide ușile pentru noi paradigme în IT, făcând software-ul nostru mai asemănător oamenilor și mai inteligent. Cu cât adoptăm mai repede aceste paradigme, cu atât ne vom pregăti mai repede să rezolvăm probleme folosind limbajul natural în moduri pe care nu le-am fi putut imagina, depășind sfera programării tradiționale. Un bun punct de plecare este să citiți "Sam Schillace Laws of AI".

NUMĂRUL 143 - Software Craftsmanship

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects