一些容易混淆的点(个人记录)

53 阅读4分钟

config 和 configurable

config

是框架的标准流转载体,必须是请求内的局部变量,并发处理

configurable

configurable是config字典中的特殊字段,专门用来装载动态、因人而异、随时可配置的自定义参数。
存储着thread_id 和 checkpointer_id,一个是线程id,一个是节点id,精准定位。
需要注意的是,这里面的checkpoint_id是手动传进去的,是为了实现时间旅行。正常来说checkpoint_id只会存进checkpoint数据库

config = {
    # ------  config 层的“系统标准参数” ------
    "tags": ["v1.0", "production"],  # 给这次运行打标签,方便在 LangSmith 里搜索
    "metadata": {"source": "web"},   # 附加元数据
    "recursion_limit": 50,           # 【系统参数】:防止图陷入死循环,最多跑50步
    "callbacks": [my_custom_handler],# 【系统参数】:埋点监听器
    
    # ------  configurable (定制表单) ------
    "configurable": {
        # 【LangGraph 专属字段】
        "thread_id": "user_123",       # 抽屉钥匙
       # "checkpoint_id": "1ef8...",    # 时光机钥匙
        
        # 【塞自己的自定义字段!】
        "user_vip_level": "gold",      # 比如传一个用户的 VIP 等级进去
        "llm_temperature": 0.7         # 动态决定这次大模型的温度
    }
}

Pydantic模型实例Query 和 state:

Query:

定义的是请求体的格式类型
JSON 由模型反序列化和校验 为message字典列表 和 thread _id

    from pydantic import BaseModel   
    #这是 FastAPI 的专属数据类型
    class Query(BaseModel):
        question: str
        thread_id: str

State:

编排层文本内容 state存的是消息对象列表 sysmesg usermesg aimesg toolmesg,也就是单独的question

from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages

# 这是 LangGraph 的专属数据类型
class AgentState(TypedDict):
    # messages 字段专门用来存聊天记录
    # Annotated[..., add_messages] 是魔法,代表新消息会自动追加,而不是覆盖
    messages: Annotated[list, add_messages] 
    
    # 你还可以随意加别的字段,比如大模型如果查了天气,就存在这里
    # current_weather: str

两者关系

· 通过FastAPI业务逻辑:

  1. 接收 Query 实例中提取的请求体原始数据(如字符串 question 和 thread_id)。
  2. 格式转换:将通用字符串/字典转换为 LangGraph 能够识别的特定对象: · question → HumanMessage(content=question) · 历史消息列表 → List[HumanMessage, AIMessage, ...]
  3. 构造编排层所需参数: · 初始 State 字典:{"messages": [...]} · Config 字典:{"configurable": {"thread_id": query.thread_id}}
@app.post("/chat/stream")
async def chat_stream(query: Query): # <--- 拿到 FastAPI 的 Query 对象
    
    # 1. 提取钥匙
    config = {"configurable": {"thread_id": query.thread_id}}
    
    # 2. 提取文本
    #    把 Query 里的纯文本 question,包装成 LangChain 标准的 HumanMessage,并塞进一个字典,这个字典的格式必须跟 AgentState 一模一样!
    initial_state_data = {
        "messages": [HumanMessage(content=query.question)]      }
    
    # 3. 把初始的 state 数据交给 LangGraph 开始跑
    async for event  
ingraph.astream_events(initial_state_data, config):
       

数据流通详情

文字简洁版

请求中的config
请求中的thread_id
数据库中checkpointers表 数据库中State[xx message]
config 中的 thread_id → 数据库中checkpointers表→ 查历史中 State → Reducer 合并 → 执行流转 → 存回 checkpointer"这一完整链路

文字详细版

客户端层 JSON 浏览器将对话历史(messages 数组)和会话标识(thread_id 字符串)封装为 JSON 对象,通过 HTTP POST 请求体发送至服务器。

ASGI 服务器层 scope + JSON 服务器接收到请求后立即创建 ASGI scope 字典,内含请求方法、路径、头等元信息,该 scope 贯穿整个请求生命周期,为后续处理提供上下文容器。

FastAPI 路由层 scope匹配路由 + Pydantic模型对请求体反序列化得到消息字典和thread_id FastAPI 根据 scope 中的路径匹配对应路由函数,读取请求体中的 JSON 字符串,依据 Pydantic 模型(如 ChatRequest)进行反序列化与校验,得到Pydantic 模型实例 ,包含messages 字典列表和 thread_id 的 Python 对象。

FastAPI 转换层 格式转化 得到消息对象列表 构建state的messages 和 构建config 在路由函数内部,将 messages 字典列表转换为 LangChain 消息对象列表(HumanMessage、AIMessage),并以此内容 构建初始 State 字典的 messages 字段;同时从 thread_id 构造 config 字典({"configurable": {"thread_id": ...}})。

LangGraph 编排层(合并阶段) 合并state graph.invoke 接收初始 State 与 config,用 thread_id 查询数据库 checkpoints 表,获取该会话最近一次存储的历史 State,通过 Reducer 规则将历史 messages 与本次传入的 messages 合并,形成包含完整对话上下文的运行时 State。

LangGraph 编排层(执行阶段) 追加state 合并后的 State 依次流经图中各节点,节点每次返回局部更新(如追加一条 AIMessage),编排引擎自动将更新合并入 State,直至条件边判定流程结束。

LangGraph 编排层(持久化阶段) checkpoint 执行完毕后,最终 State 与当前 thread_id 绑定,系统生成新的 checkpoint_id 并连同父检查点引用一同序列化存入 checkpoints 表,形成可追溯的版本链。

响应返回层 编排层从最终 State 的 messages 列表末尾提取模型回答文本,返回至 FastAPI,FastAPI 将其与 thread_id 封装为 JSON 响应体,经 HTTP 送回浏览器,浏览器将回答追加至本地对话历史并渲染。

前后端流转

编排层流转

编排层数据流转

image.png