Spring AI 1.0 GA 了,给了 Java 人一个"留在舒适区"的选项。但 LangChain 还是要先学——这篇讲清凭什么(三个理由加一个最诚实的),再带你跑通第一次模型调用。
init_chat_model、消息类型、调用四件套、Ollama 本地模型、ChatPromptTemplate,一个不落。
"Spring AI 1.0 都 GA 了,Spring 官方下场做 AI 框架,我一个写 Java 的,干嘛还要去啃一个 Python 的 LangChain?"
这个嘀咕我听过太多次,而且它挺合理的。Spring AI 确实给了 Java 人一个"留在舒适区"的选项——熟悉的注解、熟悉的 Bean、熟悉的 application.yml,凭什么非要我去学一套 Python 的东西?
但我给的判断很直接:LangChain 还是要学,而且要先学。 本系列 5 篇,带你从零走到能搭一个能用的 Agent。第一篇,先把"凭什么"讲透,再带你跑通第一次模型调用。
一、先回答那个嘀咕:Spring AI 出了,LangChain 凭什么还要学
三个理由,加一个最诚实的。
第一,生态体量差着一个数量级。 LangChain 2022 年 10 月开源,比 ChatGPT 问世还早一个月。到 2026 年的今天,它集成的模型厂商、向量数据库、工具数量,社区里的实战案例,都是 Spring AI 的很多倍。你遇到任何稀奇古怪的模型、任何小众向量库,LangChain 基本都有现成的 langchain-xxx 包;Spring AI 还在补这门课。
第二,迭代速度。 LLM 这个领域半年一变天——新模型、新协议(MCP)、新调用方式层出不穷。LangChain 是 Python 原生,新东西当天就能用上;Spring AI 要等 Java 生态跟进,天然慢半拍。
第三,Agent 深水区,LangGraph 领先一大截。 这是关键。LangChain 现在的 Agent 底层跑的就是 LangGraph——一个专门做"有状态、可控、能存盘续跑"的 Agent 编排框架。状态机、检查点、人工审核、条件路由,这套东西 Spring 生态目前没有对等物。本系列讲完 LangChain 5 篇,会接着讲 LangGraph 4 篇,那才是真正的 Agent 主场。
最诚实的理由:Spring AI 的设计大量借鉴了 LangChain。 ChatClient 对应 ChatModel、Advisor 对应 LCEL 链、VectorStore 抽象、Tool Calling——你把 LangChain 学明白,回头看 Spring AI 的 API 会发现"哦,原来这里是这个意思"。学 LangChain 等于学了 Spring AI 的原版思路,外加一个更强大的生态兜底。
所以别纠结"二选一"。正确的姿势是:用 LangChain 学明白 LLM 应用的设计范式,至于生产用 Python 还是 Java,看你团队、看你目标岗位。要拿 Agent 方向的 offer,Python + LangChain 是绕不开的主线。
二、LangChain 是什么——一句话:LLM 应用的"Spring"
Java 人最喜欢先搞清楚"这东西在我熟悉的世界里对应啥"。LangChain 的定位,就是 LLM 应用层的 Spring——一套统一的抽象、模板、编排工具,让你不用每个模型都从头处理 HTTP 细节。
讲义把 LangChain 的核心模块划成四块,我用 Java 人听得懂的话翻译一遍:
| Model I/O | ||
| Chains | ||
| Retrieval(RAG) | ||
| Agents |
本系列 5 篇,正好对应这条线: Model I/O(本篇)→ Chains/LCEL(02)→ 结构化输出(03)→ RAG 全流程(04)→ Agent + MCP(05)。走完你能从零搭一个能跑的 Agent,并且知道它底层为什么是 LangGraph。
三、环境准备:Python 3.12 + uv,API Key 用 .env
讲义用的是 Python 3.12 + pip + venv。这套要会,因为存量项目全是它。但 2026 年的新项目,我强烈建议直接上 uv——Astral 出品、Rust 写的包管理器,替代 pip + venv + pyenv,快 10 到 100 倍,uv.lock 锁依赖。类比一下:uv 之于 Python,约等于 Maven/Gradle 之于 Java。
# 讲义教的方式(存量项目多,要会)
python -m venv .venv
.venv\Scripts\activate # Windows 激活
pip install langchain langchain-openai python-dotenv
# 2026 年新项目推荐:uv
uv init my-agent && cd my-agent
uv add langchain langchain-openai python-dotenv版本口径说清楚:基线 Python 3.12(官方支持到 2028 年 10 月,生态完全成熟)。LangChain v1 的最低要求是 3.10——那是地板,不是推荐值,别踩。本系列基于 LangChain v1.x(2026 年 7 月口径 1.2.x)。
API Key 怎么管——这是讲义反复强调的,也是 Java 人最容易偷懒的地方。别图省事写死在代码里。标准做法是 .env 文件 + python-dotenv:
# .env 文件(这个文件绝对不能进 git!)
OPENAI_API_KEY=sk-xxx
OPENAI_BASE_URL=https://api.openai-proxy.org/v1
# 代码里加载
from dotenv import load_dotenv
load_dotenv() # 把 .env 读进环境变量
import os
api_key = os.getenv("OPENAI_API_KEY") # 用的时候取对应到 Spring,这就是 application.yml + @Value("${OPENAI_API_KEY}") 那一套,心智模型完全一样。坑也一样:.env 必须加进 .gitignore,否则密钥一推就上天。
四、Model I/O:输入、处理、输出三件事
讲义把 Model I/O 拆成三件事:Format(格式化输入)/ Predict(调用模型)/ Parse(解析输出)。
这不需要死记。你调任何外部服务都是这三步——构造请求、发起调用、解析响应。LangChain 只是把"针对 LLM"的这三步标准化了:
- Format
:用提示词模板( ChatPromptTemplate)把变量填进 Prompt - Predict
:用模型对象( ChatOpenAI等)发起调用 - Parse
:用输出解析器把结果变成 JSON/对象(结构化输出)
本篇聚焦 Format 和 Predict,Parse 内容多且重要,03 篇单独讲。
五、调用模型:从 OpenAI SDK 裸调,到 LangChain 统一封装
先看 Java 人最直觉的写法——直接用 OpenAI SDK 裸调。为什么是 OpenAI SDK?因为 OpenAI 的 GPT 系列定义了大模型 API 的事实标准,Qwen、DeepSeek、ChatGLM 这些国产模型,绝大多数都兼容 OpenAI 的调用规范。
# pip install openai
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
base_url=os.getenv("OPENAI_BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY"),
)
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "把'你好'翻译成意大利语"}],
)
print(completion.choices[0].message.content)能跑,但问题来了:换个厂商就头大。调 Gemini 得装 google-genai、换一套 API;调 DeepSeek 又是另一套。到了结构化输出、工具调用这些复杂场景,各厂商构造参数的方式都有差别——你的业务代码被厂商 API 绑死了。
LangChain 的解法——统一封装掉厂商差异:
# pip install langchain langchain-openai
# 方式一:init_chat_model(推荐,最省心)
from langchain.chat_models import init_chat_model
llm = init_chat_model(
model="gpt-4o-mini",
model_provider="openai", # 换 DeepSeek 只改这里
base_url=os.getenv("OPENAI_BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY"),
)
# 方式二:直接用厂商包的类(init_chat_model 底层就是它)
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)
# 调用——不管哪个厂商,统一这一行
resp = llm.invoke("你好")
print(type(resp)) # <class 'langchain_core.messages.ai.AIMessage'>
print(resp.content) # 模型回复的文本注意返回的不是字符串,是个 AIMessage 对象——除了 .content(文本),还带元数据(token 用量、结束原因等),生产排错全靠它。
💡 记忆点:换模型只改初始化那一行(model / model_provider),业务代码一行不动。这是 LangChain 最朴素也最值钱的能力——模型可移植性。今天用 GPT,明天换 DeepSeek 省成本,后天换本地 Qwen 跑离线,业务层零改动。
对比 Spring AI:思路完全一致,ChatClient.create(model).prompt().user("你好").call().content()。学一个就会另一个。但 LangChain 的调用方式四件套(下一节)更统一、更 async-friendly。
六、消息类型:聊天记录不是一坨字符串
你可能注意到上面 llm.invoke("你好") 直接传了字符串。这适合一次性问答。但更正规的做法是传一个消息列表——因为 LLM 本身是无状态的,每次调用它都不记得上次说了啥。要让它"有记忆",就得把历史聊天记录每次都传进去。
LangChain 提供四种消息类型,对应聊天里的不同角色:
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
# 方式一:消息对象(类型最安全,推荐)
resp = llm.invoke([
SystemMessage(content="你是一个专业的数学助手"),
HumanMessage(content="你好,你是谁"),
])
# 方式二:元组(简洁)
resp = llm.invoke([("system", "..."), ("user", "...")])
# 方式三:dict(和 OpenAI 原生格式一致)
resp = llm.invoke([
{"role": "system", "content": "..."},
{"role": "user", "content": "..."},
])三种写法等价,挑顺手的用。四种消息类型各自的角色:
SystemMessage | ||
HumanMessage | ||
AIMessage | ||
ToolMessage |
对比 Spring AI 的 UserMessage/AssistantMessage/SystemMessage/ToolMessage——几乎一一对应。学一个就会另一个,这就是抽象的力量。
七、调用方式四件套:invoke / ainvoke / stream / batch
这是 Java 人最容易忽略、但生产环境最关键的一节。
# 1. 同步调用(开发调试用)
resp = llm.invoke("你好")
# 2. 异步调用(生产首选,LLM 是 IO 密集型)
import asyncio
async def ask():
response = await llm.ainvoke([("user", "什么是 LangChain")])
print(response.content)
asyncio.run(ask())
# 3. 流式调用(打字机效果,用户体验好)
for chunk in llm.stream([("user", "讲个故事")]):
print(chunk.content, end="")
# 4. 批量调用(并行多个请求,内部用线程并行)
results = llm.batch([("user", "问题1"), ("user", "问题2")])
for r in results:
print(r.content)⚠️ Java 人最大的坑——只会 invoke:LLM 调用动辄几秒十几秒,生产环境用同步 invoke 会把线程占死,一个用户请求就把你后端的线程池吃掉一格。Spring AI 这块其实也弱(Java 侧 LLM 调用多为同步,或靠 WebClient 异步)。LangChain 是 async-first——ainvoke / astream / abatch 是生产标配。还记得 Python 系列第 7 篇学的 asyncio 吗?它在 Agent 开发里是真正的主角。
(题外话:Python 3.14 的 free-threading 已经转正,多线程也能真正并行了。但 2026 年的态度还是——了解、测试、别上生产,asyncio 依然是 Agent 并发的主流解。)
八、本地模型:Ollama 让你离线也能跑
不是所有场景都能调云 API——没网、要保密、想省钱调试。这时候用 Ollama:一个本地运行大模型的框架,能一键下载、启动主流开源模型(Qwen、DeepSeek、Llama 等)。
# 装 Ollama 后,一行命令下载并运行模型
ollama run qwen3:8bLangChain 接入只要换一个类:
# pip install langchain-ollama
from langchain_ollama import ChatOllama
# 默认连本机 localhost:11434
llm = ChatOllama(model="qwen3:8b")
resp = llm.invoke("你好,请介绍一下你自己")
print(resp.content)
# 如果 Ollama 不在本机默认端口,要指定 base_url
llm = ChatOllama(model="qwen3", base_url="http://192.168.1.100:11434")注意 API 和在线模型完全一样——都是 invoke、ainvoke、消息列表。这就是抽象的好处:本地调试和云端调用,业务代码不换。
对比 Spring AI:也有 spring-ai-ollama,同构。Ollama 是 Java/Python 两侧通用的本地推理底座。
💡 记忆点:Ollama 解决的是"没有 GPU 也能开发、调试、演示"的问题。真上生产(高并发推理),换 vLLM 这类专业推理框架,或直接调云 API。讲义也强调过:Ollama 主要用于原型设计和本地开发。
九、提示词模板:别再 f-string 拼 Prompt 了
应用开发里,Prompt 很少是写死的——总有变量要填。Java 人的第一反应可能是 f-string 拼一下:
# 别这么干
prompt = f"请评价 {product} 的优缺点,包括 {aspect1} 和 {aspect2}。"能跑,但 LangChain 提供了更专业的工具——ChatPromptTemplate:
from langchain_core.prompts import ChatPromptTemplate
from langchain.chat_models import init_chat_model
template = ChatPromptTemplate.from_messages([
("system", "你是一个专业的评论员"),
("human", "请评价 {product} 的优缺点,包括 {aspect1} 和 {aspect2}。"),
])
# 填充变量,得到消息列表(PromptValue)
messages = template.invoke({"product": "iPhone 15", "aspect1": "性能", "aspect2": "外观"})
llm = init_chat_model(model="gpt-4o-mini", model_provider="openai")
resp = llm.invoke(messages)
print(resp.content)为什么不直接 f-string?三个理由:
- 模板和调用分离
——Prompt 集中管理,便于复用、迭代、做版本控制 - 变量转义防注入
——用户输入里有特殊字符不会破坏 Prompt 结构 - 能进 LCEL 管道
——下一篇讲 Chains 时, template | model | parser这种写法的基础就是它
对比 Spring AI 的 PromptTemplate / SystemPromptTemplate——同名概念,同构。Kotlin 视角:{variable} 插值 ↔ Kotlin 字符串模板 "$name",语法糖一脉相承。
Java 人最容易栽的坑
- API Key 硬编码
——别图省事写死。用 .env+load_dotenv(),.gitignore加上.env。和 Spring 的application.yml敏感信息管理同理。 - 只会 invoke
——见上面红框。LLM 是 IO 密集,生产用 ainvoke/stream,否则线程被阻塞占死。 - temperature 不设
—— ChatOpenAI默认 temperature 不是 0,每次结果有随机性。要稳定输出(结构化抽取、分类),显式temperature=0.0。 - SystemMessage 位置错
——系统消息要放消息列表最前面。放后面效果会变差,有的模型甚至会忽略它。 - Ollama 端口
——默认 11434。Ollama 不在本机时,必须指定base_url="http://ip:11434",否则连不上。 - async 函数里用 invoke
——在 async def里要用ainvoke。混用同步invoke会阻塞事件循环,把 async 的好处全废掉。
通往 Agent 之路
本篇学的 init_chat_model / ChatOpenAI,是后面所有 Agent 的起点。LangChain v1 的 create_agent(05 篇讲),第一个参数就是这个 llm 对象。
而且这里有个本系列后面要反复强调的事实:LangChain v1 的 create_agent,底层跑的就是 LangGraph。 老的 AgentExecutor 已经标记为 legacy,新代码统一走 create_agent → LangGraph 图。你以为在用 LangChain 写 Agent,其实底下是 LangGraph 在驱动。这也是为什么本系列讲完 LangChain 5 篇,要接着讲 LangGraph 4 篇——那是 Agent 的真正引擎。
下一篇讲 Chains(LCEL)——怎么把 PromptTemplate + Model + Parser 串成一根管道(prompt | model | parser)。这个 | 管道符对应 Java 人最熟的 Stream 链,但它能干的事比 Stream 多得多。
面试连环问
1. LangChain 和 Spring AI 什么关系?Java 人为什么还要学 LangChain?
Spring AI 设计大量借鉴 LangChain(ChatClient/Advisor/VectorStore 几乎一一对应),学 LangChain 等于学了原版思路;且 LangChain 生态体量、迭代速度、Agent 深水区(LangGraph)都领先。生产用哪个看团队和岗位,学习先走 LangChain。
2. init_chat_model 和直接用 ChatOpenAI 有什么区别?
没本质区别,
init_chat_model底层就是调用ChatOpenAI这种类。好处是换厂商只改model_provider字符串,业务代码不动。
3. invoke / ainvoke / stream / batch 分别什么场景?
invoke同步调试;ainvoke生产异步(LLM 是 IO 密集);stream流式打字机;batch并行多请求。
4. LangChain 的 Model I/O 三件事是什么?
Format(
PromptTemplate格式化输入)/ Predict(Model 调用)/ Parse(OutputParser解析输出,比如转 JSON)。
5. 为什么不能硬编码 API Key?.env 怎么用?
密钥进代码就会进 git 进仓库,一旦推送就泄露。标准做法:
.env文件 +python-dotenv的load_dotenv()读进环境变量,os.getenv取用。.env必须加进.gitignore。
6. Ollama 能上生产吗?
不能。Ollama 是本地开发/原型用,生产高并发推理用 vLLM 或直接调云 API。
7. ChatPromptTemplate 比 f-string 拼 Prompt 好在哪?
模板调用分离、变量自动转义防注入、能进 LCEL 管道(
template | model | parser)。
8. 消息列表里四种 Message 各代表什么?
SystemMessage系统设定;HumanMessage用户输入;AIMessage模型回复(回放历史);ToolMessage工具调用结果(Agent 场景)。
知识点自查清单
☐ 知道 LangChain 的 4 大模块(Model I/O / Chains / RAG / Agents)分别干什么 ☐ 会用 uv或venv建虚拟环境,装langchain+langchain-openai☐ 会用 .env+load_dotenv()管理 API Key,知道.env不进 git☐ 会用 init_chat_model和ChatOpenAI两种方式构造llm☐ 知道 invoke/ainvoke/stream/batch四种调用方式的区别☐ 会用 HumanMessage/SystemMessage/AIMessage构造消息列表☐ 会用 Ollama 跑本地模型, ChatOllama接入☐ 会用 ChatPromptTemplate构造带变量的提示词
📚 这是一个系列:《写给 Java 人的 LangChain》第 01 篇。完整路径 Python 基础(8 篇)→ LangChain(5 篇,你在这里)→ LangGraph(4 篇)。关注后按顺序读,走完能从零搭一个能用的生产级 Agent。
写给想转 Agent 方向的 Java/Kotlin 人,每个结论都基于 LangChain v1.x 官方文档 + 讲义实战逐行核对。这篇要是帮你理清了"要不要学 LangChain",点个赞、点个在看,转给同样在纠结的 Java 同事。关注我,下一篇《LangChain 这根链,和你想的 Stream 链不是一回事》更硬核。
夜雨聆风