boxmoe_header_banner_img

Hello! 欢迎来到我的博客!

加载中

文章导读

4.Agent – Plan & Execution


avatar
xiaoifei 2026年8月19日 9

参考资料
https://www.bilibili.com/video/BV1dw526tEMA
https://github.com/Wood-Q/MokioAgent

在处理较长的/复杂的任务时,上下文的拉长会影响模型注意力,导致遗忘任务的最终目的/遗漏任务的步骤
因此在模型进行思考前,需要指定计划与目标。

设计一个Plan节点就非常有必要了

DEFAULT_TASK = "请检查 inbox,把 a.txt 移动到 archive,然后告诉我整理后的目录变化。"
WORKSPACE = Path(__file__).resolve().parent / "demo_workspace"

# 定义全局状态流转的数据载体
class AgentState(TypedDict):
    task: str
    plan: list[str]
    messages: list[BaseMessage]
    reflection: str


def reset_workspace() -> None:

def show_workspace() -> str:

def workspace_path(path: str) -> Path:

@tool
def list_files(path: str = ".") -> str:

@tool
def move_file(source: str, target: str) -> str:

def load_llm() -> ChatOpenAI:

def parse_plan(text: str) -> list[str]:
    steps = []
    for line in text.splitlines():
        line = re.sub(r"^\s*[-*\d.、)]+\s*", "", line).strip()
        if line:
            steps.append(line)
    return steps or ["检查 inbox", "移动 a.txt 到 archive", "查看整理后的目录"]


PLANNER_PROMPT = """
把用户任务拆成 3 个步骤。
必须覆盖:检查 inbox、移动 a.txt 到 archive、查看整理后的目录。
每行一个步骤,不要写额外解释。
""".strip()

SYSTEM_PROMPT = """
你是一个 ReAct executor。
你会收到计划,请按计划用工具一步步完成任务。
每一轮最多调用一个工具。
如果有 reflection note,请优先参考它决定下一步。
""".strip()

REFLECTION_PROMPT = """
你是 reviewer。根据计划和最近工具结果,给 executor 一句下一步建议。
如果已经看到 archive/a.txt,请提醒 executor 停止调用工具并总结。
只输出一句 reflection note。
""".strip()


def main() -> None:
    task = " ".join(sys.argv[1:]).strip() or DEFAULT_TASK
    reset_workspace()

    print("=== 04. LangGraph Plan + ReAct + Reflection ===")
    print("\n用户任务:")
    print(task)
    print("\n运行前 workspace:")
    print(show_workspace())

    tools = [list_files, move_file]
    tool_map = {item.name: item for item in tools}
    base_llm = load_llm()
    tool_llm = base_llm.bind_tools(tools)

    def planner_node(state: AgentState) -> AgentState:
        print("\n[planner] 生成计划")
        response = base_llm.invoke(
            [SystemMessage(content=PLANNER_PROMPT), HumanMessage(content=state["task"])]
        )

        plan = parse_plan(str(response.content))

        #  输出步骤
        for index, step in enumerate(plan, start=1):
            print(f"{index}. {step}")

        plan_text = "\n".join(f"{index}. {step}" for index, step in enumerate(plan, start=1))

        return {
            **state,
            "plan": plan,
            "messages": [HumanMessage(content=f"用户任务:{state['task']}\n\n计划:\n{plan_text}")], # 将任务作为用户方信息发送
        }

    def agent_node(state: AgentState) -> AgentState:
        print("\n[agent] 按计划执行下一步")
        prompt = SYSTEM_PROMPT

        if state["reflection"]:
            prompt += f"\n\nReflection note: {state['reflection']}" # 每次将反馈上下文交给SYSTEM_PROMPT

        response = tool_llm.invoke([SystemMessage(content=prompt), *state["messages"]])
        return {**state, "messages": [*state["messages"], response]}

    def tools_node(state: AgentState) -> AgentState:
        response = state["messages"][-1]
        new_messages = list(state["messages"])

        for tool_call in response.tool_calls:
            print("\n[tools] 执行工具")
            print(f"tool_name = {tool_call['name']}")
            print(f"tool_args = {tool_call['args']}")
            result = tool_map[tool_call["name"]].invoke(tool_call["args"])
            print(result)
            new_messages.append(
                ToolMessage(
                    content=str(result),
                    name=tool_call["name"],
                    tool_call_id=tool_call["id"],
                )
            )

        return {**state, "messages": new_messages}

    def reflection_node(state: AgentState) -> AgentState:
        print("\n[reflection] 复盘计划和工具结果")
        plan_text = "\n".join(state["plan"])
        transcript = "\n".join(str(message.content) for message in state["messages"][-4:])
        note = base_llm.invoke(
            [
                SystemMessage(content=REFLECTION_PROMPT),
                HumanMessage(content=f"计划:\n{plan_text}\n\n最近记录:\n{transcript}"),
            ]
        ).content
        print(note)
        return {**state, "reflection": str(note)}

    def should_continue(state: AgentState) -> str:
        last_message = state["messages"][-1]
        return "tools" if getattr(last_message, "tool_calls", None) else END

    graph = StateGraph(AgentState)
    graph.add_node("planner", planner_node)
    graph.add_node("agent", agent_node)
    graph.add_node("tools", tools_node)
    graph.add_node("reflection", reflection_node)
    
    graph.add_edge(START, "planner")
    graph.add_edge("planner", "agent")
    graph.add_conditional_edges("agent", should_continue)
    graph.add_edge("tools", "reflection")
    graph.add_edge("reflection", "agent")

    result = graph.compile().invoke(
        {"task": task, "plan": [], "messages": [], "reflection": ""},
        config={"recursion_limit": 50},
    )

    print("\n最终回答:")
    print(result["messages"][-1].content)
    print("\n运行后 workspace:")
    print(show_workspace())


if __name__ == "__main__":
    main()



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码