18.2 PostgreSQL 的安装

这个操作指南将带你一步步完成 PostgreSQL 的安装与配置,并最终整合到 LangGraph 中,让你的 Agent 拥有基于数据库的、可靠的"长期记忆"。


💻 准备工作

开始前,请确认你的电脑满足以下条件:

  1. 操作系统:Windows 10/11。
  2. 环境:已安装 Python 3.9 或更高版本。
  3. 工具:拥有管理员权限,并且可以访问互联网以下载软件。

🗄️ 第一步:安装与配置 PostgreSQL

我们从官网下载并安装 PostgreSQL。

  1. 下载安装包 :访问 PostgreSQL 官网,下载适合你系统的 Windows 版本(推荐最新版本)。下载的文件通常是一个名为 postgresql-xx.x-windows-x64.exe 的安装程序。
  2. 运行安装程序 :双击运行安装程序,按照向导的指引进行安装。在安装过程中,请务必记住你设置的数据库超级用户密码
  3. 选择组件和目录
    • 选择组件:按默认设置安装即可,但推荐将"Command Line Tools"、"PostgreSQL Server"和"pgAdmin 4"全部安装。
    • 选择数据目录 :尽量选择一个非系统盘(如 D:\PostgreSQL\xx\data)来存放数据,这样可以避免系统盘空间不足的问题。
    • 完成安装 :安装结束后,PostgreSQL 服务通常会自动启动并设为开机自启。
  4. 配置环境变量 :为了让命令行能识别 psql 等命令,需要将 PostgreSQL 的 bin 目录(例如 C:\Program Files\PostgreSQL\xx\bin)添加到系统的 PATH 环境变量中。
  5. 验证安装 :打开命令提示符,输入 psql -V。如果正确返回版本信息,则环境变量配置成功。

🗄️ 第二步:创建数据库与用户

这一步是为我们的 LangGraph 应用在数据库中创建"专属空间"。

  1. 打开 psql 命令行:在开始菜单找到 "SQL Shell (psql)",并运行它。

  2. 连接到服务器:在提示符下,依次输入你在安装时设置的密码等信息,端口保持默认(通常是5432)。

  3. 创建数据库用户

    sql 复制代码
    CREATE USER langgraph_user WITH PASSWORD 'your_strong_password';
  4. 创建数据库

    sql 复制代码
    CREATE DATABASE langgraph_db;
  5. 授予权限 :将新数据库的所有权限授予刚刚创建的用户。

    sql 复制代码
    GRANT ALL PRIVILEGES ON DATABASE langgraph_db TO langgraph_user;

现在,我们的数据库和用户已经准备好了。你可以使用 \q 命令退出 psql


🐍 第三步:配置 LangGraph 开发环境

现在切换到 Python 环境,安装 LangGraph 与 PostgreSQL 集成所需要的库。

  1. 激活虚拟环境:打开你的项目终端,并激活之前课程中使用的虚拟环境。

  2. 安装依赖包

    bash 复制代码
    pip install langgraph langgraph-checkpoint-postgres psycopg[binary,pool] langchain-openai python-dotenv
    • langgraph-checkpoint-postgres:实现 LangGraph 与 PostgreSQL 连接的关键库。
    • psycopg[binary,pool]:Python 连接 PostgreSQL 的驱动。
    • langchain-openaipython-dotenv:用于配置和使用我们熟悉的 Qwen 模型。

🚀 第四步:编写 LangGraph 代码

接下来,我们用代码将这一切串联起来。

  1. 配置连接 :在 .env 文件中,存放数据库连接字符串(Database URI)。

    复制代码
    DATABASE_URI=postgresql://langgraph_user:your_strong_password@localhost:5432/langgraph_db

    这个URI的格式是:postgresql://用户名:密码@地址:端口/数据库名。具体说明如下:

    • postgresql://:固定协议头,用于连接 PostgreSQL 数据库。
    • langgraph_user:your_strong_password:替换成你之前创建的用户名和密码。
    • @localhost:5432 :指定数据库服务器地址。这里是连接本机的数据库服务,5432 是 PostgreSQL 的默认端口。
    • /langgraph_db:指定要连接的数据库名称。
    • ?sslmode=disable:一个常见参数,表示禁用 SSL 加密。
  2. 编写 Agent 代码:创建一个新的 Python 文件,然后将下面的完整代码复制进去。

    python 复制代码
    import os
    from dotenv import load_dotenv
    from langchain_openai import ChatOpenAI
    from langgraph.graph import StateGraph, MessagesState, START
    from langgraph.checkpoint.postgres import PostgresSaver
    
    load_dotenv()
    
    # 1. 获取数据库连接字符串
    DB_URI = os.getenv("DATABASE_URI")
    
    # 2. 初始化 LLM (以千问为例)
    llm = ChatOpenAI(
        model="qwen-plus",
        temperature=0.7,
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        base_url=os.getenv("DASHSCOPE_BASE_URL"),
        model_kwargs={"extra_body": {"enable_thinking": False}}
    )
    
    # 3. 定义 Agent 节点
    def call_agent(state: MessagesState):
        response = llm.invoke(state["messages"])
        return {"messages": [response]}
    
    # 4. 集成 PostgreSQL Checkpointer
    print("正在连接 PostgreSQL 数据库...")
    with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
        # *首次运行时,必须调用 setup() 以在数据库中创建 LangGraph 所需的表*
        checkpointer.setup()
        print("数据库检查点(Checkpointer)初始化完成。")
    
        builder = StateGraph(MessagesState)
        builder.add_node("call_agent", call_agent)
        builder.add_edge(START, "call_agent")
    
        # 编译 Graph 时,将 checkpointer 传入
        graph = builder.compile(checkpointer=checkpointer)
    
        thread_id = "user_12345"
        config = {"configurable": {"thread_id": thread_id}}
    
        # 第一轮对话
        user_input_1 = "你好,我叫虎哥,我最喜欢编程。"
        print(f"\n用户: {user_input_1}")
        for event in graph.stream(
            {"messages": [("user", user_input_1)]},
            config=config,
            stream_mode="values"
        ):
            event["messages"][-1].pretty_print()
    
        # 第二轮对话(检验记忆)
        user_input_2 = "你还记得我叫什么名字吗?"
        print(f"\n用户: {user_input_2}")
        for event in graph.stream(
            {"messages": [("user", user_input_2)]},
            config=config,
            stream_mode="values"
        ):
            event["messages"][-1].pretty_print()
    
    print("\n程序执行完毕,状态已存入 PostgreSQL。")

▶️ 第五步:运行与验证

  1. 运行代码 :在终端执行 python your_script_name.py
  2. 查看结果:你应该能看到 Agent 成功地"记住"了你的名字。
  3. 验证数据库 :你可以用 pgAdminpsql 连接到数据库 langgraph_db,查看 langgraph_checkpoints 等表里是否新增了记录,这证实了状态已被持久化。

🩺 第六步:常见问题排查

如果在运行中遇到问题,可以参考下面的排查步骤:

问题现象 可能原因与解决方法
ModuleNotFoundError: No module named 'langgraph.checkpoint.postgres' LangGraph 的 PostgreSQL 功能需要单独安装,请在终端执行 pip install langgraph-checkpoint-postgres 命令。
psycopg.OperationalError: FATAL: password authentication failed for user ... 代码里的数据库密码和创建时输入的不一致,请仔细核对。
psycopg.OperationalError: could not connect to server: ... 表示没有找到数据库服务,请检查本地 PostgreSQL 服务是否已启动。
代码运行后,数据库里没有新表? 在代码中,checkpointer.setup() 至关重要,这是 LangGraph 在数据库中自动创建表的指令,请确认这行代码已被执行。

💎 总结与面试准备

通过以上步骤,你的 LangGraph Agent 已经拥有了一个由 PostgreSQL 支撑的、牢靠的"记忆"。这不仅是技术的实践,也是面试中展示你工程能力的重要砝码。

面试问题 核心回答要点
LangGraph 的 PostgresSaver 在生产环境有何优势? PostgresSaver 通过数据库实现状态持久化、并发支持和故障恢复 。相比开发的 InMemorySaver,它能保证在服务重启后不丢失对话状态,是企业级部署的基础。
checkpointer.setup() 的作用是什么? setup() 方法会在 PostgreSQL 数据库中自动创建所需的系统表 (如 checkpoints 表),初始化持久化环境。
如何为不同的用户隔离会话 (session)? 通过在调用 graph.invoke 时,为 config 参数中的 thread_id 提供唯一标识符 。LangGraph 会使用该 thread_id 来区分和存取不同用户的状态。
PostgreSQL 在 LangGraph 中,核心是作为生产环境的状态持久化引擎,用来解决像 SQLite 这样的本地存储方案在生产环境中难以胜任的问题。

简单来说,PostgreSQL 承担了三大核心职责:

  • 状态持久化(Checkpoint):存储 LangGraph 在执行过程中的所有状态快照,是实现长对话、任务中断恢复和"时间旅行"调试的关键。
  • 长期记忆存储(Store):以结构化的方式,存储 Agent 跨会话的长期记忆,如用户画像或知识。
  • 语义向量存储 :通过扩展 pgvector,在数据库中直接存储和检索向量数据,简化了系统架构。

🆚 为什么是 PostgreSQL?它与 SQLite 有何不同?

对比维度 PostgreSQL (生产环境首选) ⚠️ SQLite (学习/原型首选)
定位 生产级数据库管理系统 轻量级嵌入式数据库
并发性能 高。支持高并发读写,多服务实例可同时连接。 低。写入操作是全局锁定的,不适合高并发场景。
数据规模 大。单表可存储海量数据,一个 checkpoint 字段支持最大 1GB。 小。数据库文件大小通常受限,不适合存储大量对话历史。
可靠性 高。具备完善的 ACID 事务、故障恢复等企业级特性。 基础。可靠性依赖于文件系统。
扩展性 强。支持复杂查询、自定义类型、pgvector 扩展等。 弱。功能相对基础。
部署与运维 需要独立安装、配置和管理数据库服务。 无需安装,直接通过文件使用,运维成本为零。
学习成本 较高。需要掌握 SQL 基础和数据库管理知识。 极低。

🛠️ LangGraph 与 PostgreSQL 集成实战

在 LangGraph 中集成 PostgreSQL 主要有两种方式:使用 CheckpointerStore

1. 集成 Checkpointer(状态检查点)

这是最基础也是最重要的应用,用于保存工作流的状态。

  • 安装依赖

    bash 复制代码
    pip install langgraph langgraph-checkpoint-postgres psycopg[binary,pool]
  • 代码示例

    python 复制代码
    from langgraph.checkpoint.postgres import PostgresSaver
    from psycopg_pool import ConnectionPool
    
    # PostgreSQL 数据库连接字符串
    DB_URI = "postgresql://user:pass@host:5432/langgraph_db?sslmode=require"
    
    # 创建连接池(生产环境最佳实践)
    pool = ConnectionPool(conninfo=DB_URI, max_size=10)
    # 创建并初始化检查点存储器
    checkpointer = PostgresSaver(pool)
    
    # 注意:首次使用时需要调用 checkpointer.setup() 创建数据表
    checkpointer.setup()
    
    # 假设你已经构建好了图(builder),编译时注入 checkpointer
    graph = builder.compile(checkpointer=checkpointer)
    
    # 创建线程配置,thread_id 是会话的唯一标识
    config = {"configurable": {"thread_id": "user_123"}}
    
    # 第一次执行,状态会被保存到 PostgreSQL
    # graph.invoke(initial_input, config=config)
    
    # 下一次执行时,使用相同的 thread_id 即可自动从 PostgreSQL 恢复状态
    # graph.invoke({"messages": [HumanMessage(content="继续刚刚的话题")]}, config=config)
2. 集成 Store(长期记忆)

Store 用于保存和管理 Agent 的跨会话长期记忆。

  • 安装依赖

    bash 复制代码
    pip install langgraph langgraph-store-postgres psycopg[binary,pool]
  • 代码示例

    python 复制代码
    from langgraph.store.postgres import PostgresStore
    
    store = PostgresStore.from_conn_string(DB_URI)
    store.setup()  # 首次使用时需要创建数据表
    
    # 在图的编译或运行时,将 store 对象注入
    graph = builder.compile(store=store)

🔗 图解:PostgreSQL 如何与 LangGraph 的 Checkpointer 协同工作

为了帮助你理解整个流程,下图展示了当用户与 LangGraph 驱动的 Agent 交互时,PostgreSQL 在其中扮演的角色:
PostgreSQL LangGraph 应用 User PostgreSQL LangGraph 应用 User #mermaid-svg-2DCLG5FKG09tCFea{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2DCLG5FKG09tCFea .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2DCLG5FKG09tCFea .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2DCLG5FKG09tCFea .error-icon{fill:#552222;}#mermaid-svg-2DCLG5FKG09tCFea .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2DCLG5FKG09tCFea .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2DCLG5FKG09tCFea .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2DCLG5FKG09tCFea .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2DCLG5FKG09tCFea .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2DCLG5FKG09tCFea .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2DCLG5FKG09tCFea .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2DCLG5FKG09tCFea .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2DCLG5FKG09tCFea .marker.cross{stroke:#333333;}#mermaid-svg-2DCLG5FKG09tCFea svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2DCLG5FKG09tCFea p{margin:0;}#mermaid-svg-2DCLG5FKG09tCFea .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-2DCLG5FKG09tCFea text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-2DCLG5FKG09tCFea .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-2DCLG5FKG09tCFea .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-2DCLG5FKG09tCFea .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-2DCLG5FKG09tCFea .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-2DCLG5FKG09tCFea #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-2DCLG5FKG09tCFea .sequenceNumber{fill:white;}#mermaid-svg-2DCLG5FKG09tCFea #sequencenumber{fill:#333;}#mermaid-svg-2DCLG5FKG09tCFea #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-2DCLG5FKG09tCFea .messageText{fill:#333;stroke:none;}#mermaid-svg-2DCLG5FKG09tCFea .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-2DCLG5FKG09tCFea .labelText,#mermaid-svg-2DCLG5FKG09tCFea .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-2DCLG5FKG09tCFea .loopText,#mermaid-svg-2DCLG5FKG09tCFea .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-2DCLG5FKG09tCFea .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-2DCLG5FKG09tCFea .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-2DCLG5FKG09tCFea .noteText,#mermaid-svg-2DCLG5FKG09tCFea .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-2DCLG5FKG09tCFea .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-2DCLG5FKG09tCFea .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-2DCLG5FKG09tCFea .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-2DCLG5FKG09tCFea .actorPopupMenu{position:absolute;}#mermaid-svg-2DCLG5FKG09tCFea .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-2DCLG5FKG09tCFea .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-2DCLG5FKG09tCFea .actor-man circle,#mermaid-svg-2DCLG5FKG09tCFea line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-2DCLG5FKG09tCFea :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 状态: {"messages": ...} 1. 发起新对话 (thread_id="user_123") 创建初始状态 2. 存储状态快照 (insert checkpoint) 3. 继续对话 (相同 thread_id) 4. 查询最新状态 (select * ...) 5. 返回历史状态 6. 基于历史状态继续执行 7. 存储新的状态快照 (update checkpoint)

  1. 用户发起新对话,LangGraph 应用会为该线程创建初始状态。
  2. 这个初始状态会作为一个 checkpoint 存入 PostgreSQL 数据库。
  3. 用户稍后继续对话。
  4. LangGraph 应用会带着唯一的 thread_idPostgreSQL 查询。
  5. PostgreSQL 找到该线程的历史状态并返回。
  6. LangGraph 应用得以在上次的"记忆"基础上继续对话。
  7. 执行完新一轮的操作后,最新的状态会再次存入 PostgreSQL,覆盖或新增 checkpoint

💎 面试知识点总结

面试问题 核心回答要点
你理解LangGraph的Checkpointer吗?它和Memory的关系是什么? Checkpointer 是LangGraph的核心概念,用于持久化整个图的状态 。它和 Memory(如ConversationBufferMemory不是二选一的关系,而是互补关系Memory是图中状态(State)的一部分,Checkpointer是负责把整个State保存下来的机制。
PostgreSQL在LangGraph中具体扮演什么角色? PostgreSQL是一种高性能、可扩展的Checkpointer后端存储 。它将LangGraph的状态数据持久化到磁盘,确保了即使在应用重启或发生故障后,Agent的对话历史和状态也能完整恢复,是实现生产级应用的关键。
PostgreSQL相比SQLite有哪些优势? SQLite适合本地开发和测试,而PostgreSQL是生产环境的首选 。它支持高并发 访问,数据存储容量更大 ,并提供更强大的数据一致性和故障恢复 能力,还能通过pgvector等扩展支持向量存储。
如何为LangGraph选择Memory后端(PostgreSQL vs. SQLite)? 开发/学习/小规模单机部署 :SQLite最简单。生产/高并发/多服务实例/大规模数据:必须选择PostgreSQL以保障性能和可靠性。
相关推荐
啾啾Fun1 小时前
【向量数据库】Milvus:为大规模、高性能而生的企业级向量数据库
数据库·milvus
海南java第二人11 小时前
Nebula Graph 实战:基于图数据库存储 CMDB 实体关系
数据库·图数据库·nebula
曹牧11 小时前
oracle:“not all variables bound”
数据库·oracle
数据库百宝箱11 小时前
Oracle RMAN Image Copy 本地恢复
数据库·oracle
zuYM4g7Dp12 小时前
NoSql数据库设计心得
数据库·nosql
睡不醒男孩03082314 小时前
第七篇:揭秘 PostgreSQL 数据库内核级管控:CLup 深度架构设计与高可用底座技术白皮书
数据库·postgresql·clup
cmes_love15 小时前
Level 2逐笔成交历史数据下载方法笔记
数据库·笔记·oracle
swordbob15 小时前
MySQL字符集陷阱:从Oracle迁移踩坑到utf8mb4强制规范
数据库·sql
牛油果子哥q15 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++