langgraph基础概念

#聊聊Agent开发#

1. 状态(State)

代表应用程序当前快照的共享数据结构

可以使用 TypedDict 或 Pydantic 模型定义

包含作为所有节点和边输入模式的模式(schema)

通过减速器函数(reducer functions)进行更新,指定如何应用更改

1. TypedDict 和 Pydantic 是什么?

它们都是定义状态结构的方式:、

简单说:都是用来定义你的数据结构,就像数据库的字段定义。

#pydantic方式
from pydantic import BaseModel

class State(BaseModel):
    messages: list
    llm_calls: int

#typedDict方式
from typing_extensions import TypedDict, Annotated
import operator

class State(TypedDict):
    messages: list
    llm_calls: int

2. 减速器函数(Reducer Function)是什么?

减速器函数定义了如何合并状态更新

比如,节点可能返回 {"messages": [new_msg]},但你想追加到消息列表,而不是覆盖它。

from typing_extensions import TypedDict, Annotated
import operator

# ❌ 没有减速器 - 会被覆盖
class State1(TypedDict):
    messages: list

# ✅ 有减速器 - 会追加
class State2(TypedDict):
    messages: Annotated[list, operator.add]  # 使用 add 函数追加

2. 节点(Nodes)

编码代理逻辑的函数

接收当前状态作为输入

执行计算或副作用

返回更新后的状态

代表图中执行的实际工作

3. 边(Edges)

基于当前状态确定接下来执行哪个节点的函数

可以是条件分支或固定转换

告诉图接下来要做什么

启用图中的路由和控制流

4. 状态图(StateGraph)

构建LangGraph应用程序的主要抽象

允许你定义节点和边的图

编译时自动创建Pregel应用程序

使得组合复杂的循环工作流变得简单

from langgraph.graph import StateGraph, START
from typing_extensions import TypedDict, Annotated
import operator

# 定义状态
class State(TypedDict):
    messages: Annotated[list, operator.add]
    topic: str
    essay: str

# 定义节点
def write_essay(state: State):
    """写文章"""
    essay_content = f"关于 {state['topic']} 的文章内容..."
    print(f"[write_essay 节点] 写了文章: {essay_content}")
    return {"essay": essay_content}

def review_essay(state: State):
    """审阅文章"""
    review = f"审阅意见:文章讲的是 {state['topic']}"
    print(f"[review_essay 节点] 添加审阅: {review}")
    return {"messages": [review]}

# 构建图
builder = StateGraph(State)
builder.add_node("write", write_essay)
builder.add_node("review", review_essay)
builder.add_edge(START, "write")
builder.add_edge("write", "review")

# 编译
graph = builder.compile()

# 运行
print("=== 开始执行图 ===\n")
result = graph.invoke({
    "messages": ["开始"],
    "topic": "AI",
    "essay": ""
})

print("\n=== 最终输出 ===")
print(f"messages: {result['messages']}")
print(f"topic: {result['topic']}")
print(f"essay: {result['essay']}")

实际输出会是这样=== 开始执行图 === [write_essay 节点] 写了文章: 关于 AI 的文章内容... [review_essay 节点] 添加审阅: 审阅意见:文章讲的是 AI === 最终输出 === messages: ['开始', '审阅意见:文章讲的是 AI'] topic: AI essay: 关于 AI 的文章内容... 

关键点解释

1.messages 追加了:从 ['开始'] 变成 ['开始', '审阅意见:文章讲的是 AI']因为我们用了 Annotated[list, operator.add] 减速器

2.essay 被设置:从空字符串变成 "关于 AI 的文章内容..."因为 essay 没有减速器,所以直接被覆盖

3.topic 保持不变:因为没有节点修改它,所以还是 "AI"

如果没有减速器会怎样?

class State(TypedDict):
    messages: list  # 没有 operator.add
# 输出会是:
messages: ['审阅意见:文章讲的是 AI']  # 原来的 '开始' 被覆盖了!

关键原则

节点做工作,边决定做什么。 这种设计使控制流显式且可追踪——你总是可以通过查看当前节点和状态来理解代理接下来会做什么。

通过组合节点和边,你可以创建复杂的代理工作流,使状态随时间演变。节点和边仅仅是函数,所以它们可以包含LLM或任何其他代码逻辑。

参考资料:

https://docs.langchain.com/oss/python/langgraph/use-graph-api

https://docs.langchain.com/oss/python/langgraph/graph-api

全部评论
点赞 回复 分享
发布于 今天 11:47 北京

相关推荐

02-07 12:06
已编辑
华侨大学 测试开发
最近看到很多 92 的,甚至是硕士,开始往测开赛道卷,说实话有点看不懂。先把话说清楚,大厂里的测开,绝大多数时间干的还是测试的活,只是写点自动化脚本、维护测试平台、接接流水线,真正像开发一样做系统、做架构、做核心平台的测开少得可怜,基本都集中在核心提效组,而且人很少,外面进去的大概率轮不到你,我想真正干过人都清楚。很多人被洗脑了,以为测开也是开,和后端差不多,只是更简单、更轻松、还高薪。现实情况是,测开和开发的职业路径完全不一样。开发的核心是业务和系统能力,测开的核心是稳定性和覆盖率,前者是往上走,后者天花板非常明显。你可以见到很多开发转测开,但你很少见到干了几年测开还能顺利转回开发的。更现实一点说,92 的高学历如果拿来做测开,大部分时间就是在做重复性很强的杂活,这种工作对个人能力的放大效应非常弱。三年下来,你和一个双非的,甚至本科的测开差距不会太大,但你和同龄的后端、平台开发差距会非常明显。这不是努不努力的问题,是赛道问题。所谓测开简单高薪,本质上是把极少数核心测开的上限,当成了整个岗位的常态来宣传。那些工资高、技术强的测开,本身就是开发水平,只是挂了个测开的名。普通人进去,99% 做的都是项目兜底型工作,而不是你想象中的平台开发。测开不是不能做,但它绝对不是开发的平替,也不是性价比最优解。如果你是真的不想做开发,追求稳定,那测开没问题。但如果你只是觉得测开比后端容易,还能进大厂,那我劝你冷静一点,这只是在用短期安全感换长期天花板。有92的学历,如果你连测开这些重复性工作都能心甘情愿接受,那你把时间精力用在真正的开发、系统、业务深度上,回报大概率比卷测开要高得多。想清楚再下场,别被岗位名和话术带偏了,就算去个前端客户端也是随便占坑的,测开是一个坑位很少赛道,反而大面积学历下放,不用想也能知道会是什么结果,我想各位在JAVA那里已经看到了
小浪_Coding:工作只是谋生的手段 而不是相互比较和歧视
点赞 评论 收藏
分享
评论
3
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务