Переделываю систему под агента-планировщика
This commit is contained in:
111
orchestrator.py
111
orchestrator.py
@@ -1,5 +1,5 @@
|
||||
# orchestrator.py
|
||||
from typing import Dict, Any, Literal
|
||||
from typing import Dict, Any, Literal, TypedDict, List
|
||||
from langgraph.graph import StateGraph, END
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
import uuid
|
||||
@@ -8,6 +8,14 @@ from models import Task, TaskStatus, CodeSolution, ReviewResult, IterationRecord
|
||||
from agent import DeveloperAgent, ReviewerAgent
|
||||
from config import MAX_REVIEW_RETRIES
|
||||
|
||||
class AgentState(TypedDict):
|
||||
task: str
|
||||
plan: List[Dict]
|
||||
execution_results: List[Dict]
|
||||
review: Dict
|
||||
iteration: int
|
||||
max_iterations: int
|
||||
|
||||
class Orchestrator:
|
||||
"""Оркестратор - управляет процессом разработки"""
|
||||
|
||||
@@ -19,7 +27,6 @@ class Orchestrator:
|
||||
# Создаем граф состояний
|
||||
self.workflow = self._build_workflow()
|
||||
self.checkpointer = MemorySaver()
|
||||
self.app = self.workflow.compile()
|
||||
|
||||
def _add_history(self, task: Task, agent: str, action: str,
|
||||
input_summary: str = None, output_summary: str = None,
|
||||
@@ -37,36 +44,72 @@ class Orchestrator:
|
||||
)
|
||||
task.history.append(record)
|
||||
|
||||
def _build_workflow(self) -> StateGraph:
|
||||
def _build_workflow(self):
|
||||
"""Строит граф процесса разработки"""
|
||||
|
||||
# Определяем состояния
|
||||
workflow = StateGraph(Dict)
|
||||
workflow = StateGraph(AgentState)
|
||||
|
||||
# Добавляем узлы
|
||||
workflow.add_node("developer", self._developer_node)
|
||||
workflow.add_node("reviewer", self._reviewer_node)
|
||||
workflow.add_node("finalize", self._finalize_node)
|
||||
workflow.add_node("planner", self._plan_node)
|
||||
workflow.add_node("executor", self._exec_node)
|
||||
workflow.add_node("reviewer", self._review_node)
|
||||
|
||||
# Определяем переходы
|
||||
workflow.set_entry_point("developer")
|
||||
workflow.add_edge("developer", "reviewer")
|
||||
workflow.set_entry_point("planner")
|
||||
workflow.add_edge("planner", "executor")
|
||||
workflow.add_edge("executor", "reviewer")
|
||||
|
||||
# Условные переходы после ревью
|
||||
workflow.add_conditional_edges(
|
||||
"reviewer",
|
||||
self._decide_next_step,
|
||||
{
|
||||
"approved": "finalize",
|
||||
"rework": "developer",
|
||||
"rejected": "finalize",
|
||||
"failed": "finalize"
|
||||
}
|
||||
)
|
||||
workflow.add_conditional_edges("reviewer", self._after_review, {
|
||||
"approved": END,
|
||||
"rework": "executor", # повторить выполнение с тем же планом? или перепланировать?
|
||||
"replan": "planner",
|
||||
"reject": END
|
||||
})
|
||||
|
||||
workflow.add_edge("finalize", END)
|
||||
return workflow.compile()
|
||||
|
||||
def _plan_node(self, state: AgentState):
|
||||
print(f"\n🔧 [Iteration {state.get('iteration', 0)}] Планировщик начал работу...")
|
||||
# Сначала получим описания инструментов для планировщика
|
||||
tools_desc = [{"name": t.name, "description": t.description, "args": t.args} for t in self.tools]
|
||||
plan = self.planner.create_plan(state["task"], tools_desc)
|
||||
state["plan"] = plan
|
||||
return state
|
||||
|
||||
def _exec_node(self, state: AgentState):
|
||||
"""Узел разработчика"""
|
||||
print(f"\n🔧 [Iteration {state.get('iteration', 0)}] Исполнитель начал работу...")
|
||||
|
||||
return workflow
|
||||
# Логируем начало работы разработчика
|
||||
results = self.executor.execute_plan(state["plan"])
|
||||
state["execution_results"] = results
|
||||
return state
|
||||
|
||||
def _review_node(self, state: AgentState):
|
||||
print(f"\n🔧 [Iteration {state.get('iteration', 0)}] Ревьювер начал работу...")
|
||||
|
||||
review = self.reviewer.review(state["task"], state["plan"], state["execution_results"])
|
||||
state["review"] = review
|
||||
state["iteration"] = state.get("iteration", 0) + 1
|
||||
return state
|
||||
|
||||
def _after_review(self, state: AgentState):
|
||||
status = state["review"].get("status")
|
||||
if status == "approved":
|
||||
return "approved"
|
||||
elif status == "changes_requested":
|
||||
if state["iteration"] >= state.get("max_iterations", 3):
|
||||
return "reject"
|
||||
# пробуем перевыполнить те же шаги (может, ошибка временная)
|
||||
return "rework"
|
||||
elif status == "rejected":
|
||||
if state["iteration"] >= state.get("max_iterations", 3):
|
||||
return "reject"
|
||||
# нужен новый план
|
||||
return "replan"
|
||||
else:
|
||||
return "reject"
|
||||
|
||||
def _developer_node(self, state: Dict) -> Dict:
|
||||
"""Узел разработчика"""
|
||||
@@ -244,26 +287,26 @@ class Orchestrator:
|
||||
f.write(test_content)
|
||||
print(f" 💾 Сохранен тест: {testpath}")
|
||||
|
||||
def run(self, requirement: str, task_id: str = None) -> Dict:
|
||||
def run(self, task: str, max_iterations:int = None) -> Dict:
|
||||
"""Запускает процесс разработки"""
|
||||
|
||||
if not task_id:
|
||||
task_id = str(uuid.uuid4())
|
||||
task_id = str(uuid.uuid4())
|
||||
|
||||
initial_task = Task(
|
||||
id=task_id,
|
||||
requirement=requirement,
|
||||
status=TaskStatus.PENDING,
|
||||
iteration=0
|
||||
)
|
||||
initial_state = {
|
||||
"task": task,
|
||||
"plan": [],
|
||||
"execution_results": [],
|
||||
"review": {},
|
||||
"iteration": 0,
|
||||
"max_iterations": max_iterations
|
||||
}
|
||||
|
||||
print(f"\n🚀 Запуск мультиагентной системы")
|
||||
print(f"📝 Задача: {requirement}")
|
||||
print(f"📝 Задача: {task}")
|
||||
print(f"🆔 ID: {task_id}")
|
||||
|
||||
# Запускаем граф
|
||||
initial_state = {"task": initial_task}
|
||||
final_state = self.app.invoke(initial_state)
|
||||
final_state = self.workflow.invoke(initial_state)
|
||||
|
||||
return final_state
|
||||
|
||||
|
||||
Reference in New Issue
Block a user