Spaces:
Sleeping
Sleeping
| # agent_plan_solve/graph/nodes.py | |
| from langchain_core.prompts import ChatPromptTemplate, PromptTemplate | |
| from langgraph.prebuilt import create_react_agent | |
| from langgraph.prebuilt.chat_agent_executor import AgentState | |
| from agent_plan_solve.graph.state import Plan, PlanState | |
| from agent_plan_solve.utils.llm_config import get_openai_llm | |
| from agent_plan_solve.tools.calculator import calculator_tool | |
| from langchain.agents import load_tools | |
| from typing import Literal | |
| # Load LLM | |
| llm = get_openai_llm() | |
| # Planner prompt | |
| planner_prompt = ChatPromptTemplate.from_messages([ | |
| ("system", | |
| "For the given task, come up with a step-by-step plan.\n" | |
| "Each step should be self-contained and lead to the final answer.\n" | |
| "Avoid superfluous steps."), | |
| ("user", "Prepare a plan to solve the following task:\n{task}\n") | |
| ]) | |
| planner = planner_prompt | llm.with_structured_output(Plan) | |
| # Toolset | |
| tools = load_tools( | |
| tool_names=["ddg-search", "arxiv", "wikipedia"], | |
| llm=llm | |
| ) + [calculator_tool] | |
| # Execution agent prompt | |
| step_prompt = ChatPromptTemplate.from_messages([ | |
| ("system", | |
| "You're a smart assistant that carefully helps solve complex tasks.\n" | |
| "Use tools to verify facts, compute results, and avoid assumptions."), | |
| ("user", | |
| "TASK:\n{task}\n\nPLAN:\n{plan}\n\nSTEP TO EXECUTE:\n{step}\n") | |
| ]) | |
| class StepState(AgentState): | |
| task: str | |
| plan: str | |
| step: str | |
| execution_agent = create_react_agent( | |
| model=llm, | |
| tools=tools, | |
| state_schema=StepState, | |
| prompt=step_prompt | |
| ) | |
| # Final response prompt | |
| final_prompt = PromptTemplate.from_template( | |
| "You're a helpful assistant that has executed a plan.\n" | |
| "Given the results, prepare the final response.\n" | |
| "TASK:\n{task}\n\nPLAN WITH RESULTS:\n{plan}\nFINAL RESPONSE:\n" | |
| ) | |
| # Utility functions | |
| def get_current_step(state: PlanState) -> int: | |
| return len(state.get("past_steps", [])) | |
| def get_full_plan(state: PlanState) -> str: | |
| full_plan = [] | |
| for i, step in enumerate(state["plan"].steps): | |
| full_step = f"# {i+1}. Planned step: {step}\n" | |
| if i < get_current_step(state): | |
| full_step += f"Result: {state['past_steps'][i]}\n" | |
| full_plan.append(full_step) | |
| return "\n".join(full_plan) | |
| # Node functions | |
| async def _build_initial_plan(state: PlanState) -> PlanState: | |
| plan = await planner.ainvoke(state["task"]) | |
| return {"plan": plan} | |
| async def _run_step(state: PlanState) -> PlanState: | |
| plan = state["plan"] | |
| current_step = get_current_step(state) | |
| step = await execution_agent.ainvoke({ | |
| "plan": get_full_plan(state), | |
| "step": plan.steps[current_step], | |
| "task": state["task"] | |
| }) | |
| return {"past_steps": [step["messages"][-1].content]} | |
| async def _get_final_response(state: PlanState) -> PlanState: | |
| final_response = await (final_prompt | llm).ainvoke({ | |
| "task": state["task"], | |
| "plan": get_full_plan(state) | |
| }) | |
| return {"final_response": final_response} | |
| def _should_continue(state: PlanState) -> Literal["run", "response"]: | |
| return "run" if get_current_step(state) < len(state["plan"].steps) else "response" |