84 lines
4.4 KiB
Markdown
84 lines
4.4 KiB
Markdown
**What was implemented**
|
||
|
||
- 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**
|
||
|
||
| 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. |
|
||
|
||
**Key code excerpts**
|
||
|
||
*`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}")
|
||
```
|
||
|
||
*`src/nodes.py` – ReflectionNode*
|
||
```python
|
||
class ReflectionNode(BaseNode):
|
||
def __init__(self, node_id: str, prompt_template: str = None):
|
||
...
|
||
self.llm = get_llm()
|
||
|
||
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()}
|
||
```
|
||
|
||
*`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. |