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:
<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__:
window.__AI_CONTEXT__ = {
name: 'view_editor', // 后端 AiContextProviderInterface::getName()
buildPrompt: function(msg) { // 可选,构造发送给后端的消息
return '[当前视图ID: xxx]\n\n' + msg;
},
};مثال على تسجيل محرر العرض:
<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 مزوّدي السياق:
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:
App\Service\AI\Context\ViewEditorAiContext:
tags:
- { name: 'app.ai_context' }إضافة سياق صفحة جديد
- أنشئ فئة تنفّذ
AiContextProviderInterface - أضف
tags: [{ name: 'app.ai_context' }]فيservices.yaml - اضبط
window.__AI_CONTEXT__ = { name: 'your_name' }في قالب الصفحة
وقت تشغيل Agent
AiAssistant هو مصنع Agent معمّم، حيث تنشئ كل استدعاء chat() مثيل Agent مستقل لضمان عدم تلوث الحالة:
$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:- إضافة مصفوفة ToolCall إلى MessageBag
- تنفيذ ToolCall ← كتابة ToolResult مرة أخرى إلى MessageBag
- الاستدعاء العودي حتى يتم إرجاع
TextResult
نظام الأدوات
يتم تمييز طرق الأدوات عبر خاصية #[AsTool] من symfony/ai-agent:
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
{
"context": "view_editor",
"message": "帮我改成三列布局"
}الاستجابة الناجحة:
{
"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 | أدوات قراءة وكتابة ملفات العرض |