开启左侧

LangGraph

[复制链接]
创想小编 发表于 2 小时前 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
作者:、、、、南山小雨、、、、
多智能体工作流:串行,并行,一级一个模型负责生成,一个模型负责评估,评估不过继续反馈生成,直到评估通过

LangGraph-1.png

多Agent的特点:

LangGraph-2.png


多智能体架构:
LangGraph-3.png

在新版本的langchain,把langgrach单独拿出了,并赋予了更多的agent功能,langGraph相对于langChain增强了三个部分,其中包括云平台/监看。
LangGraph-4.png

节点 边 图 是langGrach中的重要概念,其中边是连接节点的条件:
LangGraph-5.png

要点:
1.每个节点的返回return必须是状态。
2.在一开始就规划好全部的节点图,除了conditional,其他的都是确定的,只能执行节点里有的流程。
3.跟langchain不同,大模型不能直接调用工具,只能在AIMessage中包含tools_call,在里面放入想要调用的工具,需要自行用conditional的边来执行。
4.工具只有加入成为一个节点才能最终被执行,多个工具一般为为一个节点。由大语言模型中的tools_call决定调用哪一个。执行到工具的节点,如action(ToolNode),它是根据 last_message.tool_calls 里的 name 来决定执行哪个工具。
注意:
model.bind_tools(tools)工具如果绑定模型,模型就有可能在tools_call中表明调他,但如果它不在节点中,无法被执行。
  1. from langchain_core.messages importAnyMessage
  2. from typing_extensions importTypedDict
  3. # 自定义节点间通讯的消息类型
  4. classState(TypedDict):
  5.     messages: list[AnyMessage]
  6.     extra_field:int
  7. #定义节点
  8. from langchain_core.messages importAIMessage
  9. def node(state: State):
  10.     messages = state["messages"]
  11.     new_message =AIMessage("你好!")return{"messages": messages +[new_message],"extra_field":10}
  12. from langgraph.graph importStateGraph
  13. graph_builder =StateGraph(State) #graph_builder就行一张空白的纸,后面的节点都要画在这个纸上 State定义了机器能传递什么数据
  14. graph_builder.add_node(node) #向图添加节点
  15. graph_builder.set_entry_point("node") #设置这个图运行的起点
  16. graph = graph_builder.compile() #编译这个图,让他成为真正可以运行的机器
  17. #使用:
  18. # 运行图(最常见方式)
  19. result = graph.invoke({"messages":[],           # 向这个图中添加State类型的数据
  20.     "extra_field":0}) #它就会把这个函数传递给node函数了
  21. print(result["messages"])
复制代码
串行控制
  1. from typing_extensions importTypedDict
  2. from IPython.display importImage, display
  3. from langgraph.graph importSTART, StateGraph
  4. classState(TypedDict):
  5.     value_1: str
  6.     value_2:int
  7. def step_1(state: State):return{"value_1":"a"}
  8. def step_2(state: State):
  9.     current_value_1 = state["value_1"]return{"value_1": f"{current_value_1} b"}
  10. def step_3(state: State):return{"value_2":10}//一直有一个公共的State值,每个节点都在修改//这里的核心在于,每个节点的返回值都是在修改这个公共的值,下一个节点的输入值,就是这个公共的值
  11. graph_builder =StateGraph(State)#Add nodes
  12. graph_builder.add_node(step_1)
  13. graph_builder.add_node(step_2)
  14. graph_builder.add_node(step_3)#Add edges
  15. graph_builder.add_edge(START,"step_1")
  16. graph_builder.add_edge("step_1","step_2")
  17. graph_builder.add_edge("step_2","step_3")
  18. graph = graph_builder.compile()display(Image(graph.get_graph().draw_mermaid_png()))
复制代码
LangGraph-6.png

  1. graph.invoke({"value_1":"c"}){'value_1':'a b','value_2':10}
复制代码
分支结构
  1. importoperator
  2. from typing importAnnotated, Any
  3. from typing_extensions importTypedDict
  4. from langgraph.graph importStateGraph, START, END
  5. from IPython.display importImage, display
  6. #Annotated允许为类型提示添加额外的元数据,而不影响类型检查器对类型本身的理解classState(TypedDict):
  7.     aggregate: Annotated[list,operator.add] #每次都是添加进list
  8. def a(state: State):print(f'Adding "A" to {state["aggregate"]}')return{"aggregate":["A"]}
  9. def b(state: State):print(f'Adding "B" to {state["aggregate"]}')return{"aggregate":["B"]}
  10. def c(state: State):print(f'Adding "C" to {state["aggregate"]}')return{"aggregate":["C"]}
  11. def d(state: State):print(f'Adding "D" to {state["aggregate"]}')return{"aggregate":["D"]}
  12. builder =StateGraph(State)
  13. builder.add_node(a)
  14. builder.add_node(b)
  15. builder.add_node(c)
  16. builder.add_node(d)
  17. builder.add_edge(START,"a")
  18. builder.add_edge("a","b")
  19. builder.add_edge("a","c")
  20. builder.add_edge("b","d")
  21. builder.add_edge("c","d")
  22. builder.add_edge("d", END)
  23. graph = builder.compile()display(Image(graph.get_graph().draw_mermaid_png()))//运行时配置,{"configurable": {"thread_id": "foo"}} 这个是标记这个graph的,用于Memory(记忆)Checkpointer(断点恢复)。在这里没真正使用它的功能
  24. graph.invoke({"aggregate":[]},{"configurable":{"thread_id":"foo"}})
  25. Adding "A" to []
  26. Adding "B" to ['A']
  27. Adding "C" to ['A']
  28. Adding "D" to ['A','B','C']{'aggregate':['A','B','C','D']}
复制代码
LangGraph-7.png


条件分支
  1. importoperator
  2. from typing importAnnotated, Literal
  3. from typing_extensions importTypedDict
  4. from langgraph.graph importStateGraph, START, END
  5. classState(TypedDict):
  6.     aggregate: Annotated[list,operator.add]
  7. def a(state: State):print(f'Node A sees {state["aggregate"]}')return{"aggregate":["A"]}
  8. def b(state: State):print(f'Node B sees {state["aggregate"]}')return{"aggregate":["B"]}#Define nodes
  9. builder =StateGraph(State)
  10. builder.add_node(a)
  11. builder.add_node(b)
  12. #这个地方的核心在于return"b"就是直接转到执行b节点
  13. #Define edges
  14. def route(state: State)-> Literal["b", END]:iflen(state["aggregate"])<7:return"b"else:return END
  15. builder.add_edge(START,"a")
  16. builder.add_conditional_edges("a", route)
  17. builder.add_edge("b","a")
  18. graph = builder.compile()
复制代码
//打印
  1. from IPython.display importImage, display
  2. display(Image(graph.get_graph().draw_mermaid_png()))
复制代码
LangGraph-8.png

  1. graph.invoke({"aggregate":[]})
  2. Node A sees []
  3. Node B sees ['A']
  4. Node A sees ['A','B']
  5. Node B sees ['A','B','A']
  6. Node A sees ['A','B','A','B']
  7. Node B sees ['A','B','A','B','A']
  8. Node A sees ['A','B','A','B','A','B']
  9. graph.invoke({"aggregate":[]})//为了防止异常情况况下无限循环,设置能在这个结构体上操作的最大次数
  10. from langgraph.errors importGraphRecursionErrortry:
  11.     graph.invoke({"aggregate":[]},{"recursion_limit":4})
  12. except GraphRecursionError:print("Recursion Error")
复制代码
循环

//循环就是添加边的时候,指向值前
  1. importoperator
  2. from typing importAnnotated, Literal
  3. from typing_extensions importTypedDict
  4. from langgraph.graph importStateGraph, START, END
  5. from IPython.display importImage, display
  6. classState(TypedDict):
  7.     aggregate: Annotated[list,operator.add]
  8. def a(state: State):print(f'Node A sees {state["aggregate"]}')return{"aggregate":["A"]}
  9. def b(state: State):print(f'Node B sees {state["aggregate"]}')return{"aggregate":["B"]}
  10. def c(state: State):print(f'Node C sees {state["aggregate"]}')return{"aggregate":["C"]}
  11. def d(state: State):print(f'Node D sees {state["aggregate"]}')return{"aggregate":["D"]}
  12. # 节点
  13. builder =StateGraph(State)
  14. builder.add_node(a)
  15. builder.add_node(b)
  16. builder.add_node(c)
  17. builder.add_node(d)
  18. # 边
  19. def route(state: State)-> Literal["b", END]:iflen(state["aggregate"])<7:return"b"else:return END
  20. builder.add_edge(START,"a")
  21. builder.add_conditional_edges("a", route)
  22. builder.add_edge("b","c")
  23. builder.add_edge("b","d")
  24. builder.add_edge(["c","d"],"a")
  25. graph = builder.compile()display(Image(graph.get_graph().draw_mermaid_png()))
复制代码
LangGraph-9.png

  1. result = graph.invoke({"aggregate":[]})
  2. Node A sees []
  3. Node B sees ['A']
  4. Node C sees ['A','B']
  5. Node D sees ['A','B']
  6. Node A sees ['A','B','C','D']
  7. Node B sees ['A','B','C','D','A']
  8. Node C sees ['A','B','C','D','A','B']
  9. Node D sees ['A','B','C','D','A','B']
  10. Node A sees ['A','B','C','D','A','B','C','D']
复制代码
图的运行时配置
  1. importoperator
  2. from typing importAnnotated, Sequence
  3. from typing_extensions importTypedDict
  4. from langchain_deepseek importChatDeepSeek
  5. from langchain_openai importChatOpenAIimportos
  6. from langchain_core.messages importBaseMessage, HumanMessage
  7. from langchain_core.runnables.config importRunnableConfig
  8. from langgraph.graph importEND, StateGraph, START
  9. model =ChatDeepSeek(
  10.     model="Pro/deepseek-ai/DeepSeek-V3",
  11.     temperature=0,
  12.     api_key=os.environ.get("DEEPSEEK_API_KEY"),
  13.     base_url=os.environ.get("DEEPSEEK_API_BASE"),)
  14. model1 =ChatOpenAI(
  15.     model="gpt-3.5-turbo",
  16.     temperature=0,
  17.     api_key=os.environ.get("OPENAI_API_KEY"),
  18.     base_url=os.environ.get("OPENAI_API_BASE"),)
  19. # 定义要切换的模型
  20. models ={"deepseek": model,"openai": model1,}classAgentState(TypedDict):
  21.     messages: Annotated[Sequence[BaseMessage],operator.add]
  22. def _call_model(state: AgentState, config: RunnableConfig):
  23.     # 使用LCEL的配置
  24.     model_name = config["configurable"].get("model","deepseek")
  25.     model = models[model_name]
  26.     response = model.invoke(state["messages"])return{"messages":[response]}#Define anew graph
  27. builder =StateGraph(AgentState)
  28. builder.add_node("model", _call_model)
  29. builder.add_edge(START,"model")
  30. builder.add_edge("model", END)
  31. graph = builder.compile()//没有增加运行时配置的情况下,它会默认调用deepseek
  32. graph.invoke({"messages":[HumanMessage(content="hi 你是谁?")]})//图的运行时配置,就是多个行参而已
  33. config ={"configurable":{"model":"openai"}}
  34. graph.invoke({"messages":[HumanMessage(content="hi 你是谁?")]}, config=config)
复制代码
激活持久层:
[code]from langchain_deepseek importChatDeepSeekimportos
from langgraph.graph importStateGraph, MessagesState, START

model =ChatDeepSeek(
    model="Pro/deepseek-ai/DeepSeek-V3",
    temperature=0,
    api_key=os.environ.get("DEEPSEEK_API_KEY"),
    base_url=os.environ.get("DEEPSEEK_API_BASE"),)


def call_model(state: MessagesState):
    response = model.invoke(state["messages"])return{"messages": response}


builder =StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_edge(START,"call_model")


from langgraph.checkpoint.memory importMemorySaver
# 使用 MemorySaver 保存中间状态 这个是内存,且聊天记录是没有向量化,直接存入
memory =MemorySaver()
#加上memory就能保持记忆了,激活持久化层
graph = builder.compile(checkpointer=memory)

config ={"configurable":{"thread_id":"1"}}
input_message ={"role":"user","content":"hi! 我是tomie"}#stream_mode="values"方式就是每次经过一个节点就返回一次MessagesState数据for chunk in graph.stream({"messages":[input_message]}, config, stream_mode="values"):
    chunk["messages"][-1].pretty_print()

input_message ={"role":"user","content":"我叫什么名字?"}for chunk in graph.stream({"messages":[input_message]}, config, stream_mode="values"):
    chunk["messages"][-1].pretty_print()================================ Human Message =================================

我叫什么名字?================================== Ai Message ==================================

哈哈,你刚刚说过啦!你叫 **Tomie**~
LangGraph-10.png
LangGraph-11.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题
阅读排行更多+

Powered by Discuz! X3.4© 2001-2013 Discuz Team.( 京ICP备17022993号-3 )