يعد Askit مكونًا إضافيًا للغة لـ TypeScript يمكّنك من الاستفادة من إمكانيات نموذج لغة كبير (LLM) ، مثل GPT-4 ، مباشرة في بيئة البرمجة الخاصة بك ، لا يلزم وجود واجهات برمجة التطبيقات المعقدة. تتضمن مجموعة تطبيقات Askit الواسعة:
بنيت على API Openai ، يوفر Askit واجهة سهلة الاستخدام لدمج LLMs في تطبيقاتك. يمكنك استخدام Askit ليس فقط في TypeScript ، ولكن أيضًا في JavaScript و Python.
لدمج Askit مع JavaScript ، يرجى الرجوع إلى قسم JavaScript المقابل.
إذا كانت Python هي لغتك المفضلة ، فيمكنك معرفة المزيد حول كيفية استخدام Askit من خلال زيارة صفحة Askit (Pyaskit) المخصصة.
التحكم في الإخراج الموجهة: احصل على استجابة في النوع المحدد.
تعريف الوظيفة القائم على القالب: تحديد الوظائف باستخدام قالب موجه.
توليد الكود: إنشاء وظائف من الواجهة الموحدة. انظر توليد الكود مع Askit لمزيد من التفاصيل.
البرمجة بالمثال (PBE): تحديد الوظائف باستخدام أمثلة. انظر البرمجة بالمثال مع Askit لمزيد من التفاصيل.
قبل البدء ، تأكد من تثبيت Node.js و NPM على نظامك. ثم ، قم بتنفيذ الأمر التالي:
npm install ts-askit تعتمد هذه الحزمة على ts-patch . لتثبيت ts-patch ، قم بتشغيل:
npx ts-patch install أضف المقتطف التالي إلى tsconfig.json :
"compilerOptions" : {
"plugins" : [{ "transform" : " ts-askit/transform " }]
} يتيح هذا التعديل لمرجم TypeScript دعم معلمات النوع لـ ask and define واجهات برمجة التطبيقات في Askit.
تعد حزمة ts-patch أمرًا بالغ الأهمية لإطلاق العنان للإمكانات الكاملة لـ Askit ، حيث تمتد على برنامج التحويل البرمجي TypeScript لدمج نظام نوع Askit بالكامل. على الرغم من أنه يمكن استخدام Askit بدون ts-patch ، فإن هذا التكامل يوفر تجربة أكثر غنية بالميزات.
قبل استخدام ASKIT ، تحتاج إلى تعيين مفتاح Openai API كمتغير البيئة OPENAI_API_KEY :
export OPENAI_API_KEY= < your OpenAI API key > <your OpenAI API key> عبارة عن سلسلة تبدو مثل: sk-<your key> . يمكنك العثور على مفتاح API الخاص بك في لوحة القيادة Openai.
يمكنك أيضًا تحديد اسم النموذج كمتغير بيئة ASKIT_MODEL :
export ASKIT_MODEL= < model name > <model name> هو اسم النموذج الذي تريد استخدامه. تم اختبار أحدث ASSIT مع gpt-4 و gpt-3.5-turbo-16k . يمكنك العثور على قائمة النماذج المتاحة في وثائق Openai API.
فيما يلي بعض الأمثلة التمهيدية:
import { ask } from 'ts-askit' ;
ask < string > ( 'Paraphrase "Hello World!"' ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; في هذا المثال ، ask هي وظيفة API تسمح لبرنامجك بوضع استعلامات لنموذج لغة كبير (LLM). تمثل المعلمة النوع نوع الإخراج المتوقع من LLM. هنا ، نوع الإخراج string . يتم تمرير المطالبة كوسيطة في اللغة الطبيعية ، واصفا مهمة LLM لأداء. ask غير متزامن ، وإعادة Promise بنوع الإخراج المحدد. يجب أن يطبع مقتطف الكود أعلاه شيئًا كهذا:
Greetings, Universe!
للحصول على موجه مع المعلمات ، يمكنك استخدام API define على النحو التالي:
import { define } from 'ts-askit' ;
const paraphrase = define < string > ( 'Paraphrase {{text}}' ) ;
paraphrase ( { text : 'Hello World!' } ) . then ( ( result ) => {
console . log ( result ) ;
} ) ; define هي وظيفة API تتيح لك تحديد وظيفة مخصصة. تشير معلمة نوعها إلى نوع الإخراج من LLM ، وبالتالي ، قيمة إرجاع الوظيفة. تستقبل الوظيفة قالب سلسلة كوسيطة ، بمثابة موجه مهمة LLM. يمكن أن يتضمن القالب معلمات محاطة بأقواس مجعد مزدوجة. في المثال أعلاه ، text هو معلمة داخل القالب ، ويمكن أن يكون أي معرف JavaScript صالح.
بمجرد تحديد الوظيفة ، يمكن استدعاءها مثل أي وظيفة أخرى. تقبل هذه الوظيفة كائن كوسيطة ، والتي تقوم بتعيين قيم معلمات القالب. في هذه الحالة ، يقوم text بالخرائط إلى السلسلة "Hello World!".
Askit بارع في إنشاء رمز من أوصاف اللغة الطبيعية. هذا مثال:
import { define } from 'ts-askit' ;
const sort = define < number [ ] , { numbers : number [ ] } > (
'Sort {{numbers}} in ascending order'
) ; يعرض هذا المثال وظيفة تفرز مجموعة من الأرقام في ترتيب تصاعدي ، باستخدام API define لتوجيه LLM لتحديد الوظيفة. على الرغم من فعالية المفهوم ، قد تبدو هذه الطريقة ثقيلة من الناحية الحسابية لأن كل استدعاء وظيفة تتطلب مهمة LLM جديدة.
لتبسيط هذه العملية ، يمكننا الاستفادة من LLM لإنشاء رمز وظيفة الفرز ، بدلاً من اللجوء إلى LLM لكل مهمة فرز. هذا يعمل على تحسين الوظيفة دون الحاجة إلى أي تغييرات في تنفيذها ، وذلك بفضل إمكانيات توليد رمز Askit .
يمكن إنشاء رمز الوظيفة المذكورة أعلاه في ثلاث خطوات:
tsc . يقوم محلل ASKIT بمسح الكود ويقوم بإنشاء ملف JSONL يحتوي على تفاصيل حول مكالمات define API ask .npx askgen < jsonl file >tsc . هذه المرة ، يتم استبدال مكالمات API define and ask بالمراجع والمكالمات إلى الوظيفة التي تم إنشاؤها حديثًا ، على التوالي ، بفضل ميزة الاستبدال التلقائي لـ Askit . يتيح لك Askit الاستفادة من قوة البرمجة بالمثال (PBE). يقوم PBE بتبسيط عملية البرمجة عن طريق تمكينك من تحديد الوظائف من خلال أمثلة بدلاً من المنطق المرمز. يوضح المثال التالي هذا من خلال توضيح كيفية إضافة رقمين ثنائيين باستخدام PBE مع Askit .
import { define , Example } from 'ts-askit' ;
const trainingExamples : Example [ ] = [
{ input : { x : '1' , y : '0' } , output : '1' } ,
{ input : { x : '1' , y : '1' } , output : '10' } ,
{ input : { x : '101' , y : '11' } , output : '1000' } ,
{ input : { x : '1001' , y : '110' } , output : '1111' } ,
{ input : { x : '1111' , y : '1' } , output : '10000' } ,
] ;
const testExamples = [
{ input : { x : '0' , y : '1' } , output : '1' } ,
{ input : { x : '10' , y : '0' } , output : '10' } ,
{ input : { x : '110' , y : '10' } , output : '1000' } ,
] ;
const addInBase2 = define < string , { x : string ; y : string } > (
'Add {{x}} and {{y}}' ,
trainingExamples ,
testExamples
) ;
async function doit ( ) {
console . log ( await addInBase2 ( { x : '101' , y : '11' } ) ) ;
}
doit ( ) ; في هذا المثال ، نحدد وظيفة addInBase2 التي تأخذ رقمين ثنائيين (ممثلة كأوتام) ويضيفهما. يتم استدعاء وظيفة define بمطالبة ومصفوفتان من الأمثلة: أمثلة تدريب وأمثلة اختبار. تنعكس أمثلة التدريب في المطالبة بطريقة تعليمية قليلة. من ناحية أخرى ، يتم استخدام أمثلة الاختبار للتحقق من صحة الوظيفة التي تم إنشاؤها. أمثلة الاختبار غير مطلوبة إذا لم تنشئ رمزًا للوظيفة.
والنتيجة هي ميزة قوية تتيح لك توجيه LLM لأداء عمليات معقدة ، مثل الإضافة الثنائية ، ولا شيء سوى أمثلة. يمكّنك هذا النهج من تطوير وظائف معقدة بسرعة وبنطق أقل وضوحًا.
بمجرد تعريف الوظيفة addInBase2 ، يمكنك تسميتها بأسلاك الأرقام الثنائية لأداء الإضافة في القاعدة 2. كما هو الحال مع مكالمات الوظائف التقليدية ، ask عملية Askit بإرجاع وعد يحل بالنتيجة المحسوبة.
يمكن لمطوري JavaScript استغلال إمكانية التحكم في الإخراج الموجهة من النوع الذي توفره Askit . تمامًا مثل TypeScript Sibling ، تتضمن JavaScript طريقة API ask تحقيق ذلك. تأخذ الوظيفة ask معلمتين: نوع ومطالبة.
فيما يلي مجموعة من الأمثلة التي توضح استخدامها:
const ai = require ( 'ts-askit' )
const t = require ( 'ts-askit/types' )
ai . ask ( t . number , 'What is the third prime number?' ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . string , "What is the month number of 'January'?" ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . array ( t . number ) , "What are the month numbers in the second quarter?" ) ;
const monthType = t . type ( {
name : t . string ,
number : t . number
} )
ai . ask ( monthType , "What is the month number of 'October'?" ) . then ( ( answer ) => { console . log ( answer ) } ) ;
ai . ask ( t . array ( monthType ) , "What are the months in the second quarter?" ) . then ( ( answer ) => { console . log ( answer ) } ) ; في مقتطف الكود أعلاه ، يتم استدعاء وظيفة ask بنوع ومطالبة. تخدم المعلمة النوع الغرض من إبلاغ Askit حول تنسيق وهيكل الإخراج المطلوب. يصبح هذا مفيدًا للغاية عندما تتعامل مع هياكل البيانات المعقدة.
مع Askit ، لدى مطوري JavaScript القدرة على تحديد الوظائف باستخدام قوالب سهلة الفهم. طريقة define هي البطل وراء الكواليس هنا ، حيث إنها تساعد في إنشاء وظائف بناءً على قالب المهمة المقدم. بمجرد إنشائها ، يمكن استدعاء هذه الوظائف مع أي كائن يوفر قيمًا للعناصر النائبة في القالب.
إليك مثال على كيفية القيام به:
const ai = require ( 'ts-askit' )
const t = require ( 'ts-askit/types' )
let f = ai . define ( t . string , 'Translate {{text}} into {{language}}' ) ;
f ( { text : 'Hello' , language : 'French' } ) . then ( ( answer ) => { console . log ( answer ) } ) ; في الكود أعلاه ، يتم استخدام طريقة define لإنشاء دالة f باستخدام قالب المهمة "ترجمة {{text}} إلى {{language}} '. ثم يتم استدعاء الوظيفة f بكائن يوفر قيمًا text language .
وحدة 'ts-askit/types' هي كنز من الأنواع التي يمكنك استخدامها لتوجيه إخراج Askit . إليك جدول لمساعدتك بسرعة على فهم هذه الأنواع:
| يكتب | وصف | اكتب مثال | مثال على القيمة |
|---|---|---|---|
NumberType | نوع رقمي | t.number | 123 |
StringType | نوع السلسلة | t.string | "مرحبا بالعالم!" |
BooleanType | نوع منطقي | t.boolean | حقيقي |
LiteralType | نوع القيمة الحرفية | t.literal(123) | 123 |
ArrayType | نوع الصفيف | t.array(t.number) | [1 ، 2 ، 3] |
UnionType | نوع الاتحاد (قيم متعددة محتملة) | t.union([t.literal('yes'), t.literal('no')]) | "نعم أو لا" |
InterfaceType | واجهة/نوع القاموس | t.type({a: t.number, b: t.number}) | {a: 1 ، b: 2} |
CodeType | نوع الرمز | t.code('python') | "def hello_world (): print ('Hello ، World!')" |
يحتوي كل نوع على خصائص محددة تستخدمها ASKIT لفهم المهمة في متناول اليد وتنسيق الإخراج بشكل صحيح.
اعتبارًا من وقت كتابة هذا التقرير ، تتوفر ميزة توليد الكود بشكل حصري في TypeScript. ومع ذلك ، فإن الجهود على قدم وساق لتوسيع هذه الميزة القوية إلى عالم JavaScript. إذا كانت متطلباتك تدعو إلى استخدام توليد الكود في غضون ذلك ، فإننا نوصي باستخدام TypeScript حتى التحديثات الإضافية.
للحصول على تفاصيل حول مدونة قواعد سلوكنا وعملية تقديم طلبات السحب ، يرجى الرجوع إلى المساهمة.
هذا المشروع مرخص بموجب ترخيص معهد ماساتشوستس للتكنولوجيا. لمزيد من المعلومات ، راجع ملف الترخيص.
@misc { okuda2023askit ,
title = { AskIt: Unified Programming Interface for Programming with Large Language Models } ,
author = { Katsumi Okuda and Saman Amarasinghe } ,
year = { 2023 } ,
eprint = { 2308.15645 } ,
archivePrefix = { arXiv } ,
primaryClass = { cs.PL }
}