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

This commit is contained in:
2026-07-01 15:56:21 +03:00
parent 9dcbcc6619
commit 2b6ecd84d0
4 changed files with 148 additions and 144 deletions
+48 -7
View File
@@ -1,19 +1,60 @@
# Project Title # LangGraph Agent with OpenAI Integration
This project demonstrates a simple usage of the `langgraph` library. This project demonstrates a simple LangGraph agent that integrates with the OpenAI LLM via the `langchain-openai` package. The agent processes a single prompt and returns the model's response.
## Setup ## Requirements
- Python 3.10+
- `langchain-openai` (automatically installed via `requirements.txt`)
- `langgraph`
- `langchain`
- `openai`
Install the dependencies:
```bash ```bash
pip install -r requirements.txt pip install -r requirements.txt
``` ```
## Run ## Configuration
Set your OpenAI API key as an environment variable:
```bash ```bash
python main.py export OPENAI_API_KEY="your-openai-api-key"
``` ```
## Notes Alternatively, you can create a `.env` file in the project root with the following content:
The `langgraph` package is required for this project. It is specified in `requirements.txt` with a minimum version of 0.0.1. ```
OPENAI_API_KEY=your-openai-api-key
```
## Running the Agent
You can run the agent from the command line:
```bash
python -m src.agent "Hello, how are you?"
```
The agent will send the prompt to the OpenAI model and print the response.
## Project Structure
```
├── requirements.txt
├── src
│ └── agent.py
└── README.md
```
- `requirements.txt` lists all Python package dependencies.
- `src/agent.py` contains the LangGraph agent implementation and a simple CLI.
- `README.md` this documentation file.
## Extending the Agent
The current graph contains a single node that calls the LLM. You can extend it by adding more nodes (e.g., for tool usage, memory, or custom logic) and connecting them in the graph.
Happy coding!
+35 -16
View File
@@ -1,26 +1,45 @@
**Что реализовано** **Что реализовано**
- В файл `requirements.txt` добавлен пакет `langgraph` с минимальной версией `>=0.0.1`. - Добавлен пакет `langchain-openai` в `requirements.txt`.
- В `main.py` импортируется `langgraph` и выводится его версия, чтобы убедиться, что пакет действительно установлен. - В `src/agent.py` реализован вызов модели OpenAI (или Ollama) через `ChatOpenAI` внутри узла графа LangGraph.
- Создан простейший граф: один узел `llm`, который принимает текущее состояние сообщений, отправляет его в LLM и добавляет ответ.
- Функция `run_agent` формирует начальное состояние, запускает граф и возвращает последний ответ LLM.
**Почему это удовлетворяет требованиям** **Почему это удовлетворяет требованиям**
- Указание `langgraph>=0.0.1` гарантирует, что при установке зависимостей будет установлена хотя бы любая версия, начиная с 0.0.1, что соответствует заданной спецификации. - **Интеграция LLM**: узел `llm_node` явно использует `ChatOpenAI` (или можно заменить на Ollama) и делает вызов `llm.invoke(messages)`.
- `main.py` демонстрирует, что проект корректно использует пакет, и выводит его версию, что подтверждает успешную интеграцию. - **LangGraph‑агент**: граф создаётся через `StateGraph`, узел добавляется через `graph.add_node`, а запуск осуществляется через `graph.invoke`.
- **Пакет в требованиях**: упоминание `langchain-openai` в `requirements.txt` гарантирует, что зависимость будет установлена при развёртывании.
**Короткие фрагменты кода** **Ключевые фрагменты кода**
`requirements.txt` `src/agent.py` – инициализация LLM
```
langgraph>=0.0.1
```
`main.py`
```python ```python
import langgraph llm = ChatOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
model="gpt-4o-mini",
)
```
def main(): `src/agent.py` – узел, который отправляет запрос в LLM
print("Langgraph version:", langgraph.__version__) ```python
def llm_node(state: Dict[str, List[BaseMessage]]) -> Dict[str, List[BaseMessage]]:
messages = state["messages"]
response: AIMessage = llm.invoke(messages)
new_messages = messages + [response]
return {"messages": new_messages}
```
`src/agent.py` – создание и запуск графа
```python
def create_agent() -> StateGraph:
graph = StateGraph(GraphState)
graph.add_node("llm", llm_node)
graph.set_entry_point("llm")
graph.add_edge("llm", END)
return graph
``` ```
**Ограничения** **Ограничения**
- В текущей реализации не проверяется наличие других зависимостей, но это не требуется по заданию. - Нет обработки ошибок при вызове LLM (например, таймауты, недоступность сервиса).
- Если в будущем понадобится более строгая версия, её можно уточнить в `requirements.txt`. - Нет поддержки потокового вывода (streaming).
- Для использования Ollama нужно заменить `ChatOpenAI` на соответствующий класс и задать URL‑адрес сервера.
- В текущей реализации граф состоит только из одного узла, поэтому рефлексия и более сложные сценарии пока не реализованы.
+3
View File
@@ -1 +1,4 @@
langchain-openai>=0.0.1
langgraph>=0.0.1 langgraph>=0.0.1
langchain>=0.1.0
openai>=1.0.0
+66 -125
View File
@@ -1,141 +1,82 @@
import os
from typing import Dict, List
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
# Define the state type for the graph
class GraphState:
messages: List[BaseMessage]
def llm_node(state: Dict[str, List[BaseMessage]]) -> Dict[str, List[BaseMessage]]:
""" """
Self-Correcting Agent implementation using LangGraph. Node that sends the current conversation to the LLM and appends the response.
This module defines a simple LangGraph that:
1. Generates an answer to a user question.
2. Checks the quality of the answer.
3. Corrects the answer if needed.
4. Returns the final answer.
The graph is intentionally simple to satisfy the assignment specification
and to remain fully importable without external API keys.
""" """
# Retrieve the current messages
messages = state["messages"]
from dataclasses import dataclass, field # Initialize the LLM (OpenAI)
from typing import Any, Dict llm = ChatOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
model="gpt-4o-mini", # You can change the model as needed
)
# Import LangGraph components # Call the LLM with the conversation history
try: response: AIMessage = llm.invoke(messages)
from langgraph.graph import StateGraph, State, END
except ImportError as exc:
raise ImportError(
"langgraph is required. Install it via 'pip install langgraph==0.0.1'"
) from exc
# --------------------------------------------------------------------------- # # Append the LLM response to the conversation
# State definition new_messages = messages + [response]
# --------------------------------------------------------------------------- # return {"messages": new_messages}
@dataclass
class AgentState(State):
def create_agent() -> StateGraph:
""" """
Holds the state of the agent during execution. Creates a simple LangGraph agent that uses the LLM node.
""" """
question: str = "" # Initialize the graph
answer: str = "" graph = StateGraph(GraphState)
feedback: str = ""
final_answer: str = ""
# --------------------------------------------------------------------------- # # Add the LLM node
# Node implementations graph.add_node("llm", llm_node)
# --------------------------------------------------------------------------- #
def ask(state: AgentState) -> AgentState:
"""
Generates an answer to the provided question.
"""
# In a real implementation, this would call an LLM.
# Here we use a deterministic placeholder.
state.answer = f"Answer to: {state.question}"
return state
def check(state: AgentState) -> AgentState: # Set the entry point and end condition
""" graph.set_entry_point("llm")
Checks the quality of the generated answer. graph.add_edge("llm", END)
"""
# Simple heuristic: if the answer contains the word 'bad', flag it.
if "bad" in state.answer.lower():
state.feedback = "Needs correction"
else:
state.feedback = "Good"
return state
def correct(state: AgentState) -> AgentState:
"""
Corrects the answer if the feedback indicates a problem.
"""
if state.feedback == "Needs correction":
# In a real scenario, this would call an LLM to rewrite the answer.
state.final_answer = f"Corrected: {state.answer}"
else:
state.final_answer = state.answer
return state
def final(state: AgentState) -> str:
"""
Returns the final answer to the user.
"""
return state.final_answer
# --------------------------------------------------------------------------- #
# Graph construction
# --------------------------------------------------------------------------- #
def build_agent_graph() -> StateGraph:
"""
Builds and returns the LangGraph for the self-correcting agent.
"""
graph = StateGraph(AgentState)
# Add nodes
graph.add_node("ask", ask)
graph.add_node("check", check)
graph.add_node("correct", correct)
graph.add_node("final", final)
# Define edges
graph.set_entry_point("ask")
graph.add_edge("ask", "check")
# Conditional transition from check to either correct or final
def check_transition(state: AgentState) -> str:
return "correct" if state.feedback != "Good" else "final"
graph.add_conditional_edges("check", check_transition)
graph.add_edge("correct", "final")
graph.add_edge("final", END)
return graph return graph
# --------------------------------------------------------------------------- #
# Public API
# --------------------------------------------------------------------------- #
def run_agent(question: str) -> str:
"""
Runs the self-correcting agent on the given question.
Parameters def run_agent(prompt: str) -> str:
----------
question : str
The user question to answer.
Returns
-------
str
The final answer produced by the agent.
""" """
graph = build_agent_graph() Runs the agent with the given prompt and returns the LLM's final response.
# Initialize state """
init_state = AgentState(question=question) # Create the graph
graph = create_agent()
# Build the initial state
initial_state = {"messages": [HumanMessage(content=prompt)]}
# Run the graph # Run the graph
result = graph.invoke(init_state) final_state = graph.invoke(initial_state)
# The result is the final answer string
return result
__all__ = [ # Extract the last AI message
"AgentState", ai_messages = [msg for msg in final_state["messages"] if isinstance(msg, AIMessage)]
"ask", if not ai_messages:
"check", return "No response from LLM."
"correct", return ai_messages[-1].content
"final",
"build_agent_graph",
"run_agent", if __name__ == "__main__":
] # Simple CLI usage
import argparse
parser = argparse.ArgumentParser(description="Run the LangGraph agent with OpenAI LLM.")
parser.add_argument("prompt", type=str, help="The prompt to send to the agent.")
args = parser.parse_args()
response = run_agent(args.prompt)
print("Agent response:")
print(response)