AR ▾
الحصول على مفتاح API

تطبيق عملي لنافذة السياق بـ 100k: الإكمال، التلخيص، التقسيم، والميزانية

قد يبدو سياق 100,000 رمزًا واسعًا، لكن عند الاستخدام الفعلي تكتشف أن رواية كاملة قد لا تتسع، أو أن مستندًا طويلًا مع المخرجات المطلوبة يقترب من الحد. ندير السياق الطويل كميزانية: كيف تقدر الرموز، كيف تخصص مساحة للمخرجات، كيف تقسم المستندات الطويلة للتلخيص، وكيف تستخدم النافذة المنزلقة مع ملخص متحرك لمتابعة الروايات. الكود مكتوب بـ Python، لكن المنطق ينطبق على أي لغة.

تم التحديث في

نقاط رئيسية

  • 100,000 هو مجموع الـ prompt و completion، وليس حدًا للإدخال فقط.
  • عدد رموز اللغة الصينية يُقدّر تقريبًا، بحوالي 1 إلى 1.5 رمز لكل حرف، ويعتمد الرقم النهائي على usage في الاستجابة.
  • تلخيص النصوص الطويلة يعتمد على التقسيم والدمج، ومتابعة الروايات تعتمد على النصوص الأخيرة مع ملخص متحرك.
  • max_tokens افتراضيًا 2048، والحد الأقصى 16,000؛ احسب الميزانية قبل الكتابة الطويلة.

احسب الحدود بوضوح أولاً

ثلاثة أرقام تحدد كل شيء:

  • إجمالي السياق 100,000 رمز، ⟨الموجّه والإكمال معاً.
  • max_tokens افتراضيًا 2048، والحد الأقصى للطلب الواحد 16,000.
  • حجم جسم الطلب لا يتجاوز 8 MB؛ هذا الحد نادر الوصول له للنصوص، فالرموز هي التي تصل للحد أولاً.

معادلة الميزانية بسيطة: ⟨الموجّه المتاح = 100000 - max_tokens⟩. إذا أردت 4000 رمز، يتبقى 60,000 للموجّه. تجاوز الحد يعيد 400 ولا يقطع تلقائياً.

فهم خاطئ شائع آخر: كلما كان max_tokens أكبر، كان ذلك أكثر أماناً. في الواقع، هو مساحة مخصصة للمخرجات، فإعداد 16,000 يعني أن الـ prompt لن يتجاوز 48,000. اضبطه حسب الحاجة، ولا ترفعه للحد الأقصى بلا تفكير.

مثال على الحساب: افترض أن لديك نص مقابلة من 300,000 كلمة تريد تلخيصه. بتقدير خشن بـ 1.3 رمز (token) لكل كلمة، يصبح المجموع حوالي 390,000 رمز (token)، وهو أكثر من ستة أضعاف الحد الأقصى، لذا لا يمكن إرساله كاملاً. افترض أيضاً أن التلخيص الفردي يتطلب 800 رمز (token) من المخرجات، فيكون الحد الأقصى لكل كتلة إدخال 63,000 رمز (token). مع ترك هامش أمان بنسبة 10٪، يتبقى حوالي 50,000 رمز (token) فقط. لكن هذا ليس الحل الأمثل؛ فعندما تكون الكتل كبيرة، يضعف تركيز النموذج على المحتوى الأوسط. لذا، الحل أدناه هو تقسيم الكتل إلى أحجام أصغر، حتى لو تطلّب ذلك استدعاءات أكثر.

تقدير الرموز: خوارزمية تقريبية

بدون مُجزئ محلي، استخدم هذه القيم التقريبية. ⟨القيم تقريبية وليست دقيقة، وقد يختلف النص بنسبة 10-20%.

نوع النصالتحويل التقريبي
نص صينيحوالي 1 إلى 1.5 رمز لكل كلمة
الإنجليزيةحوالي 1 رمز لكل 4 أحرف، أو 1.3 رمز لكل كلمة
الكود، JSON، والنصوص كثيفة الرموزتستهلك رموزًا أكثر من النص العادي؛ يُنصح بالتقدير بقيم أعلى تحفظًا.

دالة تقديرية كافية مع حساب الميزانية مع الاحتياطي:

CONTEXT = 100000

def est_tokens(text: str) -> int:
    """粗估:中文按每字 1.3 token,其余字符按每 4 个字符 1 token。仅为近似。"""
    zh = sum(1 for c in text if "\u4e00" <= c <= "\u9fff")
    other = len(text) - zh
    return int(zh * 1.3 + other / 4) + 1

def max_prompt_budget(max_tokens: int, margin: float = 0.1) -> int:
    """给定计划的 max_tokens,返回 prompt 最多能用多少 token(留 margin 余量)。"""
    return int((CONTEXT - max_tokens) * (1 - margin))

# 例:计划让模型写 3000 token,prompt 预算
print(max_prompt_budget(3000))   # 54900

طريقة المعايرة: أرسل طلبًا بجزء نموذجي، اقرأ usage.prompt_tokens، قارنه بتقديرك، احسب معاملك الخاص، ثم عدّل الدالة. التقدير يحدد "هل أقسم؟"، أما المحاسبة فتعتمد على usage.

تلخيص المستندات الطويلة: التقسيم والدمج

عند تجاوز الميزانية، الطريقة القياسية هي map-reduce: قسم النص وخلص كل جزء، ثم ادمج الملخصات. انتبه:

  1. اقطع عند حدود الفقرات، لا تقطع حسب عدد الأحرف الثابت لتجنب قطع الجمل.
  2. خصص ميزانية لكل جزء، يُنصح بألا يتجاوز ثلث الحد الأقصى، واترك مساحة للتعليمات والمخرجات.
  3. اطلب من الملخصات الحفاظ على الأسماء والأرقام والأحداث الرئيسية، وإلا ستضيع المعلومات عند الدمج.
  4. إذا كان ملخص الملخص لا يزال طويلاً، كرر العملية.
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])

def split_paragraphs(text, budget):
    """按段落切块,每块估算不超过 budget token。"""
    chunks, cur, used = [], [], 0
    for p in text.split("\n"):
        t = int(len(p) * 1.3) + 1          # 中文粗估
        if used + t > budget and cur:
            chunks.append("\n".join(cur))
            cur, used = [], 0
        cur.append(p)
        used += t
    if cur:
        chunks.append("\n".join(cur))
    return chunks

def ask(prompt, max_tokens=800):
    r = client.chat.completions.create(
        model="uncensored",
        temperature=0.3,
        max_tokens=max_tokens,
        messages=[{"role": "user", "content": prompt}],
    )
    return r.choices[0].message.content

def summarize_long(text, budget=12000):
    parts = split_paragraphs(text, budget)
    partial = [ask("用不超过 200 字概括下面这段,保留人名和关键事件:\n\n" + p) for p in parts]
    merged = "\n".join(f"第{i+1}部分:{s}" for i, s in enumerate(partial))
    return ask("下面是分段摘要,请合并成一份 400 字以内的整体摘要:\n\n" + merged, max_tokens=900)

استخدم temperature بقيمة 0.3 للتثبيت. الاستدعاءات مستقلة ويمكن أن تكون parallel requests، لكن احذر من حد المعدل 300 طلب/دقيقة لكل مفتاح.

لا يوجد حجم قياسي للكتل. تجريبياً، 10,000 إلى 15,000 رمز يوفر توازنًا بين التفاصيل وعدد الاستدعاءات. جرب أحجام 5000، 12000، و25000 على عينة، وقارن عدد الحقائق المفقودة. الوثائق عالية الكثافة تحتاج كتلًا أصغر، والسجلات الحوارية ذات الحشو تسمح بكتل أكبر.

متابعة الروايات: النافذة المنزلقة والملخص المتحرك

عند الوصول للفصل العاشر، لن يتسع النص الكامل ولا يحتاج لذلك. استخدم ذاكرة على مستويين:

  • المشهد القريب: آخر فصلين أو ثلاثة لضمان استمرارية الأسلوب والحوار.
  • المشهد البعيد: فصول سابقة مضغوطة في ملخص، مع الحفاظ على العلاقات والخيوط غير المحلولة.

بعد كتابة كل فصل، اطلب من النموذج تلخيص هذا الفصل في ثلاث إلى خمس جمل وإضافتها إلى الـ outline؛ وإذا تجاوز الـ outline نفسه 3000 رمز (token)، قم بضغطه بالكامل مرة أخرى.

def continue_story(chapters, outline, new_hint, keep_last=3):
    """chapters: 已写章节列表。只带最近 keep_last 章原文,更早的用 outline(滚动大纲)代替。"""
    recent = "\n\n".join(chapters[-keep_last:])
    prompt = (
        f"【全书大纲(早期章节摘要)】\n{outline}\n\n"
        f"【最近章节原文】\n{recent}\n\n"
        f"【下一章要求】\n{new_hint}\n\n请写下一章,约 2000 字。"
    )
    return ask(prompt, max_tokens=4000)

أكثر ما يضيع هو الخيوط المتشابكة (الحواف). نوصي بإدراج عمون "الحواف غير المستغلة" بشكل منفصل في الـ outline، ومتابعة طلب معالجة واحدة منها في كل فصل. كما يجب إدراج أسماء الشخصيات والأماكن في قائمة ثابتة في system لتجنب أن يغيّر النموذج الأسماء تلقائياً عند خروجها من نافذة السياق.

مشكلة أخرى: انحراف الأسلوب. النموذج يميل لأسلوب الفصول الأخيرة. لحل ذلك، أضف "عينة أسلوب" في system كنقطة ثبات لا تتحرك مع النافذة.

max_tokens والقطع

يحدث قطع الإجابة في حالتين:

  1. finish_reason هو length: وصلت لحد max_tokens. الحل: زيادة max_tokens أو طلب الكتابة على مراحل.
  2. الطلب يعود 400: مجموع الموجّه و max_tokens تجاوز 100,000. الحل هو تقليل المدخلات أو تقليل max_tokens.

جدول ميزانية عملي:

المهمةmax_tokens المقترحالموجّه متاح (تقريباً)
التلخيص، الاستخراج80063,200
استكمال الفصل (حوالي 2000 كلمة)400060,000
إطالة المخرجات لمستوى الآلاف من الكلمات16000 (الحد الأقصى)48,000

تتأثر المخرجات الطويلة أيضاً بـ«وقت الاستجابة»، لذا يُنصح باستخدام البث المتدفق لعرض المخرجات أثناء توليدها.

عند انقطاع الإكمال، لا تقم بإلقاء النص المقطوع على النموذج وقل "استمر". الطريقة الأكثر استقراراً هي إعادة الجزء المُولّد كرسالة assistant في messages، ثم إضافة رسالة user تقول "استمر من الجملة الأخيرة دون تكرار"، مما يضمن أكثر سلاسة. انتبه: هذه الخطوة تطيل الموجّه، لذا أعد حساب الميزانية.

قائمة مراجعة سياق طويل

  • استخدم دالة التقدير لحساب حجم الموجّه قبل كل طلب، وإذا تجاوزت الميزانية فانتقل إلى مسار التقسيم.
  • سجل usage في كل استجابة للمعايرة المستمرة لمعامل التقدير.
  • ضع رسالة system والخطة في بداية المحتوى، وأعد التأكيد على المتطلبات الأساسية في نهاية التعليمات.
  • تحقق من finish_reason؛ إذا كان length فعّل التنبيه أو الاستكمال.
  • حدد حداً أقصى لرسائل المحادثة التاريخية، وحذف الأقدم عند تجاوز الحد، ولا تنتظر حتى يعيد الواجهة خطأ 400.

محتوى ذو صلة: هيكل الموجّه في كتابة الموجّه، معالجة الأخطاء في دليل أكواد الأخطاء، التسعير في صفحة الأسعار.

تذكير أخير: السياق الطويل لا يعني الذاكرة الطويلة. يقرأ النموذج ما تقدمه من محتوى من الصفر في كل طلب، ولا يتذكر أي شيء من الاستدعاء السابق؛ لذا يجب عليك توفير التاريخ لضمان الاستمرارية.

الأسئلة الشائعة

هل سياق 100k يتضمن المخرجات؟

نعم. الحد الأقصى هو مجموع الموجّه والإكمال، لذا كلما زاد max_tokens، قل حجم المدخلات التي يمكن إدخالها.

كم يمثل الحرف الصيني الواحد من الرموز؟

يمكن تقديره تقريبياً بحوالي 1 إلى 1.5 رمز لكل حرف، مع تباين حسب النص. الطريقة الأكثر دقة هي قراءة حقل usage في الاستجابة لضبط القيم بناءً على القياس الفعلي.

هل يتم قص المدخلات تلقائياً عند تجاوز الحد؟

لا، الطلب سيعود 400. تحتاج أنت إلى تقسيم المحتوى أو تجاهل القديم قبل الاستدعاء.

ما هو الحد الأقصى لطول المخرجات في الطلب الواحد؟

max_tokens افتراضي 2048، والحد الأقصى للطلب الواحد 16,000. للمحتوى الأطول، قم بتوليد النص على مراحل واستخدم الملخص للحفاظ على الاتساق.

املأ النموذج فقط للحصول على المفتاح

أنشئ حساباً، انسخ المفتاح، وعدّل Base URL. الإعداد بهذه البساطة.