Вынес агентов в отдельные файлы

This commit is contained in:
ki.sagidullin
2026-04-12 08:51:33 +05:00
parent f110f52e91
commit 324097988b
9 changed files with 203 additions and 100 deletions

137
agent/developer.py Normal file
View File

@@ -0,0 +1,137 @@
from typing import Optional, Dict, Any
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_community.chat_models import ChatOllama
import json
from config import MODEL_NAME, TEMPERATURE, LLM_HOST
from models import CodeSolution, ReviewResult, ReviewComment, Task
import re
class DeveloperAgent:
"""Агент-разработчик: генерирует код по требованию"""
def __init__(self):
self.llm = ChatOllama(
model=MODEL_NAME,
temperature=TEMPERATURE,
base_url=LLM_HOST,
num_predict=8192
)
def develop(self, task: Task, previous_comments: list = None) -> CodeSolution:
"""Генерирует код с улучшенным парсингом JSON"""
system_prompt = """Ты - опытный разработчик. Твоя задача - написать качественный код.
Ты должен:
1. Писать чистый, читаемый код с комментариями
2. Добавлять обработку ошибок
3. Писать юнит-тесты (pytest/unittest)
4. Следовать PEP8 (для Python) или стандартам языка
ВАЖНО: Возвращай ТОЛЬКО валидный JSON без лишних символов.
ЗАПРЕЩЕНЫ trailing commas (запятые перед закрывающей скобкой).
Формат ответа (пример):
{
"files": {
"main.py": "print('hello')"
},
"description": "Краткое описание",
"tests": {
"test_main.py": "def test_hello(): assert True"
}
}
Не добавляй пояснений вне JSON.
"""
user_prompt = f"""
Требование: {task.requirement}
Текущая итерация: {task.iteration}
"""
if previous_comments:
user_prompt += f"""
Замечания с предыдущего ревью:
{json.dumps(previous_comments, indent=2, ensure_ascii=False)}
Пожалуйста, исправь код согласно замечаниям.
"""
messages = [
SystemMessage(content=system_prompt),
HumanMessage(content=user_prompt)
]
response = self.llm.invoke(messages)
raw_content = response.content
# Пытаемся извлечь JSON из разных форматов
parsed_data = self._extract_json(raw_content)
if parsed_data is None:
# Если не удалось, пробуем повторно с explicit инструкцией
print("⚠️ Не удалось распарсить JSON, повторный запрос с исправлением...")
correction_prompt = f"""
Предыдущий ответ содержал невалидный JSON (возможно, trailing commas).
Пожалуйста, исправь и верни ТОЛЬКО валидный JSON в формате:
{{
"files": {{"filename": "content"}},
"description": "text",
"tests": {{"testfile": "test_content"}}
}}
Твоя предыдущая попытка:
{raw_content[:1000]}
Требование: {task.requirement}
"""
messages2 = [
SystemMessage(content="Ты - разработчик. Верни только валидный JSON без лишних символов."),
HumanMessage(content=correction_prompt)
]
response2 = self.llm.invoke(messages2)
parsed_data = self._extract_json(response2.content)
if parsed_data is None:
raise ValueError(f"Failed to parse JSON after retry. Raw: {response2.content[:500]}")
return CodeSolution(
files=parsed_data.get("files", {}),
description=parsed_data.get("description", ""),
tests=parsed_data.get("tests", {})
)
def _extract_json(self, text: str) -> Optional[dict]:
"""Извлекает и очищает JSON из текста ответа LLM"""
# 1. Извлечь блок между ```json и ``` или просто ```
if "```json" in text:
text = text.split("```json")[1].split("```")[0]
elif "```" in text:
text = text.split("```")[1].split("```")[0]
text = text.strip()
# 2. Удалить trailing commas в объектах и массивах
# Удаляем запятую перед } или ]
text = re.sub(r',\s*}', '}', text)
text = re.sub(r',\s*]', ']', text)
# 3. Удалить комментарии (// ...) если есть
text = re.sub(r'//.*?(\n|$)', '', text)
# 4. Попробовать распарсить
try:
return json.loads(text)
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
# 5. Еще одна попытка: найти любой JSON объект в строке
match = re.search(r'\{.*\}|\[.*\]', text, re.DOTALL)
if match:
try:
return json.loads(match.group())
except:
pass
return None