**摘要:**本文介绍 LangChain 1.0 中 Runtime 运行时的核心概念与实战用法。Runtime 是由 LangGraph 提供的依赖注入容器和执行环境,负责统一调度临时信息、外部资源、会话记忆、流式输出、权限身份等,让 Agent 在执行任务时通过 Runtime 获取 Context 上下文、Store 存储对象和 State 状态。文章通过源码截图和完整代码示例,详细演示了如何创建自定义上下文、通过 invoke 的 context 参数传递数据、在工具中使用 ToolRuntime 注入并访问上下文,以及通过 Command 更新状态和 Store 保存长期记忆,帮助读者理解 Runtime 如何简化工具开发、减少重复传参。
内容参考于:图灵AI大模型全栈
Runtime运行时在LangChain1.0版本后出的,它是由LangGraph提供的一个依赖注入的容器和执行环境,可以把Runtime看着是Agent使用的一个微型的工作台操作系统,所有临时的信息、外部资源、会话的记忆、流式是醋壶的内容、权限身份都由Runtime统一调度,就是给Agent的大脑和手脚提供一个完整的有序的工作环境
简单说Agent在执行一次任务的时候可以通过Runtime获取Context上下文、Store存储对象(可以用来获取长期记忆)、State状态,Agent任务执行完Runtime也就没有了,Agent再次执行新任务时又会创建一个新Runtime,在现在的LangChain中Runtime指的是ToolRuntime
Runtime
如上图如果不存在Runtime我们在写工具时如果用到了配置信息,比如数据库连接、用户id、apikey这种,每个工具都要通过参数进行传递,你写10个工具就要写十份配置信息的入参,这就导致代码重复传参,测试也很难,全局变量还容易冲突,而如果有了Runtime,我们只需要传递一个Runtime类型的参数就能都解决了,LangChain把配置信息、全局数据全都放到了一个类中,这些信息只需要初始化一次后面直接在工具中使用即可,这样工具从多参数就变成了单个Runtime类型的参数
Runtime里封装的内容说明:
Context上下文:它里面存放用户信息、配置、Apikey等,它的规定是静态数据,不能随意修改,想修改数据可以修改state里的数据
Store存储:它是数据库,可以读写长期记忆,可以通过工具存储用户的偏好和手动保存的内容
StreamWriter流式输出:自定义流式输出,工具中的日志、工具执行状态可以通过它反馈出来让我查看工具的执行状态
ExecutionInfo执行信息:元数据,这次会话的信息、线程id、运行id、重试次数,用来做日志追踪
ServerInfo服务器信息:它需要LangSmith部署才会用到有了Runtime我们在开发工具时就可以只关注业务代码、业务参数,不需要关心配置信息了,它会创建多个 Runtime 实例来保存不同用户的信息,也就从环境配置中脱离出来只关注业务
如下图红框源码中写的 Runtime 可以获取的所有内容,在执行不同的工具中 Runtime 它的内容在当前Agent的任务中都是固定的,除非在工具里手动修改了
看代码比较好理解
如下图首先创建一个类
然后再调用大模型时创建Context的实例并给到invoke方法中的context参数
然后如下图红框,LangChain会传进来一个Runtime类型的数据,就是通过 invoke 调用大模型,大模型思考我们的问题,然后生成调用工具的入参,然后LangChain会把大模型的入参拼接成Runtime类型传递到工具里(注入的过程),它 ToolRuntimeContext 是固定的参数,但是被ToolRuntimeContext修饰的runtime变量可以动态的添加数据
然后就可以通过LangChain提供的变量来访问对应的数据了,这样工具的参数只需传递一个Runtime其它的我们都不需要管
它的整体逻辑就是首先创建一个自定义的上下文,然后在工具如入参里使用ToolRuntime类型做修饰,把上下文传递给ToolRuntime进行注入(注入的意思是把我们自定义的上下文里的内容放到runtime变量里),然后通过invoke方法的context参数传递自定义的上下文,LangChain会把大模型回复的内容自动转换成ToolRuntime类型,然后就可以通过ToolRuntime类型提供的变量取出对应的数据
上下文可以传递的类型
按着CTRL鼠标左键单击下图红框
然后再按着CTRL鼠标左键单击下图红框
然后再按着CTRL鼠标左键单击下图红框
它支持下图红框的四种类型
TypedDictLikeV1 / TypedDictLikeV2的代码实例
pythonclass State(TypedDict): messages: list count: int state: State = {"messages": [], "count": 0} 正确 state["messages"] state["count"] state.get("count", 0) "count" in state 错误:dict 不支持属性访问 state.messages # AttributeErrorDataclassLike的代码实例,本章的代码实例就用的DataclassLike方式
pythonfrom dataclasses import dataclass, field @dataclass class State: messages: list = field(default_factory=list) count: int = 0 state = State(messages=[], count=0) 正确 state.messages state.count getattr(state, "count") 错误:dataclass 不支持字典下标 state["messages"] # TypeErrorBaseModel代码实例,它是pydantic
pythonfrom pydantic import BaseModel, Field class State(BaseModel): messages: list = Field(default_factory=list) count: int = 0 state = State(messages=[], count=0) 正确 state.messages state.count getattr(state, "count") 通常不支持字典下标 state["messages"] # TypeError: 'State' object is not subscriptable
效果图:

它的流程,这个流程先看完下方的代码,再看这里的流程否则看不懂
1.创建自定义上下文,创建方式有TypedDictLikeV1、TypedDictLikeV2、DataclassLike、BaseModel
2.然后通过agent.invoke函数中的 context 参数传递自定义上下文,LangChain会通过大模型的回复给我们自动组装成Runtime类型
3.在工具中通过ToolRuntime获取上下文 ToolRuntimeContext.state"messages"可以得到短期记忆,ToolRuntimeContext.context可以得到我们通过invoke函数中的 context 参数传递的内容
4.修改state中的内容在工具中通过return Command函数来实现
上面看不懂,直接看代码
python
from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain_core.messages import ToolMessage
from langgraph.types import Command # 可以在工具中修改状态
from langgraph.store.memory import InMemoryStore
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent, AgentState
from langchain_qwq import ChatQwen
from dotenv import load_dotenv
import os
加载环境变量
load_dotenv()
初始化模型
llm = ChatQwen(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url=os.getenv("DASHSCOPE_BASE_URL")
)
自定义状态
class CustomAgent(AgentState):
# 用户爱好
user_hobby: list[str]
自定义上下文的属性
@dataclass #
class Context: # 名字随便取 UserContext
user_id: str # 用户id
user_name: str # 用户名称
创建工具
@tool
def get_user_name(runtime: ToolRuntime[Context]): # 在工具中使用runtime,runtime只存在一次任务中
"""获取用户姓名"""
print(runtime.state["messages"]) # 获取状态(短期记忆)
return runtime.context.user_name # 工具返回值会自动处理转成ToolMessage
@tool
def set_user_hobby(hobby: list[str], runtime: ToolRuntime[Context]): # state是存在一次会话中的
"""设置用户爱好"""
print(f"提取的用户爱好:{hobby}")
# state是短期记忆,要想长期保存需要使用长期记忆 长期记忆会在langgraph详细介绍
print(f"{runtime.config.get('configurable').get('thread_id')}", runtime.context.user_name)
# 构造的 Namespace 和存放路径,命名空间
# runtime.context.user_id是用户id
# memories意思是记忆
# 如果想要存储别的东西,可以在这里修改
# 注意 命名空间 的值是要有意义的,就是通过看命名空间就可以知道它是做什么的
# 比如下方 runtime.context.user_id是用户id "memories"是记忆,一眼可以看出这是用户的记忆信息
namespace = (runtime.context.user_id, "memories") # 对应:(用户ID, 记忆类别)
key = "user_profile" # 记忆条目的 Key
# 新增长期记忆
store.put(
# 存储当前用户的记忆相关的内容,比如爱好
namespace=namespace,
key=key,
value={
"user_name": runtime.context.user_name,
"hobby": hobby
}
)
# 可以使用command在工具中更新状态,它是专门用来改状态信息的
# runtime.state["messages"] 可以获取状态
return Command(
update={ # 更新Agent的state状态
"user_hobby": hobby,
"messages": [
ToolMessage(
content=f"已更新用户爱好:{hobby}",
tool_call_id=runtime.tool_call_id
)
]
}
)
创建一个内存的长期记忆
store = InMemoryStore() # 存储容器-用户的长期记忆
创建一个内存的短期记忆(state)
checkpointer = InMemorySaver()
创建代理
agent = create_agent(
model=llm, # 模型
# 设置工具
tools=[get_user_name, set_user_hobby],
# 设置自定义的state(状态)
state_schema=CustomAgent,
# 设置长期记忆存储方式
store=store,
# 设置短期记忆存储方式
checkpointer=checkpointer,
# 设置上下文类型
context_schema=Context,
)
config = {"configurable": {"thread_id": "user_1"}}
runtime的生命周期是Agent执行一次任务
response = agent.invoke(
{"messages": [{"role": "user", "content": "我的名字叫什么"}]},
config=config,
# 传递当前任务的上下文,它可以传递对象类型
context=Context(user_id="user1", user_name="计算机王")
)
print(response["messages"][-1].content)
print("------更新用户爱好------")
response = agent.invoke(
{"messages": [{"role": "user", "content": "我目前的爱好喜欢编程、看电视、看球赛等"}]},
config=config,
context=Context(user_id="user1", user_name="计算机王")
)
print("长期记忆中存储的内容:", store.get(("user1", "memories"), "user_profile"))










