ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

(LangGraph教程)3. UX and Human-in-the-Loop-——Lesson 2:Breakpoints断点(未索引)

(LangGraph教程)3. UX and Human-in-the-Loop-——Lesson 2:Breakpoints断点(未索引) https://academy.langchain.com/courses/intro-to-langgraphhttps://github.com/shangxiang0907/langchain-academy文章目录Breakpoints 断点Review 回顾Goals 目标Breakpoints for human approval 用于人工审批的断点Breakpoints with LangGraph API 使用 LangGraph API 的断点Breakpoints 断点Review 回顾Forhuman-in-the-loop, we often want to see our graph outputs as its running.对于human-in-the-loop人在回路中我们通常希望在图运行时实时查看其输出。We laid the foundations for this with streaming.我们已通过流式传输streaming为此奠定了基础。Goals 目标Now, let’s talk about the motivations forhuman-in-the-loop:现在让我们探讨human-in-the-loop的动机(1)Approval- We can interrupt our agent, surface state to a user, and allow the user to accept an action1审批Approval——我们可以中断代理执行将当前状态呈现给用户并允许用户批准某项操作(2)Debugging- We can rewind the graph to reproduce or avoid issues2调试Debugging——我们可以将图倒回到某一状态以复现或规避问题(3)Editing- You can modify the state3编辑Editing——您可以修改状态LangGraph offers several ways to get or update agent state to support varioushuman-in-the-loopworkflows.LangGraph 提供了多种方式来获取或更新代理状态以支持各类human-in-the-loop工作流。First, we’ll introduce breakpoints, which provide a simple way to stop the graph at specific steps.首先我们将介绍 断点breakpoints它提供了一种在特定步骤处暂停图执行的简便方法。We’ll show how this enables userapproval.我们将展示该机制如何实现用户审批。%%capture--no-stderr%pip install--quiet-U langgraph langchain_openai langgraph_sdk langgraph-prebuiltimportos,getpassdef_set_env(var:str):ifnotos.environ.get(var):os.environ[var]getpass.getpass(f{var}: )fromdotenvimportfind_dotenv,load_dotenv load_dotenv(find_dotenv(usecwdTrue))_set_env(OPENAI_API_KEY)Breakpoints for human approval 用于人工审批的断点Let’s re-consider the simple agent that we worked with in Module 1.让我们重新审视模块 1 中使用过的简单代理。Let’s assume that are concerned about tool use: we want to approve the agent to use any of its tools.假设我们对工具调用有所顾虑我们希望在代理调用任何工具前获得人工审批。All we need to do is simply compile the graph withinterrupt_before[tools]wheretoolsis our tools node.我们只需在编译图时指定interrupt_before[tools]即可其中tools是我们的工具节点。This means that the execution will be interrupted before the nodetools, which executes the tool call.这意味着执行将在节点tools即执行工具调用的节点之前被中断。importosfromlangchain_openaiimportChatOpenAIdefmultiply(a:int,b:int)-int:Multiply a and b. Args: a: first int b: second int returna*b# This will be a tooldefadd(a:int,b:int)-int:Adds a and b. Args: a: first int b: second int returnabdefdivide(a:int,b:int)-float:Divide a by b. Args: a: first int b: second int returna/b tools[add,multiply,divide]llmChatOpenAI(modelos.getenv(OPENAI_MODEL,qwen-plus),base_urlos.getenv(OPENAI_BASE_URL,https://dashscope.aliyuncs.com/compatible-mode/v1))llm_with_toolsllm.bind_tools(tools)fromIPython.displayimportImage,displayfromlanggraph.checkpoint.memoryimportMemorySaverfromlanggraph.graphimportMessagesStatefromlanggraph.graphimportSTART,StateGraphfromlanggraph.prebuiltimporttools_condition,ToolNodefromlangchain_core.messagesimportAIMessage,HumanMessage,SystemMessage# System messagesys_msgSystemMessage(contentYou are a helpful assistant tasked with performing arithmetic on a set of inputs.)# Nodedefassistant(state:MessagesState):return{messages:[llm_with_tools.invoke([sys_msg]state[messages])]}# GraphbuilderStateGraph(MessagesState)# Define nodes: these do the workbuilder.add_node(assistant,assistant)builder.add_node(tools,ToolNode(tools))# Define edges: these determine the control flowbuilder.add_edge(START,assistant)builder.add_conditional_edges(assistant,# If the latest message (result) from assistant is a tool call - tools_condition routes to tools# If the latest message (result) from assistant is a not a tool call - tools_condition routes to ENDtools_condition,)builder.add_edge(tools,assistant)memoryMemorySaver()graphbuilder.compile(interrupt_before[tools],checkpointermemory)# Showdisplay(Image(graph.get_graph(xrayTrue).draw_mermaid_png()))# Inputinitial_input{messages:HumanMessage(contentMultiply 2 and 3)}# Threadthread{configurable:{thread_id:1}}# Run the graph until the first interruptionforeventingraph.stream(initial_input,thread,stream_modevalues):event[messages][-1].pretty_print()[1m Human Message [0m Multiply 2 and 3 [1m Ai Message [0m Tool Calls: multiply (call_oFkGpnO8CuwW9A1rk49nqBpY) Call ID: call_oFkGpnO8CuwW9A1rk49nqBpY Args: a: 2 b: 3We can get the state and look at the next node to call.我们可以获取当前状态并查看下一个待调用的节点。This is a nice way to see that the graph has been interrupted.这是一种直观地确认图已被中断的好方法。stategraph.get_state(thread)state.next(tools,)Now, we’ll introduce a nice trick.现在我们将介绍一个实用技巧。When we invoke the graph withNone, it will just continue from the last state checkpoint!当我们以None作为输入调用图时它将直接从上一个状态检查点继续执行For clarity, LangGraph will re-emit the current state, which contains theAIMessagewith tool call.为清晰起见LangGraph 将重新发出当前状态该状态包含带有工具调用的AIMessage。And then it will proceed to execute the following steps in the graph, which start with the tool node.随后它将继续执行图中的后续步骤这些步骤以工具节点为起点。We see that the tool node is run with this tool call, and it’s passed back to the chat model for our final answer.我们看到工具节点使用该工具调用执行并将结果传回聊天模型以生成最终答案。foreventingraph.stream(None,thread,stream_modevalues):event[messages][-1].pretty_print()[1m Ai Message [0m Tool Calls: multiply (call_oFkGpnO8CuwW9A1rk49nqBpY) Call ID: call_oFkGpnO8CuwW9A1rk49nqBpY Args: a: 2 b: 3 [1m Tool Message [0m Name: multiply 6 [1m Ai Message [0m The result of multiplying 2 and 3 is 6.Now, lets bring these together with a specific user approval step that accepts user input.现在让我们将上述内容整合起来加入一个接受用户输入的具体人工审批步骤。# Inputinitial_input{messages:HumanMessage(contentMultiply 2 and 3)}# Threadthread{configurable:{thread_id:2}}# Run the graph until the first interruptionforeventingraph.stream(initial_input,thread,stream_modevalues):event[messages][-1].pretty_print()# Get user feedbackuser_approvalinput(Do you want to call the tool? (yes/no): )# Check approvalifuser_approval.lower()yes:# If approved, continue the graph executionforeventingraph.stream(None,thread,stream_modevalues):event[messages][-1].pretty_print()else:print(Operation cancelled by user.)[1m Human Message [0m Multiply 2 and 3 [1m Ai Message [0m Tool Calls: multiply (call_tpHvTmsHSjSpYnymzdx553SU) Call ID: call_tpHvTmsHSjSpYnymzdx553SU Args: a: 2 b: 3 [1m Ai Message [0m Tool Calls: multiply (call_tpHvTmsHSjSpYnymzdx553SU) Call ID: call_tpHvTmsHSjSpYnymzdx553SU Args: a: 2 b: 3 [1m Tool Message [0m Name: multiply 6 [1m Ai Message [0m The result of multiplying 2 and 3 is 6.Breakpoints with LangGraph API 使用 LangGraph API 的断点⚠️ Notice⚠️ 注意Since filming these videos, we’ve updated Studio so that it can now be run locally and accessed through your browser.自录制本视频以来我们已更新 Studio使其现在可本地运行并通过浏览器访问。This is the preferred way to run Studio instead of using the Desktop App shown in the video.这是运行 Studio 的首选方式而非视频中演示的桌面应用。It is now calledLangSmith Studioinstead ofLangGraph Studio.它现在被称为LangSmith Studio而非LangGraph Studio。Detailed setup instructions are available in the “Getting Setup” guide at the start of the course.详细的安装说明请参阅本课程开头的“环境准备Getting Setup”指南。You can find a description of Studio here, and specific details for local deployment here.您可在此处查阅 Studio 的说明文档 此处以及本地部署的具体细节 此处。To start the local development server, run the following command in your terminal in the/studiodirectory in this module:要在本地启动开发服务器请在本模块的/studio目录下于终端中运行以下命令langgraph devYou should see the following output:您应看到如下输出- API: http://127.0.0.1:2024 - Studio UI: https://smith.langchain.com/studio/?baseUrlhttp://127.0.0.1:2024 - API Docs: http://127.0.0.1:2024/docsOpen your browser and navigate to theStudio UIURL shown above.打开您的浏览器并导航至上方显示的Studio UIURL。The LangGraph API supports breakpoints.LangGraph API 支持断点。ifgoogle.colabinstr(get_ipython()):raiseException(Unfortunately LangGraph Studio is currently not supported on Google Colab)# This is the URL of the local development serverfromlanggraph_sdkimportget_client clientget_client(urlhttp://127.0.0.1:2024)As shown above, we can addinterrupt_before[node]when compiling the graph that is running in Studio.如上所示我们可在 Studio 中运行的图进行编译时添加interrupt_before[node]。However, with the API, you can also passinterrupt_beforeto the stream method directly.但借助 API您也可以直接将interrupt_before参数传递给stream方法。initial_input{messages:HumanMessage(contentMultiply 2 and 3)}threadawaitclient.threads.create()asyncforchunkinclient.runs.stream(thread[thread_id],assistant_idagent,inputinitial_input,stream_modevalues,interrupt_before[tools],):print(fReceiving new event of type:{chunk.event}...)messageschunk.data.get(messages,[])ifmessages:print(messages[-1])print(-*50)Receiving new event of type: metadata... -------------------------------------------------- Receiving new event of type: values... {content: Multiply 2 and 3, additional_kwargs: {}, response_metadata: {}, type: human, name: None, id: 2a3b1e7a-f6d9-44c2-a4b4-b7f67aa3691c, example: False} -------------------------------------------------- Receiving new event of type: values... {content: , additional_kwargs: {tool_calls: [{id: call_ElnkVOf1H80dlwZLqO0PQTwS, function: {arguments: {a:2,b:3}, name: multiply}, type: function}], refusal: None}, response_metadata: {token_usage: {completion_tokens: 18, prompt_tokens: 134, total_tokens: 152, completion_tokens_details: {accepted_prediction_tokens: 0, audio_tokens: 0, reasoning_tokens: 0, rejected_prediction_tokens: 0}, prompt_tokens_details: {audio_tokens: 0, cached_tokens: 0}}, model_name: gpt-4o-2024-08-06, system_fingerprint: fp_eb9dce56a8, finish_reason: tool_calls, logprobs: None}, type: ai, name: None, id: run-89ee14dc-5f46-4dd9-91d9-e922c4a23572-0, example: False, tool_calls: [{name: multiply, args: {a: 2, b: 3}, id: call_ElnkVOf1H80dlwZLqO0PQTwS, type: tool_call}], invalid_tool_calls: [], usage_metadata: {input_tokens: 134, output_tokens: 18, total_tokens: 152, input_token_details: {audio: 0, cache_read: 0}, output_token_details: {audio: 0, reasoning: 0}}} --------------------------------------------------Now, we can proceed from the breakpoint just like we did before by passing thethread_idandNoneas the input!现在我们可以通过传入thread_id和None作为输入像之前一样从断点处继续执行asyncforchunkinclient.runs.stream(thread[thread_id],agent,inputNone,stream_modevalues,interrupt_before[tools],):print(fReceiving new event of type:{chunk.event}...)messageschunk.data.get(messages,[])ifmessages:print(messages[-1])print(-*50)Receiving new event of type: metadata... -------------------------------------------------- Receiving new event of type: values... {content: , additional_kwargs: {tool_calls: [{id: call_ElnkVOf1H80dlwZLqO0PQTwS, function: {arguments: {a:2,b:3}, name: multiply}, type: function}], refusal: None}, response_metadata: {token_usage: {completion_tokens: 18, prompt_tokens: 134, total_tokens: 152, completion_tokens_details: {accepted_prediction_tokens: 0, audio_tokens: 0, reasoning_tokens: 0, rejected_prediction_tokens: 0}, prompt_tokens_details: {audio_tokens: 0, cached_tokens: 0}}, model_name: gpt-4o-2024-08-06, system_fingerprint: fp_eb9dce56a8, finish_reason: tool_calls, logprobs: None}, type: ai, name: None, id: run-89ee14dc-5f46-4dd9-91d9-e922c4a23572-0, example: False, tool_calls: [{name: multiply, args: {a: 2, b: 3}, id: call_ElnkVOf1H80dlwZLqO0PQTwS, type: tool_call}], invalid_tool_calls: [], usage_metadata: {input_tokens: 134, output_tokens: 18, total_tokens: 152, input_token_details: {audio: 0, cache_read: 0}, output_token_details: {audio: 0, reasoning: 0}}} -------------------------------------------------- Receiving new event of type: values... {content: 6, additional_kwargs: {}, response_metadata: {}, type: tool, name: multiply, id: 5331919f-a26b-4d75-bf33-6dfaea2be1f7, tool_call_id: call_ElnkVOf1H80dlwZLqO0PQTwS, artifact: None, status: success} -------------------------------------------------- Receiving new event of type: values... {content: The result of multiplying 2 and 3 is 6., additional_kwargs: {refusal: None}, response_metadata: {token_usage: {completion_tokens: 15, prompt_tokens: 159, total_tokens: 174, completion_tokens_details: {accepted_prediction_tokens: 0, audio_tokens: 0, reasoning_tokens: 0, rejected_prediction_tokens: 0}, prompt_tokens_details: {audio_tokens: 0, cached_tokens: 0}}, model_name: gpt-4o-2024-08-06, system_fingerprint: fp_eb9dce56a8, finish_reason: stop, logprobs: None}, type: ai, name: None, id: run-06b901ad-0760-4986-9d3f-a566e0d52efd-0, example: False, tool_calls: [], invalid_tool_calls: [], usage_metadata: {input_tokens: 159, output_tokens: 15, total_tokens: 174, input_token_details: {audio: 0, cache_read: 0}, output_token_details: {audio: 0, reasoning: 0}}} --------------------------------------------------
返回列表