使用百炼大模型:LangGraph快速构建Agent工作流应用

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

使用百炼大模型:LangGraph快速构建Agent工作流应用

1、工作流

在这里插入图片描述

2、完整执行流程示意

输入问题
   ↓
[planner] → 输出计划 → event 循环捕获 → 打印日志
   ↓
[agent] → 执行搜索 → event 循环捕获 → 打印日志
   ↓
[replan] → 判断是否完成 → event 循环捕获 → 打印日志
   ↓
[agent](如果需要继续)... 循环直到完成
   ↓
[__end__] → 跳过,退出循环

3、代码

# 导入 tavily 搜索 api 库
from langchain_tavily import TavilySearch
from dotenv import load_dotenv
import os
from pydantic import BaseModel, Field
from typing import Annotated, List, Tuple, TypedDict, Optional
from typing import Literal

# 加载.env 文件中的环境变量
env_path = os.path.join(os.path.dirname(__file__), '..', '.env')
load_dotenv(env_path)

# 创建 TavilySearchResults 工具,设置最大结果数为 1
tools = [TavilySearch(max_results=1)]

# 导入 ChatOpenAI 类和必要的库
from langchain_openai import ChatOpenAI
import asyncio
from langchain.agents import create_agent

# 使用阿里百炼 API
llm = ChatOpenAI(
    model=os.getenv("DASHSCOPE_MODEL", "qwen3.5-plus"),
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    temperature=0.0
)

# 创建一个 REACT 代理执行器,使用指定的 LLM 和工具
agent_executor = create_agent(llm, tools)

import operator


# 定义状态类
class PlanExecute(TypedDict):
    input: str
    plan: List[str]
    past_steps: Annotated[List[Tuple], operator.add]
    response: str


# 定义计划模型
class Plan(BaseModel):
    """任务分解计划"""
    steps: List[str] = Field(description="需要执行的步骤列表,按顺序排列")


# 定义最终答案模型
class FinalAnswer(BaseModel):
    """最终答案"""
    answer: str = Field(description="整合所有信息后的完整答案")


from langchain_core.prompts import ChatPromptTemplate

# 计划生成 prompt
planner_prompt = ChatPromptTemplate.from_template(
    """请将以下问题分解为多个独立的搜索步骤。每个步骤应该获取一个具体信息,所有步骤完成后能得出完整答案。

问题:{input}

请只返回 JSON 格式:{{"steps": ["步骤 1", "步骤 2", ...]}}"""
)

planner = planner_prompt | llm.with_structured_output(Plan)


# 定义行为模型 - 简化为直接判断是否完成
class ReplanAction(BaseModel):
    """重新规划动作"""
    is_complete: bool = Field(description="是否已完成所有必要搜索,可以给出最终答案")
    next_step: Optional[str] = Field(default=None, description="如果未完成,下一个要执行的步骤")
    final_answer: Optional[str] = Field(default=None, description="如果已完成,最终答案是什么")


# 重新计划 prompt
replanner_prompt = ChatPromptTemplate.from_template(
    """基于以下信息判断是否需要继续搜索:

原始问题:{input}
已完成步骤:{past_steps}

请评估:
1. 是否已有足够信息回答原始问题?
2. 如果需要更多信息,下一步应该搜索什么?
3. 如果信息已足够,请直接给出完整答案。

请只返回 JSON 格式:
- 如果未完成:{{"is_complete": false, "next_step": "下一步要搜索的内容"}}
- 如果已完成:{{"is_complete": true, "final_answer": "整合所有信息的完整答案"}}"""
)

replanner = replanner_prompt | llm.with_structured_output(ReplanAction)


# 异步主函数
async def main():
    # 计划步骤
    async def plan_step(state: PlanExecute):
        try:
            plan = await planner.ainvoke({"input": state["input"]})
            print(f"\n=== 任务分解 ===\n共 {len(plan.steps)} 个步骤:")
            for i, step in enumerate(plan.steps, 1):
                print(f"{i}. {step}")
            return {"plan": list(plan.steps)}
        except Exception as e:
            print(f"计划生成失败:{e}")
            return {"plan": [f"搜索并回答:{state['input']}"]}

    # 执行步骤
    async def execute_step(state: PlanExecute):
        if not state["plan"]:
            return {"past_steps": state["past_steps"]}

        plan = state["plan"]
        plan_str = "\n".join(f"{i + 1}. {step}" for i, step in enumerate(plan))
        task = plan[0]
        task_formatted = f"""当前总任务:{state["input"]}
                            待执行计划:
                            {plan_str}
                            请执行第 1 步:{task}
                            提供准确、详细的信息。"""

        print(f"\n=== 执行步骤 ===\n正在搜索:{task}")
        agent_response = await agent_executor.ainvoke(
            {"messages": [("user", task_formatted)]}
        )
        result = agent_response["messages"][-1].content
        print(f"搜索结果:{result[:200]}...")

        return {
            "past_steps": state["past_steps"] + [(task, result)],
        }

    # 重新计划步骤
    async def replan_step(state: PlanExecute):
        try:
            output = await replanner.ainvoke({
                "input": state["input"],
                "past_steps": state["past_steps"]
            })

            if output.is_complete and output.final_answer:
                print(f"\n=== 整合答案 ===\n{output.final_answer}")
                return {"response": output.final_answer}
            elif not output.is_complete and output.next_step:
                # 还有未完成的步骤,继续执行
                remaining_plan = state["plan"][1:] if len(state["plan"]) > 1 else [output.next_step]
                print(f"\n=== 进度更新 ===\n下一步:{output.next_step}")
                return {"plan": remaining_plan}
            else:
                # 降级策略
                if state.get("past_steps"):
                    last_result = state["past_steps"][-1][1]
                    return {"response": f"基于搜索结果:{last_result}"}
                else:
                    return {"plan": [f"继续搜索:{state['input']}"]}

        except Exception as e:
            print(f"重新计划失败:{e}")
            if state.get("past_steps"):
                last_result = state["past_steps"][-1][1]
                return {"response": f"基于已有信息:{last_result}"}
            else:
                return {"plan": [f"重新尝试:{state['input']}"]}

    # 判断是否结束
    def should_end(state: PlanExecute) -> Literal["agent", "__end__"]:
        if "response" in state and state["response"]:
            return "__end__"
        else:
            return "agent"

    from langgraph.graph import StateGraph, START, END

    # 创建工作流
    workflow = StateGraph(PlanExecute)

    # 添加节点
    workflow.add_node("planner", plan_step)
    workflow.add_node("agent", execute_step)
    workflow.add_node("replan", replan_step)

    # 添加边
    workflow.add_edge(START, "planner")
    workflow.add_edge("planner", "agent")
    workflow.add_edge("agent", "replan")

    # 添加条件边
    workflow.add_conditional_edges(
        "replan",
        should_end,
        {
            "__end__": END,
            "agent": "agent"
        }
    )

    # 编译
    app = workflow.compile()

    # 生成流程图
    graph_png = app.get_graph().draw_mermaid_png()
    with open("agent_workflow.png", "wb") as f:
        f.write(graph_png)

    # 执行
    config = {"recursion_limit": 50}
    inputs = {"input": "2024 年巴黎奥运会男子 100 米自由泳决赛冠军的家乡是哪里?请用中文答复"}

    print("=" * 60)
    print(f"开始处理问题:{inputs['input']}")
    print("=" * 60)

    async for event in app.astream(inputs, config=config):
        for k, v in event.items():
            if k != "__end__":
                print(f"\n[{k.upper()}] 输出:")
                print(v)

    print("\n" + "=" * 60)
    print("处理完成!")
    print("=" * 60)


# 运行
if __name__ == "__main__":
    asyncio.run(main())

4、结果展示

============================================================
开始处理问题:2024 年巴黎奥运会男子 100 米自由泳决赛冠军的家乡是哪里?请用中文答复
============================================================

=== 任务分解 ===2 个步骤:
1. 搜索 2024 年巴黎奥运会男子 100 米自由泳决赛冠军的姓名
2. 搜索该冠军的家乡或出生地信息

[PLANNER] 输出:
{'plan': ['搜索 2024 年巴黎奥运会男子 100 米自由泳决赛冠军的姓名', '搜索该冠军的家乡或出生地信息']}

=== 执行步骤 ===
正在搜索:搜索 2024 年巴黎奥运会男子 100 米自由泳决赛冠军的姓名
搜索结果:2024 年巴黎奥运会男子 100 米自由泳决赛的冠军是**潘展乐**。

他的家乡是**中国浙江省温州市**(具体祖籍为温州市永嘉县桥下镇,出生于温州市区)。

在 2024 年巴黎奥运会上,潘展乐以 4640 的成绩打破世界纪录并夺得金牌,成为中国首位在该项目上获得奥运冠军的运动员。...

[AGENT] 输出:
{'past_steps': [('搜索 2024 年巴黎奥运会男子 100 米自由泳决赛冠军的姓名', '2024 年巴黎奥运会男子 100 米自由泳决赛的冠军是**潘展乐**。\n\n他的家乡是**中国浙江省温州市**(具体祖籍为温州市永嘉县桥下镇,出生于温州市区)。\n\n在 2024 年巴黎奥运会上,潘展乐以 46 秒 40 的成绩打破世界纪录并夺得金牌,成为中国首位在该项目上获得奥运冠军的运动员。')]}

=== 整合答案 ===
2024 年巴黎奥运会男子 100 米自由泳决赛冠军是潘展乐,他的家乡是中国浙江省温州市。

[REPLAN] 输出:
{'response': '2024 年巴黎奥运会男子 100 米自由泳决赛冠军是潘展乐,他的家乡是中国浙江省温州市。'}

============================================================
处理完成!
============================================================

Process finished with exit code 0

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值