LangGraph官网学习之路——4.人工介入协助

https://langchain-ai.github.io/langgraph/tutorials/introduction/#part-4-human-in-the-loop

话说,AI不是任何时候的特别可靠的。人工智能技术出现以来,无法离开人工对信息,算法的干预。我们需要再AI智能体工作的过程中可控的调整和介入,那就要求langgraph这类框架具备人类交互相关的功能。

我们直接解析代码来的更清晰一点吧。LangGraph提供interrupt和Command两个接口来实现用户的交互。

  1. 实现这一功能的主要接口是interrupt函数。在节点内部调用interrupt会暂停执行,并让用户输入内容。我们先添加一个工具,在工具节点中调用。

from langgraph.types import Command, interrupt



@tool

def human_assistance(query: str) -> str:

    """Request assistance from a human."""

    human_response = interrupt({"query": query})

    return human_response["data"]

   

tools = [tool, human_assistance]

interrupt提供类似Python的input()功能,可以让用户在命令行中输入内容,humna_assistance工具被LLM调用的时候,LLM会把用户的问题转发到这里(query)。@tool装饰器告诉Graph这是一个工具,注意方法中的第一行,这是必填的docstring注释文本(也可以通过docstring参数传入human_assistance),LLM是根据这段文本来判断是否要调用这个工具,就是说每当用户对话中告诉AI,需要人类协助时,AI会调用这个工具,在命令行中请人类回答(通过interrupt方法)。

LangGraph需要持久层的记忆存储功能来支持人类用户的协助,能够依据用户反馈暂停和恢复执行。所以,memory还是配上:


memory = MemorySaver()



graph = graph_builder.compile(checkpointer=memory)

在对话聊天节点我们需要做点修改。AI对话返回的结果message,先看看返回的消息,如果返回的消息中,同时要用到两个工具(搜索和人类协助),则断言终止。这样做是为了防止恢复本节点运行时,又重复调用工具(interrupt设置时需要考虑到一些副作用)。


def chatbot(state: State):

    message = llm_with_tools.invoke(state["messages"])

    # Because we will be interrupting during tool execution,

    # we disable parallel tool calling to avoid repeating any

    # tool invocations when we resume.

    assert len(message.tool_calls) <= 1

    return {"messages": [message]}

现在,我们硬编码提供一个用户提问:


user_input = "I need some expert guidance for building an AI agent. Could you request assistance for me?"

config = {"configurable": {"thread_id": "1"}}



events = graph.stream(

    {"messages": [{"role": "user", "content": user_input}]},

    config,

    stream_mode="values",

)

for event in events:

    if "messages" in event:

        event["messages"][-1].pretty_print()

用户提出请AI帮我申请人工协助,这时,AI理解了用户的意思并查看工具箱里(tools)调用human_assistance工具。human_assistance会中断图的执行流(注意,不是中断整个应用程序)。输出的结果:


================================ Human Message =================================



I need some expert guidance for building an AI agent. Could you request assistance for me?

================================== Ai Message ==================================

Tool Calls:

  human_assistance (call_0_1ab00496-f5eb-45f1-a6a3-bb433d509704)

 Call ID: call_0_1ab00496-f5eb-45f1-a6a3-bb433d509704

  Args:

    query: I need expert guidance for building an AI agent. Could you provide assistance?



我输出的内容和官网输出的不一样,官网在调用工具之前,先回答你:


================================[1m Human Message [0m=================================



I need some expert guidance for building an AI agent. Could you request assistance for me?

==================================[1m Ai Message [0m==================================



[{'text': "Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]

Tool Calls:

  human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)

 Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW

  Args:

    query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?

我试了半天是不是哪里不对,后来想想,这应该是deepseek和openAI(官网使用openAI)的机制上的差异,这个也不是重点。那现在我们中断(interrupt)对话,我们现在再模拟一个人类的回答:


human_response = (

    "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent."

    " It's much more reliable and extensible than simple autonomous agents."

)

human_command = Command(resume={"data": human_response})



events = graph.stream(human_command, config, stream_mode="values")

for event in events:

    if "messages" in event:

        event["messages"][-1].pretty_print()



Cammand方法在graph中经常用于跟interrupt搭配使用,在graph的stream,invoke,ainvoke方法中作为参数,可以使得在图中的断点恢复执行,并带上返回值或者更新State。上述代码将一个拥有data属性的对象返回到graph图中,并从chatbot这个节点恢复。输出结果如下:


================================ Human Message =================================



I need some expert guidance for building an AI agent. Could you request assistance for me?

================================== Ai Message ==================================

Tool Calls:

  human_assistance (call_0_079ba1c8-a63b-4d6a-bc75-3821c73b9778)

 Call ID: call_0_079ba1c8-a63b-4d6a-bc75-3821c73b9778

  Args:

    query: I need some expert guidance for building an AI agent. Could you request assistance for me?

================================== Ai Message ==================================

Tool Calls:

  human_assistance (call_0_079ba1c8-a63b-4d6a-bc75-3821c73b9778)

 Call ID: call_0_079ba1c8-a63b-4d6a-bc75-3821c73b9778

  Args:

    query: I need some expert guidance for building an AI agent. Could you request assistance for me?

================================= Tool Message =================================

Name: human_assistance



We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.

================================== Ai Message ==================================

Tool Calls:

  tavily_search_results_json (call_0_8a717d8d-4d49-45b1-9752-7ad69118573f)

 Call ID: call_0_8a717d8d-4d49-45b1-9752-7ad69118573f

  Args:

    query: LangGraph AI agent

================================= Tool Message =================================

Name: tavily_search_results_json



[{"title": "AI Agents in LangGraph - DeepLearning.AI", "url": "https://www.deeplearning.ai/short-courses/ai-agents-in-langgraph/", "content": "AI Agents in LangGraph - DeepLearning.AI AI Agents in LangGraph AI Agents in LangGraph AI Agents in LangGraph Learn about LangGraph’s components and how they enable the development, debugging, and maintenance of AI agents. Learn directly from LangChain founder Harrison Chase and Tavily founder Rotem Weiss. In this course you will learn to build an agent from scratch using Python and an LLM, and then you will rebuild it using LangGraph, learning about  its components and how to combine them to build flow-based applications. If you have intermediate Python knowledge and want to learn how to create more controllable agents using the LangGraph open source framework, this course is for you. AI Agents in LangGraph", "score": 0.8773195}, {"title": "How to Build AI Agents with LangGraph: A Step-by-Step Guide", "url": "https://medium.com/@lorevanoudenhove/how-to-build-ai-agents-with-langgraph-a-step-by-step-guide-5d84d9c7e832", "content": "In this step, we’ll define how the AI agent manages its state (the ongoing context of the conversation) and ensure it responds appropriately to the user’s input and tool output. This involves creating a template for the conversation, specifying the tools that the assistant will use, and configuring how the AI agent will respond to user input and trigger different functions (like calculating solar savings). This step ensures that the AI assistant can access and trigger the tools as needed during the conversation, creating a seamless interaction between the user and the assistant. By following these steps, you have successfully created an AI assistant using LangGraph that can calculate solar panel energy savings based on user inputs.", "score": 0.84277284}]



模拟人类回答后,这里deepseek的行为跟openAI的又不一样,openAI会回复Graph相关的信息。deepseek发现还有个tavilysearch的工具,那干脆直接用tailysearch搜索引擎帮你查查什么是LangGraph。哈哈哈,一千个AI就有一千个哈姆雷特。

完整代码:


import getpass

import os



def _set_env(var: str):

    print(f"Checking if {var} is set...")

    if not os.environ.get(var):

        print(f"{var} is not set, prompting user for input.")

        os.environ[var] = getpass.getpass(f"{var}: ")

        print(f"{var} has been set.{os.environ.get(var)}")

    else:

        print(f"{var} is already set to: {os.environ[var]}")



_set_env("TAVILY_API_KEY")



from langchain_community.tools.tavily_search import TavilySearchResults



# tool.invoke("What's a 'node' in LangGraph?")



# 接下来就跟第一部分一样,创建LLM,创建图、节点、起终点

# 把上面的tavily变成一个节点塞到graph里面

from typing import Annotated



from typing_extensions import TypedDict



from langgraph.graph import StateGraph, START, END

from langgraph.graph.message import add_messages

from langchain_core.tools import tool

from IPython.display import Image, display

from langchain.schema import HumanMessage, AIMessage

from langgraph.prebuilt import ToolNode, tools_condition

from langgraph.types import Command, interrupt

from langchain_openai import ChatOpenAI

from langgraph.checkpoint.memory import MemorySaver



class State(TypedDict):

    messages: Annotated[list, add_messages]



graph_builder = StateGraph(State)



@tool

def human_assistance(query: str) -> str:

    """Request assistance from a human."""

    human_response = interrupt({query: query})

    return human_response["data"]



tool = TavilySearchResults(max_results=2)

tools = [tool, human_assistance]

llm = ChatOpenAI(

    max_retries=2,

    base_url="https://api.deepseek.com/v1",

    api_key="sk-xxxxxxxxxxxxxxxx",  # 替换为你的API密钥

    model="deepseek-chat"  # 根据实际模型名称修改

)

llm_with_tools = llm.bind_tools(tools)



def chatbot(state: State):

    message = llm_with_tools.invoke(state["messages"])

    # Because we will be interrupting during tool execution,

    # we disable parallel tool calling to avoid repeating any

    # tool invocations when we resume.

    assert len(message.tool_calls) <= 1

    # print("模型原始响应:", messages)  # 检查是否包含正确的tool_calls

    return {"messages": [message]}



graph_builder.add_node("chatbot", chatbot)



tool_node = ToolNode(tools=tools)

graph_builder.add_node("tools", tool_node)



graph_builder.add_conditional_edges(

    "chatbot",

    tools_condition,

)



graph_builder.add_edge("tools", "chatbot")

graph_builder.add_edge(START, "chatbot")



memory = MemorySaver()

graph = graph_builder.compile(checkpointer=memory)



# user_input = "How to play switch"

user_input = "I need some expert guidance for building an AI agent. Could you request assistance for me?"

config = {"configurable": {"thread_id": "1"}}



events = graph.stream(

    {"messages": [{"role": "user", "content": user_input}]},

    config,

    stream_mode="values",

)

for event in events:

    if "messages" in event:

        event["messages"][-1].pretty_print()



human_response = (

    "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent."

    " It's much more reliable and extensible than simple autonomous agents."

)

human_command = Command(resume={"data": human_response})



events = graph.stream(human_command, config, stream_mode="values")

for event in events:

    if "messages" in event:

        event["messages"][-1].pretty_print()



### LangGraph 的概念与特性 LangGraph 是一种扩展了 LangChain 功能的框架,专注于利用大语言模型(LLMs)来构建具有复杂逻辑的应用程序[^1]。它的设计目标是解决传统基于 DAG(有向无环图)的工作流所无法实现的功能需求,特别是在需要循环处理和状态管理的情况下。 #### 核心特点 LangGraph 提供的核心能力包括但不限于以下几个方面: - **循环支持**:不同于传统的 DAG 结构仅允许单次前向传递的任务调度方式,LangGraph 支持复杂的循环结构,从而能够适应更广泛的场景需求,例如对话系统的持续交互过程[^3]。 - **细粒度控制**:作为一款底层框架,开发者可以精确地定义并调整应用内的每一个环节及其运行条件,这种灵活性对于确保代理行为的一致性和可靠性尤为重要。 - **持久化机制**:内置的记忆存储方案让长期会话管理和人工介入变得可行,进一步增强了用户体验的同时也简化了维护成本。 此外,借助可视化调试平台——LangGraph Studio,用户能够在图形界面下轻松完成原型搭建、参数调节乃至错误排查等一系列操作,极大地降低了技术门槛并提高了工作效率[^2]。 ### 在 LLM 应用开发中的角色定位 当谈及到如何促进大型预训练模型的实际落地时,LangGraph 显得尤为突出。它不仅继承了来自 LangChain 的诸多优秀特质,还针对特定领域进行了针对性优化改进,使之更适合承担起诸如聊天机器人定制化服务提供者这样的重任。 具体而言,在以下几类典型项目里可以看到 LangGraph 发挥重要作用的身影: - 多轮对话管理系统; - 自动问答引擎建设; - 游戏NPC智能化改造工程等等。 这些案例均依赖于强大的后台算法支撑才能达成预期效果,而 LangGraph 正好满足这一系列苛刻的要求组合在一起形成的整体解决方案包。 ```python from langgraph import Graph, Node # 创建一个简单的节点实例 node_example = Node( id="example_node", function=lambda input_data: f"Processed {input_data}", ) # 初始化图表对象并将上述节点加入其中 graph_instance = Graph() graph_instance.add_node(node_example) ``` 以上代码片段展示了如何使用 Python 来初始化 LangGraph 中的基本组件之一 —— 节点 (Node),并通过将其添加至更大的网络结构(Graph)当中去初步建立起整个系统的基础骨架雏形。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值