Langchain-core 统一运行协议 Runnable


1.思考:不用 Runnable,我们写链式代码会是什么样?
点击查看代码
def to_upper(s:str):
return s.upper()
def add_suffix(s:str):
return s + " --processed"
# 调用:一层一层嵌套
input_text = "hello world"
res1 = to_upper(input_text)
res2 = add_suffix(res1)
print(res2)
# HELLO WORLD --processed
#同步调用、异步调用、批量跑一堆输入、流式返回**,每个函数我都要自己手写 4 套逻辑
2.RunnableLambda:把普通函数包成 Runnable
点击查看代码
from langchain_core.runnables import RunnableLambda
def to_upper(s:str):
return s.upper()
def add_suffix(s:str):
return s + " --processed"
r_upper = RunnableLambda(to_upper)
r_suffix = RunnableLambda(add_suffix)
# 管道 | :把两个runnable拼接起来
chain = r_upper | r_suffix
# chain 本质就是 RunnableSequence
result = chain.invoke("hello world")
print(result) # HELLO WORLD --processed
# 执行 `r_upper | r_suffix`,触发 Runnable 内部的 `__or__`运算符,生成一个`RunnableSequence(steps=[r_upper, r_suffix])`对象。

| other 类型 | 说明 |
|---|---|
| Runnable[Any, Other] | 已经是 Runnable 实例,直接用 |
| Callable[[Any], Other] | 普通同步函数 func(x) → 包装成 RunnableLambda |
| Callable[[Iterator[Any]], Iterator[Other]] | 同步迭代器函数(流式处理) |
| Callable[[AsyncIterator[Any]], AsyncIterator[Other]] | async 迭代器函数,适配流式输出 |
| Mapping[str, ...] | {"key": another_runnable}→ 生成RunnableParallel` 并行分支 |
3.RunnablePassthrough:透传
点击查看代码
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
def upper_name(d:dict):
return d["name"].upper()
chain = (
RunnablePassthrough.assign(
name_upper = RunnableLambda(upper_name)
)
)
res = chain.invoke({"name":"alice"})
print(res)
# {'name': 'alice', 'name_upper': 'ALICE'}
4.RunnableMap,并行输出多个结果
点击查看代码
from langchain_core.runnables import RunnableLambda, RunnableMap
r_upper = RunnableLambda(lambda s: s.upper())
r_lower = RunnableLambda(lambda s: s.lower())
# RunnableMap:同一个输入,同时喂给多个runnable,输出字典
map_chain = RunnableMap({
"origin": RunnableLambda(lambda x:x),
"upper": r_upper,
"lower": r_lower
})
res = map_chain.invoke("Hello")
print(res)
# {'origin': 'Hello', 'upper': 'HELLO', 'lower': 'hello'}
5.RunnableRouter,条件分支
点击查看代码
from langchain_core.runnables import RunnableLambda, RunnableRouter
r_even = RunnableLambda(lambda x: x + 1)
r_odd = RunnableLambda(lambda x: x * 2)
# router函数:接收输入,返回key,用来选择runnable
def route_func(num:int) -> str:
if num % 2 == 0:
return "even_key"
else:
return "odd_key"
router_chain = RunnableRouter(
router=route_func,
runnables={
"even_key": r_even,
"odd_key": r_odd
}
)
print(router_chain.invoke(4)) # 偶数 4+1=5
print(router_chain.invoke(5)) # 奇数 5*2=10
6.RunnableConfig 运行时上下文
点击查看代码
#RunnableConfig 不是业务输入数据,是链路的附加环境信息,整条链路透传。
from langchain_core.runnables import RunnableLambda
from langchain_core.runnables.config import RunnableConfig
def show_config(x:int, config:RunnableConfig):
print(f"拿到config: {config['tags']}")
return x * 10
r = RunnableLambda(show_config)
cfg = RunnableConfig(tags=["test_demo"])
res = r.invoke(2, config=cfg)
# 打印:拿到config: ['test_demo']
print(res) #20
7.完整示例
点击查看代码
from langchain_core.runnables import (
RunnableLambda, RunnablePassthrough, RunnableMap, RunnableRouter
)
from langchain_core.runnables.config import RunnableConfig
# 1.基础lambda
add1 = RunnableLambda(lambda x: x+1)
mul2 = RunnableLambda(lambda x: x*2)
# 2.路由分支
def rt_func(x):
return "even" if x%2==0 else "odd"
router = RunnableRouter(
router=rt_func,
runnables={"even":add1, "odd":mul2}
)
# 3.整体管道:先路由,再做map并行输出
full_chain = router | RunnableMap({
"raw_input": RunnableLambda(lambda x:x),
"double": RunnableLambda(lambda x:x*100)
})
config = RunnableConfig(tags=["full_demo"])
out = full_chain.invoke(4, config=config)
print(out)
# raw_input = 5(4是偶数执行+1),double = 500
| 类/接口 | 作用 |
|---|---|
🅰️Runnable抽象类 |
规定所有组件必须有 invoke/ainvoke/batch...这一套接口 |
🅲RunnableLambda |
把普通函数包装成标准 Runnable |
🅲RunnableSequence |
`管道生成,顺序执行一组 runnable |
🅲RunnablePassthrough |
透传字典数据,.assign()追加字段 |
🅲RunnableBinding |
.bind()产生,包装绑定参数 |
🅲RunnableMap |
同一个输入并行跑多个 runnable,输出字典 |
🅲RunnableRouter |
根据输入做 if‑else 分支路由 |
🅲RunnableConfig |
全链路透传的上下文环境对象,和业务数据分开 |
浙公网安备 33010602011771号