Skip to main content

16 · langchain_core 全地图:那个”地基包”里到底装了什么

开头的现象

老王问小林:“你能一口气说出 langchain_core 里有哪些模块吗?” 小林掰着手指头数:“messages、prompts、runnables……呃,还有……” 数到第五个就卡住了。 他打开 D:\lib\miniconda3\envs\learn-langchain\Lib\site-packages\langchain_core\ 目录,数了数——29 个模块。 小林倒吸一口凉气:“我学了两个月,只用了里面的五六个。” 他决定用一天时间把整个包翻一遍,搞清楚:每个模块是干嘛的?哪些我天天用?哪些我这辈子可能都用不上?用不上的,为什么用不上?

第一幕:小林先搞懂了 langchain_core 的”地位”——它是协议层

小林翻到 langchain_core/__init__.py,看到版本号 1.5.1。他又看了看自己装的包,恍然大悟:
他明白了:langchain_core 是”地基”——定义”接口长什么样”;各集成包是”砖头”——实现”怎么连到具体服务”。 他用的 ChatAnthropic 住在 langchain_anthropic,但它的”爹” BaseChatModel 住在 langchain_core.language_models他天天 import 的是砖头,但砖头长什么样,是地基说了算。 他还把 29 个模块分成了 5 大家族,画了一张图:
想验证”地位”吗?在 Python 里 from langchain_core.language_models import BaseChatModel,然后 issubclass(ChatAnthropic, BaseChatModel)——返回 True。你的 ChatAnthropic 就是 BaseChatModel 的孩子。

第二幕:小林逐个拜访——他标记了”天天用”的模块

小林从第①家族开始,一个一个拜访。他发现自己天天用的,集中在几个模块: messages(57 个导出)——他的老朋友。 第 02、08、10 篇的 AIMessage、tool_calls、usage_metadata 全在这。他扫了一眼导出列表,看到了 BaseMessage(爹)、HumanMessage/SystemMessage/AIMessage/ToolMessage(四个孩子)、ToolCall(工具调用结构)、trim_messages(第 4 篇说的剪枝)。“我天天用,不用复习。” prompts(21 个导出)——刚吵完架的那个。 ChatPromptTemplateMessagesPlaceholderPromptTemplate——第 3 篇刚说过。 language_models(19 个导出)——爹在这。 BaseChatModel(invoke/stream/bind_tools/with_structured_output 全定义在这)、BaseLLM(旧式文本模型)、还有一堆 FakeListChatModel 假模型。小林看到假模型,眼睛一亮:“测试用!不用真调 API 就能模拟模型回复!” embeddings(3 个导出)——第 8 篇的接口。 Embeddings 基类:embed_query/embed_documents。他的 HuggingFaceEmbeddings 就是实现这个接口的。 documents(3 个导出)——第 7 篇的盒子。 Document(page_content + metadata)、BaseDocumentTransformer(切分器的爹)、BaseDocumentCompressor(压缩器的爹)。 retrievers(1 个类)——第 9 篇的检索器。 BaseRetrieverinvoke(query) 返回 Document 列表。 vectorstores(4 个导出)——第 8 篇的库。 VectorStore(add_texts/similarity_search/as_retriever)、VectorStoreRetriever、还有 InMemoryVectorStore——小林看到这个乐了:“内存版向量库?测试不用装 Chroma 了!” runnables(29 个导出)——第 9 篇的流水线。 Runnable(invoke/stream/|/batch)、RunnablePassthroughRunnableLambdaRunnableWithMessageHistory官方废弃,别学——1.3.3 标记 deprecated,2.0 移除)。小林看到它旁边的 deprecated 标记,心里暗暗庆幸自己没在它身上浪费时间。 tools(19 个导出)——第 10 篇的 @tool。 BaseTooltool 装饰器、ToolExceptioncreate_retriever_tool 小林画了张表,标出他的使用频率:
想验证”天天用”吗?翻你自己的 .py 文件——01_first_chat.py 用了 language_models(间接)、messages;09_rag.py 用了 prompts/runnables/output_parsers/documents/retrievers/vectorstores。你早就在用了,只是没意识到它们住在哪个包里。

第三幕:小林拜访了”知道就行”的模块——以及为什么用不上

小林接着拜访剩下的模块,每个都问一句”我用得上吗”: callbacks(34 个导出)——“进阶才用,但很有用。” 监听模型/链/工具的生命周期:on_llm_starton_llm_endon_tool_start……小林心想:“做生产应用想’看到每次调用花了多少 token、耗时多久’,就写个 BaseCallbackHandler 子类。LangSmith 追踪底层就是它。” chat_history(普通模块)——“记忆的存储抽象。” BaseChatMessageHistoryInMemoryChatMessageHistory。小林想起第 10 篇:“这就是我手写 session 历史的’正规军’。LangGraph 的 checkpointer 是它的’进化版’。” exceptions(7 个导出)——“报错时认类型用。” LangChainException(所有异常的爹)、OutputParserException(解析失败)。小林点点头:“报错先看异常类型,LangChainException 是总爹,catch 它不会漏。” outputs(7 个导出)——“内部结构,日常碰不到。” LLMResultChatResult。小林解释给自己听:model.invoke() 直接给你 AIMessage,碰不到这些。它们是 generate() 批量接口和回调里的原始结构。” load(6 个导出)——“序列化,配置管理才用。” dumps/loads。小林心想:“把 prompt 存成 JSON 文件,下次加载——生产配置管理才需要。” stores(普通模块)——“通用 KV 存储。” BaseStoreInMemoryStore。小林:“比 chat_history 更底层——存任何键值数据,跨会话共享。Agent 的记忆库用它。课程用不上。” indexing(8 个导出)——“增量索引,生产文档更新才用。” index()RecordManager。小林:“第 8 篇我每次 shutil.rmtree 重建库;生产环境文档会更新,才需要只处理新文档。课程用不上。” rate_limiters(2 个导出)——“API 限速,批量调用才用。” BaseRateLimiterInMemoryRateLimiter。小林:“个人学习调 API 量小,用不上;生产批量调用才要防 429。” example_selectors(5 个导出)——“few-shot 选例子。” SemanticSimilarityExampleSelector。小林:“给模型几个例子再提问(few-shot)时,自动挑最相关的例子。做分类/抽取任务才有用。” cross_encoders(2 个导出)——“重排序,RAG 进阶才用。” BaseCrossEncoder。小林:“检索后再精排(Reranker),生产级 RAG 才用。我的 2-Step RAG 用向量相似度够了。” caches(7 个导出)、chat_loaders/chat_sessions、structured_query、agents、utils、prompt_values、document_loaders…… 小林一个个扫过,大多数是”知道存在即可”。 他特别注意到两个”容易踩雷”的: agents(普通模块)——“历史的包袱。” 里面是 AgentAction/AgentStep/AgentFinish。小林查了查,发现这是 LangChain 0.x 时代 AgentExecutor 的数据结构,现在他用 create_agent(走 LangGraph)根本不碰。“看到旧教程里 AgentExecutor/AgentAction 就明白是历史包袱。” 还有——根本没有 structured_output 模块! 小林之前找过,翻遍整个包都没有。他查了查,明白了:“结构化输出不是独立模块,是 BaseChatModel.with_structured_output() 方法 + output_parsers 里的 Pydantic 系列实现的。” 他差点因为这个跑去装不存在的包。
想验证”没有 structured_output 模块”吗?试试 from langchain_core.structured_output import ...——直接 ImportError。结构化输出在 BaseChatModel.with_structured_output() 里。

第四幕:小林给 29 个模块排了”优先级”

拜访完所有模块,小林画了一张”最终地图”:
他写下了一句总结,贴在工位上:
你 7 章学的”组件”(ChatModel/Document/Embeddings/VectorStore/Retriever/Memory/Tools/Agent)——抽象基类全在 langchain_core;具体实现在各集成包(ChatAnthropic/Chroma/HuggingFaceEmbeddings);编排在 langgraph。langchain_core = 协议层,集成包 = 实现层,langgraph = 编排层。三层各司其职。
想验证”三层各司其职”吗?from langchain_core.language_models import BaseChatModel(协议层)→ from langchain_anthropic import ChatAnthropic(实现层)→ from langgraph.graph import StateGraph(编排层)。三个 import,三层架构。

🔧 技术细节:langchain_core 关键类签名速查(本章全景)

小林把”天天用”的模块里的核心类签名整理成了一张速查表(实测签名): ① messages——消息与工具结构
② prompts——模板
③ language_models——模型基类(最常用)
④ output_parsers / embeddings / documents / retrievers / vectorstores
⑤ runnables——LCEL 引擎
⑥ tools / callbacks / exceptions
想验证吗?from langchain_core.language_models import BaseChatModel; isinstance(ChatAnthropic(...), BaseChatModel) 返回 True——证明这些签名就是”统一插口”的物理定义。help(ChatPromptTemplate.from_messages) 能看到完整签名。

结论(小林用一天换来的)

langchain_core 是 LangChain 的协议层(地基):29 个模块,5 大家族。 你真正天天用的只有 10 个(messages/prompts/language_models/embeddings/documents/retrievers/vectorstores/runnables/tools/output_parsers),其余大多是”知道存在即可”——用不上的原因是”你的场景没到那一步”(生产要观测才用 callbacks、文档会更新才用 indexing、批量调用才用 rate_limiters、RAG 进阶才用 cross_encoders)。没有 structured_output 模块(结构化输出在方法里)。agents 模块是 0.x 历史包袱。 记住”协议层/实现层/编排层”三层架构,你就抓住了整个 LangChain 的骨架。

复现信号:什么时候你会想起这一章

  1. from langchain_core.structured_output import ... 报错——没这个模块,用 with_structured_output()
  2. from langchain_core.agents import AgentExecutor 报错——agents 只有数据结构,AgentExecutor 是 langchain-classic 遗留。
  3. 想给模型加”观测”(token/耗时/日志)——写 BaseCallbackHandler 子类(callbacks 模块)。
  4. 报错搞不清类型——catch LangChainException(exceptions 模块的爹)。
  5. 想知道”这个类是哪个包定义的”——抽象在 langchain_core,实现在集成包。
小林把整个”地基”翻完了。他觉得自己理论知识差不多了,但老王说:“你学了一堆玩具(员工手册),能不能拿一份’真的’文件练练手?” 小林想起 data 目录里躺着两份真实的国家政策文件——十五五就业规划和十五五教育规划。他决定做一次”实战”:用真实文件,把学过的切块、向量化、检索全部走一遍——翻到第 16 篇:给真实政策文件做问答