LangChain 79 LangGraph 从入门到精通一

LangChain系列文章

  1. LangChain 60 深入理解LangChain 表达式语言23 multiple chains链透传参数 LangChain Expression Language (LCEL)
  2. LangChain 61 深入理解LangChain 表达式语言24 multiple chains链透传参数 LangChain Expression Language (LCEL)
  3. LangChain 62 深入理解LangChain 表达式语言25 agents代理 LangChain Expression Language (LCEL)
  4. LangChain 63 深入理解LangChain 表达式语言26 生成代码code并执行 LangChain Expression Language (LCEL)
  5. LangChain 64 深入理解LangChain 表达式语言27 添加审查 Moderation LangChain Expression Language (LCEL)
  6. LangChain 65 深入理解LangChain 表达式语言28 余弦相似度Router Moderation LangChain Expression Language (LCEL)
  7. LangChain 66 深入理解LangChain 表达式语言29 管理prompt提示窗口大小 LangChain Expression Language (LCEL)
  8. LangChain 67 深入理解LangChain 表达式语言30 调用tools搜索引擎 LangChain Expression Language (LCEL)
  9. LangChain 68 LLM Deployment大语言模型部署方案
  10. LangChain 69 向量数据库Pinecone入门
  11. LangChain 70 Evaluation 评估、衡量在多样化数据上的性能和完整性
  12. LangChain 71 字符串评估器String Evaluation衡量在多样化数据上的性能和完整性
  13. LangChain 72 reference改变结果 字符串评估器String Evaluation
  14. LangChain 73 给结果和参考评分 Scoring Evaluator
  15. LangChain 74 有用的或者有害的helpful or harmful Scoring Evaluator
  16. LangChain 75 打造你自己的OpenAI + LangChain网页应用
  17. LangChain 76 LangSmith 从入门到精通一
  18. LangChain 77 LangSmith 从入门到精通二
  19. LangChain 78 LangSmith 从入门到精通三

在这里插入图片描述

1. LangGraph

LangGraph是一个用于构建具有LLMs的有状态多角色应用程序的库,建立在LangChain之上(并打算与之一起使用)。它通过扩展LangChain表达语言,使其能够以循环方式协调多个链(或者角色)在计算的多个步骤之间。它的灵感来自Pregel和Apache Beam。当前提供的接口受NetworkX的启发。

主要用途是为您的LLM应用程序添加循环。关键是,这不是一个DAG框架。如果您想要构建DAG,您应该只使用LangChain表达语言。

循环对于类似Agent-like代理的行为非常重要,您在循环中调用LLM,询问它下一步应该采取什么行动。

安装 LangGraph

pip install langgraph

2. 快速开始

在这里,我们将介绍一个创建简单代理的示例,该代理使用聊天模型和函数调用。这个代理将把所有状态表示为消息列表。

我们需要安装一些LangChain软件包,以及Tavily作为示例工具。

pip install -U langchain langchain_openai tavily-python

我们还需要导出一些我们代理程序所需的环境变量。

export OPENAI_API_KEY=sk-...
export TAVILY_API_KEY=tvly-...

我们可以选择性地为最佳可观察性设置LangSmith。

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY=ls__...

3. 设置工具

我们首先要定义我们想要使用的工具。对于这个简单的例子,我们将使用Tavily内置的搜索工具。然而,创建自己的工具非常容易 - 可以查看这里的文档来了解如何操作。

from langchain_community.tools.tavily_search import TavilySearchResults

tools = [TavilySearchResults(max_results=1)]

现在我们可以将这些工具封装在一个简单的ToolExecutor中。这是一个非常简单的类,它接收一个ToolInvocation并调用该工具,返回输出。ToolInvocation是任何具有tooltool_input属性的类。

from langgraph.prebuilt import ToolExecutor

tool_executor = ToolExecutor(tools)

4. 建立模型

现在我们需要加载我们想要使用的聊天模型。重要的是,这应该满足两个标准:

  1. 它应该能够处理消息。我们将以消息的形式表示所有代理状态,因此它需要能够很好地处理它们。
  2. 它应该能够与OpenAI函数调用一起使用。这意味着它应该是一个OpenAI模型或者是一个暴露类似接口的模型。

注意:这些模型要求不是使用LangGraph的要求 - 它们只是这个例子的要求。

from langchain_openai import ChatOpenAI

# We will set streaming=True so that we can stream tokens
# See the streaming section for more information on this.
model = ChatOpenAI(temperature=0, streaming=True)

5. 定义代理agent状态

Langgraph中的主要图形类型是StatefulGraph。该图形是由一个状态对象参数化的,它将该对象传递给每个节点。然后,每个节点返回操作以更新该状态。这些操作可以是在状态上设置特定属性(例如,覆盖现有值)或者添加到现有属性。是设置还是添加由您构建图形时注释的状态对象来表示。

对于此示例,我们要跟踪的状态只是一个消息列表。我们希望每个节点只是向该列表添加消息。因此,我们将使用一个TypedDict,其中只有一个key(messages),并对其进行注释,以便messages属性始终被添加到其中。

from typing import TypedDict, Annotated, Sequence
import operator
from langchain_core.messages import BaseMessage


class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]

6. 定义节点nodes

我们现在需要在我们的图中定义一些不同的节点。在langgraph中,一个节点可以是一个函数或runnable 接口。对于这个我们需要两个主要的节点:

  1. Agent 代理:负责决定要采取什么(如果有的话)行动。
  2. 调用工具的函数:如果代理决定采取行动,那么这个节点将执行该行动。

我们还需要定义一些边。其中一些边可能是有条件的。它们有条件的原因是根据节点的输出,可能会采取几条路径中的一条。采取的路径在运行该节点之前是未知的(LLM决定)。

  1. Conditional Edge 有条件边:代理被调用后,我们应该要么:a. 如果代理说要采取行动,那么应该调用调用工具的函数 b. 如果代理说它已经完成了,那么它应该完成
  2. Normal Edge 正常边:在调用工具后,它应该总是回到代理那里决定下一步要做什么

让我们定义这些节点,以及一个决定采取什么条件边的函数。

from langgraph.prebuilt import ToolInvocation
import json
from langchain_core.messages import FunctionMessage

# Define the function that determines whether to continue or not
def should_continue(state):
    messages = state['messages']
    last_message = messages[-1]
    # If there is no function call, then we finish
    if "function_call" not in last_message.additional_kwargs:
        return "end"
    # Otherwise if there is, we continue
    else:
        return "continue"

# Define the function that calls the model
def call_model(state):
    messages = state['messages']
    response = model.invoke(messages)
    # We return a list, because this will get added to the existing list
    return {"messages": [response]}

# Define the function to execute tools
def call_tool(state):
    messages = state['messages']
    # Based on the continue condition
    # we know the last message involves a function call
    last_message = messages[-1]
    # We construct an ToolInvocation from the function_call
    action = ToolInvocation(
        tool=last_message.additional_kwargs["function_call"]["name"],
        tool_input=json.loads(last_message.additional_kwargs["function_call"]["arguments"]),
    )
    # We call the tool_executor and get back a response
    response = tool_executor.invoke(action)
    # We use the response to create a FunctionMessage
    function_message = FunctionMessage(content=str(response), name=action.tool)
    # We return a list, because this will get added to the existing list
    return {"messages": [function_message]}

7. 定义图表 State graph

现在我们可以把所有内容放在一起,定义图表了!

from langgraph.graph import StateGraph, END
# Define a new graph
workflow = StateGraph(AgentState)

# Define the two nodes we will cycle between
workflow.add_node("agent", call_model)
workflow.add_node("action", call_tool)

# Set the entrypoint as `agent`
# This means that this node is the first one called
workflow.set_entry_point("agent")

# We now add a conditional edge
workflow.add_conditional_edges(
    # First, we define the start node. We use `agent`.
    # This means these are the edges taken after the `agent` node is called.
    "agent",
    # Next, we pass in the function that will determine which node is called next.
    should_continue,
    # Finally we pass in a mapping.
    # The keys are strings, and the values are other nodes.
    # END is a special node marking that the graph should finish.
    # What will happen is we will call `should_continue`, and then the output of that
    # will be matched against the keys in this mapping.
    # Based on which one it matches, that node will then be called.
    {
        # If `tools`, then we call the tool node.
        "continue": "action",
        # Otherwise we finish.
        "end": END
    }
)

# We now add a normal edge from `tools` to `agent`.
# This means that after `tools` is called, `agent` node is called next.
workflow.add_edge('action', 'agent')

# Finally, we compile it!
# This compiles it into a LangChain Runnable,
# meaning you can use it as you would any other runnable
app = workflow.compile()

8. 使用它!

我们现在可以使用它! 这样就可以暴露与所有其他LangChain可运行程序相同的接口 same interface。 这个可运行程序接受消息列表。

from langchain_core.messages import HumanMessage

inputs = {"messages": [HumanMessage(content="what is the weather in sf")]}
app.invoke(inputs)

这可能需要一点时间 - 它在幕后进行了几次调用。为了开始看到一些中间结果,我们可以使用流式传输 - 有关更多信息,请参见下文。

代码

https://github.com/zgpeace/pets-name-langchain/tree/develop

参考

https://python.langchain.com/docs/langsmith/walkthrough

你可能感兴趣的:(LLM-Large,Language,Models,langchain,langgraph,agent,llm,chatgpt)