| """Supervisor Agent - LLM-driven dynamic workflow routing |
| |
| Tier 2 ์์ธ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ์ ํ๋์ LLM์ด ๋์ ์ผ๋ก ๊ฒฐ์ ํฉ๋๋ค. |
| threshold ๊ธฐ๋ฐ conditional edge(orchestrator)์ ๋ค๋ฅธ ์ : |
| - ์ฌ๋์ด ์ ์ํ ์๊ณ์น๊ฐ ์๋๋ผ LLM์ด ๋งฅ๋ฝ์ ๋ณด๊ณ ํ๋จ |
| - ๊ธฐ์ฌ๋ยท์ฆ์ยท์ํฅ lotยท๊ณต์ critical ์ฌ๋ถ๋ฅผ ์ข
ํฉ ๊ณ ๋ ค |
| |
| ๊ฐ์ฉ action: |
| - proceed_full: ํ์ค ๊ฒฝ๋ก (Tier 3 -> Tier 4) |
| - fast_track: ์์ธ์ด ๋ช
ํํด ์ํฅ ํ๊ฐ skip, Tier 4 ์ง์ง (latencyยทcost ์ ๊ฐ) |
| - escalate: ๊ณ ์ํ - ์ ์ ์งํ + human review ํ๋๊ทธ |
| |
| severity ๋ถ๋ฅ: low / medium / high / critical |
| |
| ๋น์ฉ ์ ๊ฐ: ์์ฌ๊ฒฐ์ ๋ง ํ๋ ์์์
์ด๋ผ SUPERVISOR_MODEL = gpt-4o-mini |
| ํ๊ฒฝ๋ณ์ SUPERVISOR_ENABLED=false ๋ฉด ํญ์ proceed_full (Supervisor ํธ์ถ ์์ฒด skip) |
| """ |
| import json |
| import os |
|
|
| from langsmith import traceable |
|
|
| from agents.llm import client |
| from core.schema import Tier1, Tier2 |
|
|
| SUPERVISOR_MODEL = "gpt-4o-mini" |
|
|
| ACTION_SCHEMA = { |
| "type": "object", |
| "properties": { |
| "action": { |
| "type": "string", |
| "enum": ["proceed_full", "fast_track", "escalate"], |
| }, |
| "severity": { |
| "type": "string", |
| "enum": ["low", "medium", "high", "critical"], |
| }, |
| "reasoning": {"type": "string"}, |
| }, |
| "required": ["action", "severity", "reasoning"], |
| "additionalProperties": False, |
| } |
|
|
| SYSTEM_PROMPT = """๋น์ ์ ๋ฐ๋์ฒด fab์ incident response supervisor ์์ด์ ํธ์
๋๋ค. |
| ์์ธ ๋ถ์(Tier 2) ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ์ ๋จ๊ณ ์งํ ๋ฐฉ์์ ๊ฒฐ์ ํฉ๋๋ค. |
| |
| [๊ฐ์ฉ action] |
| - proceed_full: ํ์ค - Tier 3(์ํฅํ๊ฐ) โ Tier 4(๋์๊ถ๊ณ ) ์์ฐจ ์งํ (๋๋ถ๋ถ์ ๊ฒฝ์ฐ) |
| - fast_track: ์์ธ์ด 1~2๊ฐ๋ก ๋ช
ํํ๊ณ ์ฆ์ ์กฐ์น๋ง ํ์ - Tier 3 skip, Tier 4 ์ง์ง (latencyยทcost ์ ๊ฐ) |
| - escalate: ๊ณ ์ํ - ์ ์ ์งํํ๋ human review ํ๋๊ทธ (์กฐ์น ์ ์ด์์ ์ถ๊ฐ ๊ฒํ ๊ฐ์ ) |
| |
| [severity ๋ถ๋ฅ] |
| - low: ์ฌ์ํ ๋ณ๋, ์๋ ์ฒ๋ฆฌ ๊ฐ๋ฅ |
| - medium: ํ์ค ๋์์ผ๋ก ์ถฉ๋ถ |
| - high: ์ํฅ ํผ, ๋น ๋ฅธ ์กฐ์น ํ์ |
| - critical: ๋ผ์ธ ์ ์ง ๊ฒํ ์์ค |
| |
| [ํ๋จ ๊ธฐ์ค] |
| - ์์ธ 1๊ฐ๊ฐ ๊ธฐ์ฌ๋ 70%+ ๋จ๋
์ฐ์ธ + medium/low severity โ fast_track ํ๋ณด |
| - ์์ธ ๋ค์(3๊ฐ+) ๋ถํฌ ๋๋ high/critical severity โ proceed_full |
| - critical severity, downstream ์ํฅ์ด ํด ๊ฒ์ผ๋ก ์ถ์ โ escalate |
| - ์ผ๋ฐ์ ์ผ๋ก proceed_full์ด ์์ ํ ๊ธฐ๋ณธ๊ฐ |
| |
| [์ค์] reasoning์ ํ ๋ฌธ์ฅ์ผ๋ก ๊ฒฐ์ ๊ทผ๊ฑฐ๋ฅผ ๋ช
์ (์: "๋จ์ผ ์์ธ 80% ๋จ๋
์ฐ์ธ, medium severity โ fast_track")""" |
|
|
|
|
| def _build_user_prompt(alarm: dict, tier1: Tier1, tier2: Tier2) -> str: |
| causes = "\n".join( |
| f"- [{c['pct']}%] {c['name']}: {c['evidence'][:120]}" |
| for c in tier2["causes"] |
| ) |
| return f"""## ์ด์ ์๋ |
| - ๊ณต์ : {alarm['title']} |
| - lot: {alarm['lot_id']} |
| |
| ## Tier 1 ์ด์ ํ์ง |
| - ์ด์ ์ ์: {tier1['score']} |
| |
| ## Tier 2 ์์ธ ๋ถ์ ๊ฒฐ๊ณผ |
| {causes} |
| |
| ํ์ actionยทseverityยทreasoning์ ๊ฒฐ์ ํด ์ฃผ์ธ์.""" |
|
|
|
|
| def supervisor_enabled() -> bool: |
| return os.getenv("SUPERVISOR_ENABLED", "true").lower() not in ("false", "0", "no") |
|
|
|
|
| @traceable(name="Supervisor_Agent", run_type="chain") |
| def run_supervisor(alarm: dict, tier1: Tier1, tier2: Tier2) -> dict: |
| """ํ์ workflow action์ LLM์ด ๊ฒฐ์ |
| |
| ๋ฐํ: {"action": "proceed_full"|"fast_track"|"escalate", |
| "severity": "low"|"medium"|"high"|"critical", |
| "reasoning": str} |
| """ |
| if not supervisor_enabled(): |
| return {"action": "proceed_full", "severity": "medium", |
| "reasoning": "(Supervisor ๋นํ์ฑ - ํญ์ ํ์ค ๊ฒฝ๋ก)"} |
|
|
| resp = client().chat.completions.create( |
| model=SUPERVISOR_MODEL, |
| messages=[ |
| {"role": "system", "content": SYSTEM_PROMPT}, |
| {"role": "user", "content": _build_user_prompt(alarm, tier1, tier2)}, |
| ], |
| response_format={ |
| "type": "json_schema", |
| "json_schema": {"name": "supervisor", "schema": ACTION_SCHEMA, "strict": True}, |
| }, |
| ) |
| return json.loads(resp.choices[0].message.content) |
|
|