基于langGraph设计一个智能可控的Agent

前言

在上篇文章中langchain系列之基于create_react_agent 创建一个Agent-CSDN博客,开发了一个基于商品下单支付的智能体,但是存在一个问题是,就是在支付和下单的时候,智能体直接去创建订单支付了,在下单支付的时候,并没有询问用户的意图,基于这个原因,现在用langGraph完善上文中的功能,加入询问用户意图的功能

示例代码

备注:下面用到的商品查询、订单创建、下单的工具就是langchain系列之基于create_react_agent 创建一个Agent-CSDN博客 这个里面的三个工具

1、导入库

import json
import time
import os
from dotenv import load_dotenv
from langchain_core.tools import tool
from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate
from langchain.agents import create_react_agent
from typing import TypedDict,Union,Annotated,List
from langchain_core.messages import BaseMessage
from langchain_core.agents import AgentAction,AgentFinish
import operator
from langchain_core.agents import AgentAction,AgentFinish
from langgraph.graph import StateGraph,END
from langgraph.checkpoint.memory import MemorySaver

2、定义State以及模型

#定义graph的输入
class AgentState(TypedDict):
    #定义用户的输入字符串
    input: str
    
    user_input: str
    
    #定义用户的历史会话信息
    chat_history: list[BaseMessage]
    #对代理的给定调用的结果,需要"None"作为有效类型,因为这就是它的开头
    agent_outcome: Union[AgentAction, AgentFinish, None]

    # 行动和相应意见清单
    # 在这里,我们用"operator.add"对此进行注释,以指示对的操作
    # 该状态应添加到现有值中(而不是覆盖它)
    intermediate_steps: Annotated[List[tuple[AgentAction, str]], operator.add]

# 工具列表
tools = [
    query_goods,
    create_order,
    order_pay
]

llm_ds = init_chat_model(
    "deepseek-chat",
    api_key = os.getenv("DEEPSEEK_API_KEY"),
    base_url = os.getenv("DEEPSEEK_URL"),
    model_provider = "deepseek"
)

3、定义智能体

def react_agent(data):
    print("***********************************************************react_agent***********************************************************")
    print("我是智能体数据:",data)
   
    # if ("agent_outcome" in data) and (isinstance(data["agent_outcome"], AgentFinish)):
    #     return {"agent_outcome": data["agent_outcome"]}

    react_prompt = ChatPromptTemplate.from_template("""
        Answer the following questions as best you can. You have access to the following tools:
        {tools}
        Use the following format:
        Question: the input question you must answer
        Thought: you should always think about what to do
        Action: the action to take, should be one of [{tool_names}]
        Action Input: the input to the action     
        Observation: the result of the action
        ... (this Thought/Action/Action Input/Observation can repeat N times)
        Thought: I now know the final answer
        Final Answer: the final answer to the original input question
        Begin!
        Question: {input}
        {agent_scratchpad}
                                                    
        注意:
        agent_outcome中的的log是英语文的话,所以需要将log中的英文翻译成中文
                                                    
    """
    )

    

    # 创建ReAct代理
    agent = create_react_agent(
        llm=llm_ds,
        tools=tools,
        prompt=react_prompt
        #handle_parsing_errors=True # 添加错误处理
    )
    # 传递完整的数据,包含intermediate_steps
    result = agent.invoke(data)

    return {"agent_outcome": result}

4、定义工具执行器

def execute_tools(data):
    agent_action = data["agent_outcome"]
    
    # 如果是AgentAction才执行工具
    if isinstance(agent_action, AgentAction):
        # 获取工具名称和输入
        tool_name = agent_action.tool
        tool_input = agent_action.tool_input
        
        # 对于create_order和order_pay工具,先询问用户
        if tool_name in ["create_order", "order_pay"]:
            agent_finish = handle_user_interaction(data, tool_name)
            if agent_finish:
                # 用户不同意,直接返回AgentFinish状态,这样should_continue会返回"end"
                # return {"agent_outcome": agent_finish, "intermediate_steps": [],"input":agent_finish.return_values["output"]}
                return {"input":agent_finish.return_values["output"],"intermediate_steps": []}
        
        # 找到对应的工具函数
        tool_func = next((t for t in tools if t.name == tool_name), None)
        
        if tool_func:
            # 执行工具函数
            try:
                tool_output = tool_func.invoke(tool_input)
                return {"intermediate_steps": [(agent_action, str(tool_output))]}
            except Exception as e:
                return {"intermediate_steps": [(agent_action, f"Error: {str(e)}")]}
        else:
            return {"intermediate_steps": [(agent_action, f"Tool {tool_name} not found")]}
    else:
        # 如果不是AgentAction,返回空列表
        return {"intermediate_steps": []}

5、定义条件边判断以及用户确认入口

# 定义下一步应该如何走的逻辑
def should_continue(data):
    # 如果代理结果是AgentFinish,则返回"end"字符串
    if isinstance(data["agent_outcome"], AgentFinish):
        action_flag = "end"
    else:
        action_flag = "continue"
    return action_flag


# 用于处理用户交互
def handle_user_interaction(state, action_type):
    print("***********************************************************handle_user_interaction***********************************************************")
    print("我的判断状态值:", state)
    order_log = state["agent_outcome"].log
    print("【购买信息】:", order_log)
    if action_type == "create_order":
        user_input = input("是否为您【创建订单】,输入'Y'则继续,输入'N'或其他则结束,并说明您的理由: ")
        if user_input.upper() == "Y":
            print("正在创建订单----------------------------------------")
            return None
        else:
            # 创建AgentFinish对象,结束流程
            return AgentFinish(
                return_values={"output": f"订单创建被用户取消,理由是: {user_input},流程结束"},
                log=""
            )
    elif action_type == "order_pay":
        user_input = input("订单已经创建完成,是否为您【进行支付】,输入'Y'则继续,输入'N'或其他则结束,并说明您的理由: ")
        if user_input.upper() == "Y":
            print("正在支付订单----------------------------------------")
            return None
        else:
            # 创建AgentFinish对象,结束流程
            return AgentFinish(
                return_values={"output": f"订单支付被用户取消,理由是: {user_input},流程结束"},
                log=""
            )
    return None

6、创建图谱

# 持久化信息
memory = MemorySaver()
# 定义图
def langgraph():
    # 定义图
    workflow = StateGraph(AgentState)
    # 添加节点
    workflow.add_node("agent", react_agent)
    workflow.add_node("action", execute_tools)
    # 定义入口节点
    workflow.set_entry_point("agent")
    # 增加条件边
    workflow.add_conditional_edges(
        # 定义开始节点,使用agent,即意味着从agent开始
        source="agent",
        # 传入函数,来判定执行下一个执行节点
        path=should_continue,
        # 最后我们传入一个映射。
        # key是字符串,value是其他节点。
        # END是一个特殊的节点,标记图形应该完成。
        # 我们将调用"should_continue",然后输出将与此映射中的键相匹配。
        # 根据它匹配的节点,然后将调用该节点。
        path_map={
            "continue":"action",
            "end":END,
        }
    )
    
    # 添加从action节点回到agent节点的边,形成循环
    workflow.add_edge("action", "agent")
    
    app = workflow.compile(checkpointer=memory)
    
    # print(app.get_graph().print_ascii())
    
    return app


thread_config = {"configurable": {"thread_id": "my_thread_id"}}

app = langgraph()
inputs = {
    "input": "我要买一部手机,我的预算是2000元,帮我推荐一款合适的手机,并进行下单支付", 
    "chat_history": [],
    "user_input": None
    # "intermediate_steps": [],
    # "agent_outcome": None,
}

# 移除直接调用,只通过print_result函数运行
# result = app.invoke(inputs, config=thread_config)
# print("最终结果:", result['agent_outcome'].return_values['output'])

def print_result(inputs):
    for msg in app.stream(inputs, thread_config, stream_mode="values"):
        stateSnapshot = app.get_state(thread_config)
        
        # if ("agent_outcome" in stateSnapshot.values) and (isinstance(stateSnapshot.values["agent_outcome"], AgentAction)):
        #     tool = stateSnapshot.values["agent_outcome"].tool
        #     if tool == "query_goods":
        #         print("正在查询商品信息=========================================")
            
        if ("agent_outcome" in stateSnapshot.values) and (isinstance(stateSnapshot.values["agent_outcome"], AgentFinish)):
            print("最终结果:", stateSnapshot.values['agent_outcome'].return_values['output'])
    
        

# 主程序入口
if __name__ == "__main__":
    # 用户可以选择运行主流程或测试
    # 取消注释下面的代码以运行主流程
    app = langgraph()
    inputs = {
       "input": "我要买一部手机,我的预算是2000元,帮我推荐一款合适的手机,并进行下单支付", 
       "chat_history": [],
       "user_input": None
    }

    print_result(inputs)

演示结果

1、完整的下单流程演示

进行下单确认

进行支付确认 

2、下单和支付拒绝操作

拒绝下单

拒绝支付

写在最后

上面是一个简单的可控的智能体功能,完成了基本的用户询问操作。里面可以继续添加其他的操作功能,例如支付的时候用户输入支付方式、订单创建以后,取消订单以及变成可是的web页面操作等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值