目的
为避免一学就会、一用就废,这里做下笔记
内容
在 LangGraph 中,context_schema 和 config_schema 是两个用于类型安全和数据传递的重要概念,但它们服务于不同的目的。
🎯 核心区别
| 维度 | context_schema |
config_schema |
|---|---|---|
| 用途 | 节点间共享的只读上下文 | 运行时可配置参数 |
| 生命周期 | 整个图执行期间不变 | 每次调用可不同 |
| 修改权限 | 只读,节点不能修改 | 可读,通常不修改 |
| 使用场景 | 共享资源、依赖注入 | 运行时配置、用户参数 |
| 传递方式 | 编译时注入 | 调用时传入 |
📦 1. context_schema:共享上下文
context_schema 用于在图的所有节点间共享只读数据,比如数据库连接、API 客户端、配置对象等。
定义和使用
python
from typing import TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
# 1. 定义 context 的类型
class MyContext(TypedDict):
db_connection: str # 数据库连接
api_client: object # API 客户端
model_config: dict # 模型配置
user_id: str # 用户ID(只读,这里作为反例看)
# 2. 定义 state
class State(TypedDict):
messages: list
results: list
# 3. 在节点中访问 context
def process_node(state: State, context: MyContext):
# context 是只读的,不能修改
db = context["db_connection"]
user = context["user_id"]
# 可以读取,但不能赋值给 context
print(f"Processing for user: {user}")
# 修改 state 是允许的
return {"results": ["processed"]}
# 4. 编译时注入 context
graph = (
StateGraph(State)
.add_node("process", process_node)
.compile(
context_schema=MyContext, # 指定 context 类型
context={
"db_connection": "postgresql://localhost/db",
"api_client": some_client,
"model_config": {"temperature": 0.7},
"user_id": "user_123"
}
)
)
典型使用场景
python
# 场景1: 共享数据库连接
class AppContext(TypedDict):
db_pool: object
redis_client: object
logger: object
def query_node(state, context):
# 从 context 获取连接
db = context["db_pool"]
result = db.execute("SELECT * FROM users")
return {"data": result}
# 场景2: 依赖注入
def ml_node(state, context):
model = context["model"] # 注入预训练的模型
prediction = model.predict(state["features"])
return {"prediction": prediction}
⚙️ 2. config_schema:运行时配置
config_schema 用于定义每次调用时可以传入的配置参数 ,通过 RunnableConfig 传递。
定义和使用
python
from typing import TypedDict, Optional
from langgraph.graph import StateGraph
from langgraph.config import RunnableConfig
# 1. 定义配置类型
class MyConfig(TypedDict):
thread_id: str # 线程ID
user_id: str # 用户ID
temperature: float # LLM 温度
max_tokens: Optional[int] # 最大token数
debug_mode: bool # 调试模式
# 2. 状态定义
class State(TypedDict):
messages: list
response: str
# 3. 在节点中访问 config
def llm_node(state: State, config: RunnableConfig):
# 从 config 中读取配置(类型安全)
configurable = config.get("configurable", {})
temperature = configurable.get("temperature", 0.7)
user_id = configurable.get("user_id")
# 根据配置调整行为
if configurable.get("debug_mode"):
print(f"Debug: Processing for user {user_id}")
# 使用配置调用 LLM
response = call_llm(state["messages"], temperature=temperature)
return {"response": response}
# 4. 编译时指定 config_schema
graph = (
StateGraph(State)
.add_node("llm", llm_node)
.compile(config_schema=MyConfig) # 指定 config 类型
)
# 5. 调用时传入配置
config = {
"configurable": {
"thread_id": "thread_123",
"user_id": "user_456",
"temperature": 0.9,
"debug_mode": True
}
}
# 执行时传入配置
for chunk in graph.stream(
{"messages": [("human", "Hello")]},
config=config # 运行时配置
):
print(chunk)
与 LangGraph 内置配置的集成
python
from langgraph.config import get_config
def my_node(state):
# 可以在节点内直接获取配置
config = get_config()
user_id = config.get("configurable", {}).get("user_id")
# 或者使用 config_schema 定义的字段
temperature = config["configurable"]["temperature"]
return {"result": f"Processed for {user_id}"}
🔄 实际对比示例
python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.config import RunnableConfig
# 定义 context - 编译时固定
class AppContext(TypedDict):
db_connection: str # 数据库连接(整个应用共享)
model_path: str # 模型路径(不变)
# 定义 config - 运行时可变
class RuntimeConfig(TypedDict):
user_id: str # 每次调用不同
temperature: float # 可调整
batch_size: int # 批处理大小
# 状态
class State(TypedDict):
query: str
results: list
# 节点实现
def process_node(state: State, context: AppContext, config: RunnableConfig):
# context: 只读,编译时确定
db = context["db_connection"]
# config: 运行时配置
runtime = config.get("configurable", {})
user_id = runtime.get("user_id")
temperature = runtime.get("temperature", 0.7)
# 使用两者
print(f"Using DB: {db}")
print(f"Processing for user: {user_id} with temp={temperature}")
# 查询数据库(使用 context 的连接)
# 调用模型(使用 config 的参数)
return {"results": ["result1", "result2"]}
# 编译图
graph = (
StateGraph(State)
.add_node("process", process_node)
.add_edge(START, "process")
.add_edge("process", END)
.compile(
context_schema=AppContext,
context={
"db_connection": "postgresql://prod/db",
"model_path": "/models/v2/model.pkl"
},
config_schema=RuntimeConfig
)
)
# 每次调用可以传入不同的 config
# 用户 A 的请求
config_a = {
"configurable": {
"user_id": "user_a",
"temperature": 0.9,
"batch_size": 100
}
}
graph.stream({"query": "data for user A"}, config=config_a)
# 用户 B 的请求
config_b = {
"configurable": {
"user_id": "user_b",
"temperature": 0.5,
"batch_size": 50
}
}
graph.stream({"query": "data for user B"}, config=config_b)
📊 选择指南
| 场景 | 使用 context_schema | 使用 config_schema |
|---|---|---|
| 数据库连接池 | ✅ 适合 | ❌ 不适合 |
| API 密钥 | ✅ 适合 | ⚠️ 可考虑 |
| 用户 ID | ❌ 不适合 | ✅ 适合 |
| 模型超参数 | ❌ 不适合 | ✅ 适合 |
| 第三方客户端 | ✅ 适合 | ❌ 不适合 |
| 调试开关 | ❌ 不适合 | ✅ 适合 |
| 环境配置 | ✅ 适合 | ⚠️ 可考虑 |
💡 最佳实践
1. 分离关注点
python
# context: 基础设施和依赖
class Context(TypedDict):
db: DatabasePool
cache: RedisClient
logger: Logger
# config: 业务参数
class Config(TypedDict):
user_id: str
session_id: str
feature_flags: dict
2. 类型安全
python
from typing import TypedDict, Optional
class MyContext(TypedDict):
db: str
api_key: str
class MyConfig(TypedDict):
user_id: str
temperature: float
debug: Optional[bool] # 可选字段
3. 默认值处理
python
def my_node(state, config: RunnableConfig):
# 安全地获取配置值
configurable = config.get("configurable", {})
temperature = configurable.get("temperature", 0.7) # 默认值
debug = configurable.get("debug", False)
# context 必须有值(编译时保证)
# ...
🎯 总结
context_schema:编译时注入的只读共享数据,用于依赖注入和全局资源config_schema:运行时传入的可变配置,用于个性化每次调用
两者的结合让 LangGraph 能够既保持图的结构稳定,又能在每次执行时灵活配置行为,同时保证类型安全。