【LLM大模型】LangChain框架:Agent之LangGraph的使用

(一)Chain、LangChain代理、LangGraph

1.Chain:线性执行的顺序链

LangChain的核心优势在于其能够轻松构建自定义链,这些链通常是线性的,类似于有向无环图(DAG),每个步骤都严格按顺序执行,每个任务只有一个输出和一个后续任务,形成一个没有循环的线性流程。
在遇到复杂任务时,比如第一次搜索没有找到想要的内容,我们可能需要进行第二次、第三次搜索,甚至可能需要调用网络搜索来完成。在这种情况下,顺序执行的任务(DAG)显然无法满足需求。
请求方和搜索方之间需要经历多次来回沟通,请求方可能会要求搜索方根据反馈调整搜索策略,这种多次的循环沟通才能逐步逼近最终答案。

2.LangChain代理:循环图,但是无法控制

这种情况下,我们需要的不再是DAG,而是一个循环图,它能够描述多个参与者之间的多轮对话和互动,以确认最终的答案。这种循环图能够处理更模糊、更复杂的用例,因为它允许系统根据反馈进行调整和迭代。那么,在循环图的运行模式就是智能代理,也就是AI Agent。

在这里插入图片描述

3.LangGraph,可以对智能代理进行更多的控制

在实际应用过程中,我们发现需要对智能代理进行更多的控制。例如,我们可能希望智能代理始终首先调用特定工具,或者我们可能希望对工具的调用方式有更多的控制,甚至可能希望根据智能代理的状态使用不同的提示。为了解决这些问题,LangGraph提出了“状态机”的概念。通过状态机为图创建对应的状态机,这种方法可以更好地控制智能代理的行动流程,使其更加灵活和有效地处理复杂任务。

补充:LangChain代理和LangGraph对比

可靠性灵活性
Langchain 代理可靠性较低,因为 LLM 需要在每个步骤上做出正确的决策更灵活,因为 LLM 可以选择任何动作序列
LangGraph可靠性更高,因为控制流已经设置好,LLM 在每个节点上有具体的任务灵活性较低,因为动作受限于在每个节点上设置控制流

(二)LangGraph概念

1.StateGraph(状态图):包含了状态表示的一个图结构

StateGraph是一个类,它负责表示整个图的结构;需要通过传入一个状态定义来初始化这个类(图状态),这个图状态代表了一个中心状态对象,它会在执行过程中不断更新。这个图状态对象由图中的节点更新,节点会以键值对的形式,返回对状态属性的操作。

状态对象的属性可以通过两种方式更新,在定义图状态的时候,需要指定属性的更新方式:(可以有多个属性,每个属性需要单独指定一种更新方式)

  • 覆盖更新:如果一个属性需要被新的值替换,我们可以让节点返回这个新值进行替换。
  • 增量更新:如果一个属性是一个动作列表(或类似的操作),我们可以在原有的列表上添加新的动作。
旅行为例:
1.输入目的地(Edges里面的起始边)
2.任务规划,包括预定航班、预订酒店(Nodes里面的各个节点)
3.任务规划之间是有关联关系的,比如航班夜晚,我们就不要酒店了,航班改中间位置就要修改酒店地址,之间有因果关系(Edges里面的边,分为普通边和条件边,普通边就是任务有序执行,条件边就是可能根据情况不一样)
4.StateGraph类就是这样的旅行计划,而节点就像是规划旅行的不同步骤,比如确定目的地、预定航班和预定酒店。每个步骤都会更新你的旅行计划,可能是完全替换旧的计划,也可能是添加新的信息到现有的计划中

2.Nodes(节点)

创建了StateGraph之后,需要向其中添加节点;每个节点都代表一个任务,它们执行的结果会影响StateGraph的状态。这些节点通过边相互连接,形成了一个有向无环图(DAG),确保了任务的正确执行顺序。

上面旅行计划的例子,Nodes(节点)就好像旅行计划中需要完成的任务,例如:预定航班、预订酒店。Nodes(节点)接受旅行计划(图状态对象)作为输入,并输出一个更新后的任务状态,例如:完成酒店的预订

3.Edges(边)

Edges(边)是连接Nodes(节点)并定义StateGraph(状态图)中节点执行顺序的关键部分。边主要分为以下几种:

  • 起始边(Starting Edge):作为图的开始,比如在旅行计划中,起始边就是确定你的目的地。一旦目的地被确定,你的旅行计划就可以开始执行了。
  • 普通边(Normal Edges):这些边表示一个节点总是要在另一个节点之后被调用。在旅行计划中,普通边就像是确定了任务执行的顺序。例如,在找到合适的航班之后,你可能会决定预订酒店。这个顺序确保了任务的有序执行。
  • 条件边(Conditional Edges):使用函数(通常由LLM提供)来确定首先调用哪个节点。在旅行计划中,条件边就像是根据你的喜好或者天气情况来决定你的下一步行动。比如,如果你发现没有合适的航班,你可能会选择推迟预订酒店,而去查找火车车票。条件边提供了灵活性,使得系统可以根据不同的情况来调整执行的顺序。

边定义了节点之间的依赖关系和执行顺序。起始边确定了图的开始,普通边确保了任务的正确执行顺序,而条件边则根据特定的条件来决定下一步的操作

二:LangGraph使用

(一)步骤归纳

1.初始化model和tools,可以通过agent关联models和tools
2.定义图状态,包括各个属性比如:用户输入(覆盖),聊天历史(增量),中间步骤(代理采取的行动和相应的观察),代理结果(代理的响应)
3.定义图节点,包括1中的代理、工具
4.定义边的逻辑判断(条件边)
5.定义工作流状态图
    a.通过图状态初始化工作流
    b.添加节点、边
    c.编译工作流成runnable
6.执行状态图

(二)实例一:状态图stateGraph和节点node的使用(不含图状态和注解)

from langgraph.graph import START, StateGraph

#1.不涉及model和tool

#2.不涉及图状态

#3.定义图节点,定义节点需要设置一个节点的action(函数)
def my_node(state):
    return {"x": state["x"] + 1, "y": state["y"]-1,"z":10}

#4.不需要条件边

#5.定义工作流状态图
builder = StateGraph(dict)  #注意:没有传入图状态,dict默认全部input的字段都作为图状态属性传入,比如后面的x,y都是StateGraph的state
builder.add_node("my_fair_node", my_node)   #添加节点
builder.add_edge(START, "my_fair_node") #添加起始边

#6.编译
graph = builder.compile()   
step1 = graph.invoke({"x": 1,"y":2})
print(step1)

在这里插入图片描述

如果我们尝试更新节点的action,会发现每一步的图状态更新和节点的返回结果相关

def my_node(state):
    return {"x": state["x"] + 1}

在这里插入图片描述

我们传递了y,但是节点没有返回

(三)实例二:状态图stateGraph和节点node的使用(包含图状态和注解)

from langchain_core.runnables import RunnableConfig
from typing_extensions import Annotated, TypedDict
from langgraph.graph import StateGraph

#1.不涉及model和tool


#2.定义图状态
def reducer(a: list, b: list | None) -> list: #进行追加
    if b is not None:
        return a + b
    return a

class State(TypedDict): #这里是图中状态的定义,也是标识运行时的input中哪些字段可以透传给状态图
    #https://blog.csdn.net/randy521520/article/details/133826255
    x: Annotated[list, reducer] #Annotated: 用于添加类型注解的装饰器。可以在类型提示中添加额外的元数据信息;这里表示更新list数据的时候,通过reducer方法进行更新(第一个参数时原数据list,第二个参数是要更新的数据int)

class ConfigSchema(TypedDict):  #这里是标识运行时的RunnableConfig中哪些字段可以透传给状态图
    r: float

#3.定义图节点,定义节点需要设置一个节点的action(函数)
def node_runner(state: State, config: RunnableConfig) -> dict: #传入图状态,可以进行修改;还可以传入config,config在调用时传递,同时还需要在创建状态图时再声明哪些变量可以传递到图中
    r = config["configurable"].get("r", 1.0) #从config中获取配置字段值
    print(state["x"])
    x = state["x"][-1] #获取最新的状态
    next_value = x * r * (1 - x)    #随便的操作
    return {"x": [next_value],"y":10}    #注意:返回的值,会通过注解里面的reducer进行更新(作为第二个参数),所以类型要一致
    
#4.不需要条件边

#5.定义工作流状态图,没有边
graph = StateGraph(State, config_schema=ConfigSchema)
graph.add_node("A", node_runner) #添加节点,包括节点的action
graph.set_entry_point("A")  #设置进入节点
graph.set_finish_point("A")  #设置结束节点

#6.编译
compiled = graph.compile()
step1 = compiled.invoke({"x": [0.5,1],"y":0.3}, {"configurable": {"r": 3.0}})
print(step1)

在这里插入图片描述

可以看到,我们显式定义了图状态里面的属性后,节点返回的数据在更新图状态时只会去获取图状态定义中的字段进行更新

(四)实例三:包含了model和tool的使用

这里用到了一个新的模型anthropic.claude-3-5-sonnet,Claude 3 是一系列最先进的人工智能(AI)模型,可让您根据自己的需求,从智能、速度和成本方面考虑选择最适合的组合。并且该模型能够可靠地从图像等非结构化数据中提取信息。

https://docs.anthropic.com/zh-CN/docs/intro-to-claude

但是有国家限制,离谱了,得到API Key也没有用,还要配合技术才行

from typing import Literal

from langchain_core.messages import ToolMessage
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.checkpoint import MemorySaver
from langgraph.graph import END, StateGraph, MessagesState
from langgraph.prebuilt import ToolNode
from langchain.prompts import MessagesPlaceholder,ChatPromptTemplate

#1.初始化model和tools,可以通过agent关联models和tools
@tool
def search(query: str):
    """Call to surf the web."""
    # This is a placeholder, but don't tell the LLM that...
    if "sf" in query.lower() or "san francisco" in query.lower():
        return ["It's 60 degrees and foggy."]
    return ["It's 90 degrees and sunny."]

tools = [search]

prompt = ChatPromptTemplate.from_messages(
                [
                    ("system", "You are a helpful assistant"),
                    MessagesPlaceholder("chat_history", optional=True),
                    ("human", "{messages}"),
                    MessagesPlaceholder("agent_scratchpad", optional=True),
                ]
            )

#model在这里用于选取tools
model = prompt | ChatOpenAI(model="gpt-3.5-turbo", temperature=0).bind_tools(tools)

#2.定义图状态,这里使用的MessagesState,属性如下:
# class MessagesState(TypedDict):
#     messages: Annotated[list[AnyMessage], add_messages]

# 3.定义图节点
# tool_node = ToolNode(tools) 这也是一种方法,定义tool和model的运行action
tools_by_name = {tool.name: tool for tool in tools}
def tool_node(state: dict):
    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool = tools_by_name[tool_call["name"]]
        observation = tool.invoke(tool_call["args"])
        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    return {"messages": result}

def call_model(state: MessagesState):
    response = model.invoke(state)
    return {"messages": [response]} #add_messages兼容list和非list,都会转成list

# 4.定义边的逻辑判断(条件边),判断是否继续
def should_continue(state: MessagesState) -> Literal["tools", "__end__"]: #Literal用于限制返回的值的可选值
    messages = state['messages']
    last_message = messages[-1]
    if last_message.tool_calls: #判断models是否返回tools调用,有则告诉调用tools节点,否则结束
        return "tools"
    return END

# 5.定义工作流状态图
# 5.a.通过图状态初始化工作流
workflow = StateGraph(MessagesState)

# 5.b.添加节点、边
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)

workflow.set_entry_point("agent")
workflow.add_conditional_edges(
    "agent",
    should_continue,    #判断下一个调用的节点
)

workflow.add_edge("tools", 'agent')

# 5.c.编译工作流成一个runnable,通过invoke调用
app = workflow.compile()

# 6.执行状态图
final_state = app.invoke(
    {"messages": "what is the weather in sf"},
    config={"configurable": {"thread_id": 42}}
)

print(final_state["messages"][-1].content)

在这里插入图片描述

如何系统的去学习AI大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

👉CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)👈

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

  • 目标:了解AI大模型的基本概念、发展历程和核心原理。
  • 内容
    • L1.1 人工智能简述与大模型起源
    • L1.2 大模型与通用人工智能
    • L1.3 GPT模型的发展历程
    • L1.4 模型工程
      - L1.4.1 知识大模型
      - L1.4.2 生产大模型
      - L1.4.3 模型工程方法论
      - L1.4.4 模型工程实践
    • L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

  • 目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
  • 内容
    • L2.1 API接口
      - L2.1.1 OpenAI API接口
      - L2.1.2 Python接口接入
      - L2.1.3 BOT工具类框架
      - L2.1.4 代码示例
    • L2.2 Prompt框架
      - L2.2.1 什么是Prompt
      - L2.2.2 Prompt框架应用现状
      - L2.2.3 基于GPTAS的Prompt框架
      - L2.2.4 Prompt框架与Thought
      - L2.2.5 Prompt框架与提示词
    • L2.3 流水线工程
      - L2.3.1 流水线工程的概念
      - L2.3.2 流水线工程的优点
      - L2.3.3 流水线工程的应用
    • L2.4 总结与展望

阶段3:AI大模型应用架构实践

  • 目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
  • 内容
    • L3.1 Agent模型框架
      - L3.1.1 Agent模型框架的设计理念
      - L3.1.2 Agent模型框架的核心组件
      - L3.1.3 Agent模型框架的实现细节
    • L3.2 MetaGPT
      - L3.2.1 MetaGPT的基本概念
      - L3.2.2 MetaGPT的工作原理
      - L3.2.3 MetaGPT的应用场景
    • L3.3 ChatGLM
      - L3.3.1 ChatGLM的特点
      - L3.3.2 ChatGLM的开发环境
      - L3.3.3 ChatGLM的使用示例
    • L3.4 LLAMA
      - L3.4.1 LLAMA的特点
      - L3.4.2 LLAMA的开发环境
      - L3.4.3 LLAMA的使用示例
    • L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

  • 目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
  • 内容
    • L4.1 模型私有化部署概述
    • L4.2 模型私有化部署的关键技术
    • L4.3 模型私有化部署的实施步骤
    • L4.4 模型私有化部署的应用场景

学习计划:

  • 阶段1:1-2个月,建立AI大模型的基础知识体系。
  • 阶段2:2-3个月,专注于API应用开发能力的提升。
  • 阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。
  • 阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的所有 ⚡️ 大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

全套 《LLM大模型入门+进阶学习资源包↓↓↓ 获取~

👉CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)👈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值