الاستجابات والبث
- معيارية
- مسودة 1.0
- آخر تحديث
- عرض بصيغة Markdown
6.1 الطلب
POST /lmsp/v1/responses
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG
LMSP-Version: 1.0
{
"model": "qwen3:14b-q4_k_m",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Describe a local model service in one sentence."
}
]
}
],
"stream": false,
"max_output_tokens": 512,
"temperature": 0.7,
"response_format": {
"type": "text"
},
"store": true
}
يستخدم البروتوكول الأساسي بنية input وoutput على نمط Responses بدلًا من قائمة بسيطة من سلاسل الرسائل، ليتسع شكل طلب واحد لما يلي:
- رسائل متعددة الأدوار؛
- نصوصًا وصورًا وصوتًا وملفات؛
- استدعاءات أدوات ونتائجها؛
- مخرجات منظَّمة؛
- ملخصات الاستدلال؛
- مخرجات متعددة الوسائط.
يحدد LMSP 1.0 المحتوى النصي فقط. أما أنواع محتوى الصور والصوت والملفات فمحجوزة للإصدارات اللاحقة.
| الحقل | إلزامي | المعنى |
|---|---|---|
model |
نعم | معرّف النموذج المراد استخدامه. |
input |
نعم | مصفوفة عناصر الإدخال. عنصر message له role (system أو user أو assistant) ومصفوفة content من الأجزاء، مثل input_text. ويضيف استخدام الأدوات عنصري function_call وfunction_call_output (القسم 6.5). |
stream |
لا | true لاستقبال أحداث يرسلها الخادم. والافتراضي false. |
max_output_tokens |
لا | حد أعلى لعدد الرموز المولَّدة. |
temperature |
لا | درجة حرارة أخذ العينات. |
response_format |
لا | {"type": "text"} (الافتراضي)، أو {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} للمخرجات المنظَّمة. يتطلب القدرة structured_output. |
tools, tool_choice |
لا | أدوات دالّية يمكن للنموذج استدعاؤها (القسم 6.5). يتطلب القدرة tools. |
store |
لا | يطلب من الخدمة الاحتفاظ بالاستجابة، لإمكان استرجاعها لاحقًا واستخدامها بوصفها previous_response_id. والافتراضي false. تتجاهله الخدمات التي لا تملك القدرة conversations. |
previous_response_id |
لا | يواصل من استجابة مخزَّنة. يتطلب القدرة conversations. |
extensions |
لا | امتدادات خاصة (القسم 9.1). |
يُرفض الطلب الذي يحتاج إلى قدرة ليست لدى النموذج بـ 400 مع unsupported_capability. ويُرفض الطلب الذي لا تتسع له نافذة السياق بـ 400 مع context_length_exceeded.
يجوز للخدمة القادرة على تخزين المحادثات أن تدعم previous_response_id أيضًا. وإلا فإنه يجب أن يحمل كل طلب السياق كاملًا. ولا يجوز للخدمة أن تعتمد على اتصال HTTP لحفظ حالة المحادثة.
6.2 الاستجابة المتزامنة
عندما تكون stream هي false، تعيد الخدمة 200 OK مع كائن استجابة بعد انتهاء التوليد.
{
"id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF",
"object": "response",
"created_at": 1794200000,
"status": "completed",
"model": "qwen3:14b-q4_k_m",
"output": [
{
"id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE",
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device."
}
]
}
],
"usage": {
"input_tokens": 28,
"output_tokens": 31,
"total_tokens": 59
},
"error": null,
"incomplete_details": null
}
| الحقل | المعنى |
|---|---|
id |
معرّف الاستجابة، مثل resp_.... |
object |
دائمًا "response". |
created_at |
وقت الإنشاء بالثواني منذ حقبة Unix. |
status |
in_progress أو completed أو incomplete أو failed أو cancelled. وتُعاد الاستجابة المتزامنة بحالة نهائية. |
model |
معرّف النموذج الذي أنتج الاستجابة. |
output |
مصفوفة عناصر المخرجات. |
usage |
أعداد الرموز: input_tokens وoutput_tokens وtotal_tokens. |
error |
null، أو كائن مشكلة (القسم 9.3) عندما تكون status هي failed. |
incomplete_details |
null، أو كائن فيه reason مثل max_output_tokens عندما تكون status هي incomplete. |
أنواع عناصر المخرجات:
| نوع العنصر | الشكل |
|---|---|
message |
id وrole (assistant) وcontent، وهي مصفوفة أجزاء output_text يحمل كل منها text. |
function_call |
id وcall_id وname وarguments، وهي سلسلة مرمَّزة بصيغة JSON. |
reasoning |
id وsummary، وهي مصفوفة أجزاء summary_text يحمل كل منها text. |
إذا فشل التوليد، يُرد على الطلب المتزامن بحالة خطأ ومستند مشكلة (القسم 9.3)، لا بكائن استجابة. وتظهر الحالة failed في التدفقات والمهام والاستجابات المخزَّنة.
يعيد GET /lmsp/v1/responses/{response_id} استجابة خُزّنت بـ store: true. وهو اختياري ويتطلب القدرة conversations. والمعرّف المجهول يعطي 404 مع response_not_found.
6.3 البث
للبث، اضبط stream في الطلب:
{
"stream": true
}
ترد الخدمة بـ 200 OK مع Content-Type: text/event-stream وترسل أحداثًا دلالية. لكل حدث id واسم event وكائن JSON هو data:
id: 1
event: response.created
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"}
id: 2
event: response.output_item.added
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}}
id: 3
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "}
id: 4
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."}
id: 5
event: response.output_item.done
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}}
id: 6
event: response.completed
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}}
تُعرَّف هذه الأحداث على الأقل:
| الحدث | المعنى | حقول البيانات |
|---|---|---|
response.created |
أُنشئت الاستجابة. | response_id، status (in_progress) |
response.output_item.added |
بدأ عنصر مخرجات جديد. | response_id، output_index، item |
response.output_text.delta |
أُلحق نص بعنصر رسالة. | response_id، item_id، delta |
response.output_item.done |
اكتمل عنصر مخرجات. | response_id، output_index، item |
response.completed |
انتهت الاستجابة. الحدث الأخير. | response_id، status، usage |
response.incomplete |
توقف التوليد مبكرًا، مثلًا عند حد الرموز. الحدث الأخير. | response_id، status، incomplete_details، usage |
response.failed |
فشل التوليد. الحدث الأخير. | response_id، status، error |
response.cancelled |
أُلغيت الاستجابة. الحدث الأخير. | response_id، status |
error |
مشكلة غير مرتبطة باستجابة واحدة، ولا يمكن للتدفق أن يستمر بعدها. | error، وهو كائن مشكلة |
تغلق الخدمة التدفق بعد حدث أخير أو حدث error.
يجوز للخدمات إرسال أحداث إضافية، مثل أحداث لوسائط استدعاءات الأدوات والصور والصوت ودلتا JSON المنظَّم. ويجب على العملاء تجاهل أنواع الأحداث التي لا يعرفونها.
إذا أغلق العميل اتصال طلب مبثوث، ينبغي للخدمة أن تتوقف عن التوليد.
6.4 معرّفات الأحداث وإعادة الاتصال
يجب أن يكون id الحدث رقمًا تسلسليًا صحيحًا يزداد بصرامة داخل الاستجابة، ويبدأ من 1.
بعد انقطاع الاتصال، يستأنف العميل بإرسال آخر معرّف تلقّاه. ويفعل ذلك بترويسة:
Last-Event-ID: 2
أو بمعامل استعلام:
GET /lmsp/v1/tasks/{task_id}/events?after=2
وكلاهما يذهب إلى نقطة نهاية أحداث المهمة (القسم 7.4). وتعيد الخدمة إرسال الأحداث التي يزيد رقمها التسلسلي على 2 فقط. وإن وُجد الاثنان فالأسبقية لـ after.
إذا كانت الأحداث المطلوبة أقدم من مدة الاحتفاظ، ترد الخدمة بـ 410 Gone مع الخطأ event_history_expired. فيجلب العميل عندها النتيجة النهائية بدلًا من ذلك، بـ GET /lmsp/v1/tasks/{task_id}.
الاستجابة المبثوثة مباشرةً من POST /lmsp/v1/responses تخص اتصال HTTP ذاك ولا يمكن استئنافها. وينبغي للعميل الذي يحتاج إلى مخرجات قابلة للاستئناف أن ينشئ مهمة ويتابع أحداثها.
6.5 استدعاءات الأدوات
يحدد LMSP 1.0 أدوات دالّية ينفذها العميل. والخدمة لا تشغّل الأدوات بنفسها. والنطاق tools:execute محجوز للامتدادات التي تفعل ذلك (القسم 10.3).
أولًا، يسرد العميل الأدوات. لكل إدخال type قيمته function، وname، وdescription، وparameters وهو كائن JSON Schema. وقيمة tool_choice هي auto (الافتراضي) أو none أو required أو {"type": "function", "name": "get_weather"}.
{
"model": "qwen3:14b-q4_k_m",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What is the weather in Hangzhou?"
}
]
}
],
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
],
"tool_choice": "auto"
}
عندما يقرر النموذج استدعاء أداة، تحتوي الاستجابة على عنصر function_call. وتكون arguments فيه سلسلة مرمَّزة بصيغة JSON. وفي التدفق يصل العنصر كاملًا في response.output_item.done.
{
"id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH",
"object": "response",
"created_at": 1794200050,
"status": "completed",
"model": "qwen3:14b-q4_k_m",
"output": [
{
"id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK",
"type": "function_call",
"call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
"name": "get_weather",
"arguments": "{\"city\":\"Hangzhou\"}"
}
],
"usage": {
"input_tokens": 74,
"output_tokens": 18,
"total_tokens": 92
},
"error": null,
"incomplete_details": null
}
ينفذ العميل الأداة، ثم يرسل طلبًا جديدًا يحمل السياق كاملًا: عناصر الإدخال السابقة، وعنصر function_call كما استُلم، وعنصر function_call_output بـ call_id نفسه. وoutput فيه سلسلة، وتكون عادةً مرمَّزة بصيغة JSON.
{
"type": "function_call_output",
"call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
"output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}