codebuff-agent 2.1.74__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codebuff_agent-2.1.74.data/data/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/package.json +157 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/150.39fa98117cc8ca590465.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/166.386ff9b2c37ac865fdee.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/216.25cf81131bf7274dabf4.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/353.581bd1cb00746399b62e.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/367.575f9621b63c9a641aa9.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/421.11dac223a2c2da1b09f5.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/481.cc2dec9fa869d66f1407.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/487.0796e931d6e651482c14.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/49.d326f554b6f9ccde6580.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/541.26897ea32845659e36be.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/579.e569d3edd8391fd8fbb3.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/666.d9bfdb23f98489d0a188.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/68.26b6f59c8454adb17f20.js +204 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/694.4ac443814260057e68f7.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/791.61affb8d3480d3d60e0d.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/style.js +4 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/third-party-licenses.json +724 -0
- codebuff_agent-2.1.74.dist-info/METADATA +142 -0
- codebuff_agent-2.1.74.dist-info/RECORD +217 -0
- codebuff_agent-2.1.74.dist-info/WHEEL +4 -0
- codebuff_agent-2.1.74.dist-info/licenses/LICENSE +21 -0
- codebuff_core/__init__.py +153 -0
- codebuff_core/codebuff_config_defaults.json +64 -0
- codebuff_core/core/__init__.py +35 -0
- codebuff_core/core/code_validator.py +1238 -0
- codebuff_core/core/error_classifier.py +579 -0
- codebuff_core/core/exceptions.py +49 -0
- codebuff_core/data/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +100256 -0
- codebuff_core/directory_policy.py +32 -0
- codebuff_core/factory.py +155 -0
- codebuff_core/interfaces.py +197 -0
- codebuff_core/knowledge/__init__.py +31 -0
- codebuff_core/knowledge/chunking.py +375 -0
- codebuff_core/knowledge/loader.py +339 -0
- codebuff_core/knowledge/watchdog_service.py +354 -0
- codebuff_core/legacy_paths.py +69 -0
- codebuff_core/llm/__init__.py +13 -0
- codebuff_core/llm/service.py +407 -0
- codebuff_core/managers/__init__.py +22 -0
- codebuff_core/managers/config_manager.py +690 -0
- codebuff_core/managers/remote_config.py +673 -0
- codebuff_core/managers/remote_skills.py +539 -0
- codebuff_core/managers/session_manager.py +255 -0
- codebuff_core/middleware/__init__.py +3 -0
- codebuff_core/middleware/error_recovery.py +394 -0
- codebuff_core/middleware/logging_utils.py +33 -0
- codebuff_core/models/__init__.py +111 -0
- codebuff_core/models/agent.py +306 -0
- codebuff_core/models/chat.py +57 -0
- codebuff_core/models/common.py +82 -0
- codebuff_core/models/rag.py +300 -0
- codebuff_core/platform_rules.py +127 -0
- codebuff_core/prompts/__init__.py +44 -0
- codebuff_core/prompts/auto_agent_prompts.py +1278 -0
- codebuff_core/services/__init__.py +30 -0
- codebuff_core/services/agent_service.py +345 -0
- codebuff_core/services/analytics_aggregate.py +837 -0
- codebuff_core/services/chat_service.py +898 -0
- codebuff_core/services/context_condenser.py +306 -0
- codebuff_core/services/pii_guardrail.py +393 -0
- codebuff_core/services/rag_chat_agent.py +2993 -0
- codebuff_core/services/rag_collections.py +2740 -0
- codebuff_core/services/rag_manager.py +890 -0
- codebuff_core/services/rag_service.py +145 -0
- codebuff_core/services/retriever.py +260 -0
- codebuff_core/services/vllm_embedding_service.py +290 -0
- codebuff_core/tests/__init__.py +1 -0
- codebuff_core/tests/conftest.py +81 -0
- codebuff_core/tests/test_error_recovery.py +647 -0
- codebuff_core/tests/test_factory.py +135 -0
- codebuff_core/tests/test_services.py +150 -0
- jupyter_ext/__init__.py +266 -0
- jupyter_ext/_version.py +4 -0
- jupyter_ext/agent/__init__.py +49 -0
- jupyter_ext/agent/agent_factory.py +2270 -0
- jupyter_ext/agent/ast_tools.py +451 -0
- jupyter_ext/agent/autofix_middleware.py +481 -0
- jupyter_ext/agent/background_procs.py +372 -0
- jupyter_ext/agent/code_history_middleware.py +211 -0
- jupyter_ext/agent/codex_autofix.py +160 -0
- jupyter_ext/agent/codex_bridge.py +3339 -0
- jupyter_ext/agent/codex_hooks.py +320 -0
- jupyter_ext/agent/codex_slash.py +685 -0
- jupyter_ext/agent/codex_threads.py +114 -0
- jupyter_ext/agent/content_injection.py +377 -0
- jupyter_ext/agent/continuation_middleware.py +548 -0
- jupyter_ext/agent/custom_skills.py +335 -0
- jupyter_ext/agent/file_diffs.py +99 -0
- jupyter_ext/agent/git_history.py +188 -0
- jupyter_ext/agent/guardrail_middleware.py +421 -0
- jupyter_ext/agent/json_repair_utils.py +54 -0
- jupyter_ext/agent/langchain_tools.py +2673 -0
- jupyter_ext/agent/mermaid_fixer.py +289 -0
- jupyter_ext/agent/mermaid_middleware.py +135 -0
- jupyter_ext/agent/middleware.py +359 -0
- jupyter_ext/agent/middleware_prompts.py +53 -0
- jupyter_ext/agent/observability.py +334 -0
- jupyter_ext/agent/patch_tool_calls.py +57 -0
- jupyter_ext/agent/prompts.py +112 -0
- jupyter_ext/agent/skill_middleware.py +257 -0
- jupyter_ext/agent/skills/airflow_dag_development.md +36 -0
- jupyter_ext/agent/skills/anomaly_detection.md +12 -0
- jupyter_ext/agent/skills/athena_sql.md +156 -0
- jupyter_ext/agent/skills/bdp_table_search.md +33 -0
- jupyter_ext/agent/skills/bigquery.md +65 -0
- jupyter_ext/agent/skills/bigquery_oracle.md +231 -0
- jupyter_ext/agent/skills/bigquery_tuning.md +307 -0
- jupyter_ext/agent/skills/classification_evaluation.md +11 -0
- jupyter_ext/agent/skills/clustering_analysis.md +12 -0
- jupyter_ext/agent/skills/comprehensive_eda.md +11 -0
- jupyter_ext/agent/skills/data_analysis.md +236 -0
- jupyter_ext/agent/skills/data_cleaning_pipeline.md +12 -0
- jupyter_ext/agent/skills/data_loading.md +158 -0
- jupyter_ext/agent/skills/data_quality_report.md +13 -0
- jupyter_ext/agent/skills/dimensionality_reduction.md +12 -0
- jupyter_ext/agent/skills/emr_script_development.md +17 -0
- jupyter_ext/agent/skills/experiment_tracking.md +13 -0
- jupyter_ext/agent/skills/feature_importance_analysis.md +10 -0
- jupyter_ext/agent/skills/hyperparameter_tuning.md +12 -0
- jupyter_ext/agent/skills/hypothesis_testing.md +12 -0
- jupyter_ext/agent/skills/imbalanced_data_handling.md +12 -0
- jupyter_ext/agent/skills/inference.md +392 -0
- jupyter_ext/agent/skills/lambda_function_development.md +19 -0
- jupyter_ext/agent/skills/model_comparison.md +11 -0
- jupyter_ext/agent/skills/model_explainability.md +12 -0
- jupyter_ext/agent/skills/model_training.md +318 -0
- jupyter_ext/agent/skills/pyspark.md +352 -0
- jupyter_ext/agent/skills/python_code_quality.md +35 -0
- jupyter_ext/agent/skills/regression_evaluation.md +12 -0
- jupyter_ext/agent/skills/spring_java_development.md +35 -0
- jupyter_ext/agent/skills/text_preprocessing.md +12 -0
- jupyter_ext/agent/skills/time_series_analysis.md +13 -0
- jupyter_ext/agent/skills/unit_testing.md +203 -0
- jupyter_ext/agent/todo_prompts.py +57 -0
- jupyter_ext/agent/tool_report.py +45 -0
- jupyter_ext/analytics_ingest.py +599 -0
- jupyter_ext/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- jupyter_ext/handlers/__init__.py +8 -0
- jupyter_ext/handlers/analytics_handler.py +170 -0
- jupyter_ext/handlers/benchmark_handler.py +794 -0
- jupyter_ext/handlers/eda_benchmark_handler.py +1328 -0
- jupyter_ext/handlers/rag_admin_handler.py +689 -0
- jupyter_ext/handlers/websocket.py +497 -0
- jupyter_ext/http_handlers.py +8744 -0
- jupyter_ext/idle_monitor.py +346 -0
- jupyter_ext/labextension/package.json +157 -0
- jupyter_ext/labextension/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- jupyter_ext/labextension/static/150.39fa98117cc8ca590465.js +1 -0
- jupyter_ext/labextension/static/166.386ff9b2c37ac865fdee.js +1 -0
- jupyter_ext/labextension/static/216.25cf81131bf7274dabf4.js +1 -0
- jupyter_ext/labextension/static/353.581bd1cb00746399b62e.js +1 -0
- jupyter_ext/labextension/static/367.575f9621b63c9a641aa9.js +1 -0
- jupyter_ext/labextension/static/421.11dac223a2c2da1b09f5.js +1 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js +2 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/481.cc2dec9fa869d66f1407.js +1 -0
- jupyter_ext/labextension/static/487.0796e931d6e651482c14.js +1 -0
- jupyter_ext/labextension/static/49.d326f554b6f9ccde6580.js +1 -0
- jupyter_ext/labextension/static/541.26897ea32845659e36be.js +1 -0
- jupyter_ext/labextension/static/579.e569d3edd8391fd8fbb3.js +1 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/666.d9bfdb23f98489d0a188.js +1 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js +2 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/68.26b6f59c8454adb17f20.js +204 -0
- jupyter_ext/labextension/static/694.4ac443814260057e68f7.js +1 -0
- jupyter_ext/labextension/static/791.61affb8d3480d3d60e0d.js +1 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js +2 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- jupyter_ext/labextension/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- jupyter_ext/labextension/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- jupyter_ext/labextension/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- jupyter_ext/labextension/static/style.js +4 -0
- jupyter_ext/labextension/static/third-party-licenses.json +724 -0
- jupyter_ext/log_paths.py +113 -0
- jupyter_ext/resource_usage.py +519 -0
- jupyter_ext/secrets_bootstrap.py +116 -0
- jupyter_ext/team_access.py +105 -0
- jupyter_ext/tests/__init__.py +1 -0
- jupyter_ext/tests/test_context.py +234 -0
- jupyter_ext/tests/test_factory.py +563 -0
- jupyter_ext/tests/test_file_finder.py +139 -0
- jupyter_ext/tests/test_handlers.py +58 -0
- jupyter_ext/tests/test_mcp_selftest.py +204 -0
- jupyter_ext/tests/test_mermaid_fixer.py +272 -0
- jupyter_ext/tests/test_resource_tiers.py +298 -0
- jupyter_ext/tools/__init__.py +15 -0
- jupyter_ext/tools/base.py +90 -0
- jupyter_ext/tools/context.py +268 -0
- jupyter_ext/tools/dir_complete.py +86 -0
- jupyter_ext/tools/file_finder.py +303 -0
- jupyter_ext/tools/file_tools.py +244 -0
- jupyter_ext/tools/jupyter_tools.py +296 -0
- jupyter_ext/tools/registry.py +159 -0
- jupyter_ext/tools/search_tools.py +230 -0
- jupyter_ext/tools/security_tools.py +657 -0
- jupyter_ext/tools/shell_tools.py +109 -0
- jupyter_ext/tools/user_tools.py +132 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SkillMiddleware
|
|
3
|
+
|
|
4
|
+
Middleware that provides progressive skill loading for code generation agents.
|
|
5
|
+
Based on LangChain Skills pattern for token-efficient context injection.
|
|
6
|
+
|
|
7
|
+
Key features:
|
|
8
|
+
- Injects skill metadata into system prompt (~250 tokens)
|
|
9
|
+
- Provides load_skill tool for on-demand full content loading
|
|
10
|
+
- Reads skill definitions from markdown files
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from functools import lru_cache
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, Dict, List, Optional
|
|
17
|
+
|
|
18
|
+
import yaml
|
|
19
|
+
from langchain_core.tools import tool
|
|
20
|
+
from pydantic import BaseModel, Field
|
|
21
|
+
|
|
22
|
+
from . import custom_skills
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Skills directory path
|
|
27
|
+
SKILLS_DIR = Path(__file__).parent / "skills"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _parse_skill_metadata(file_path: Path) -> Optional[Dict[str, str]]:
|
|
31
|
+
"""Parse skill metadata from markdown file's YAML frontmatter.
|
|
32
|
+
|
|
33
|
+
Expected format:
|
|
34
|
+
---
|
|
35
|
+
name: skill-name
|
|
36
|
+
description: Skill description
|
|
37
|
+
---
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
content = file_path.read_text(encoding="utf-8")
|
|
41
|
+
|
|
42
|
+
if not content.startswith("---"):
|
|
43
|
+
logger.warning(f"Skill file missing YAML frontmatter: {file_path}")
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
parts = content.split("---", 2)
|
|
47
|
+
if len(parts) < 3:
|
|
48
|
+
logger.warning(f"Invalid YAML frontmatter format: {file_path}")
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
frontmatter = yaml.safe_load(parts[1])
|
|
52
|
+
if not frontmatter or "name" not in frontmatter:
|
|
53
|
+
logger.warning(f"Missing 'name' in frontmatter: {file_path}")
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
"name": frontmatter.get("name"),
|
|
58
|
+
"description": frontmatter.get("description", "No description"),
|
|
59
|
+
"path": str(file_path),
|
|
60
|
+
}
|
|
61
|
+
except Exception as e:
|
|
62
|
+
logger.error(f"Failed to parse skill file {file_path}: {e}")
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _load_all_skills() -> Dict[str, Dict[str, str]]:
|
|
67
|
+
"""Load all skill metadata from the skills directory."""
|
|
68
|
+
skills = {}
|
|
69
|
+
|
|
70
|
+
if not SKILLS_DIR.exists():
|
|
71
|
+
logger.warning(f"Skills directory not found: {SKILLS_DIR}")
|
|
72
|
+
return skills
|
|
73
|
+
|
|
74
|
+
for file_path in SKILLS_DIR.glob("*.md"):
|
|
75
|
+
metadata = _parse_skill_metadata(file_path)
|
|
76
|
+
if metadata:
|
|
77
|
+
skills[metadata["name"]] = metadata
|
|
78
|
+
logger.debug(f"Loaded skill: {metadata['name']}")
|
|
79
|
+
|
|
80
|
+
logger.info(f"Loaded {len(skills)} skills from {SKILLS_DIR}")
|
|
81
|
+
return skills
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _get_skill_content(skill_name: str, skills: Dict[str, Dict[str, str]]) -> str:
|
|
85
|
+
"""Load full content of a skill file (excluding YAML frontmatter)."""
|
|
86
|
+
if skill_name not in skills:
|
|
87
|
+
# `_`/`-`·대소문자를 가리지 않는다 — 재정의 판정·codex 와 같은 `skill_key` (이슈 #220)
|
|
88
|
+
key = custom_skills.skill_key(skill_name)
|
|
89
|
+
for registered_name in skills:
|
|
90
|
+
if custom_skills.skill_key(registered_name) == key:
|
|
91
|
+
skill_name = registered_name
|
|
92
|
+
break
|
|
93
|
+
if skill_name not in skills:
|
|
94
|
+
available = ", ".join(skills.keys())
|
|
95
|
+
return f"Error: Unknown skill '{skill_name}'. Available skills: {available}"
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
file_path = Path(skills[skill_name]["path"])
|
|
99
|
+
if skills[skill_name].get("custom"):
|
|
100
|
+
return custom_skills.read_body(file_path)
|
|
101
|
+
content = file_path.read_text(encoding="utf-8")
|
|
102
|
+
|
|
103
|
+
# Remove YAML frontmatter
|
|
104
|
+
if content.startswith("---"):
|
|
105
|
+
parts = content.split("---", 2)
|
|
106
|
+
if len(parts) >= 3:
|
|
107
|
+
content = parts[2].strip()
|
|
108
|
+
|
|
109
|
+
return content
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return f"Error loading skill '{skill_name}': {str(e)}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _build_skills_prompt_section(skills: Dict[str, Dict[str, str]]) -> str:
|
|
115
|
+
"""Build the Available Skills section for system prompt injection (~250 tokens)."""
|
|
116
|
+
if not skills:
|
|
117
|
+
return ""
|
|
118
|
+
|
|
119
|
+
lines = ["## Available Skills"]
|
|
120
|
+
lines.append("")
|
|
121
|
+
lines.append("### Context 리소스 정보")
|
|
122
|
+
lines.append(
|
|
123
|
+
"Main Agent가 task 호출 시 제공하는 Context에는 다음 정보가 포함됩니다:"
|
|
124
|
+
)
|
|
125
|
+
lines.append("- **파일 크기**: `file_size: 200MB`, `total_size: 1.5GB` 등")
|
|
126
|
+
lines.append("- **시스템 메모리**: `available_memory: 16GB`, `gpu_memory: 8GB` 등")
|
|
127
|
+
lines.append("- **데이터 행 수**: `row_count: 10000000` 등")
|
|
128
|
+
lines.append("")
|
|
129
|
+
lines.append("### 스킬 로드 규칙 (MANDATORY)")
|
|
130
|
+
lines.append(
|
|
131
|
+
"**분야 작업이면 설명이 맞는 스킬을 먼저 읽는다** — Athena·Airflow·EMR·Lambda·"
|
|
132
|
+
"Spring·BigQuery·EDA 같은 작업은 아래 목록에서 설명이 맞는 스킬을 "
|
|
133
|
+
"load_skill_tool로 읽고 그 규칙을 따른다."
|
|
134
|
+
)
|
|
135
|
+
# 로드 기준(파일 크기·행 수·GPU 등)은 각 스킬의 description 에 있다 — codex 도 같은
|
|
136
|
+
# 목록을 받으므로 여기에 따로 적지 않는다 (이슈 #228)
|
|
137
|
+
lines.append(
|
|
138
|
+
"**설명에 적힌 조건(파일 크기·행 수·GPU 등)에 해당하면 코드를 쓰기 전에"
|
|
139
|
+
" load_skill_tool tool을 먼저 사용하세요"
|
|
140
|
+
" (tool call로 호출, Python 코드로 작성하지 마세요).**"
|
|
141
|
+
)
|
|
142
|
+
lines.append(
|
|
143
|
+
"조건에 못 미치면(작은 파일·적은 행 수·단순 출력) 또는 Context 에 리소스 정보가"
|
|
144
|
+
" 없으면 최적화 스킬은 읽지 않는다."
|
|
145
|
+
)
|
|
146
|
+
lines.append("")
|
|
147
|
+
|
|
148
|
+
for name, metadata in sorted(skills.items()):
|
|
149
|
+
lines.append(f"- **{name}**: {metadata['description']}")
|
|
150
|
+
|
|
151
|
+
return "\n".join(lines)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _create_load_skill_tool(skills: Dict[str, Dict[str, str]]):
|
|
155
|
+
"""Create the load_skill_tool for on-demand skill loading."""
|
|
156
|
+
available_skills = ", ".join(sorted(skills.keys()))
|
|
157
|
+
|
|
158
|
+
class LoadSkillInput(BaseModel):
|
|
159
|
+
"""Input schema for load_skill_tool"""
|
|
160
|
+
|
|
161
|
+
skill_name: str = Field(
|
|
162
|
+
description=f"Name of the skill to load. Available: {available_skills}"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
@tool(args_schema=LoadSkillInput)
|
|
166
|
+
def load_skill_tool(skill_name: str) -> str:
|
|
167
|
+
"""
|
|
168
|
+
Load the full guide of a skill listed in the Available Skills section.
|
|
169
|
+
|
|
170
|
+
Use this tool when the task matches a skill's description in that list.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
skill_name: Name of the skill to load
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Full optimization guide with code patterns and best practices
|
|
177
|
+
"""
|
|
178
|
+
logger.info(f"Loading skill: {skill_name}")
|
|
179
|
+
content = _get_skill_content(skill_name, skills)
|
|
180
|
+
|
|
181
|
+
if not content.startswith("Error"):
|
|
182
|
+
logger.info(f"Skill '{skill_name}' loaded: {len(content)} chars")
|
|
183
|
+
|
|
184
|
+
return content
|
|
185
|
+
|
|
186
|
+
return load_skill_tool
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class SkillMiddleware:
|
|
190
|
+
"""Middleware that adds skill loading capability to code generation agents.
|
|
191
|
+
|
|
192
|
+
This middleware:
|
|
193
|
+
1. Injects Available Skills section into system prompt (~250 tokens)
|
|
194
|
+
2. Adds the `load_skill` tool for on-demand content loading
|
|
195
|
+
3. Enables token-efficient progressive disclosure of optimization guides
|
|
196
|
+
|
|
197
|
+
워크스페이스를 주면 커스텀 스킬(`custom_skills`)을 합친다 — 이름이 겹치면 커스텀이
|
|
198
|
+
이긴다 (이슈 #134). 없으면 내장 스킬만이라 프롬프트가 전과 같다.
|
|
199
|
+
|
|
200
|
+
Usage:
|
|
201
|
+
skill_mw = get_skill_middleware(workspace_root)
|
|
202
|
+
skills_section = skill_mw.get_prompt_section()
|
|
203
|
+
tools = skill_mw.get_tools()
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
def __init__(self, workspace_root: Optional[str] = None):
|
|
207
|
+
custom = custom_skills.discover(workspace_root) if workspace_root else []
|
|
208
|
+
# 철자만 다른 이름(`athena-sql`)도 같은 스킬이다 — codex 와 같은 판정 (이슈 #220)
|
|
209
|
+
custom_keys = {custom_skills.skill_key(s.name) for s in custom}
|
|
210
|
+
builtin = {
|
|
211
|
+
name: meta
|
|
212
|
+
for name, meta in _builtin_skills().items()
|
|
213
|
+
if custom_skills.skill_key(name) not in custom_keys
|
|
214
|
+
}
|
|
215
|
+
self.skills = dict(builtin)
|
|
216
|
+
for s in custom:
|
|
217
|
+
self.skills[s.name] = {
|
|
218
|
+
"name": s.name,
|
|
219
|
+
"description": s.description,
|
|
220
|
+
"path": str(s.path),
|
|
221
|
+
"custom": "1",
|
|
222
|
+
}
|
|
223
|
+
self.prompt_section = _build_skills_prompt_section(builtin)
|
|
224
|
+
custom_section = custom_skills.prompt_section(custom, "load_skill_tool")
|
|
225
|
+
if custom_section:
|
|
226
|
+
self.prompt_section += "\n\n" + custom_section
|
|
227
|
+
self.load_skill_tool = _create_load_skill_tool(self.skills)
|
|
228
|
+
|
|
229
|
+
logger.info(
|
|
230
|
+
f"SkillMiddleware initialized with {len(self.skills)} skills: "
|
|
231
|
+
f"{list(self.skills.keys())}"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def get_prompt_section(self) -> str:
|
|
235
|
+
"""Get the Available Skills section for system prompt."""
|
|
236
|
+
return self.prompt_section
|
|
237
|
+
|
|
238
|
+
def get_tools(self) -> List[Any]:
|
|
239
|
+
"""Get the tools provided by this middleware."""
|
|
240
|
+
return [self.load_skill_tool]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@lru_cache(maxsize=1)
|
|
244
|
+
def _builtin_skills() -> Dict[str, Dict[str, str]]:
|
|
245
|
+
"""패키지 옆 내장 스킬은 코드와 함께 움직이므로 프로세스당 한 번 읽는다."""
|
|
246
|
+
return _load_all_skills()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def get_skill_middleware(workspace_root: Optional[str] = None) -> SkillMiddleware:
|
|
250
|
+
"""에이전트를 만들 때마다 새로 만든다.
|
|
251
|
+
|
|
252
|
+
커스텀 스킬은 워크스페이스마다 달라서 프로세스 싱글턴으로 둘 수 없다 (이슈 #134).
|
|
253
|
+
내장 스킬 파싱은 `_builtin_skills` 가 캐시하므로 커스텀 스킬 디렉터리만 다시 훑는다.
|
|
254
|
+
HTTP 스트림은 에이전트 그래프를 캐시하지만 캐시 키에 스킬 목록이 들어가므로
|
|
255
|
+
(`http_handlers._skills_cache_key`), 기동 뒤 더한 스킬도 다음 요청부터 목록에 뜬다.
|
|
256
|
+
"""
|
|
257
|
+
return SkillMiddleware(workspace_root)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: airflow_dag_development
|
|
3
|
+
description: 'Airflow Development & Operations Workflow. 이런 요청에 쓴다: airflow, dag, operator, taskflow, 에어플로우, mwaa, composer, cloud composer, 워크플로우 오케스트레이션, airflow 튜닝, airflow 에러, airflow 로그, task concurrency, parallelism, pool slot'
|
|
4
|
+
---
|
|
5
|
+
## Airflow Development & Operations Workflow
|
|
6
|
+
1. **Structure**: default_args, DAG context, task dependencies
|
|
7
|
+
2. **Tune**: parallelism, concurrency, pool slots, scheduler tuning
|
|
8
|
+
3. **Debug**: task logs, scheduler logs, error tracing
|
|
9
|
+
4. **Validate**: python -c "from airflow.models import DagBag; ..."
|
|
10
|
+
5. **Deploy**: MWAA S3 sync / Composer GCS bucket upload
|
|
11
|
+
|
|
12
|
+
## Guidelines
|
|
13
|
+
- DAG ID는 snake_case, 설명적 이름 사용
|
|
14
|
+
- default_args에 owner, retries, retry_delay 포함
|
|
15
|
+
- catchup=False를 기본으로 설정
|
|
16
|
+
|
|
17
|
+
## 분석 작성 가이드
|
|
18
|
+
- DAG 구조 시각화: Mermaid graph로 task dependency 표현
|
|
19
|
+
- 병목 지점 식별: 성능 이슈 원인 분석
|
|
20
|
+
- 플랫폼별 차이: MWAA vs Composer 구분 명시
|
|
21
|
+
- 에러 패턴: 에러 메시지 → 원인 → 영향도 분석
|
|
22
|
+
- 로그 해석: 핵심 로그 라인 인용 및 의미 설명
|
|
23
|
+
|
|
24
|
+
## Mermaid 다이어그램 컬러 코딩
|
|
25
|
+
- 정상/성공: `fill:#4CAF50,color:white` (green)
|
|
26
|
+
- 경고/주의: `fill:#FF9800,color:white` (orange)
|
|
27
|
+
- 에러/병목: `fill:#F44336,color:white` (red)
|
|
28
|
+
- 정보/중립: `fill:#2196F3,color:white` (blue)
|
|
29
|
+
- 대기/미실행: `fill:#9E9E9E,color:white` (gray)
|
|
30
|
+
|
|
31
|
+
## 권고 작성 가이드
|
|
32
|
+
- 구체적 설정값 제시 (airflow.cfg 파라미터)
|
|
33
|
+
- MWAA와 Composer 각각의 설정 방법 명시
|
|
34
|
+
- 단계별 적용 가이드 (순서 중요한 경우)
|
|
35
|
+
- 검증 방법 포함
|
|
36
|
+
- 모든 설정 권고에 MWAA/Composer 플랫폼별 적용 방법 포함
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: anomaly_detection
|
|
3
|
+
description: 'Anomaly Detection Template. 이런 요청에 쓴다: anomaly detection, isolation forest, outlier detection, 이상탐지, 이상치 탐지'
|
|
4
|
+
---
|
|
5
|
+
## Anomaly Detection Template
|
|
6
|
+
1. **EDA**: Distribution plots, box plots to visually identify outliers
|
|
7
|
+
2. **Statistical Methods**: Z-score (|z| > 3), IQR (< Q1-1.5*IQR or > Q3+1.5*IQR)
|
|
8
|
+
3. **Isolation Forest**: `IsolationForest(contamination=0.05).fit_predict(X)`
|
|
9
|
+
4. **Local Outlier Factor**: `LocalOutlierFactor(n_neighbors=20)`
|
|
10
|
+
5. **Evaluation**: If labels available — precision, recall; otherwise visual inspection
|
|
11
|
+
6. **Visualization**: Scatter plot highlighting anomalies, time-series anomaly overlay
|
|
12
|
+
7. **Action**: Remove, cap, or flag anomalies based on domain context
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: athena_sql
|
|
3
|
+
description: Athena(Trino) SQL 작성·튜닝. BDP 테이블 조회 쿼리 작성, 파티션 프루닝으로 스캔 비용 절감, EXPLAIN 오류 수정, Iceberg DML 제약 확인.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Athena SQL 가이드
|
|
7
|
+
BDP의 테이블은 Athena 쿼리로만 수행이 가능.
|
|
8
|
+
Athena는 Trino(Presto) 기반 서버리스 SQL 엔진. S3 데이터를 직접 쿼리. 과금: 스캔 데이터 $5/TB.
|
|
9
|
+
|
|
10
|
+
## 엔진 특성
|
|
11
|
+
|
|
12
|
+
- DML: SELECT, INSERT INTO, UPDATE, DELETE, MERGE INTO (Iceberg 테이블만)
|
|
13
|
+
- DDL: CREATE TABLE, CREATE VIEW, ALTER TABLE, DROP TABLE, CTAS
|
|
14
|
+
- DDL은 HiveQL 기반 (백틱 `\`` 사용), DML은 Trino 기반 (큰따옴표 `"` 사용)
|
|
15
|
+
|
|
16
|
+
## BDP에서 Athena 쿼리 수행 시 주의할 점
|
|
17
|
+
- 반드시 테이블 명 앞에 DB명을 명시하여 SQL을 생성 (예시: wdp_bdp_dlk_l1_msk_view.card_pchs)
|
|
18
|
+
- 숫자 컬럼 집계 시 NULL 처리 필수: SUM(COALESCE(col, 0)), AVG(COALESCE(col, 0))
|
|
19
|
+
- SELECT에 있는 비집계 컬럼은 GROUP BY에 빠짐없이 포함
|
|
20
|
+
- **Athena는 영문 컬럼 alias만 지원합니다.** `AS 한글명` 문법을 사용하지 마세요. 컬럼명을 한글화하지 마세요.
|
|
21
|
+
- 주요 로직(조인 조건, 필터, 집계 등)에 한글 주석을 간결하게 추가 (-- 형식)
|
|
22
|
+
|
|
23
|
+
## 데이터 타입
|
|
24
|
+
|
|
25
|
+
| 타입 | 설명 | 예시 |
|
|
26
|
+
|------|------|------|
|
|
27
|
+
| `STRING` / `VARCHAR` | 문자열 | `'hello'` |
|
|
28
|
+
| `INT` / `BIGINT` | 정수 | `42` |
|
|
29
|
+
| `DOUBLE` | 실수 | `3.14` |
|
|
30
|
+
| `DECIMAL(p,s)` | 고정 소수점 | `DECIMAL(18,2)` |
|
|
31
|
+
| `DATE` | 날짜 | `DATE '2024-01-15'` |
|
|
32
|
+
| `TIMESTAMP` | 일시 | `TIMESTAMP '2024-01-15 10:30:00'` (공백 필수, T 사용 불가) |
|
|
33
|
+
| `BOOLEAN` | 불리언 | `TRUE` / `FALSE` |
|
|
34
|
+
| `ARRAY<T>` | 배열 | `ARRAY[1, 2, 3]` |
|
|
35
|
+
| `MAP<K,V>` | 맵 | `MAP(ARRAY['a'], ARRAY[1])` |
|
|
36
|
+
| `STRUCT` | 구조체 | `ROW(name VARCHAR, age INT)` |
|
|
37
|
+
|
|
38
|
+
### 타입 주의사항
|
|
39
|
+
- TIMESTAMP 형식: `YYYY-MM-DD HH:MM:SS.SSS` (T 구분자 사용 불가)
|
|
40
|
+
- 파티션 키는 `STRING` 권장 (DATE 타입은 성능 저하)
|
|
41
|
+
- Long → Timestamp 암묵적 변환 불가 → `from_unixtime()` 사용
|
|
42
|
+
- `CONCAT()`은 최소 2개 인자 필요
|
|
43
|
+
|
|
44
|
+
## 날짜/시간 함수
|
|
45
|
+
|
|
46
|
+
| 함수 | 설명 | 예시 |
|
|
47
|
+
|------|------|------|
|
|
48
|
+
| `current_date` | 오늘 날짜 | `WHERE dt = current_date` |
|
|
49
|
+
| `current_timestamp` | 현재 시각 | |
|
|
50
|
+
| `date_add('day', n, date)` | 날짜 더하기 | `date_add('day', -7, current_date)` |
|
|
51
|
+
| `date_diff('day', d1, d2)` | 날짜 차이 | `date_diff('day', start_dt, end_dt)` |
|
|
52
|
+
| `date_trunc('month', dt)` | 절삭 | `date_trunc('month', txn_date)` |
|
|
53
|
+
| `format_datetime(ts, fmt)` | 포맷 | `format_datetime(ts, 'yyyy-MM-dd')` |
|
|
54
|
+
| `date_parse(str, fmt)` | 파싱 | `date_parse('2024-01-15', '%Y-%m-%d')` |
|
|
55
|
+
| `from_unixtime(epoch)` | 에포크→타임스탬프 | `from_unixtime(1705276800)` |
|
|
56
|
+
| `to_unixtime(ts)` | 타임스탬프→에포크 | `to_unixtime(current_timestamp)` |
|
|
57
|
+
| `year(dt)` / `month(dt)` / `day(dt)` | 추출 | `year(txn_date) = 2024` |
|
|
58
|
+
|
|
59
|
+
**주의**: `date_format()` 대신 `format_datetime()` 권장 (동작이 더 직관적).
|
|
60
|
+
|
|
61
|
+
## 문자열 함수
|
|
62
|
+
|
|
63
|
+
| 함수 | 설명 |
|
|
64
|
+
|------|------|
|
|
65
|
+
| `LOWER(s)` / `UPPER(s)` | 대소문자 |
|
|
66
|
+
| `TRIM(s)` / `LTRIM(s)` / `RTRIM(s)` | 공백 제거 |
|
|
67
|
+
| `LENGTH(s)` | 길이 |
|
|
68
|
+
| `SUBSTR(s, start, len)` | 부분 문자열 |
|
|
69
|
+
| `REPLACE(s, from, to)` | 치환 |
|
|
70
|
+
| `SPLIT(s, delim)` | 분할 → 배열 |
|
|
71
|
+
| `REGEXP_EXTRACT(s, pattern, group)` | 정규식 추출 |
|
|
72
|
+
| `REGEXP_LIKE(s, pattern)` | 정규식 매칭 |
|
|
73
|
+
| `CONCAT(s1, s2, ...)` | 연결 (최소 2개 인자) |
|
|
74
|
+
| `COALESCE(a, b, ...)` | NULL 대체 |
|
|
75
|
+
| `CAST(x AS type)` | 타입 변환 |
|
|
76
|
+
|
|
77
|
+
## 윈도우 함수
|
|
78
|
+
|
|
79
|
+
```sql
|
|
80
|
+
-- ROW_NUMBER: 순위
|
|
81
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY txn_date DESC) rn
|
|
82
|
+
FROM db.txn;
|
|
83
|
+
|
|
84
|
+
-- LAG / LEAD: 이전/다음 행
|
|
85
|
+
SELECT txn_date, amount,
|
|
86
|
+
LAG(amount) OVER (ORDER BY txn_date) prev_amount,
|
|
87
|
+
LEAD(amount) OVER (ORDER BY txn_date) next_amount
|
|
88
|
+
FROM db.txn;
|
|
89
|
+
|
|
90
|
+
-- 누적합
|
|
91
|
+
SELECT txn_date, amount,
|
|
92
|
+
SUM(amount) OVER (ORDER BY txn_date ROWS UNBOUNDED PRECEDING) running_total
|
|
93
|
+
FROM db.txn;
|
|
94
|
+
|
|
95
|
+
-- FIRST_VALUE / LAST_VALUE
|
|
96
|
+
SELECT *, FIRST_VALUE(amount) OVER (PARTITION BY category ORDER BY txn_date) first_amt
|
|
97
|
+
FROM db.txn;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**주의**: `IGNORE NULLS`는 `first_value`, `last_value`, `nth_value`, `lag`, `lead`에서만 사용 가능.
|
|
101
|
+
|
|
102
|
+
## JOIN
|
|
103
|
+
**JOIN 최적화**: 작은 테이블을 오른쪽(또는 JOIN의 두 번째)에 배치.
|
|
104
|
+
|
|
105
|
+
## CTAS (Create Table As Select)
|
|
106
|
+
|
|
107
|
+
```sql
|
|
108
|
+
-- Parquet + Snappy 압축으로 결과 저장
|
|
109
|
+
CREATE TABLE db.result
|
|
110
|
+
WITH (format = 'PARQUET', write_compression = 'SNAPPY', external_location = 's3://bucket/result/')
|
|
111
|
+
AS SELECT * FROM db.source WHERE condition;
|
|
112
|
+
|
|
113
|
+
-- 파티셔닝 포함
|
|
114
|
+
CREATE TABLE db.result
|
|
115
|
+
WITH (format = 'PARQUET', partitioned_by = ARRAY['dt'])
|
|
116
|
+
AS SELECT col1, col2, dt FROM db.source;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 성능 최적화
|
|
120
|
+
|
|
121
|
+
- Optimize for performance:
|
|
122
|
+
- Use appropriate aggregations
|
|
123
|
+
|
|
124
|
+
### 1. 파티션 프루닝 (가장 중요)
|
|
125
|
+
- 반드시 테이블의 파티션키를 먼저 파악하고 해당 컬럼을 최대한 활용한다.
|
|
126
|
+
```sql
|
|
127
|
+
-- 좋음: 파티션 키(dt)로 필터
|
|
128
|
+
SELECT * FROM db.txn WHERE dt = DATE '2024-01-15';
|
|
129
|
+
|
|
130
|
+
-- 나쁨: 파티션 키 없이 전체 스캔
|
|
131
|
+
SELECT * FROM db.txn WHERE amount > 1000;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 2. 컬럼 프루닝
|
|
135
|
+
```sql
|
|
136
|
+
-- 좋음: 필요한 컬럼만
|
|
137
|
+
SELECT id, name, amount FROM db.txn;
|
|
138
|
+
|
|
139
|
+
-- 나쁨: 전체 컬럼
|
|
140
|
+
SELECT * FROM db.txn;
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 4. LIMIT 활용
|
|
144
|
+
```sql
|
|
145
|
+
-- 탐색적 쿼리에 LIMIT 필수
|
|
146
|
+
SELECT * FROM db.large_table LIMIT 100;
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 5. APPROX 함수 (대용량)
|
|
150
|
+
```sql
|
|
151
|
+
-- 정확한 COUNT DISTINCT 대신
|
|
152
|
+
SELECT APPROX_DISTINCT(user_id) FROM db.txn;
|
|
153
|
+
|
|
154
|
+
-- 백분위수
|
|
155
|
+
SELECT APPROX_PERCENTILE(amount, 0.95) FROM db.txn;
|
|
156
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bdp_table_search
|
|
3
|
+
description: 쿼리 도우미의 BDP 테이블 메타데이터 검색(rag_search·get_table_columns) 규칙. 두 도구가 있을 때만 쓴다 — SQL을 쓰기 전에 실제 테이블명·컬럼명·DB명을 검색 결과로 확인할 때.
|
|
4
|
+
---
|
|
5
|
+
# BDP 테이블 검색
|
|
6
|
+
|
|
7
|
+
**[기존 SQL]이 존재할 때 반드시 정확한 테이블 정보 확인을 위해 rag_search를 호출한 후 응답을 생성하세요**
|
|
8
|
+
|
|
9
|
+
## RAG 검색 도구
|
|
10
|
+
|
|
11
|
+
rag_search로 BDP 테이블 메타데이터를 검색할 수 있습니다.
|
|
12
|
+
[기존 SQL]이 제공된 경우에도, SQL에 사용된 테이블명을 match_text에 지정하여 반드시 rag_search를 호출하세요.
|
|
13
|
+
**절대로 검색 결과 없이 테이블명이나 컬럼명을 만들어내지 마세요.**
|
|
14
|
+
|
|
15
|
+
### 컬렉션
|
|
16
|
+
- **bdp_tables**: BDP 테이블 메타데이터 (테이블명, 컬럼명, 타입, 스키마)
|
|
17
|
+
|
|
18
|
+
### 도구 호출 규칙
|
|
19
|
+
1. **`rag_search`**: queries 배열에 쿼리를 담아 **1회만 호출**. bdp_tables 컬렉션 사용.
|
|
20
|
+
- **query 작성법**: 반드시 `"필드명:값"` 형식을 사용하거나 자연어 키워드로 작성하세요.
|
|
21
|
+
예: `"테이블명:card_pchs"`, `"테이블한글명:카드매출"`, `"컬럼명:brno"`, `"원천DB명:ADW"`
|
|
22
|
+
모르는 정보만 있을 땐 자연어 키워드도 가능: `"카드매출 관련 테이블"`
|
|
23
|
+
- **match_text**: 정확한 테이블 영문명을 알 때 추가. 예: `"match_text": ["card_pchs"]`
|
|
24
|
+
2. **`get_table_columns`**: 테이블의 전체 컬럼 목록을 조회. rag_search 결과에서 컬럼이 축약된 경우 사용.
|
|
25
|
+
- 예: `get_table_columns(table_name="card_pchs", collection="bdp_tables")`
|
|
26
|
+
3. 결과가 0건일 때만 쿼리를 변경하여 1회 재시도를 허용합니다.
|
|
27
|
+
|
|
28
|
+
### 검색 결과 사용 시 주의사항
|
|
29
|
+
- 테이블명, 컬럼명 등 고유명사는 **RAG 검색 결과에 있는 값을 그대로** 사용하세요.
|
|
30
|
+
- 검색 결과에 "[토큰 제한으로 컬럼 정보가 축약되었습니다]" 안내가 있으면 get_table_columns로 전체 컬럼을 조회하세요.
|
|
31
|
+
|
|
32
|
+
### 도구 호출 시 주의사항
|
|
33
|
+
- 도구 호출(tool call)이 필요하면, content에는 "검색 중입니다"처럼 **한 줄 상태 메시지만** 넣으세요.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bigquery
|
|
3
|
+
description: BigQuery 요청(쿼리 설명·오류 수정·성능 튜닝·비용 분석·Oracle→BQ 변환)이면 먼저 읽는 라우터. 요청 유형별 응답 구조와 Mermaid 시각화 규칙을 담고, 세부 가이드는 bigquery_tuning, bigquery_oracle 참조.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# BigQuery Expert Guide
|
|
7
|
+
|
|
8
|
+
BQ agent의 3대 역할별 세부 가이드:
|
|
9
|
+
|
|
10
|
+
| 요청 유형 | 로드할 스킬 | 설명 |
|
|
11
|
+
|-----------|------------|------|
|
|
12
|
+
| 성능 튜닝 / 비용 최적화 / anti-pattern | `bigquery_tuning` | 900-slot 최적화, anti-pattern 10종, 비용 공식, INFORMATION_SCHEMA |
|
|
13
|
+
| Oracle → BQ 변환 | `bigquery_oracle` | 구문 매핑, 실행 모델 비교, Hint 대체, anti-pattern 체크 |
|
|
14
|
+
| 쿼리 오류 수정 | `bigquery_tuning` | anti-pattern 탐지 + 비용/성능 분석으로 오류 원인 진단 |
|
|
15
|
+
|
|
16
|
+
## 사용법
|
|
17
|
+
1. 요청 유형 판단
|
|
18
|
+
2. `bigquery_tuning` 또는 `bigquery_oracle` 스킬 본문을 읽는다
|
|
19
|
+
3. 두 가지 모두 필요하면 둘 다 읽는다
|
|
20
|
+
|
|
21
|
+
## 응답 구조 가이드
|
|
22
|
+
|
|
23
|
+
### Oracle→BQ 변환 시:
|
|
24
|
+
- **변환 개요**: 변환 배경, 핵심 변경사항 3~5줄 요약, Oracle 전용 구문 개수
|
|
25
|
+
- **SQL**: ```sql 블록에 변환된 SQL (인라인 주석으로 변경 포인트 설명)
|
|
26
|
+
- **구문 매핑 상세**: 각 Oracle→BQ 구문 변환의 동작 차이, 주의사항, 엣지 케이스를 매핑 테이블 + 서술로 설명
|
|
27
|
+
- **실행 흐름 비교**: Oracle vs BQ 실행 방식을 **Mermaid 다이어그램**으로 시각화 + 비교 테이블 (인덱스 vs 컬럼나, 비용 모델 등)
|
|
28
|
+
- **데이터 타입 주의사항**: 암묵적 형변환, 정밀도 차이, NULL 처리 차이
|
|
29
|
+
- **BQ 최적화 권고**: 파티셔닝, 클러스터링, 매터리얼라이즈드 뷰 등 구체적 제안
|
|
30
|
+
|
|
31
|
+
### 성능 튜닝 시:
|
|
32
|
+
- **쿼리 분석 요약**: 쿼리 목적, 현재 성능 특성
|
|
33
|
+
- **SQL**: ```sql 블록에 최적화된 SQL
|
|
34
|
+
- **Anti-pattern 탐지**: 발견된 anti-pattern과 개선 방안 (코드 스니펫 포함)
|
|
35
|
+
- **실행 계획 분석**: 예상 슬롯 사용량, 병렬화 전략을 **Mermaid 다이어그램**으로 시각화
|
|
36
|
+
- **비용 분석**: 바이트 처리량, 비용 절감 방안
|
|
37
|
+
- **파티셔닝/클러스터링 권고**: 구체적 DDL 예시 포함
|
|
38
|
+
|
|
39
|
+
### 오류 수정 시:
|
|
40
|
+
- **에러 원인 분석**: 에러 메시지 해석, 근본 원인
|
|
41
|
+
- **SQL**: ```sql 블록에 수정된 SQL
|
|
42
|
+
- **오류 흐름 시각화**: 에러 발생 흐름 → 수정 후 정상 흐름을 **Mermaid 다이어그램**으로 표현
|
|
43
|
+
- **수정 내용 상세**: 각 수정 포인트의 이유와 영향
|
|
44
|
+
- **유사 오류 방지 가이드**: 같은 실수를 피하는 패턴
|
|
45
|
+
|
|
46
|
+
### 쿼리 설명 시:
|
|
47
|
+
- **쿼리 목적**: 비즈니스 로직과 데이터 흐름
|
|
48
|
+
- **SQL**: ```sql 블록에 원본 SQL (주석으로 각 절의 역할 설명)
|
|
49
|
+
- **실행 흐름 단계별 분석**: FROM → WHERE → GROUP BY → SELECT 순서로 데이터 흐름을 **Mermaid 다이어그램**으로 시각화 + 설명
|
|
50
|
+
- **성능 특성**: 예상 비용, 병목 구간
|
|
51
|
+
- **개선 포인트**: 성능/가독성 개선 제안
|
|
52
|
+
|
|
53
|
+
### 복합 요청 시:
|
|
54
|
+
해당하는 모든 섹션을 논리적 순서로 구성하세요.
|
|
55
|
+
|
|
56
|
+
## 작성 원칙
|
|
57
|
+
- 각 섹션은 충분히 상세하게 서술하세요 (chat 모드 수준의 풍부함)
|
|
58
|
+
- 코드 스니펫은 마크다운 코드 블록으로 제시
|
|
59
|
+
- 매핑 테이블과 서술을 병행하여 이해도를 높이세요
|
|
60
|
+
|
|
61
|
+
## ⚠️ 필수: Mermaid 시각화
|
|
62
|
+
|
|
63
|
+
**모든 BQ 응답에는 반드시 ```mermaid 다이어그램을 포함하세요.** 시각화 없는 응답은 불완전합니다.
|
|
64
|
+
- 쿼리 설명: 데이터 흐름을 단계별 Mermaid 다이어그램으로 시각화
|
|
65
|
+
- 튜닝·오류 수정·변환은 세부 스킬의 필수 출력 규칙을 따른다
|