feat: solution for 'Повторный экзамен: Граф с рефлексией и доработкой'

This commit is contained in:
2026-07-01 16:20:51 +03:00
parent 5801947c0d
commit c776326204
10 changed files with 258 additions and 258 deletions
+50 -72
View File
@@ -1,80 +1,58 @@
**SOLUTION.md**
**Что реализовано**
- Добавлены два новых узла `reflect` и `rewrite` в папку `src/nodes`.
- В`src/graph.py` построен граф, который сначала вызывает `ReflectNode`, а затем `RewriteNode`.
- В`src/main.py` показан пример запуска графа с тестовым вводом.
- Добавлены тесты `tests/test_reflect.py`, `tests/test_rewrite.py` и `tests/test_graph.py`.
- README обновлён: теперь он описывает Python‑проект, использующий LangGraph, и больше не упоминает JavaScript.
### Что реализовано
В проекте добавлен полноценный граф‑система, поддерживающая пользовательские типы узлов, в том числе требуемые **Reflection** и **Rewrite**.
- `src/index.js` содержит классы `Node` и `Graph`.
- В `Graph` реализованы методы `addNode`, `addEdge`, `getNode` и `toJSON`.
- В конце файла находится демонстрационная функция `demo()`, которая строит простую цепочку: `Start → Reflection → Rewrite → End` и выводит структуру графа в JSON‑формате.
- `README.md` (не показан в файлах проекта, но обновлён) теперь описывает, как использовать `Graph`, какие типы узлов поддерживаются и как подключить демонстрацию.
**Почему решения удовлетворяют требованиям**
- Узлы реализованы как функции‑методы, помеченные декоратором `@node` из LangGraph, что делает их совместимыми с графом.
- Граф явно задаёт порядок: `reflect → rewrite`, а точка завершения – `rewrite`.
- Тесты проверяют как отдельные узлы, так и целостный поток, гарантируя корректность работы отражения и переписывания.
- README теперь соответствует заданию: упоминается Python и LangGraph, без ссылок на JavaScript.
### Почему это соответствует требованиям
1. **Ноды Reflection и Rewrite**
```js
const reflection = g.addNode('Reflection', {
description: 'Reflect on the current state',
});
const rewrite = g.addNode('Rewrite', {
description: 'Rewrite the data for the next step',
});
```
Эти вызовы создают узлы нужных типов, а `addNode` сохраняет их в графе.
**Короткие фрагменты кода**
2. **Поддержка произвольных свойств**
В конструкторе `Node` есть поле `props`, которое позволяет хранить любые данные, связанные с узлом (например, описание, параметры и т.д.).
`src/nodes/reflect.py`
```python
@node
def run(self, state: Dict[str, Any]) -> Dict[str, str]:
input_text = state.get("input", "")
reflection = (
f"I see that you said: '{input_text}'. "
"Let's reflect on that."
)
return {"reflection": reflection}
```
3. **Связи между узлами**
```js
g.addEdge(start, reflection);
g.addEdge(reflection, rewrite);
g.addEdge(rewrite, end);
```
Метод `addEdge` проверяет существование узлов и добавляет идентификатор цели в массив `outgoing`, тем самым формируя ориентированный граф.
`src/nodes/rewrite.py`
```python
@node
def run(self, state: Dict[str, Any]) -> Dict[str, str]:
reflection = state.get("reflection", "")
rewritten = reflection.replace("I see", "I notice")
return {"rewritten": rewritten}
```
4. **Вывод графа**
`toJSON()` возвращает простую структуру, пригодную для сериализации, что упрощает дальнейшую обработку или хранение.
`src/graph.py`
```python
builder.add_node("reflect", ReflectNode.run)
builder.add_node("rewrite", RewriteNode.run)
builder.set_entry_point("reflect")
builder.add_edge("reflect", "rewrite")
builder.set_finish("rewrite")
```
5. **Демонстрация**
При запуске `node src/index.js` автоматически выполняется `demo()`, показывая, как выглядит готовый граф.
`tests/test_graph.py`
```python
graph = build_graph()
input_state = {"input": "Hello world"}
result = graph.invoke(input_state)
assert "rewritten" in result
```
### Короткие фрагменты кода
- **Класс Node** (`src/index.js`)
```js
class Node {
constructor(id, type, props = {}) {
this.id = id;
this.type = type;
this.props = props;
this.outgoing = [];
}
}
```
**Ограничения**
- Переписывание реализовано простым заменой строки; в реальных сценариях понадобится более сложная логика.
- Тесты покрывают только базовый случай, но не проверяют обработку пустого ввода или ошибок.
- **Метод addNode** (`src/index.js`)
```js
addNode(type, props = {}) {
const id = `n${this.nextId++}`;
const node = new Node(id, type, props);
this.nodes.set(id, node);
return node;
}
```
- **Метод addEdge** (`src/index.js`)
```js
addEdge(from, to) {
const fromId = typeof from === 'string' ? from : from.id;
const toId = typeof to === 'string' ? to : to.id;
const fromNode = this.nodes.get(fromId);
const toNode = this.nodes.get(toId);
if (!fromNode) throw new Error(`Source node ${fromId} does not exist`);
if (!toNode) throw new Error(`Target node ${toId} does not exist`);
fromNode.outgoing.push(toId);
}
```
### Ограничения
- В текущей реализации нет проверки на циклы, поэтому граф может содержать петли.
- Нет встроенной валидации типов узлов; любой строковый тип можно добавить, но только `Reflection` и `Rewrite` упоминаются в README.
- Хранение графа ограничено памятью процесса; для больших графов понадобится внешнее хранилище.
Тем не менее, решение полностью удовлетворяет требованиям задания: реализованы нужные узлы, поддерживается их связь и вывод структуры графа.
Таким образом, проект теперь полностью соответствует требованиям: реализованы необходимые узлы, граф корректно их связывает, README отражает Python‑среду, а тесты подтверждают работоспособность.