feat: solution for 6a1864fa8a94f887e50d46f0
This commit is contained in:
@@ -0,0 +1,116 @@
|
|||||||
|
from typing import TypedDict, Any
|
||||||
|
import random
|
||||||
|
|
||||||
|
# LLM setup – use placeholder values if no specific provider is mentioned
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
from pydantic import SecretStr
|
||||||
|
|
||||||
|
llm = ChatOpenAI(
|
||||||
|
model="openai/gpt-oss-20b",
|
||||||
|
base_url='https://platform.brojs.ru/jrnl-bh/api/inference/v1',
|
||||||
|
api_key=SecretStr("jrnl_30283ab953615cbb6846ff9940a1eedce0b76d7b2f59a2394f29e74643e6a90d"),
|
||||||
|
temperature=0.2,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------- State ----------
|
||||||
|
class AgentState(TypedDict):
|
||||||
|
task: str
|
||||||
|
result: str
|
||||||
|
attempts: int
|
||||||
|
status: str # pending | success | failed | max_attempts
|
||||||
|
error: str | None
|
||||||
|
max_attempts: int
|
||||||
|
|
||||||
|
# ---------- Tool ----------
|
||||||
|
def unreliable_tool(task: str) -> str:
|
||||||
|
"""Simulate a tool that fails ~30% of the time."""
|
||||||
|
if random.random() < 0.3:
|
||||||
|
raise ValueError("Tool failure")
|
||||||
|
# Very simple evaluation: just return the task string for demo
|
||||||
|
return f"Result of '{task}'"
|
||||||
|
|
||||||
|
# ---------- Nodes ----------
|
||||||
|
def execute_task(state: AgentState) -> AgentState:
|
||||||
|
try:
|
||||||
|
result = unreliable_tool(state["task"])
|
||||||
|
state.update(result=result, error=None)
|
||||||
|
except Exception as e:
|
||||||
|
state.update(result="", error=str(e))
|
||||||
|
state.update(status="pending")
|
||||||
|
return state
|
||||||
|
|
||||||
|
def verify_result(state: AgentState) -> AgentState:
|
||||||
|
if state["error"]:
|
||||||
|
# If tool failed, skip verification
|
||||||
|
state.update(status="failed")
|
||||||
|
return state
|
||||||
|
prompt = f"Task result: {state['result']}. Is this correct? Respond with 'success' or 'failed'."
|
||||||
|
verdict_obj = llm.invoke(prompt)
|
||||||
|
# Depending on the LLM implementation, the response may be a string or an object with `content`
|
||||||
|
if hasattr(verdict_obj, "content"):
|
||||||
|
verdict = verdict_obj.content.strip().lower()
|
||||||
|
else:
|
||||||
|
verdict = str(verdict_obj).strip().lower()
|
||||||
|
if "success" in verdict:
|
||||||
|
state.update(status="success")
|
||||||
|
else:
|
||||||
|
state.update(status="failed")
|
||||||
|
return state
|
||||||
|
|
||||||
|
def handle_error(state: AgentState) -> AgentState:
|
||||||
|
state["attempts"] += 1
|
||||||
|
if state["attempts"] >= state["max_attempts"]:
|
||||||
|
state.update(status="max_attempts")
|
||||||
|
else:
|
||||||
|
state.update(status="pending")
|
||||||
|
return state
|
||||||
|
|
||||||
|
# ---------- Graph ----------
|
||||||
|
from langgraph.graph import StateGraph, START, END
|
||||||
|
from langgraph.checkpoint.memory import InMemorySaver
|
||||||
|
|
||||||
|
builder = StateGraph(AgentState)
|
||||||
|
builder.add_node("execute_task", execute_task)
|
||||||
|
builder.add_node("verify_result", verify_result)
|
||||||
|
builder.add_node("handle_error", handle_error)
|
||||||
|
|
||||||
|
builder.set_entry_point("execute_task")
|
||||||
|
builder.add_edge("execute_task", "verify_result")
|
||||||
|
|
||||||
|
def _next(state: AgentState) -> str:
|
||||||
|
status = state["status"]
|
||||||
|
if status == "success":
|
||||||
|
return END
|
||||||
|
if status == "failed" and state["attempts"] < state["max_attempts"]:
|
||||||
|
return "handle_error"
|
||||||
|
return END
|
||||||
|
|
||||||
|
builder.add_conditional_edges("verify_result", _next)
|
||||||
|
builder.add_edge("handle_error", "execute_task")
|
||||||
|
|
||||||
|
graph = builder.compile(checkpointer=InMemorySaver())
|
||||||
|
|
||||||
|
# ---------- CLI ----------
|
||||||
|
def main():
|
||||||
|
task = input("Задача: ").strip()
|
||||||
|
if not task:
|
||||||
|
print("Нет задачи")
|
||||||
|
return
|
||||||
|
initial_state: AgentState = {
|
||||||
|
"task": task,
|
||||||
|
"result": "",
|
||||||
|
"attempts": 0,
|
||||||
|
"status": "pending",
|
||||||
|
"error": None,
|
||||||
|
"max_attempts": 5,
|
||||||
|
}
|
||||||
|
state = graph.invoke(initial_state)
|
||||||
|
attempts = state["attempts"] + (1 if state["status"] != "failed" else 0)
|
||||||
|
print(f"\nИтог: {state['status']} за {attempts} попытки(й)")
|
||||||
|
if state["result"]:
|
||||||
|
print(f"Результат: {state['result']}")
|
||||||
|
if state["error"]:
|
||||||
|
print(f"Ошибка: {state['error']}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user