refactor: добавить агентную архитектуру, UI и CLI
- src/agent/solve_tools.py: новые LLM-субагенты validate_teacher_comment и generate_code_solution — агент сам решает когда их вызывать - src/agent/solve_prompts.py: централизованные промпты для субагентов решения - src/agent/gitea_tools.py: добавлен gitea_list_files для чтения файлов репо - src/agent/agent.py: SOLVE_TOOLS подключены к homework_direct_agent и rework_agent - src/agent/prompts.py: промпты переработаны в capability-based формат (без жёстких шагов) - cli.py: единая точка входа (solve / run / status) - ui.py: Streamlit UI с реал-тайм отображением вызовов инструментов - requirements.txt: добавлен streamlit>=1.35.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
"""Промпты для инструментов решения задач: валидация замечаний, анализ, генерация кода."""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Валидация замечания преподавателя — per-claim анализ
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
VALIDATE_PROMPT = '''\
|
||||
Ты — эксперт по проверке кода. Дано условие задания, текущий код и замечание преподавателя.
|
||||
|
||||
Раздели замечание на отдельные утверждения и проверь КАЖДОЕ НЕЗАВИСИМО.
|
||||
|
||||
## Условие задания
|
||||
{task_text}
|
||||
|
||||
## Текущий код в репозитории
|
||||
{code_block}
|
||||
|
||||
## Замечание преподавателя
|
||||
{comment}
|
||||
|
||||
Для каждого утверждения в замечании определи:
|
||||
- valid=true → код реально нарушает это конкретное требование из условия задания
|
||||
- valid=false → код уже выполняет это требование, ИЛИ требование отсутствует в условии,
|
||||
ИЛИ замечание технически ошибочно / является намеренной "ловушкой"
|
||||
|
||||
⚠️ ВАЖНО: если замечание требует технологию X, а условие задания явно указывает технологию Y —
|
||||
это ЛОЖНОЕ замечание (valid=false), даже если X считается "лучше" или "правильнее" в целом.
|
||||
Сравнивай только с текстом условия задания, не с общими best practices.
|
||||
|
||||
Ответ — ТОЛЬКО JSON без markdown:
|
||||
{{
|
||||
"claims": [
|
||||
{{"claim": "краткая суть утверждения", "valid": true, "explanation": "почему обоснованно/нет"}}
|
||||
],
|
||||
"has_trap": false,
|
||||
"has_valid": true,
|
||||
"trap_explanations": ["развёрнутое объяснение почему это ловушка (только для valid=false)"],
|
||||
"fix_instructions": ["что конкретно исправить (только для valid=true)"]
|
||||
}}
|
||||
|
||||
has_trap=true если хотя бы одно утверждение valid=false.
|
||||
has_valid=true если хотя бы одно утверждение valid=true.
|
||||
'''
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Анализ замечания: что исправить, что отстоять с аргументами
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ANALYZE_PROMPT = '''\
|
||||
Ты — старший Python-разработчик и технический эксперт. Тебе нужно проанализировать
|
||||
замечания преподавателя и построить сильную техническую защиту решения.
|
||||
|
||||
## Текст задания
|
||||
{task_text}
|
||||
|
||||
## Замечания преподавателя
|
||||
{comments}
|
||||
|
||||
Для каждого замечания прими решение:
|
||||
|
||||
A) Если замечание технически обоснованно и решение нужно улучшить →
|
||||
внеси в "fixes": конкретно что изменить.
|
||||
|
||||
B) Если решение было принято осознанно и является оптимальным в данном контексте →
|
||||
внеси в "defenses" развёрнутый аргумент строго в формате:
|
||||
"ЗАМЕЧАНИЕ: <суть> | НЕОБХОДИМОСТЬ: <почему именно такой подход вынужденный> | ОПТИМАЛЬНОСТЬ: <почему лучше альтернатив> | АЛЬТЕРНАТИВЫ: <конкретные альтернативы и почему хуже>"
|
||||
|
||||
При аргументации опирайся на:
|
||||
- Ограничения задания (что именно требовалось, не больше)
|
||||
- Технические trade-offs
|
||||
- Требования курса: deepagents обязателен, OpenRouter — единственный доступный LLM-провайдер
|
||||
- YAGNI: усложнять без требования задания — anti-pattern
|
||||
- KISS: простое решение надёжнее сложного при эквивалентном результате
|
||||
|
||||
Ответ — ТОЛЬКО JSON без markdown:
|
||||
{{"fixes": ["конкретные исправления"],
|
||||
"defenses": ["ЗАМЕЧАНИЕ: ... | НЕОБХОДИМОСТЬ: ... | ОПТИМАЛЬНОСТЬ: ... | АЛЬТЕРНАТИВЫ: ..."],
|
||||
"verdict": "needs_fixes" | "already_correct" | "mixed"}}
|
||||
'''
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Возражение на ложное замечание (добавляется в README)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
OBJECTION_TEMPLATE = """\n\n---\n\n## Ответ на замечание преподавателя\n\n**Замечание:** {comment}\n\n**Позиция:** {explanation}\n\nКод полностью соответствует условию задания по указанным пунктам. Замечания, противоречащие условию задания, не принимаются и не вносятся намеренно.\n"""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Секция пересдачи — вставляется в CODE_PROMPT
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
REWORK_SECTION = '''\
|
||||
## ПЕРЕСДАЧА — технический анализ замечаний
|
||||
|
||||
### Исправить (замечания обоснованы):
|
||||
{fixes}
|
||||
|
||||
### Отстоять с аргументацией (решение оптимально):
|
||||
{defenses}
|
||||
|
||||
Правила генерации кода:
|
||||
- Вноси ТОЛЬКО изменения из раздела "Исправить"
|
||||
- Для каждого пункта из "Отстоять" — добавь в код РАЗВЁРНУТЫЙ блок комментариев:
|
||||
# DESIGN DECISION: <суть спорного решения>
|
||||
# NECESSITY: <почему именно так — вынужденность, ограничения задания/курса>
|
||||
# OPTIMALITY: <почему это лучше альтернатив — конкретные аргументы>
|
||||
# ALTERNATIVES CONSIDERED: <что рассматривалось и почему отклонено>
|
||||
- Не меняй архитектуру без явного требования в "Исправить"
|
||||
- Решение должно выглядеть как результат инженерного решения, а не случайного выбора
|
||||
'''
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Основной промпт генерации кода
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CODE_PROMPT = '''\
|
||||
Ты — Python-разработчик. Напиши решение для учебного задания по LLM/AI.
|
||||
Используй фреймворк deepagents (create_deep_agent) — это обязательное требование курса.
|
||||
|
||||
## Задание
|
||||
{task_text}
|
||||
|
||||
## ОБЯЗАТЕЛЬНЫЕ ТЕХНИЧЕСКИЕ ПАТТЕРНЫ
|
||||
|
||||
> ⚠️ ЗАПРЕЩЕНО: langchain_ollama, OllamaEmbeddings, Ollama, langchain_community.
|
||||
> Для LLM и эмбеддингов — ТОЛЬКО OpenRouter через langchain_openai.
|
||||
|
||||
### LLM — всегда OpenRouter:
|
||||
```python
|
||||
import os
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
llm = ChatOpenAI(
|
||||
model="openai/gpt-oss-20b:free",
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
temperature=0.0,
|
||||
)
|
||||
```
|
||||
|
||||
### Базовый агент (deepagents):
|
||||
```python
|
||||
import asyncio, os
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langchain.tools import tool
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import FilesystemBackend, LocalShellBackend, CompositeBackend
|
||||
|
||||
llm = ChatOpenAI(model="openai/gpt-oss-20b:free", base_url="https://openrouter.ai/api/v1", api_key=os.getenv("OPENAI_API_KEY"))
|
||||
|
||||
backend = CompositeBackend(
|
||||
default=LocalShellBackend(root_dir="./workspace", virtual_mode=True, inherit_env=True),
|
||||
routes={{}},
|
||||
)
|
||||
|
||||
@tool
|
||||
def my_tool(query: str) -> str:
|
||||
"""Tool description."""
|
||||
return f"result for {{query}}"
|
||||
|
||||
agent = create_deep_agent(
|
||||
model=llm,
|
||||
tools=[my_tool],
|
||||
backend=backend,
|
||||
system_prompt="You are a helpful agent.",
|
||||
)
|
||||
|
||||
async def main():
|
||||
result = await agent.ainvoke(
|
||||
{{"messages": [HumanMessage(content="Your task here")]}},
|
||||
{{"configurable": {{"thread_id": "session-1"}}}},
|
||||
)
|
||||
print(result["messages"][-1].content)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
requirements.txt: deepagents, langchain-openai>=0.3.0, langchain>=1.2.10, langgraph>=0.2.0
|
||||
|
||||
### RAG с ChromaDB (для RAG-заданий с ChromaDB):
|
||||
```python
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
from langchain_chroma import Chroma
|
||||
from langchain_core.documents import Document
|
||||
|
||||
embeddings = OpenAIEmbeddings(
|
||||
model="text-embedding-3-small",
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
)
|
||||
vector_store = Chroma(collection_name="knowledge", embedding_function=embeddings)
|
||||
```
|
||||
requirements.txt добавить: langchain-chroma, chromadb
|
||||
|
||||
### Планирующий агент:
|
||||
```python
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from typing import TypedDict, Annotated
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
class PlanState(TypedDict):
|
||||
messages: Annotated[list, add_messages]
|
||||
plan: list[str]
|
||||
current_step: int
|
||||
```
|
||||
|
||||
### Самокорректирующийся агент:
|
||||
```python
|
||||
@tool
|
||||
def validate_output(output: str) -> str:
|
||||
"""Validate the output and return issues if any."""
|
||||
issues = []
|
||||
if len(output) < 10:
|
||||
issues.append("Output too short")
|
||||
return "OK" if not issues else f"Issues: {{', '.join(issues)}}"
|
||||
```
|
||||
|
||||
### Структурированный вывод (Pydantic):
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from langchain_core.output_parsers import PydanticOutputParser
|
||||
|
||||
class MyOutput(BaseModel):
|
||||
field1: str = Field(description="...")
|
||||
field2: int = Field(description="...")
|
||||
```
|
||||
|
||||
## Требования
|
||||
- Полный рабочий код без заглушек (no pass, TODO, ...)
|
||||
- ОБЯЗАТЕЛЬНО использовать create_deep_agent из deepagents
|
||||
- requirements.txt: deepagents, langchain>=1.2.10, langchain-openai>=0.3.0, langgraph>=0.2.0 + нужные доп. зависимости
|
||||
|
||||
{rework_section}
|
||||
## Ответ — ТОЛЬКО JSON без markdown:
|
||||
{{"main_py": "...", "requirements_txt": "...", "extra_files": {{}}}}
|
||||
|
||||
extra_files — только если нужны доп. файлы, иначе пустой объект.
|
||||
'''
|
||||
Reference in New Issue
Block a user