AI 어시스턴트
Doggy는 전역 AI 어시스턴트를 제공하며, 플로팅 버튼 + 사이드 패널 형태로 모든 페이지에 존재하고 컨텍스트 등록 메커니즘을 통해 페이지와 심층 통합되며 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' }새 페이지 컨텍스트 추가
AiContextProviderInterface를 구현하는 클래스 생성services.yaml에tags: [{ name: 'app.ai_context' }]추가- 페이지 템플릿에서
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의 Tool 메타데이터 주입
- processOutput: 결과가
ToolCallResult인 경우:- ToolCall 배열을 MessageBag에 추가
- ToolCall 실행 → ToolResult를 MessageBag에 기록
TextResult가 반환될 때까지 재귀 호출
도구 체계
symfony/ai-agent의 #[AsTool] 속성으로 도구 메서드를 표시합니다:
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 | 엔티티 필드 나열 |
설계 원칙
- 각 도구는 단일 책임 메서드
- 파라미터명은
#[AsTool]JSON Schema 파라미터명과 일치(자동 매핑) array반환(도구 결과 텍스트로 변환)
API 엔드포인트
POST /api/admin/ai/chat
json
{
"context": "view_editor",
"message": "3열 레이아웃으로 바꿔줘"
}성공 응답:
json
{
"code": 200,
"message": "success",
"data": { "reply": "3열 레이아웃으로 수정했습니다." }
}관련 파일
| 파일 | 역할 |
|---|---|
AiChatController.php | {context, message} 수신, 해당 Provider에 위임 |
AiContextRegistry.php | app.ai_context 태그 서비스 수집, name 기준 색인 |
AiAssistant.php | 범용 Agent 팩토리 |
LlmRouterPlatform.php | PlatformInterface 브리지 (MessageBag ↔ 배열) |
ChatResultConverter.php | 응답 데이터 → TextResult/ToolCallResult |
ViewEditorToolProvider.php | 뷰 편집기 Tool 메서드 |
ChromeDevToolsToolProvider.php | CDP 브라우저 디버깅 도구 |
ViewFileToolProvider.php | 뷰 파일 읽기/쓰기 도구 |