hee_!J
feat(conductor): Plan-and-Execute ํจํด - Central Planner + Tier executor (env AGENT_MODE)
3fb690f | """Central Planner Agent (Plan-and-Execute pattern) | |
| ์๋๊ณผ Tier 1 ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ์ ์ฒด ์ํฌํ๋ก์ฐ plan์ 1ํ LLM ํธ์ถ๋ก ์ฐ์ถํฉ๋๋ค. | |
| ๊ฐ Tier executor๋ plan๋๋ก ๋๊ตฌ๋ฅผ ์ง์ ํธ์ถํ๊ณ LLM 1ํ๋ก ๊ฒฐ๊ณผ๋ฅผ ํฉ์ฑํฉ๋๋ค. | |
| ๊ธฐ์กด autonomous tool-using loop ๋๋น: | |
| - LLM ํธ์ถ ~70% ๊ฐ์ (๊ฐ tier loop ์ ๊ฑฐ) | |
| - ์ฌ๊ท/๋ฌดํ๋ฃจํ ์ํ ์์ฒ ์ฐจ๋จ (LLM์ด tool์ ์์จ ์ ํํ์ง ์์) | |
| - ํต์ ์ค๋ฒํค๋ ์ต์ํ (synthesis context๋ฅผ ํ ๋ฒ์ ๊ตฌ์ฑ) | |
| - ๋น์ฉยทlatency ํฐ ํญ ์ ๊ฐ (gpt-4o-mini๋ก planning + gpt-5-mini๋ก synthesis) | |
| ์ค๊ณ: | |
| - Planner๊ฐ ๊ตฌ์ฒด์ ํจ์ ํธ์ถ์ด ์๋ "ํ์ํ ์ ๋ณด ์ฑ๋" (query/symptom/equipment_id ๋ฆฌ์คํธ)์ ์ง์ | |
| - ๊ฐ Tier executor๊ฐ ๊ทธ ์ฑ๋์ ๋ฐ์ ๊ฒฐ์ ๋ก ์ ์ผ๋ก tool ํธ์ถ (๋ณ๋ ฌ ๊ฐ๋ฅ) | |
| - Tier executor๋ ๋จ 1ํ LLM ํธ์ถ๋ก synthesis (tools ์ธ์ ์์ด) | |
| """ | |
| import json | |
| from langsmith import traceable | |
| from agents.llm import client | |
| from agents.tools.equipment import ALARM_EQUIPMENT | |
| from core.schema import Tier1 | |
| PLANNER_MODEL = "gpt-4o-mini" | |
| PLAN_SCHEMA = { | |
| "type": "object", | |
| "properties": { | |
| "tier2": { | |
| "type": "object", | |
| "properties": { | |
| "search_queries": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "์ฌ๋ด ์ง์ ๊ฒ์ ์ฟผ๋ฆฌ (1~3๊ฐ)", | |
| }, | |
| "incident_symptoms": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "๊ณผ๊ฑฐ incident DB ์กฐํ์ฉ ์ฆ์ (0~2๊ฐ)", | |
| }, | |
| "equipment_ids": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "PM ์ด๋ ฅ ์กฐํ ์ฅ๋น ID (0~1๊ฐ)", | |
| }, | |
| }, | |
| "required": ["search_queries", "incident_symptoms", "equipment_ids"], | |
| "additionalProperties": False, | |
| }, | |
| "tier3": { | |
| "type": "object", | |
| "properties": { | |
| "alarm_id": {"type": "string", "description": "WIP ์กฐํ์ฉ ์๋ ID"}, | |
| "downstream_stages": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "ํ๊ณต์ ์์กด์ฑ ์กฐํ (1๊ฐ)", | |
| }, | |
| "yield_processes": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "yield baseline ์กฐํ (1~2๊ฐ)", | |
| }, | |
| "equipment_ids": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "PM ์ด๋ ฅ ์กฐํ ์ฅ๋น ID (0~1๊ฐ)", | |
| }, | |
| }, | |
| "required": ["alarm_id", "downstream_stages", "yield_processes", "equipment_ids"], | |
| "additionalProperties": False, | |
| }, | |
| "tier4": { | |
| "type": "object", | |
| "properties": { | |
| "search_queries": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "SOP ๊ฒ์ ์ฟผ๋ฆฌ (1~3๊ฐ)", | |
| }, | |
| "incident_symptoms": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "๊ณผ๊ฑฐ ํด๊ฒฐ์ฑ ์กฐํ (0~2๊ฐ)", | |
| }, | |
| "equipment_ids": { | |
| "type": "array", | |
| "items": {"type": "string"}, | |
| "description": "PM ์๋์ฐ ์กฐํ ์ฅ๋น ID (1๊ฐ)", | |
| }, | |
| }, | |
| "required": ["search_queries", "incident_symptoms", "equipment_ids"], | |
| "additionalProperties": False, | |
| }, | |
| "action": { | |
| "type": "string", | |
| "enum": ["proceed_full", "fast_track", "escalate"], | |
| "description": "์ํฌํ๋ก์ฐ ๋ถ๊ธฐ (Tier 3 skip ์ฌ๋ถ, escalation ํ๋๊ทธ)", | |
| }, | |
| "severity": { | |
| "type": "string", | |
| "enum": ["low", "medium", "high", "critical"], | |
| }, | |
| "reasoning": {"type": "string"}, | |
| }, | |
| "required": ["tier2", "tier3", "tier4", "action", "severity", "reasoning"], | |
| "additionalProperties": False, | |
| } | |
| SYSTEM_PROMPT = """๋น์ ์ ๋ฐ๋์ฒด fab ์ธ์๋ํธ ๋์ ์์คํ ์ Central Planner Agent์ ๋๋ค. | |
| ์ด์ ์๋๊ณผ Tier 1 ํ์ง ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ์ ์ฒด ์ํฌํ๋ก์ฐ(Tier 2 ์์ธ๋ถ์ โ Tier 3 ์ํฅํ๊ฐ โ Tier 4 ๋์๊ถ๊ณ )์ ํ์ํ ์ ๋ณด ์์ง plan์ ํ ๋ฒ์ ์ฐ์ถํฉ๋๋ค. | |
| [๊ฐ์ฉ ์ ๋ณด ์ฑ๋ - tier๋ณ] | |
| Tier 2 (์์ธ ๋ถ์): | |
| - search_queries: ์ฌ๋ด ์ง์(INC/FMEA/SOP/FLOW) hybrid ๊ฒ์ (1~3๊ฐ) | |
| - incident_symptoms: ๊ณผ๊ฑฐ incident DB ๊ตฌ์กฐํ ์กฐํ (0~2๊ฐ) | |
| - equipment_ids: ์ฅ๋น PM ์ด๋ ฅ ์กฐํ (0~1๊ฐ) | |
| Tier 3 (์ํฅ ํ๊ฐ): | |
| - alarm_id: WIP ์กฐํ (๋ฐ๋์ 1๊ฐ, ์๋ ID ๊ทธ๋๋ก) | |
| - downstream_stages: ํ๊ณต์ ์์กด์ฑ (1๊ฐ, ํ์ฌ ๊ณต์ ๋ช - ์: "Photo", "Etch", "CMP") | |
| - yield_processes: yield baseline ์กฐํ (1~2๊ฐ) | |
| - equipment_ids: PM ์ด๋ ฅ ์กฐํ (0~1๊ฐ) | |
| Tier 4 (๋์ ๊ถ๊ณ ): | |
| - search_queries: SOPยทํ์ค ์ ์ฐจ ๊ฒ์ (1~3๊ฐ) | |
| - incident_symptoms: ๊ณผ๊ฑฐ ํด๊ฒฐ์ฑ ์กฐํ (0~2๊ฐ) | |
| - equipment_ids: PM ์๋์ฐ ์กฐํ (1๊ฐ, immediate ์กฐ์น์ ์คํ ๊ฐ๋ฅ ์์ ) | |
| [routing ๊ฒฐ์ ] | |
| - action: | |
| - proceed_full (๋๋ถ๋ถ, ํ์ค Tier 2 โ 3 โ 4) | |
| - fast_track (๋จ์ผ ์์ธ 80%+ ์ฐ์ธ ์ - Tier 3 LLM skip) | |
| - escalate (๊ณ ์ํยท๋ค๋์ ์ํฅ - ์ ์ ์งํ + human review ํ๋๊ทธ) | |
| - severity: low / medium / high / critical | |
| [์ค์ ์์น] | |
| - ์๋๊ณผ Tier 1์ ๋ณด๊ณ ๊ฐ์ฅ ์ ๋ณด๊ฐ์น ํฐ ์ฟผ๋ฆฌ/์กฐํ๋ง ์ ๋ณ (๋ถํ์ํ ํธ์ถ ์ ๊ฑฐ) | |
| - search_queries๋ ๋๋ฉ์ธ ์ฉ์ด๋ฅผ ํ๋ถํ๊ฒ (์: "Photo CD ์ฐํฌ ๋ ์ฆ ์ค์ผ ํค์ด์ฆ") | |
| - Tier 2์ Tier 4์ search_queries๋ ๋ชฉ์ ์ด ๋ค๋ฆ: | |
| - Tier 2: ์์ธ ํ๋ณด ํ์์ฉ | |
| - Tier 4: SOPยท์กฐ์น ์ ์ฐจ ํ์์ฉ | |
| - reasoning์ ํ ๋ฌธ์ฅ์ผ๋ก plan์ ํต์ฌ ์๋ ๋ช ์""" | |
| def _build_user_prompt(alarm: dict, tier1: Tier1) -> str: | |
| sensors = ", ".join(f["name"] for f in tier1["features"]) | |
| equipment_id = ALARM_EQUIPMENT.get(alarm["id"], "(๋ฏธ๋งคํ)") | |
| process = alarm["title"].split()[0] | |
| return f"""## ์ด์ ์๋ | |
| - ๊ณต์ : {alarm['title']} (current_stage: {process}) | |
| - lot: {alarm['lot_id']} | |
| - ์ด์ ํผ์ฒ: {alarm.get('feature')} {alarm.get('feature_arrow') or ''} | |
| - ์๋ ID: {alarm['id']} | |
| - ์ถ์ ์ฅ๋น ID: {equipment_id} | |
| ## Tier 1 ์ด์ ํ์ง ๊ฒฐ๊ณผ | |
| - ์ด์ ์ ์: {tier1['score']} | |
| - ๊ธฐ์ฌ ์ผ์(Top): {sensors} | |
| ์ ์๋์ ์ ์ฒด ์ํฌํ๋ก์ฐ(Tier 2โ3โ4) plan์ ์ฐ์ถํ์ธ์.""" | |
| def plan_workflow(alarm: dict, tier1: Tier1) -> dict: | |
| """์๋ + Tier 1์ ๋ณด๊ณ ์ ์ฒด ์ํฌํ๋ก์ฐ plan์ ํ ๋ฒ์ ์ฐ์ถ | |
| ๋ฐํ: PLAN_SCHEMA ํ์ dict (tier2/tier3/tier4 + action/severity/reasoning) | |
| """ | |
| resp = client().chat.completions.create( | |
| model=PLANNER_MODEL, | |
| messages=[ | |
| {"role": "system", "content": SYSTEM_PROMPT}, | |
| {"role": "user", "content": _build_user_prompt(alarm, tier1)}, | |
| ], | |
| response_format={ | |
| "type": "json_schema", | |
| "json_schema": {"name": "plan", "schema": PLAN_SCHEMA, "strict": True}, | |
| }, | |
| ) | |
| return json.loads(resp.choices[0].message.content) | |