DotPrompt هي مكتبة بسيطة تسمح لك بإنشاء المطالبات باستخدام بناء جملة قائم على التكوين، دون الحاجة إلى تضمينها في التطبيق الخاص بك. وهو يدعم إنشاء قوالب للمطالبات من خلال لغة قوالب Fluid، مما يسمح لك بإعادة استخدام نفس الموجه وتمرير قيم مختلفة في وقت التشغيل.
الملف الفوري هو ببساطة أي ملف ينتهي بامتداد .prompt
. الملف الفعلي نفسه هو ملف تكوين YAML، ويتيح الامتداد للمكتبة التعرف بسرعة على الملف للغرض المقصود منه.
هناك مشكلة معروفة في ملفات .prompt
تسبب سلوكًا غير معتاد في أدوات مثل Rider وIntelliJ. يمكنك التغلب على هذه المشكلة إما عن طريق تعطيل المكون الإضافي للمحطة الطرفية أو باستخدام محرر مختلف لتعديل الملفات.
تحتوي محتويات ملف الموجه على بعض خصائص التعريف ذات المستوى الأعلى، تليها معلومات التكوين ثم المطالبات في النهاية.
سيبدو ملف المطالبة الكامل بهذا الشكل.
الاسم: نموذج المثال: gpt-4oconfig: تنسيق الإخراج: نص درجة الحرارة: 0.9 الحد الأقصى للرموز: 500 الإدخال: المعلمات: الموضوع: نمط السلسلة؟: السلسلة الافتراضية: الموضوع: مطالبات الوسائط الاجتماعية: النظام: | أنت مساعد بحث مفيد وسيقدم إجابات وصفية لموضوع معين وكيفية تأثيره على مستخدم المجتمع: | اشرح تأثير {{ موضوع }} على كيفية تعاملنا مع التكنولوجيا كمجتمع {% if style -%} هل يمكنك الإجابة بأسلوب {{ style }} {% endif -%}بعض اللقطات: - المستخدم: ما هو Bluetoothresponse: Bluetooth هو معيار تقنية لاسلكية قصيرة المدى يستخدم لتبادل البيانات بين الأجهزة الثابتة والمحمولة عبر مسافات قصيرة وبناء شبكات المنطقة الشخصية. - المستخدم: كيف يختلف التعلم الآلي عن البرمجة التقليدية؟ الرد: يتيح التعلم الآلي للخوارزميات التعلم من البيانات والتحسين بمرور الوقت دون برمجتها بشكل صريح. - المستخدم: هل يمكنك تقديم مثال على الذكاء الاصطناعي في الحياة اليومية؟ الرد: يُستخدم الذكاء الاصطناعي في المساعدين الافتراضيين مثل Siri وAlexa، اللذين يفهمان الأوامر الصوتية ويستجيبان لها.
name
اختياري في التكوين، إذا لم يتم توفيره، فسيتم أخذ الاسم من اسم الملف مطروحًا منه الامتداد. لذا فإن الملف المسمى gen-lookup-code.prompt
سيحصل على الاسم gen-lookup-code
. لا يلعب هذا دورًا في إنشاء المطالبات نفسها (على الرغم من أن التحديثات المستقبلية قد تفعل ذلك)، ولكنه يسمح لك بتحديد مصدر المطالبات عند التسجيل، وتحديد الموجه من مدير المطالبات.
إذا كنت تستخدم هذه الخاصية، فعند تحميل الملف، يتم تحويل الاسم إلى أحرف صغيرة ويتم استبدال المسافات بواصلات. لذا فإن اسم My cool Prompt
سيصبح my-cool-prompt
. يتم ذلك للتأكد من سهولة الوصول إلى الاسم من خلال الكود.
يعد هذا عنصرًا اختياريًا آخر في التكوين، ولكنه يوفر معلومات لمستخدم ملف المطالبة عن النموذج (أو النشر لـ Azure Open AI) الذي يجب استخدامه. نظرًا لأن هذا يمكن أن يكون فارغًا إذا لم يتم تحديده، فيجب على المستهلك التأكد من التحقق منه قبل الاستخدام. على سبيل المثال:
نموذج فار = ملف موجه ?? "الافتراضي الخاص بي";
ومع ذلك، فإن استخدام هذا الخيار يتيح للمهندس الفوري أن يكون واضحًا جدًا بشأن النموذج الذي ينوي استخدامه لتقديم أفضل النتائج.
يحتوي قسم config
على بعض عناصر المستوى الأعلى التي يتم توفيرها للعميل لاستخدامها في مكالمات LLM الخاصة به لتعيين الخيارات في كل مكالمة. تأخذ خاصية outputFormat
قيمة إما text
أو json
اعتمادًا على كيفية استجابة LLM للطلب. في حالة تحديد json
، فإن بعض LLMs تتطلب إما مطالبة النظام أو المستخدم للإشارة إلى أن الإخراج المتوقع هو JSON أيضًا. إذا لم تكتشف المكتبة مصطلح JSON
في الموجه، فسوف تقوم بإلحاق بيان صغير بموجه النظام تطلب فيه أن تكون الاستجابة بتنسيق JSON.
يحتوي قسم input
على تفاصيل حول المعلمات التي يتم توفيرها للمطالبات. هذه ليست مطلوبة ويمكنك إنشاء مطالبات لا تحتوي على أي قيم يتم تمريرها على الإطلاق. ولكن إذا قمت بذلك فهذا هو ما تحتاجه.
تحت input
يوجد قسم parameters
الذي يحتوي على قائمة بأزواج القيمة الرئيسية حيث المفتاح هو اسم المعلمة، والقيمة هي نوعها. إذا قمت بإلحاق اسم المعلمة بعلامة استفهام (على سبيل المثال، style?
) فسيتم اعتبارها معلمة اختيارية ولن تخطئ إذا لم تقم بتوفير قيمة لها.
الأنواع المدعومة هي:
نوع المعلمة | نوع الدوت نت | ما يعادلها في لغة C# |
---|---|---|
خيط | System.String | خيط |
منطقي | System.Boolean | منطقي |
التاريخ والوقت | System.DateTimeOffset | System.DateTimeOffset |
رقم | System.Byte System.SByte System.UInt16 System.Int16 System.UInt32 System.Int32 System.UInt64 System.Int64 نظام.واحد النظام. مزدوج System.Decimal | بايت sbyte قصير قصير uint كثافة العمليات ulong طويل يطفو مزدوج عشري |
هدف | System.Object | هدف |
يتم استخدام الأربعة الأولى على النحو المنصوص عليه. الكائنات التي يتم تمريرها إلى الموجه سيتم استدعاء أسلوب ToString
الخاص بها لاستخدامها في الموجه.
يمكن عرض نوع datetime
مع تمثيل ToString
الافتراضي الخاص به، أو يمكنك استخدام مرشحات Fluid لتحديد تنسيقه وتغيير المنطقة الزمنية والمزيد.
إذا قمت بتوفير قيمة لمعلمة لا تتوافق مع النوع المحدد، فسيتم طرح خطأ.
يوجد أيضًا في input
القسم default
. يتيح لك هذا القسم تحديد القيم الافتراضية لأي من المعلمات. لذا، إذا لم يتم توفير المعلمة في تطبيقك، فسيتم استخدام القيمة الافتراضية بدلاً من ذلك.
يحتوي قسم prompts
على قوالب النظام ومطالبات المستخدم. على الرغم من أن مطالبة المستخدم مطلوبة، إلا أنك لا تحتاج إلى تحديد مطالبة النظام.
كل من مطالبات system
user
عبارة عن قيم سلسلة ويمكن تعريفها بأي طريقة يدعمها YAML. يستخدم المثال أعلاه سلسلة متعددة الأسطر حيث يتم الاحتفاظ بأحرف الإرجاع.
يتمتع YAML بدعم كبير لقيم السلسلة متعددة الأسطر من خلال Block Scalars. مع هذه فإنه يدعم كلا من السلاسل الحرفية والمطوية . باستخدام السلاسل الحرفية، يتم الحفاظ على أحرف السطر الجديدة في سلسلة الإدخال وتظل السلسلة كما هي مكتوبة تمامًا. عند طي أحرف السطر الجديد، يتم طيها واستبدالها بحرف مسافة، مما يسمح لك بكتابة سلاسل طويلة جدًا على عدة أسطر. باستخدام الطريقة المطوية، إذا كنت تستخدم حرفين جديدين في السطر، فسيتم إضافة سطر جديد إلى السلسلة.
# مثال مطوي: > السفن معلقة في السماء بنفس الطريقة التي لا تعلق بها الطوب# تنتج:# السفن معلقة في السماء بنفس الطريقة التي لا يحدث بها الطوب
#مثال حرفي: | السفن معلقة في السماء بنفس الطريقة التي لا تعلق بها الطوب.# تنتج:# السفن معلقة في السماء بنفس الطريقة التي لا يحدث بها الطوب
يستخدم بناء جملة المطالبات لغة قالب Fluid، والتي تعتمد في حد ذاتها على Liquid الذي أنشأته Shopify. تتيح لنا لغة القوالب هذه تحديد مطالبات المستخدم التي يمكن أن تتغير اعتمادًا على القيم التي يتم تمريرها إلى محلل القالب.
في المثال أعلاه، يمكنك رؤية {{ topic }}
وهو عنصر نائب للقيمة التي يتم تمريرها، وسيتم استبدالها مباشرة في القالب. يوجد أيضًا قسم {% if style -%} ... {% endif -%}
الذي يخبر المحلل بتضمين هذا القسم فقط إذا كانت معلمة style
تحتوي على قيمة. يحتوي -%}
الموجود في نهاية العلامة على رمز الواصلة الذي يخبر المحلل اللغوي بأنه يجب عليه طي الأسطر الفارغة.
يوجد برنامج تعليمي رائع حول كتابة القوالب باستخدام Fluid متاح عبر الإنترنت.
عندما تقوم بإنشاء المطالبة، فإنها لا تحل محل القالب، بل تعطيك فقط المخرجات التي تم إنشاؤها. هذا يعني أنه يمكنك إنشاء المطالبة عدة مرات كما تريد باستخدام قيم إدخال مختلفة.
fewShots
هو قسم يسمح للكاتب الفوري بتقديم تقنيات سريعة للحل. عند إنشاء موجه، يمكنك تضمين ذلك، جنبًا إلى جنب مع موجه النظام الخاص بك، ثم موجه المستخدم، وهذا يوفر أمثلة حول كيفية استجابة LLM لمطالبة المستخدم. إذا كنت تستخدم OpenAI أو Azure OpenAI، فيمكنك استخدام طرق الامتداد (انظر لاحقًا) التي ستنشئ جميع الرسائل لك.
يمكن الوصول إلى الملفات السريعة مباشرة. إذا كان لديك ملفان فقط أو كنت ترغب في اختبارهما بسرعة، فهذه طريقة بسيطة إلى حد ما للقيام بذلك.
باستخدام DotPrompt;var PromptFile = PromptFile.FromFile("path/to/prompt-file.prompt");var systemPrompt = موجهFile.GetSystemPrompt(null);var userPrompt = موجهFile.GetUserPrompt(new Dictionary<string, object>{{ " theme"، "bluetooth" }،{ "style"، "بائع سيارات مستعملة" }});
إذا كان ملف المطالبة يحتوي على المثال أعلاه، فسوف ينتج ما يلي.
System Prompt:
You are a helpful research assistant who will provide descriptive responses for a given topic and how it impacts society
User Prompt:
Explain the impact of bluetooth on how we engage with technology as a society
Can you answer in the style of a used car salesman
قد يؤدي هذا إلى رد من LLM يبدو هكذا (آسف)
سيداتي وسادتي، اجتمعوا ودعني أخبركم عن معجزة التكنولوجيا الحديثة التي أحدثت ثورة في طريقة تواصلنا مع أجهزتنا - أنا أتحدث عن تقنية البلوتوث! البلوتوث هو البطل المجهول، الخلطة السرية التي تجعل حياتنا أكثر راحة، وأكثر اتصالاً، وبالتأكيد أكثر تقنية. تصور هذا: اتصال سلس وخالي من الأسلاك بين أجهزتك المفضلة. لا مزيد من الحبال المتشابكة، لا مزيد من الفوضى. إنه مثل الحصول على بطاقة VIP إلى الصف الأمامي في المستقبل!
...
يعد مدير المطالبة هو الطريقة المفضلة للتعامل مع ملفات المطالبة الخاصة بك. فهو يسمح لك بتحميلها من موقع ما، والوصول إليها بالاسم، ثم استخدامها في تطبيقك.
الإعداد الافتراضي لمدير المطالبات هو الوصول إلى الملفات الموجودة في مجلد prompts
المحلية، على الرغم من أنه يمكنك تحديد مسار مختلف إذا كنت تريد ذلك.
// التحميل من الموقع الافتراضي لدليل "المطالبات" var PromptManager = new PromptManager();var promptFile = موجهManager.GetPromptFile("example");// استخدم مجلدًا مختلفًاvar PromptManager = new PromptManager("another-location"); var PromptFile = PromptManager.GetPromptFile("example");// قم بإدراج جميع المطالبات التي تم تحميلهاvar PromptNames = PromptManager.ListPromptFileNames();
يقوم مدير المطالبة بتنفيذ واجهة IPromptManager
، وبالتالي إذا كنت تريد استخدام ذلك من خلال حاوية DI، أو نمط IoC، فيمكنك بسهولة توفير نسخة ساخرة للاختبار.
يمكن لمدير الموجه أيضًا أن يأخذ مثيل IPromptStore
الذي يسمح لك بإنشاء مخزن مخصص قد لا يعتمد على الملف (راجع إنشاء مخزن موجه مخصص). يسمح هذا أيضًا بتوفير واجهة ساخرة حتى تتمكن من كتابة اختبارات الوحدة التي لا تعتمد على آلية التخزين.
استخدام مدير الموجهات لقراءة المطالبات ثم استخدامها في استدعاء نقطة نهاية Azure OpenAI.
ملاحظة: يفترض هذا المثال وجود دليل prompts
يحتوي على ملف المطالبات المتوفر.
باستخدام System.ClientModel;باستخدام Azure.AI.OpenAI;باستخدام DotPrompt;var openAiClient = new(new Uri("https://endpoint"), new ApiKeyCredential("abc123"));var PromptManager = new PromptManager();var موجه الملف = موجه مدير.GetPromptFile("example");// تأخذ أساليب موجه النظام وموجه المستخدم قواميس تحتوي على القيم المطلوبة لـ // القالب. إذا لم تكن هناك حاجة إلى أي شيء، فيمكنك ببساطة تمرير null.var systemPrompt = PromptFile.GetSystemPrompt(null);var userPrompt = موجهFile.GetUserPrompt(new Dictionary<string, object>{{ "topic", "bluetooth" },{ "style" , "بائع سيارات مستعملة" }});varclient = openAiClient.GetChatClient(promptFile.Model ?? "default-model");إكمال فار = انتظار العميل.CompleteChatAsync([new SystemChatMessage(systemPrompt),new UserChatMessage(userPrompt)],new ChatCompletionOptions(ResponseFormat = موجهFile.OutputFormat == OutputFormat.Json ? ChatResponseFormat.JsonObject: ChatResponseFormat.Text ،درجة حرارة = موجهFile.Config.Temperature,MaxTokens = موجهFile.Config.MaxTokens));
أو باستخدام طرق الإرشاد المتوفرة في OpenAI.
باستخدام System.ClientModel;باستخدام Azure.AI.OpenAI;باستخدام DotPrompt;باستخدام DotPrompt.Extensions.OpenAi;var openAiClient = new(new Uri("https://endpoint"), new ApiKeyCredential("abc123"));var PromManager = جديد PromptManager();var PromptFile = PromptManager.GetPromptFile("example");var PromptValues = new Dictionary<string, object>{{ "topic", "bluetooth" },{ "style", "بائع سيارات مستعملة" }};varclient = openAiClient.GetChatClient(promptFile.Model ?? "default-model" );إكمال فار = انتظار client.CompleteChatAsync(promptFile.ToOpenAiChatMessages(promptValues),promptFile.ToOpenAiChatCompletionOptions());var Response =Complete.Value;Console.WriteLine(response.Content[0].Text);
والآن، إذا أردنا تعديل الموجه الخاص بنا، فيمكننا ببساطة تغيير ملف الموجه وترك الكود الخاص بنا كما هو (بافتراض عدم تغيير المعلمات).
يوضح ما سبق كيف يمكنك استخدام DotPrompt لقراءة الملفات السريعة من القرص. ولكن ماذا لو كان لديك موقف حيث تريد مطالباتك في مكان أكثر مركزية، مثل خدمة التخزين السحابي، أو قاعدة البيانات؟ حسنًا، يمكن لمدير الموجه أن يأخذ مثيل IPromptStore
كوسيطة. في جميع الأمثلة المذكورة أعلاه، يتم استخدام FilePromptStore
المضمن، ولكن يمكنك أيضًا إنشاء ملف خاص بك. كل ما تحتاجه هو تنفيذ الواجهة وقد انتهيت.
لإعطائك مثالاً، إليك تطبيق بسيط يستخدم Azure Storage Table Store للاحتفاظ بتفاصيل المطالبة.
/// <summary>/// تنفيذ IPromptStore لجداول تخزين Azure/// </summary>فئة عامة AzureTablePromptStore: IPromptStore{/// <summary>/// تحميل المطالبات من متجر الجدول/// < /summary>عام IEnumerable<PromptFile> Load(){var tableClient = GetTableClient();var //// <summary>/// الحصول على عميل الجدول/// </summary>TableClient ثابت خاص GetTableClient(){// استبدل عناصر التكوين هنا بالقيمة الخاصة بك أو قم بالتبديل إلى استخدام // Entra Based Authenticationvar Client = new TableServiceClient(new Uri($"https://{Configuration.StorageAccountName}.table.core.windows.net /")),new TableSharedKeyCredential(Configuration.StorageAccountName, Configuration.StorageAccountKey));var tableClient = client.GetTableClient("prompts");tableClient.CreateIfNotExists();return tableClient;}}/// <summary>/// يمثل سجلًا موجودًا في جدول التخزين/// </summary>public class PromptEntity : ITableEntity{ /// <summary>/// يحصل على مفتاح القسم للسجل /// </summary>سلسلة عامة مفتاح التقسيم {احصل على؛ تعيين؛ } = string.Empty;/// <summary>/// يحصل على مفتاح الصف للسجل// </summary>public string RowKey { get; تعيين؛ } = string.Empty;/// <summary>/// يحصل على الطابع الزمني للإدخال/// </summary> public DateTimeOffset? الطابع الزمني {احصل على؛ تعيين؛ }/// <summary>/// يحصل على قيمة ETag للسجلات// </summary>public ETag ETag { get; تعيين؛ }/// <summary>/// يحصل على النموذج ليستخدمه// </summary>سلسلة عامة؟ النموذج {احصل على؛ تعيين؛ }/// <summary>/// يحصل على تنسيق الإخراج /// </summary>public string OutputFormat { get; تعيين؛ } = string.Empty;/// <summary>/// يحصل على الحد الأقصى لعدد الرموز المميزة/// </summary>public int MaxTokens { get; تعيين؛ }/// <summary>/// يحصل على، يعين معلومات المعلمة التي يتم الاحتفاظ بها كقيمة سلسلة JSON /// </summary>public string Parameters { get; تعيين؛ } = string.Empty;/// <summary>/// Gets، يعين القيم الافتراضية التي يتم الاحتفاظ بها كقيمة سلسلة JSON/// </summary>public string Default { get; تعيين؛ } = string.Empty;/// <summary>/// يحصل على قالب موجه النظام ويضبطه// </summary>public string SystemPrompt { get; تعيين؛ } = string.Empty;/// <summary>/// يحصل على قالب موجه المستخدم ويضبطه// </summary>public string UserPrompt { get; تعيين؛ } = string.Empty;/// <summary>/// إرجاع سجل كيان الموجه إلى مثيل <see cref="PromptFile"/>/// </summary>/// <returns></returns>عام PromptFile ToPromptFile(){var بارامترات = قاموس جديد<string, string>();var defaults = new Dictionary<string, object>();// إذا كانت هناك قيم معلمات، فقم بتحويلها إلى Dictionaryif (!string.IsNullOrEmpty(Parameters)){var الكيانParameters = (JsonObject)JsonNode.Parse(Parameters)!;foreach (var (prop,propType) في الكيانParameters){parameters.Add(prop,propType?.AsValue(). ToString() ?? string.Empty);}}// إذا كانت هناك قيم افتراضية، فقم بتحويلها إلى ملف Dictionaryif (!string.IsNullOrEmpty(Default)){var الكيانDefaults = (JsonObject)JsonNode.Parse(Default)!;foreach (var (prop, defaultValue) in الكيانDefaults){defaults.Add(prop, defaultValue?.AsValue(). GetValue<object>() ?? string.Empty);}}// إنشاء المطالبة الجديدة filevar PromptFile = new PromptFile{Name = RowKey,Model = Model,Config = new PromptConfig{OutputFormat = Enum.Parse<OutputFormat>(OutputFormat, true),MaxTokens = MaxTokens,Input = new InputSchema{Parameters = Parameters,Default = defaults}},Prompts = مطالبات جديدة {النظام = SystemPrompt، المستخدم = UserPrompt}};إرجاع ملف المطالبة;}}
ومن ثم لاستخدام هذا سنقوم بما يلي
var PromptManager = new PromptManager(new AzureTablePromptStore());var PromptFile = موجهManager.GetPromptFile("example");
لا يزال هناك مجال للعمل الذي يجب القيام به هنا وتشمل بعض العناصر التي نتطلع إليها
خيارات التكوين الإضافية
تقنيات تحفيز إضافية
مفتوحة لردود الفعل. هل هناك أي شيء تود رؤيته؟ اسمحوا لنا أن نعرف