Skip to content

AI 助手

يوفر Doggy مساعدًا ذكيًا عامًا يعمل على جميع الصفحات في شكل زر عائم + لوحة منزلقة جانبية، مع تكامل عميق مع الصفحات عبر آلية تسجيل السياق، ويدعم حلقة استدلال ReAct واستدعاء الأدوات.

نظرة عامة

يعتمد مساعد AI على حزمة التقنيات symfony/ai-agent + symfony/ai-platform، ويتصل ببنية بوابة LlmRouter الخاصة بالمنصة:

Client POST /api/admin/ai/chat  { context, message }
  → AiChatController
    → AiContextRegistry::get(context)
      → AiContextProviderInterface (e.g. ViewEditorAiContext)
        → AiAssistant::chat(roleCode, systemPrompt, toolProviders, message)
          → Agent::call(MessageBag, options)
            → AgentProcessor::processInput (注入 Tool)
            → LlmRouterPlatform::invoke → LlmRouter → LlmGatewayFactory
            → AgentProcessor::processOutput (ReAct 循环)
            ← string response

نقطة الدخول العامة

يتم تضمين لوحة مساعد AI بدون شرط في templates/base.html.twig:

twig
<body>
    {% block body %}{% endblock %}
    {% include 'admin/ai_chat.html.twig' %}
</body>
  • فتح/إغلاق: الزر العائم في الزاوية السفلية اليمنى toggle-ai-chat / ai-chat-close
  • الإدخال: Enter للإرسال، Shift+Enter لسطر جديد
  • حالة التحميل: تعطيل الإدخال أثناء الطلب مع عرض "جارٍ التفكير..."
  • الأنماط: public/sunui/admin/ai_chat.css

تسجيل سياق الصفحة

تقوم كل صفحة بتسجيل سياقها لدى المساعد عبر window.__AI_CONTEXT__:

js
window.__AI_CONTEXT__ = {
    name: 'view_editor',                  // 后端 AiContextProviderInterface::getName()
    buildPrompt: function(msg) {          // 可选,构造发送给后端的消息
        return '[当前视图ID: xxx]\n\n' + msg;
    },
};

مثال على تسجيل محرر العرض:

twig
<script>
  window.__VIEW_ID__ = {{ id|json_encode|raw }};
  window.__AI_CONTEXT__ = {
      name: 'view_editor',
      buildPrompt: function(msg) {
          var vid = window.__VIEW_ID__;
          return vid ? '[当前视图ID: ' + vid + ']\n\n' + msg : msg;
      },
  };
</script>

نظام مزوّدي السياق

يحدد AiContextProviderInterface مزوّدي السياق:

php
namespace App\Service\AI\Runtime;

interface AiContextProviderInterface
{
    public function getName(): string;                    // 上下文标识
    public function getRoleCode(): string;                // LlmRouter 角色代码
    public function getSystemPrompt(): string;            // Agent 系统提示词
    public function getToolProviders(): array;            // Tool 对象数组
}

يتم التسجيل عبر وسم app.ai_context:

yaml
App\Service\AI\Context\ViewEditorAiContext:
    tags:
        - { name: 'app.ai_context' }

إضافة سياق صفحة جديد

  1. أنشئ فئة تنفّذ AiContextProviderInterface
  2. أضف tags: [{ name: 'app.ai_context' }] في services.yaml
  3. اضبط window.__AI_CONTEXT__ = { name: 'your_name' } في قالب الصفحة

وقت تشغيل Agent

AiAssistant هو مصنع Agent معمّم، حيث تنشئ كل استدعاء chat() مثيل Agent مستقل لضمان عدم تلوث الحالة:

php
$platform = new LlmRouterPlatform($this->router, $this->converter);
$toolbox = new Toolbox($toolProviders);

$agent = new Agent(
    platform: $platform,
    model: $roleCode,
    inputProcessors: [
        new SystemPromptInputProcessor($systemPrompt),
        new AgentProcessor($toolbox),
    ],
    outputProcessors: [
        new AgentProcessor($toolbox),
    ],
    name: 'ai-assistant',
);

حلقة ReAct

يعمل AgentProcessor كمعالج إدخال/إخراج في آنٍ واحد، محققًا حلقة استدعاء الأدوات:

  • processInput: حقن بيانات تعريفية لأدوات Toolbox
  • processOutput: عند اكتشاف أن النتيجة من نوع ToolCallResult:
    1. إضافة مصفوفة ToolCall إلى MessageBag
    2. تنفيذ ToolCall ← كتابة ToolResult مرة أخرى إلى MessageBag
    3. الاستدعاء العودي حتى يتم إرجاع TextResult

نظام الأدوات

يتم تمييز طرق الأدوات عبر خاصية #[AsTool] من symfony/ai-agent:

php
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;

class ViewEditorToolProvider
{
    #[AsTool(name: 'view.getInfo', description: '获取视图的完整信息')]
    public function getViewInfo(string $viewId): array { ... }

    #[AsTool(name: 'view.updateSectionConfig', description: '更新视图的布局配置')]
    public function updateSectionConfig(string $viewId, string $contentWidth, ...): array { ... }
}

أدوات محرر العرض الحالية

Toolالوظيفة
view.getInfoالحصول على معلومات العرض (الكيان، الحقول، التخطيط)
view.updateSectionConfigتحديث تكوين التخطيط
view.updateFieldConfigتحديث تكوين الحقول
view.listEntityFieldsسرد حقول الكيان

مبادئ التصميم

  • كل أداة هي طريقة ذات مسؤولية واحدة
  • أسماء المعاملات مطابقة لأسماء معاملات JSON Schema الخاصة بـ #[AsTool] (الربط التلقائي)
  • إرجاع array (يُحوَّل إلى نص نتيجة الأداة)

نقطة نهاية API

POST /api/admin/ai/chat

json
{
    "context": "view_editor",
    "message": "帮我改成三列布局"
}

الاستجابة الناجحة:

json
{
    "code": 200,
    "message": "success",
    "data": { "reply": "已修改为三列布局。" }
}

الملفات ذات الصلة

الملفالمسؤولية
AiChatController.phpاستقبال {context, message} وإحالة التنفيذ للمزود المناسب
AiContextRegistry.phpجمع خدمات وسم app.ai_context وفهرستها حسب الاسم
AiAssistant.phpمصنع Agent معمّم
LlmRouterPlatform.phpجسر PlatformInterface (MessageBag ↔ المصفوفات)
ChatResultConverter.phpبيانات الاستجابة ← TextResult/ToolCallResult
ViewEditorToolProvider.phpطرق أدوات محرر العرض
ChromeDevToolsToolProvider.phpأدوات تصحيح المتصفح CDP
ViewFileToolProvider.phpأدوات قراءة وكتابة ملفات العرض

مصدر مفتوح برخصة MIT | حقوق النشر © 2026 Doggy