Skip to main content

01 · 为什么需要 LangChain:从一次”朴素 API 调用”开始

本片目标:用一个朴素 requests 调智谱 API 的例子,展示”没有 LangChain 的世界”,再展示 LangChain 的 ChatModel 如何统一一切,并回答:LangChain 到底多做了哪几件事? 新增规定性:1(此后你调模型只有一个入口:chat_model.invoke(...)数据字典:ChatAnthropic 构造参数、AIMessage 骨架。 进程线程模型:同步 invoke 在当前线程阻塞,直到响应返回。 网络模型:一次 HTTPS POST 到 /v1/messages,JSON 请求体、JSON 响应体。

1. 上集回顾

第 00 篇我们有了环境和 API key。现在问题来了:
为什么我不直接 requests.post 调智谱的 API,而要学一个叫 LangChain 的框架?
这个问题必须在第 01 篇回答。因为如果 LangChain 只是”给 requests 套了层皮”,那它不值得学——你用 requests 就够了。理解 LangChain 的价值 = 理解它解决了什么必须解决的问题。

2. 朴素世界:直接调智谱 API(Anthropic 协议)

你打开智谱的文档,看到它的接口长这样(Anthropic Messages API):
你用 requests 写出来是这样的(code/01_first_chat.py 里的 raw_api_call() 函数):
这段代码能跑,但它藏着 4 个问题
  1. 协议细节写死在代码里——anthropic-version 头、data["content"][0]["text"] 这种取数逻辑,全是你搜文档搜来的。换一家模型(比如 DeepSeek,OpenAI 协议),响应结构变成 data["choices"][0]["message"]["content"],这段代码全部要重写
  2. 消息序列化是你自己做的——{"role": "system", "content": ...} 这个字典结构,你得自己记住”system 对应什么、user 对应什么”。
  3. 错误处理、重试、超时、流式——全都没有。生产环境第一个月就会因为一次 429 超限而崩。
  4. 没法组合——你后面要做的 RAG(检索→拼上下文→生成)是多个环节的组合。用 requests 写,每个环节都要自己管理”输入从哪来、输出去哪”。

3. LangChain 的做法:一个接口,调用所有模型

对比朴素版,LangChain 替你做了 4 件事 这就是”统一接口”(规定性 1):不管底层是 Anthropic 协议还是 OpenAI 协议,你面对的都是同一个类 ChatAnthropic/ChatOpenAI,同一个方法 invoke(),同一个返回类型 AIMessage
逻辑必然性:只要你有”换模型厂商不用重写业务代码”的诉求,就必然需要一个”统一信封”——把各家协议的差异全部吸收掉。这就是 langchain-core 存在的第一理由。

4. 数据字典:ChatAnthropic(关键类的数据)

4.1 ChatAnthropic 构造参数(langchain-anthropic)

4.2 invoke() 返回:AIMessage 骨架(完整 9 字段在第 02 篇)

实测 response_metadata(智谱 glm-4.7,Anthropic 协议,2026-08 实测)
实测 usage_metadata
model_provider: "anthropic" 是判断协议来源的关键字段——智谱返回 anthropic,DeepSeek 返回 openai(第 02 篇细讲)。

5. 关键方法

注意:invoke 接受字符串(一个 HumanMessage 的快捷方式)、消息对象列表字典。本片用字符串;第 02 篇开始用消息对象。

6. 进程线程模型

结论:同步 invoke阻塞调用——调用期间当前线程什么都不干,就等网络。单线程下,一次问答 = 一次”卡住” 1~3 秒。生产环境(第 11、12 篇)会学怎么用线程池/异步解决。

7. 网络模型

关键点
  • 传输协议:HTTPS,一次 POST 请求。
  • 请求体/响应体:JSON
  • 请求头 anthropic-version 由 SDK 自动带(这是 Anthropic 协议的规定性)。
  • 超时、重试(默认 2 次)、429 处理,ChatAnthropic 已内置——这是朴素 requests 没有的。

8. 验证:跑起来

配套代码 code/01_first_chat.py 同时包含朴素 requests 版LangChain 版,并打印两者的原始响应让你对比。
预期输出(节选)

9. 边界

  • ChatAnthropic 不是唯一入口——还有 ChatOpenAI(DeepSeek/通义/Kimi)。两个类的 invoke 行为一致,但构造参数略有差异(OpenAI 协议 base_url 要带 /v1)。
  • 别自己 new httpx 调模型 API——除非你有极特殊的诉求(比如自己控制 HTTP 会话复用)。框架已内置超时/重试/流式。
  • AIMessage 还不是字符串——invoke 返回对象。想直接拿文本要么 .content,要么(第 04 篇)接 StrOutputParser

推荐资料(延伸阅读)


10. 未完待续

model.invoke("你好") 返回的 AIMessage 里有 9 个字段——contenttool_callsusage_metadata…… 为什么一个”回答”要带这么多东西?模型到底返回了什么、怎么被表达成统一信封? 这就是第 02 篇。 02 · 消息类数据字典