DeepSeek Harness: سجلات الجلسات و Trajectory

آخر تحديث: 2026-08-31

كل محادثة Agent هي رحلة غير قابلة لإعادة الإنتاج — النماذج لها عشوائية، والأدوات لها تأثيرات جانبية، والسياق يتراكم. نظام Trajectory في DSH يستخدم "سجلات الإلحاق فقط" لتسجيل كل خطوة بالكامل، مما يتيح لك التتبع والتدقيق والتفرع واستعادة حالة الجلسة في أي نقطة زمنية.

💡 نصيحة: Trajectory ليس مجرد عارض سجلات — بل هو جوهر إدارة الجلسات. يمكنك تفرع شعبة للتجربة دون التأثير على الخط الرئيسي، أو الاستعادة من أي نقطة تحقق لاختيار مسار مختلف.

📋 المتطلبات المسبقة: إكمال 07-python-sdk.md، إلمام بأساسيات SDK

1. ما ستتعلمه

دورة حياة الجلسة


2. تصميم سجلات الإلحاق فقط

(1) لماذا الإلحاق فقط؟

أنظمة السجلات التقليدية تسمح بالتعديل والحذف، لكن سجلات جلسات Agent يجب أن تكون غير قابلة للتغيير — مثل مسجل بيانات الرحلة (الصندوق الأسود)، بمجرد كتابة سجل لا يمكن تغييره:

100%
graph LR
    E1[حدث 1] --> E2[حدث 2] --> E3[حدث 3] --> E4[حدث 4] --> E5[حدث 5]
    E5 -.->|إلحاق فقط| NEW[حدث 6]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style NEW fill:#fff3e0

ثلاثة مبادئ لتصميم الإلحاق فقط:

المبدأ الوصف الفائدة
غير قابل للتغيير بمجرد الكتابة، لا يمكن تعديل أو حذف السجلات مسار تدقيق كامل
مرتب الأحداث مرتبة بدقة حسب الطابع الزمني قابل لإعادة الإنتاج
إلحاق فقط يمكن إضافة أحداث جديدة فقط، بدون حذف لا تعارض في التزامن

(2) مقارنة مع السجلات التقليدية

البُعد السجلات التقليدية سجلات إلحاق فقط في DSH
قابل للتعديل ✅ يمكن تعديل/حذف ❌ لا يمكن تعديل
آمن في التزامن يتطلب قفل آمن بطبيعته (إلحاق فقط)
قدرة التراجع يعتمد على النسخ الاحتياطية استعادة من أي نقطة
قدرة التدقيق قد يتلاعب به مقاوم للتلاعب
كفاءة التخزين قابل للضغط ينمو باستمرار (يتطلب أرشفة دورية)

(3) بنية تخزين السجلات

TEXT 📖 للعرض فقط
.dsh/
└── sessions/
    └── sess_abc123/
        ├── events.log          # سجل الأحداث (إلحاق فقط)
        ├── snapshots/          # لقطات الحالة
        │   ├── snap_001.json
        │   ├── snap_002.json
        │   └── snap_003.json
        └── metadata.json       # بيانات الجلسة الوصفية

3. تدفق أحداث SessionEvent

(1) أنواع الأحداث

كل عملية في جلسة DSH تُسجل كـ SessionEvent:

TYPESCRIPT
type SessionEventType =
  | 'session.created'
  | 'session.config_changed'
  | 'user.message'
  | 'agent.message'
  | 'agent.thinking'
  | 'tool.call'
  | 'tool.result'
  | 'tool.approval.requested'
  | 'tool.approval.resolved'
  | 'session.forked'
  | 'session.restored'
  | 'error.occurred';

(2) بنية الحدث

كل SessionEvent يحتوي على حقول قياسية:

TYPESCRIPT
interface SessionEvent {
  id: string;                  // معرف حدث فريد
  type: SessionEventType;      // نوع الحدث
  timestamp: number;           // طابع زمني Unix (ميلي ثانية)
  sessionId: string;           // معرف الجلسة الأصل
  data: Record<string, unknown>;  // بيانات حمولة الحدث
  parentId?: string;           // معرف الحدث الأصل (يُستخدم للتفرعات)
}

(3) أوصاف الأحداث التفصيلية

حدث رسالة المستخدم:

▶ مثال 1: حدث user.message

JSON
{
  "id": "evt_001",
  "type": "user.message",
  "timestamp": 1724486400000,
  "sessionId": "sess_abc123",
  "data": {
    "content": "ساعدني في إعادة هيكلة دليل utils",
    "attachments": []
  }
}

حدث استدعاء أداة:

▶ مثال 2: حدث tool.call

JSON
{
  "id": "evt_002",
  "type": "tool.call",
  "timestamp": 1724486401500,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "search",
    "params": {
      "pattern": "utils/*",
      "type": "file"
    },
    "mode": "standard"
  }
}

حدث نتيجة أداة:

▶ مثال 3: حدث tool.result

JSON
{
  "id": "evt_003",
  "type": "tool.result",
  "timestamp": 1724486402300,
  "sessionId": "sess_abc123",
  "data": {
    "toolCallId": "evt_002",
    "status": "success",
    "result": {
      "files": ["utils/format.ts", "utils/validate.ts", "utils/helpers.ts"]
    },
    "duration_ms": 800
  }
}

حدث موافقة:

▶ مثال 4: حدث tool.approval

JSON
{
  "id": "evt_004",
  "type": "tool.approval.requested",
  "timestamp": 1724486403000,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "file_edit",
    "params": {
      "action": "edit",
      "path": "utils/format.ts"
    },
    "riskLevel": "high"
  }
}
JSON
{
  "id": "evt_005",
  "type": "tool.approval.resolved",
  "timestamp": 1724486405000,
  "sessionId": "sess_abc123",
  "data": {
    "approvalId": "evt_004",
    "decision": "allowed",
    "decidedBy": "user"
  }
}

(4) مثال على تدفق أحداث كامل

TEXT 📖 للعرض فقط
الخط الزمني                  نوع الحدث
─────────────────────────────────────────
10:00:00.000   session.created
10:00:05.120   user.message          "ساعدني في إعادة هيكلة دليل utils"
10:00:06.300   tool.call             search → utils/*
10:00:07.100   tool.result           وُجد 3 ملفات
10:00:08.200   tool.call             file_edit → قراءة utils/format.ts
10:00:08.500   tool.result           أُرجع محتوى الملف
10:00:10.800   agent.thinking        تحليل خطة إعادة الهيكلة...
10:00:12.000   tool.approval.requested   file_edit → تعديل
10:00:15.000   tool.approval.resolved    → مسموح
10:00:15.200   tool.call             file_edit → تعديل utils/format.ts
10:00:15.600   tool.result           التعديل مكتمل
10:00:17.000   agent.message         "إعادة الهيكلة مكتملة!"

4. عرض Trajectory

(1) ما هو Trajectory؟

Trajectory هو الواجهة المرئية لسجلات الجلسات، تعرض "مسار" Agent الكامل:

TEXT 📖 للعرض فقط
┌─ عرض Trajectory ──────────────────────────────────────┐
│                                                         │
│ 10:00  👤 ساعدني في إعادة هيكلة دليل utils          │
│ 10:00    🔍 search(utils/*) → 3 ملفات            0.8ث  │
│ 10:00    📄 file_edit(قراءة) → utils/format.ts    0.3ث  │
│ 10:00    📄 file_edit(قراءة) → utils/validate.ts  0.2ث  │
│ 10:00    🤔 يفكر... تحليل خطة إعادة الهيكلة      │
│ 10:00    ⚠️ موافقة: تعديل utils/format.ts              │
│ 10:00      → ✅ مسموح                                  │
│ 10:00    📝 file_edit(تعديل) → utils/format.ts    0.4ث  │
│ 10:00    ⚠️ موافقة: تعديل utils/validate.ts            │
│ 10:00      → ✅ مسموح                                  │
│ 10:00    📝 file_edit(تعديل) → utils/validate.ts  0.3ث  │
│ 10:00    🤖 إعادة الهيكلة مكتملة! استُخرجت تعريفات الأنواع المشتركة... │
│                                                         │
│ [تفرع من هنا] [استعادة إلى هنا] [تصدير]             │
└─────────────────────────────────────────────────────────┘

(2) الوصول لـ Trajectory في واجهة الويب

في واجهة الويب، انقر أيقونة السجل في شريط التحكم العلوي لفتح عرض Trajectory:

TEXT 📖 للعرض فقط
شريط التحكم العلوي → 📋 → Trajectory

(3) تصفية وبحث Trajectory

▶ مثال 5: التصفية حسب نوع الحدث

TEXT 📖 للعرض فقط
فلاتر عرض Trajectory:
┌──────────────────────────────────────────┐
│ فلاتر:                                 │
│ ☑ user.message    ☑ agent.message        │
│ ☑ tool.call       ☑ tool.result          │
│ ☐ agent.thinking  ☐ أحداث الموافقة      │
│                                          │
│ بحث: [أدخل كلمات مفتاحية...]              │
└──────────────────────────────────────────┘

(4) الوصول لـ Trajectory عبر SDK

▶ مثال 6: الحصول على تدفق الأحداث عبر SDK

PYTHON
from dsh import DSHClient

client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# الحصول على جميع الأحداث
events = session.get_trajectory()

for event in events:
    print(f"[{event.timestamp}] {event.type}: {event.data}")

# التصفية حسب النوع
tool_events = session.get_trajectory(event_type="tool.call")

for event in tool_events:
    print(f"الأداة: {event.data['tool']}")
    print(f"المعاملات: {event.data['params']}")

5. تفرع واستعادة الجلسات

(1) مفهوم التفرع

ينشئ التفرع شعبة جلسة من نقطة زمنية محددة — الخط الرئيسي يستمر بينما الشعبة تتطور بشكل مستقل:

100%
graph LR
    E1[حدث 1] --> E2[حدث 2] --> E3[حدث 3] --> E4[حدث 4]
    E3 -->|تفرع| F1[حدث تفرع 1] --> F2[حدث تفرع 2]
    
    E4 --> E5[حدث 5]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style F1 fill:#e3f2fd
    style F2 fill:#e3f2fd

(2) حالات استخدام التفرع

السيناريو الوصف
استكشاف الحلول جرّب أساليب مختلفة من نفس العقدة، قارن النتائج
احتياط آمن تفرع قبل العمليات المدمرة؛ عُد للخط الرئيسي إذا فشلت
اختبار A/B قارن نفس المهمة باستخدام نماذج/أوضاع مختلفة
تغييرات تجريبية عند عدم اليقين من النتائج، جرّب في شعبة أولاً

(3) التفرع في واجهة الويب

في عرض Trajectory، انقر زر "تفرع من هنا" بجانب أي حدث:

TEXT 📖 للعرض فقط
10:00  📝 file_edit(تعديل) → utils/format.ts  [تفرع من هنا]
10:00  ⚠️ موافقة: تعديل utils/validate.ts    [تفرع من هنا]
10:00  🤖 إعادة الهيكلة مكتملة!               [تفرع من هنا]

التفرع ينشئ جلسة جديدة تبدأ من نقطة الحدث المحدد، مع نسخ جميع السياق قبل تلك النقطة.

(4) التفرع عبر SDK

▶ مثال 7: عملية تفرع عبر SDK

PYTHON
client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# التفرع من الحدث الخامس
forked = session.fork(after_event="evt_005")

print(f"جلسة متفرعة: {forked.id}")
print(f"الأصل: {forked.parent_id}")
print(f"نقطة التفرع: evt_005")

# متابعة المحادثة في الشعبة المتفرعة
response = forked.send("جرّب أسلوبًا مختلفًا لإعادة الهيكلة، قسّم حسب الدالة")

(5) الاستعادة

الاستعادة مختلفة عن التفرع — تعيد الجلسة الحالية لنقطة حدث محددة، متخلصة من الأحداث اللاحقة:

▶ مثال 8: عملية استعادة عبر SDK

PYTHON
# الاستعادة لنقطة الحدث الثالث
session.restore(to_event="evt_003")

# الأحداث بعد evt_004، evt_005، إلخ تُعلم كـ "مستعادة بعيدًا"
# الأحداث الجديدة تستمر بالإلحاق بعد evt_003

ملاحظة: الاستعادة لا تحذف الأحداث (مبدأ الإلحاق فقط)، بل تعلم الأحداث اللاحقة كغير صالحة وتضيف حدث session.restored.


6. ثبات السجلات

(1) التخزين الافتراضي

تُخزن سجلات جلسات DSH افتراضيًا في دليل .dsh/sessions/ الخاص بالمشروع:

TEXT 📖 للعرض فقط
.dsh/
├── sessions/
│   ├── sess_abc123/
│   │   ├── events.log        # سجل الأحداث
│   │   ├── snapshots/        # لقطات الحالة
│   │   └── metadata.json     # البيانات الوصفية
│   └── sess_def456/
│       ├── events.log
│       └── ...
├── config.yaml               # إعداد DSH
└── plugins/                  # دليل الإضافات

(2) إعداد الثبات

YAML
# dsh.config.yaml
storage:
  # مسار التخزين
  base_path: ".dsh/sessions"
  
  # استراتيجية اللقطات
  snapshots:
    enabled: true
    interval: 10              # حفظ لقطة كل 10 أحداث
    max_snapshots: 5          # الاحتفاظ بـ 5 لقطات كحد أقصى
  
  # تدوير السجلات
  rotation:
    max_size_mb: 100          # حد أقصى 100ميغابايت لكل ملف سجل
    max_files: 50             # الاحتفاظ بـ 50 جلسة كحد أقصى
  
  # الأرشفة
  archive:
    enabled: true
    path: ".dsh/archive/"
    after_days: 30            # أرشفة تلقائية بعد 30 يومًا

(3) تصدير سجلات الجلسات

▶ مثال 9: التصدير كـ JSON

PYTHON
# تصدير سجل جلسة كامل
session = client.get_session("sess_abc123")
events = session.get_trajectory()

import json
with open("session_export.json", "w") as f:
    json.dump([e.to_dict() for e in events], f, indent=2)

▶ مثال 10: التصدير كـ Markdown

BASH
# تصدير عبر سطر الأوامر
dsh session export sess_abc123 --format markdown --output session.md

# تنسيق المخرجات
# # Session: sess_abc123
# ## 10:00 - User
# ساعدني في إعادة هيكلة دليل utils
# ## 10:00 - Tool: search
# Pattern: utils/* → 3 ملفات موجودة
# ...

(4) تنظيف السجلات

BASH
# عرض جميع الجلسات (مرتبة حسب الحجم)
dsh session list --sort size

# أرشفة الجلسات القديمة
dsh session archive --older-than 30d

# حذف الجلسات المؤرشفة (غير قابل للعكس)
dsh session clean --archived-only

7. Trajectory والتدقيق

(1) تدقيق العمليات

يسجل Trajectory كل عملية Agent، مما يجعله مناسبًا بشكل طبيعي للتدقيق:

100%
graph TB
    AUDIT[حاجة تدقيق] --> T1[من نفذها؟]
    AUDIT --> T2[متى؟]
    AUDIT --> T3[ماذا فُعل؟]
    AUDIT --> T4[ما النتيجة؟]
    
    T1 --> TRAJ[تدفق أحداث Trajectory]
    T2 --> TRAJ
    T3 --> TRAJ
    T4 --> TRAJ

(2) سيناريوهات الامتثال

متطلب الامتثال كيف يلبيه Trajectory
تتبع العمليات كل حدث له معرف وطابع زمني ومُنفذ
تغييرات مقاومة للتلاعب سجل إلحاق فقط، لا يمكن تعديل التاريخ
سجلات الموافقة سجل كامل من approval.requested + approval.resolved
قدرة التراجع استعادة من أي نقطة تحقق

(3) توليد تقارير التدقيق

▶ مثال 11: توليد تقرير تدقيق

PYTHON
session = client.get_session("sess_abc123")
events = session.get_trajectory()

report = {
    "session_id": session.id,
    "duration": events[-1].timestamp - events[0].timestamp,
    "user_messages": len([e for e in events if e.type == "user.message"]),
    "tool_calls": len([e for e in events if e.type == "tool.call"]),
    "approvals_requested": len([e for e in events if e.type == "tool.approval.requested"]),
    "approvals_denied": len([e for e in events if e.type == "tool.approval.resolved" and e.data.get("decision") == "denied"]),
    "files_modified": list(set([
        e.data.get("path") for e in events
        if e.type == "tool.call" and e.data.get("tool") == "file_edit"
    ])),
    "errors": len([e for e in events if e.type == "error.occurred"])
}

import json
print(json.dumps(report, indent=2))

❓ أسئلة شائعة

س هل سجلات الإلحاق فقط تنمو بلا حدود؟
ج نعم، لكن DSH يوفر آليات أرشفة وتدوير. اضبط rotation.max_size_mb وarchive.after_days للإدارة التلقائية للتخزين.
س هل تتشارك الجلسات المتفرعة البيانات مع الأصل؟
ج التفرع ينسخ لقطة سياق عند نقطة التفرع؛ بعد ذلك، تكونان مستقلين تمامًا. التغييرات لا تؤثر على بعضها.
س هل تحذف الاستعادة الأحداث التاريخية فعليًا؟
ج لا. مبدأ الإلحاق فقط يضمن عدم حذف الأحداث أبدًا. الاستعادة تعلم فقط الأحداث اللاحقة كغير صالحة وتبدأ بإلحاق أحداث جديدة من نقطة الاستعادة.
س هل يمكن تصدير بيانات Trajectory؟
ج نعم. يدعم التصدير بتنسيقات JSON وMarkdown وCSV. سطر الأوامر يستخدم dsh session export؛ SDK يستخدم طريقة get_trajectory().
س هل يمكن لعدة مستخدمين رؤية Trajectory لنفس الجلسة؟
ج DSH يعمل افتراضيًا في وضع المستخدم الواحد، لذا لا توجد مشكلة مشاركة متعددة المستخدمين. إذا استخدمت تخزينًا مشتركًا (مثل NFS)، يمكن لنسخ DSH متعددة قراءة نفس السجلات.
س كيف أستخدم Trajectory في CI/CD؟
ج استخدم SDK لتصدير تدفق الأحداث، حلل عدد استدعاءات الأدوات ومعدل رفض الموافقة ومعدل الأخطاء، إلخ، كبوابات جودة.

📖 ملخص


📝 تمارين

1. ⭐ أساسي: أكمل محادثة Agent (مع استدعاءي أدوات على الأقل)، افتح عرض Trajectory، اذكر جميع الأحداث بأنواعها وطوابعها الزمنية.

2. ⭐⭐ متوسط: تفرع شعبة من الحدث الثالث لجلسة، جرّب أسلوبًا مختلفًا في الشعبة. قارن النتائج النهائية للخط الرئيسي والشعبة.

3. ⭐⭐⭐ تحدٍ: استخدم Python SDK لكتابة أداة تحليل Trajectory — أدخل معرف جلسة، أنشئ تلقائيًا تقرير تدقيق (يشمل إحصائيات العمليات، سجلات الموافقة، قائمة الملفات المعدلة، ملخص الأخطاء)، أخرج بتنسيق JSON.

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%