一、LangGraph简介

1、LangGraph特性

  • 持久化执行,任何故障后皆可无缝恢复
  • 完整的内存管理,整合短期记忆和长期记忆
  • 生产级可靠性
  • 可观测性,与LangSmith集成

一个为生产环境而生的低层级编排框架

  • 完全控制,可直接编写prompt
  • 显示状态,State, agent运转的状态记录
  • 图状结构
  • 生产级可靠

2、核心概念

2.1 state

单一事实来源
所有数据通过state在节点间传递和更新

2.2 node

每个node负责一个单一的职责
一般执行LLM调用、工具调用

2.3 Edges

node间的连接线
普通边:实线
条件边:虚线

3、适用场景

  • 多步复杂推理
  • 长时间运行任务
  • 需要人的介入
  • 追求生产级稳定性

二、LangGraph代码示例

1、基本Hello

安装依赖

> pip install langgraph langchain langchain-openai pygraphviz

代码示例:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# 定义状态TestState
class TestState(TypedDict):
    username: str

# 定义节点hello和hook
def hello(state: TestState) -> dict:
    print(f"hello {state['username']}")
    return {}


def hook(state: TestState) -> dict:
    print("握手")
    return {}

# 创建状态图
graph = StateGraph(TestState)

# 添加节点node
graph.add_node("hello", hello)
graph.add_node("hook", hook)

# 添加边
graph.add_edge(START, "hello")
graph.add_edge("hello", "hook")
graph.add_edge("hook", END)

# 编译状态图
app = graph.compile()
# 创建输入参数
username = "martin"
# 调用状态图
result = app.invoke({"username": username})

# 获取流程图
mermaid_str = app.get_graph().draw_mermaid()
html_content = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LangGraph Flow</title>
</head>
<body>
<pre class="mermaid">{mermaid_str}</pre>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({{startOnLoad:true}});</script>
</body>
</html>"""

output_path = r"e:\langGraphTest\001demo\flowchart.html"
with open(output_path, "w", encoding="utf-8") as f:
    f.write(html_content)
print(f"\n流程图已保存到: {output_path}")
print("请在浏览器中打开该文件查看流程图")

运行代码产生的流程图:
在这里插入图片描述

2、条件分支示例


from typing import TypedDict
from langgraph.graph import StateGraph, START, END


class WeatherState(TypedDict):
    temperature: int
    recommendation: str

# 为温度赋值,方便后续测试
def check_temperature(state: WeatherState) -> dict:
    return {"temperature": 25}

def hot(state: WeatherState) -> dict:
    print("推荐: 防晒")
    return {"recommendation": "防晒"}


def warm(state: WeatherState) -> dict:
    print("推荐: 半袖")
    return {"recommendation": "半袖"}


def cold(state: WeatherState) -> dict:
    print("推荐: 外套")
    return {"recommendation": "外套"}

# 从state中获取上面的赋值,根据温度返回不同的路由
def route_by_temperature(state: WeatherState) -> str:
    temp = state["temperature"]
    if temp >= 26:
        return "hot"
    elif temp >= 20:
        return "warm"
    else:
        return "cold"


graph = StateGraph(WeatherState)

graph.add_node("check", check_temperature)
graph.add_node("hot", hot)
graph.add_node("warm", warm)
graph.add_node("cold", cold)

# 添加边,从START到check,然后根据温度返回不同的路由
graph.add_edge(START, "check")
graph.add_conditional_edges(
    "check",
    route_by_temperature,
    {
        "hot": "hot",
        "warm": "warm",
        "cold": "cold",
    }
)

graph.add_edge("hot", END)
graph.add_edge("warm", END)
graph.add_edge("cold", END)

app = graph.compile()

result = app.invoke({})
print(f"\n当前温度: {result['temperature']}°C, 最终推荐: {result['recommendation']}")

mermaid_str = app.get_graph().draw_mermaid()
html_content = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LangGraph Conditional Branching</title>
</head>
<body>
<pre class="mermaid">{mermaid_str}</pre>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({{startOnLoad:true}});</script>
</body>
</html>"""

output_path = r"e:\langGraphTest\001demo\flowchart_conditional.html"
with open(output_path, "w", encoding="utf-8") as f:
    f.write(html_content)
print(f"\n流程图已保存到: {output_path}")
print("请在浏览器中打开该文件查看流程图")

运行后的流程图:
在这里插入图片描述

三、LangGraph实例

1、功能说明

这是一个LangGraph实例。作用是对用户的输入通过调用LLM对用户的输入进行智能诊断,诊断后返回用户输入中的敏感词汇和评级。再将诊断的结果交给LLM,根据诊断结果判断用户输入是否需要人工审核、还是通过检测。

# =============================================================================
# 内容智能检测 Agent
# 功能:调用 DeepSeek LLM 对用户输入进行脏话检测(脏话),
#       并根据检测结果由 LLM 判断是否需要人工审核或直接通过
# 流程:START → detect(检测) → analyze(分析决策) → human_review / pass → END
# =============================================================================

import json
import urllib.request
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# ========================= 配置区域 =========================
# DeepSeek API 配置
API_KEY = "sk-key"
API_URL = "https://api.deepseek.com/chat/completions"
MODEL = "deepseek-v4-flash"


# ========================= 状态定义 =========================
# 定义 LangGraph 工作流的状态结构,所有节点共享并读写此状态
class ContentState(TypedDict):
    user_input: str          # 用户原始输入
    detection_result: str    # LLM 检测的原始返回结果
    sensitive_words: str     # 检测到的敏感词(逗号分隔)
    reason: str              # 检测原因 + 审核决策原因
    risk_level: str          # 风险评级:低 / 中 / 高
    need_review: bool        # 是否需要人工审核(True/False)
    review_decision: str     # 最终审核决策:"需要人工审核" 或 "通过"
    final_result: str        # 格式化后的最终输出结果


# ========================= 工具函数 =========================
def call_deepseek(messages: list) -> str:
    """
    调用 DeepSeek API 发送聊天请求
    :param messages: 消息列表,格式为 [{"role": "system/user", "content": "..."}]
    :return: LLM 返回的文本内容
    """
    # 构造请求体,temperature 设为 0.1 保证输出稳定
    data = json.dumps({
        "model": MODEL,
        "messages": messages,
        "temperature": 0.1
    }).encode("utf-8")

    # 使用 urllib 发送 POST 请求(无需安装 requests 库)
    req = urllib.request.Request(
        API_URL,
        data=data,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"
        }
    )
    with urllib.request.urlopen(req) as resp:
        result = json.loads(resp.read().decode("utf-8"))

    # 提取 LLM 返回的文本内容
    return result["choices"][0]["message"]["content"]


# ========================= 节点函数定义 =========================
def detect_node(state: ContentState) -> dict:
    """
    节点1 - 内容检测节点
    职责:调用 LLM 对用户输入进行敏感词检测
    返回:敏感词列表、检测原因、风险评级
    """
    print("【节点1】正在检测用户输入...")
    user_input = state["user_input"]

    # 构造提示词:要求 LLM 以 JSON 格式返回检测结果
    messages = [
        {"role": "system", "content": """你是一个内容安全检测专家。请对用户输入的内容进行敏感词检测,检测类别包括:脏话。
            请严格以JSON格式返回,不要包含任何其他文字:
            {
                "sensitive_words": ["检测到的敏感词列表,没有则为空数组"],
                "reason": "检测分析原因的详细说明",
                "risk_level": "风险评级:低/中/高"
            }"""},
        {"role": "user", "content": f"请检测以下内容的敏感性:\n{user_input}"}
    ]

    # 调用 LLM 并打印原始返回
    result = call_deepseek(messages)
    print(f"  LLM原始返回: {result}")

    # 解析 JSON,若 LLM 返回格式异常则使用默认值
    try:
        parsed = json.loads(result)
    except json.JSONDecodeError:
        parsed = {"sensitive_words": [], "reason": "LLM返回格式异常,默认通过", "risk_level": "低"}

    # 返回状态更新:检测原始结果、敏感词、原因、风险评级
    return {
        "detection_result": result,
        "sensitive_words": ", ".join(parsed.get("sensitive_words", [])) or "无",
        "reason": parsed.get("reason", ""),
        "risk_level": parsed.get("risk_level", "低")
    }


def analyze_node(state: ContentState) -> dict:
    """
    节点2 - 分析决策节点
    职责:根据检测结果,由 LLM 判断是否需要人工审核
    返回:是否需要审核、决策结果、决策原因
    """
    print("\n【节点2】正在分析检测结果...")

    # 构造提示词:要求 LLM 根据检测结果做出审核决策
    messages = [
        {"role": "system", "content": """你是一个内容审核决策专家。根据检测结果判断该内容是否需要人工审核。
            判断标准:
            - 包含政治敏感词汇 → 需要人工审核
            - 包含脏话/侮辱性语言 → 需要人工审核
            - 风险评级为"高" → 需要人工审核
            - 风险评级为"中"且存在敏感词 → 需要人工审核
            - 其他情况 → 通过
            
            请严格以JSON格式返回,不要包含任何其他文字:
            {
                "need_review": true或false,
                "decision": "需要人工审核" 或 "通过",
                "analysis_reason": "决策原因的简要说明"
            }"""},
                    # 将用户原始输入和检测节点的结果一起传给 LLM
                    {"role": "user", "content": f"""用户原始输入:{state['user_input']}
            检测结果:
            - 敏感词:{state['sensitive_words']}
            - 原因:{state['reason']}
            - 风险评级:{state['risk_level']}"""}
    ]

    result = call_deepseek(messages)
    print(f"  LLM原始返回: {result}")

    # 解析 JSON,异常时默认需要人工审核(安全优先)
    try:
        parsed = json.loads(result)
    except json.JSONDecodeError:
        parsed = {"need_review": True, "decision": "需要人工审核", "analysis_reason": "LLM返回格式异常,默认需审核"}

    # 返回状态更新:是否需要审核、决策结果、追加决策原因
    return {
        "need_review": parsed.get("need_review", True),
        "review_decision": parsed.get("decision", "需要人工审核"),
        "reason": state["reason"] + " | 审核决策原因: " + parsed.get("analysis_reason", "")
    }


def human_review_node(state: ContentState) -> dict:
    """
    节点3a - 人工审核节点
    职责:格式化输出需要人工审核的提醒信息
    """
    # 拼接格式化的审核提醒
    result = (
        f"\n{'='*50}\n"
        f"  ⚠️  需要人工审核\n"
        f"{'='*50}\n"
        f"  用户输入: {state['user_input']}\n"
        f"  敏感词:   {state['sensitive_words']}\n"
        f"  风险评级: {state['risk_level']}\n"
        f"  检测原因: {state['reason']}\n"
        f"  审核建议: {state['review_decision']}\n"
        f"{'='*50}"
    )
    print(result)
    return {"final_result": result}


def pass_node(state: ContentState) -> dict:
    """
    节点3b - 通过节点
    职责:格式化输出内容通过检测的信息
    """
    # 拼接格式化的通过信息
    result = (
        f"\n{'='*50}\n"
        f"  ✅  内容通过检测\n"
        f"{'='*50}\n"
        f"  用户输入: {state['user_input']}\n"
        f"  风险评级: {state['risk_level']}\n"
        f"  检测结果: {state['review_decision']}\n"
        f"{'='*50}"
    )
    print(result)
    return {"final_result": result}


# ========================= 路由函数 =========================
def route_by_review(state: ContentState) -> str:
    """
    条件路由:根据 analyze 节点的 need_review 字段决定下一步走向
    :return: "human_review" 走人工审核节点,"pass" 走通过节点
    """
    return "human_review" if state.get("need_review") else "pass"


# ========================= 构建 LangGraph 工作流 =========================
# 1. 创建状态图,绑定 ContentState 作为状态结构
graph = StateGraph(ContentState)

# 2. 注册四个节点
graph.add_node("detect", detect_node)           # 内容检测节点
graph.add_node("analyze", analyze_node)         # 分析决策节点
graph.add_node("human_review", human_review_node)  # 人工审核节点
graph.add_node("pass", pass_node)               # 通过节点

# 3. 添加边,定义流程走向
graph.add_edge(START, "detect")                 # 开始 → 检测
graph.add_edge("detect", "analyze")             # 检测 → 分析

# 4. 条件分支:分析之后根据 need_review 动态路由
graph.add_conditional_edges(
    "analyze",                                  # 源节点
    route_by_review,                            # 路由函数
    {
        "human_review": "human_review",         # need_review=True → 人工审核
        "pass": "pass",                         # need_review=False → 通过
    }
)

# 5. 终止边:人工审核和通过节点都连接到 END
graph.add_edge("human_review", END)
graph.add_edge("pass", END)

# 6. 编译图,生成可执行的工作流
app = graph.compile()


# ========================= 运行工作流 =========================
# 测试输入(包含脏话和政治敏感词,预期触发人工审核)
user_input_2 = "这是一个美好的国家"
result_2 = app.invoke({
    "user_input": user_input_2,
    "detection_result": "",
    "sensitive_words": "",
    "reason": "",
    "risk_level": "",
    "need_review": False,
    "review_decision": "",
    "final_result": ""
})



# ========================= 生成并导出流程图 =========================
# 使用 Mermaid 语法生成可视化流程图,封装为 HTML 文件
mermaid_str = app.get_graph().draw_mermaid()
html_content = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Content Detection Agent Flow</title>
</head>
<body>
<pre class="mermaid">{mermaid_str}</pre>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({{startOnLoad:true}});</script>
</body>
</html>"""

# 保存 HTML 流程图文件
output_path = r"e:\langGraphTest\001demo\flowchart_agent.html"
with open(output_path, "w", encoding="utf-8") as f:
    f.write(html_content)
print(f"\n流程图已保存到: {output_path}")
print("请在浏览器中打开该文件查看流程图")

2、代码运行结果测试


【节点2】正在分析检测结果...
  LLM原始返回: {
    "need_review": false,
    "decision": "通过",
    "analysis_reason": "输入内容为中性描述,未包含政治敏感词或脏话,风险评级为低,无需人工审核。"
}

==================================================
  ✅  内容通过检测
==================================================
  用户输入: 这是一个美好的国家
  风险评级: 低
  检测结果: 通过
==================================================

流程图已保存到: e:\langGraphTest\001demo\flowchart_agent.html
请在浏览器中打开该文件查看流程图

3、代码执行的流程图

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐