Ein kleiner Assistent, der Ihre Funktionen nutzt
Sie haben jetzt alle Teile eines Assistenten, der Werkzeuge nutzt. Er braucht Werkzeuge, die das Modell benennen kann, und eine Schleife, die sie ausführt. Er braucht eine Schrittgrenze, als Ergebnisse zurückgegebene Fehler und eine Person, die riskante Aufrufe freigibt.
Diese Lektion setzt diese Teile in einem kleinen Programm zusammen.
Am Ende dieser Lektion
Notiz
Ich kann einen kleinen Assistenten bauen, der meine eigenen Funktionen nutzt.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| Assistent | ein Programm, das ein Modell und Werkzeuge für eine Aufgabe nutzt |
| Schleife | Schritte, die bis zu einer Antwort oder einer Grenze wiederholt werden |
| Verteiler | Code, der jede Anfrage an ihre Funktion schickt |
| Zustimmung | das Ja einer Person vor einem Schreibwerkzeug |
| Sicherung | eine Prüfung, die einen Aufruf am Laufen hindert |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Assistent besteht aus fünf Teilen
Jedes Teil haben Sie schon gebaut. Die Werkzeuge sind Ihre Funktionen und ihre Beschreibungen. Die Schleife fragt, führt aus und fragt erneut. Der Verteiler schickt jede Anfrage an ihre Funktion.
Die Sicherungen sind die Schrittgrenze, die Fehlerergebnisse und die Zustimmung für Schreibaufrufe. Nehmen Sie nur eine weg, wird aus einem Scheitern ein Problem.
Durchgerechnetes Beispiel: wovor jedes Teil schützt
| Teil | Was es tut | Was ohne es schiefgeht |
|---|---|---|
| Schrittgrenze | Hält nach drei Schritten an | Eine Schleife, die nie endet |
| Verteilertabelle | Lehnt ein unbekanntes Werkzeug ab | Eine Anfrage führt etwas anderes aus |
| Fehlerergebnisse | Gibt ein Scheitern zurück | Ein Absturz statt einer Erholung |
| Zustimmung | Fragt vor einem Schreiben | Ein Versehen ändert Ihre Daten |
| Protokoll | Hält jeden Aufruf fest | Niemand weiß, was geschah |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Die Helfer für Modell und Zustimmung speichern
docker exec -w /home/node/project agent node -e "const fragen=async(m,t,c)=>{const r=await fetch((process.env.AI_URL||'http://ai:4000')+'/v1/chat/completions',{method:'POST',headers:{'content-type':'application/json',authorization:'Bearer lab'},body:JSON.stringify({model:'lab',messages:m,tools:t,tool_choice:c,max_tokens:120})});const j=await r.json();if(r.ok)return j.choices[0].message;throw Error(r.status+' '+j.error.message)};const beschr=(n,d,k)=>({type:'function',function:{name:n,description:d,parameters:{type:'object',properties:{[k]:{type:'string'}}}}});const hoer=()=>{const rl=require('readline').createInterface({input:process.stdin});const it=rl[Symbol.asyncIterator]();return{ja:async q=>{process.stdout.write(q+' (j/n) ');const l=await it.next();const ok=l.value=='j';console.log(ok?'j':'n');return ok},ende:()=>rl.close()}};require('fs').writeFileSync('helfer.cjs','exports.fragen='+fragen+';exports.beschr='+beschr+';exports.hoer='+hoer+';');console.log('helfer.cjs')"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Werkzeuge des Ladens speichern
docker exec -w /home/node/project agent node -e "const bauen=()=>{const{beschr}=require('./helfer.cjs');const N=[];const k=(i,n,o)=>({role:'assistant',tool_calls:[{id:i,function:{name:n,arguments:JSON.stringify(o)}}]});return{N,T:[beschr('preis_von','Preis eines Artikels.','artikel'),beschr('notiz_hinzufuegen','Speichert eine Notiz.','text')],F:{preis_von:a=>({apfel:40,birne:45})[a.artikel]||'Fehler: nicht gefunden',notiz_hinzufuegen:a=>N.push(a.text)},FK:[k('c1','preis_von',{artikel:'birne'}),k('c2','notiz_hinzufuegen',{text:'Birne 45 Cent'}),{role:'assistant',content:'Gespeichert.'}]}};require('fs').writeFileSync('werkzeuge.cjs','exports.bauen='+bauen+';');console.log('werkzeuge.cjs gespeichert')"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Prüfen Sie einen Aufruf in fester Reihenfolge
Stellen Sie bei jeder Anfrage dieselben Fragen in derselben Reihenfolge. Steht der Name in der Tabelle? Braucht es eine Zustimmung? Hat die Person j gesagt? Führen Sie aus und machen Sie jeden Fehler zu einem Ergebnis.
Ein Aufruf, der eine Frage nicht besteht, erreicht nie die nächste. Jeder Ausgang, ausgeführt oder nicht, wird zu einer Werkzeugnachricht und einer Protokollzeile.
Den ganzen Assistenten ausführen
printf 'j\n' | docker exec -i -w /home/node/project agent node -e "const{fragen,hoer}=require('./helfer.cjs');const{T,F,N,FK}=require('./werkzeuge.cjs').bauen();const{ja,ende}=hoer();let rec=0;(async()=>{const m=[{role:'user',content:'Finde den Preis einer Birne und speichere ihn als Notiz.'}];for(let s=1;s<4;s++){let a;try{if(rec)throw 0;a=await fragen(m,T)}catch(e){rec||console.log('Kein Modell ('+e.message+'). Aufgezeichnetes Beispiel:');rec=1;a=FK[s-1]}m.push(a);if(a.tool_calls==null){console.log('Antwort: '+a.content);break}for(const c of a.tool_calls){const n=c.function.name;let r='Fehler: unbekanntes Werkzeug';if(Object.hasOwn(F,n))r=n=='notiz_hinzufuegen'&&(await ja('Erlauben: '+n+' '+c.function.arguments+'?'))===false?'Von der Person abgelehnt':String(F[n](JSON.parse(c.function.arguments)));console.log('Schritt '+s+': '+n+' -> '+r);m.push({role:'tool',tool_call_id:c.id,content:r})}}console.log('Notizen: '+N.join(', '));ende()})()"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele glauben, ein Assistent sei sicher, sobald das Modell gut ist. Auch ein gutes Modell irrt noch. Die Sicherheit steckt in Ihrem Code: der Werkzeugtabelle, der Schrittgrenze, der Zustimmung und dem Protokoll. Bauen Sie sie zuerst und vertrauen Sie dem Modell später.
Zum Weiterdenken: die Aufgabe ändern
Ändern Sie die Frage im Assistenten-Lauf in Speichere eine Notiz: Brot kaufen. Führen Sie ihn zweimal aus, einmal mit eingespeistem j und einmal mit n.
Vergleichen Sie die beiden Notizzeilen. Schreiben Sie auf, welches Teil des Programms den Unterschied machte.