100 lines
4.4 KiB
Python
100 lines
4.4 KiB
Python
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 ReviewerAgent:
|
||
"""Агент-ревьювер: проверяет качество кода"""
|
||
|
||
def __init__(self):
|
||
self.llm = ChatOllama(
|
||
model=MODEL_NAME,
|
||
temperature=0.1,
|
||
base_url=LLM_HOST,
|
||
num_predict=2048
|
||
)
|
||
|
||
def review(self, task: Task, solution: CodeSolution) -> ReviewResult:
|
||
"""Проверяет код и возвращает замечания"""
|
||
|
||
system_prompt = """Ты - строгий ревьювер кода. Твоя задача:
|
||
1. Проверить соответствие требованиям
|
||
2. Найти логические ошибки и баги
|
||
3. Оценить читаемость и стиль кода
|
||
4. Проверить покрытие тестами
|
||
5. Найти проблемы безопасности
|
||
6. Предложить улучшения
|
||
|
||
Оценивай код критически. Будь конкретен в замечаниях, указывай файлы и строки.
|
||
|
||
Допустимые уровни severity (от критичного к информационному):
|
||
- critical: блокирующие ошибки (безопасность, падения)
|
||
- major: серьёзные логические ошибки, неверная работа
|
||
- minor: стиль, читаемость, мелкие баги
|
||
- warning: потенциальные проблемы, улучшения, edge cases
|
||
- info: предложения, рекомендации, необязательные улучшения
|
||
- suggestion: альтернативные подходы
|
||
|
||
Верни JSON с полями:
|
||
- status: "approved", "changes_requested", или "rejected"
|
||
- comments: массив объектов с полями: file, line, severity, text
|
||
- summary: краткое резюме ревью
|
||
"""
|
||
# Формируем представление кода для ревью
|
||
code_for_review = ""
|
||
for filename, content in solution.files.items():
|
||
code_for_review += f"\n--- {filename} ---\n{content}\n"
|
||
|
||
if solution.tests:
|
||
code_for_review += "\n--- TESTS ---\n"
|
||
for testname, test_content in solution.tests.items():
|
||
code_for_review += f"\n--- {testname} ---\n{test_content}\n"
|
||
|
||
user_prompt = f"""
|
||
Требование: {task.requirement}
|
||
|
||
Код на ревью:
|
||
{code_for_review}
|
||
|
||
Описание решения разработчика: {solution.description}
|
||
|
||
Проведи ревью. Будь строг, но справедлив.
|
||
"""
|
||
|
||
messages = [
|
||
SystemMessage(content=system_prompt),
|
||
HumanMessage(content=user_prompt)
|
||
]
|
||
|
||
response = self.llm.invoke(messages)
|
||
|
||
# Парсим JSON ответ
|
||
try:
|
||
content = response.content
|
||
if "```json" in content:
|
||
content = content.split("```json")[1].split("```")[0]
|
||
elif "```" in content:
|
||
content = content.split("```")[1].split("```")[0]
|
||
|
||
data = json.loads(content.strip())
|
||
|
||
comments = []
|
||
for comment_data in data.get("comments", []):
|
||
comments.append(ReviewComment(
|
||
line=comment_data.get("line"),
|
||
file=comment_data.get("file"),
|
||
severity=comment_data.get("severity", "major"),
|
||
text=comment_data.get("text", "")
|
||
))
|
||
|
||
return ReviewResult(
|
||
status=data.get("status", "changes_requested"),
|
||
comments=comments,
|
||
summary=data.get("summary", "")
|
||
)
|
||
except Exception as e:
|
||
raise ValueError(f"Failed to parse reviewer response: {e}\nResponse: {response.content}") |