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

This commit is contained in:
2026-07-01 16:43:56 +03:00
parent 89b60e8f03
commit e9a6f09c70
8 changed files with 383 additions and 143 deletions
+74 -44
View File
@@ -1,54 +1,84 @@
**SOLUTION.md**
**What was implemented**
* Added a fullyfunctional LLM integration to the `reflect` and `rewrite` nodes.
* Imported and used `langchain-core` for prompt construction and chain execution.
* Configured the OpenAI LLM with a moderate temperature (0.7) to produce reflective and concise outputs.
* Built a simple graph that runs the two nodes sequentially and prints the final result.
- Added a dedicated LLM integration module (`src/llm_integration.py`) that exposes a single `get_llm()` function.
It reads the `LLM_PROVIDER` environment variable and returns a `ChatOpenAI` or `ChatOllama` instance, satisfying the requirement to use LangChain with OpenAI or Ollama.
- Updated the node definitions (`src/nodes.py`) so that both `ReflectionNode` and `RewritingNode` obtain their LLM client via `get_llm()`.
Each node builds a prompt, calls the LLM, and returns the result in a dictionary (`{"reflection": …}` or `{"rewritten": …}`).
- Created unit tests (`tests/test_nodes.py`) that patch `get_llm()` to return a mock LLM, verifying that the nodes construct the correct prompts and return the expected output.
- Updated the project structure to be a pure Python package no JavaScript files or references remain.
- Rewrote the README (not shown here) to describe the project as a Python solution, list the required environment variable, and explain how to run the graph.
**Why the main parts satisfy the requirements**
1. **LLM integration** Both nodes create an `OpenAI` instance, build a `ChatPromptTemplate` with a `HumanMessagePromptTemplate`, and wrap it in an `LLMChain`. The chain is invoked with the input string and the LLMs output is returned.
```js
// src/nodes/reflect.js
const llm = new OpenAI({ temperature: 0.7 });
const prompt = ChatPromptTemplate.fromPromptMessages([
HumanMessagePromptTemplate.fromTemplate(
"Please reflect on the following message:\n\n{input}"
),
]);
const chain = new LLMChain({ llm, prompt });
const result = await chain.invoke({ input });
return result.output;
```
2. **langchaincore usage** The code imports `ChatPromptTemplate`, `HumanMessagePromptTemplate`, and `LLMChain` from `langchain-core`, demonstrating proper message handling.
```js
const { ChatPromptTemplate, HumanMessagePromptTemplate } = require('langchain-core/prompts');
const { LLMChain } = require('langchain-core/chains');
```
3. **Package configuration** `langchain-core` is listed in `package.json` and required in the node files, ensuring it is installed and available at runtime.
```json
// package.json
"dependencies": {
"langchain-core": "^0.0.1",
"langchain-openai": "^0.0.1",
"openai": "^4.0.0"
}
```
| Requirement | How it is met |
|-------------|---------------|
| Integration code for LangChain OpenAI/Ollama for reflection node | `ReflectionNode` uses `self.llm = get_llm()` and calls it with a prompt that asks for reflection. |
| Integration code for LangChain OpenAI/Ollama for rewriting node | `RewritingNode` similarly obtains an LLM and rewrites the reflection. |
| README describes a Python project | The README now starts with “Python implementation” and removes all JavaScript references. |
| Project is a Python project only | All source files are in `src/` and use Python imports; no `.js` files exist. |
| Use LangChain with OpenAI or Ollama | `get_llm()` explicitly imports `langchain.llms` and `langchain.chat_models` and returns the appropriate class. |
| Integration nodes present | Both `ReflectionNode` and `RewritingNode` are defined in `src/nodes.py` and are exercised by the graph. |
**Short code excerpts**
**Key code excerpts**
* `src/nodes/rewrite.js` mirrors the reflect node but with a different prompt.
* `src/graph.js` simple executor that runs nodes in order.
* `src/index.js` entry point that builds the graph, checks the API key, and runs the pipeline.
*`src/llm_integration.py` LLM factory*
```python
def get_llm() -> Union[OpenAI, Ollama, ChatOpenAI, ChatOllama]:
if LLM_PROVIDER == "openai":
return ChatOpenAI(temperature=0.7)
elif LLM_PROVIDER == "ollama":
return ChatOllama(model="llama2", temperature=0.7)
else:
raise ValueError(f"Unsupported LLM provider: {LLM_PROVIDER}")
```
**Honest limitations**
*`src/nodes.py` ReflectionNode*
```python
class ReflectionNode(BaseNode):
def __init__(self, node_id: str, prompt_template: str = None):
...
self.llm = get_llm()
* No unit tests are provided; the implementation relies on manual console output.
* Error handling is basic any LLM failure throws a generic error message.
* The graph executes nodes sequentially; parallel execution or caching is not implemented.
* The OpenAI model name, max tokens, and other advanced settings are hardcoded.
* The solution assumes the environment variable `OPENAI_API_KEY` is correctly set; otherwise the program exits.
def process(self, input_data: str) -> Dict[str, str]:
prompt = self.prompt_template.format(input_text=input_data)
reflection = self.llm(prompt)
return {"reflection": reflection.strip()}
```
Despite these limitations, the core assignment requirements—LLM integration in both nodes and proper use of `langchain-core` for message handling—are fully met.
*`src/nodes.py` RewritingNode*
```python
class RewritingNode(BaseNode):
def __init__(self, node_id: str, style: str = "formal"):
...
self.llm = get_llm()
def process(self, input_data: Dict[str, str]) -> Dict[str, str]:
reflection = input_data.get("reflection", "")
prompt = (
f"Rewrite the following reflection in a {self.style} style:\n\n{reflection}\n\nRewritten:"
)
rewritten = self.llm(prompt)
return {"rewritten": rewritten.strip()}
```
*`tests/test_nodes.py` unit test for ReflectionNode*
```python
@patch("src.llm_integration.get_llm")
def test_reflection_node(self, mock_get_llm):
mock_llm = MagicMock()
mock_llm.return_value = "This is a reflection."
mock_get_llm.return_value = mock_llm
node = ReflectionNode("test_reflection")
output = node.process("Sample input text.")
mock_llm.assert_called_once_with(
"Please reflect on the following text:\n\nSample input text.\n\nReflection:"
)
```
**Limitations / Future work**
- The `get_llm()` function currently supports only the default OpenAI and Ollama models; adding custom model names or API keys would require extending the factory.
- The graph implementation is a simple linear chain; more complex DAGs or parallel execution are not yet supported.
- Error handling for LLM failures (timeouts, API errors) is minimal; production use would benefit from retries and graceful degradation.
Overall, the project now fully implements the required LangChain integration for reflection and rewriting nodes, is a clean Python codebase, and the README accurately reflects this.