libs/core 第一轮精读

摘要

libs/core 对应发布包 langchain-core,它是 LangChain 生态的基础抽象层,明确不承载第三方 provider 集成。当前最重要的阅读结论是:langchain_core.runnables 是统一调用协议与 LCEL 的核心入口,而真正的实现重心主要位于 langchain_core/runnables/base.pyconfig.py

仓库定位

包级身份

  • 包名:langchain-core
  • 版本:1.3.0
  • Python 要求:>=3.10,<4.0
  • 描述:Building applications with LLMs through composability

官方定位

根据 libs/core/README.mdlangchain_core/__init__.py

  • langchain-core 定义 LangChain 生态的基础抽象
  • 包含 chat models、LLMs、retrievers、vector stores 等接口
  • 统一调用协议(Runnables)和组合语法也定义在这里
  • 不包含第三方 integrations,依赖刻意保持轻量

目录结构(第一轮)

libs/core/langchain_core/ 下目前最值得优先关注:

  • runnables/:统一调用协议与 LCEL
  • prompts/:Prompt 抽象
  • language_models/:模型接口
  • messages/:消息类型
  • output_parsers/:输出解析
  • tools/:Tool 抽象
  • retrievers.py:检索器接口
  • documents/:文档类型
  • callbacks/tracers/:回调与追踪

Runnable 入口与导出面

入口文件

  • libs/core/langchain_core/runnables/__init__.py

入口作用

该文件主要负责:

  • 暴露 Runnable 公共 API
  • 通过动态导入将 API 分发到具体实现文件
  • 定义 LCEL 相关的公开符号

公开导出的重点对象

  • Runnable
  • RunnableSequence
  • RunnableParallel
  • RunnableLambda
  • RunnableGenerator
  • RunnablePassthrough
  • RunnableAssign
  • RunnableWithFallbacks
  • RunnableWithMessageHistory
  • RunnableConfig
  • chain

Runnable 主定义

核心文件

  • libs/core/langchain_core/runnables/base.py
  • libs/core/langchain_core/runnables/config.py

关键类行号

  • Runnablebase.py:124
  • RunnableSequencebase.py:2817
  • RunnableParallelbase.py:3565
  • RunnableLambdabase.py:4399

Runnable 的执行模型

抽象基类

Runnable 被定义为:

  • 一个可 invoke
  • batch
  • stream
  • 可组合
  • 可暴露 schema/config 信息 的通用工作单元。

关键公共方法

Runnable 基类中:

  • invoke 是抽象方法,要求子类实现
  • ainvoke 默认通过 run_in_executor 包装同步 invoke
  • batch 默认用线程池并行调用多个 invoke

这说明:

  1. invoke 是真正的最小执行核心
  2. 异步默认不是“原生 async”,而是 sync fallback + executor
  3. batch 是默认并行策略,适合 IO bound 场景
  4. 子类如果能更高效批处理,需要自己 override

RunnableConfig 的作用

runnables/config.py 中的 RunnableConfig 是整个执行协议的重要胶水层。

关键字段

  • tags
  • metadata
  • callbacks
  • run_name
  • max_concurrency
  • recursion_limit
  • configurable
  • run_id

当前理解

RunnableConfig 不只是“配置对象”,它还是:

  • tracing 元数据载体
  • 并发控制入口
  • 运行时可配置字段注入入口
  • 父子 runnable 配置传播机制的一部分

尤其重要的是:

  • var_child_runnable_configContextVar 在调用栈中传播配置
  • tracing 上下文会跟随 config 传播

两个最重要的组合原语

1. RunnableSequence

  • 定义位置:base.py:2817
  • 语义:前一个 Runnable 的输出,作为下一个 Runnable 的输入
  • 构建方式:最常见是通过 | 运算符
  • 结构:内部拆成 first / middle / last
  • 特点:自动支持 sync / async / batch

关键理解

  • 它是 LangChain 中“最重要的组合算子”之一
  • 几乎所有 chain 都会落到这个抽象上
  • sequence 的 schema 由整条链推导
  • streaming 能否贯通,取决于链中各节点是否实现 transform

很重要的一点

RunnableLambda 默认不支持 transform,所以如果链路中塞了 lambda,可能会阻断 streaming 的贯通。

2. RunnableParallel

  • 定义位置:base.py:3565
  • 语义:同一个输入并发喂给多个 Runnable,输出按 key 聚合成 dict
  • 构建方式:可直接构造,也可在 sequence 中使用 dict literal 自动 coercion

关键理解

  • 这是另一条核心组合原语
  • 它会把多个 step 的 input schema / output schema 聚合起来
  • 很适合 fan-out 结构:同一个输入并发跑多个链路

RunnableLambda 的作用

  • 定义位置:base.py:4399
  • 作用:把普通 Python callable 包装成 Runnable
  • 优点:接入门槛低、组合方便、自动接 tracing
  • 限制:默认更适合非 streaming 逻辑

特别注意

如果一个 RunnableLambda 返回的是另一个 Runnable,那么这个返回值会在运行时继续被 invoke / stream。

测试层线索

当前最值得优先阅读的测试

  • libs/core/tests/unit_tests/runnables/test_runnable.py
  • libs/core/tests/unit_tests/runnables/test_runnable_events_v2.py
  • libs/core/tests/unit_tests/runnables/test_runnable_events_v1.py
  • libs/core/tests/unit_tests/runnables/test_history.py
  • libs/core/tests/unit_tests/runnables/test_fallbacks.py

为什么先看这些

  • test_runnable.py 是 Runnable 总测试入口,覆盖面最广
  • test_runnable_events_v2.py 能反推 tracing / event stream 的真实对外契约
  • 测试中大量使用 Fake* 模型与 retriever,说明 LangChain 在 core 层很重视“协议先行、假对象验证”

第一轮结论

  1. libs/core 是全生态基础抽象层,不是具体 provider 实现层。
  2. langchain_core.runnables 是当前最值得优先精读的中心模块。
  3. base.py 是 Runnable 体系的真正核心大文件。
  4. invoke 是最小执行原语,ainvoke / batch / stream 都是围绕它扩展。
  5. RunnableSequenceRunnableParallel 是两大组合原语。
  6. RunnableConfig 是执行、追踪、并发、配置传播的统一入口。
  7. 想理解真实行为,必须结合 tests/unit_tests/runnables/ 一起看。

下一步建议

  1. 精读 RunnableSequence.invoke/batch/stream 的具体实现
  2. RunnableParallel 如何做并发和 schema 聚合
  3. 深挖 transform / astream_events / tracing 的关系
  4. 对照 promptslanguage_modelstools 看它们如何实现 Runnable 协议

未解问题

  • transform 的默认行为和 override 机制到底怎么组织?
  • stream / astream_log / astream_events 的边界分别是什么?
  • toolsRunnable 在 core 层的关系是继承、适配还是包装?
  • langchain_v1 里哪些高层抽象只是对 core Runnable 的组合封装?