0 入门
0.1 作为javaweb选手,为什么不选择spring AI、langchain4j而是langchain?
作为 JavaWeb 选手,我并不是排斥 Spring AI 或 LangChain4j,而是区分学习阶段和系统架构阶段。
在当前主流企业架构中,大模型能力通常会被独立拆成 LLM 服务,以微服务形式存在,Java 服务通过 HTTP / RPC 调用。这种情况下,Spring AI 把 LLM 嵌进 Spring 容器的一体化优势就不明显了。
我选择先系统学习 LangChain,主要是因为它在 Python 生态里定义了大模型应用的核心抽象和设计范式,比如 Prompt、Chain、Agent、Tool、Memory,这些已经成为事实上的行业标准。理解 LangChain,本质是在理解 LLM 服务的内部架构,而不是某个语言的实现方式。
在真正工程落地时,如果 LLM 能力需要直接集成在 Java 应用中,我会优先考虑 Spring AI 或 LangChain4j;但如果是独立的大模型微服务,我更关注服务边界、接口设计和演进能力,而不是是否使用 Java 框架本身。
0.2 简介
LangChain 是一个「大模型应用编排框架」。
关注:
- 输入怎么组织
- 中间步骤怎么串
- 输出怎么稳定
0.3 核心模块划分
LangChain 核心模块一览
| 模块 | 作用 | 解决的问题 | 典型类 / 接口 | 是否底层核心 |
|---|---|---|---|---|
| LLM / ChatModel | 统一大模型调用接口 | 屏蔽不同模型 API 差异 | ChatOpenAI、AzureChatOpenAI | ✅ |
| PromptTemplate | Prompt 模板化 | Prompt 拼接混乱、难维护 | PromptTemplate、ChatPromptTemplate | ✅ |
| OutputParser | 输出结构化 | 模型输出不可控 | StrOutputParser、StructuredOutputParser | ✅ |
| Chain / Runnable | 流程编排 | 多步骤逻辑难组合 | Runnable、RunnableSequence | ✅(最核心) |
| Memory | 状态管理(对话/上下文) | 模型无状态 | ConversationBufferMemory、ChatMessageHistory | ◯ |
| Tool | 外部能力封装 | LLM 不能直接调用代码 | Tool、StructuredTool | ◯ |
| Agent | 自动决策调用 Tool | 复杂任务需要多步推理 | AgentExecutor、ReActAgent | ◯ |
此外早期版本划分为以下六大模块:
| 模块 | 作用 |
|---|---|
| Models | 大语言模型接口,统一调用不同AI模型 |
| Prompts | 提示词模板和示例管理 |
| Indexes | 文档索引和检索系统 |
| Memory | 对话历史状态管理 |
| Chains | 多步骤流程链式编排 |
| Agents | 智能代理决策执行 |
0.4 安装
pip install langchain langchain-community dashscope pymilvus
0.5 应用
RAG
1 Models
1.1 简介
langchain支持的模型主要有以下三类:
1. 大语言模型
这是最基础的类型,用于生成文本。你给它一段“提示词”,它返回一段“回答文本”。功能单一,主要用于文本补全、续写、问答等。例如,你输入“中国的首都是”,它回答“北京”。
核心特点:输入是文本字符串,输出也是文本字符串。
示例:GPT-3、Llama 3的纯文本补全版本。
2. 聊天模型
这是为“对话”场景专门设计的。它不直接处理原始文本,而是处理结构化的消息,比如:
SystemMessage:设定AI角色和背景。HumanMessage:用户的提问。AIMessage:AI之前的回复历史。
核心特点:输入是消息列表,输出是AIMessage。它天然能理解多轮对话的上下文,是构建聊天机器人、AI助手的首选。
示例:GPT-4、Claude-3的聊天API版本。
3. 文本嵌入模型
这是一种“翻译”模型,将文本(词、句、段落)转换成计算机能更好理解的数字形式——高维向量(一串数字)。语义相近的文本,其向量在空间中的位置也相近。
核心作用:
- 搜索:将问题和文档都转为向量,快速找到最相关的文档。
- 聚类:将相似的文本自动归类。
- 推荐:根据你喜欢的物品的向量,推荐相似的物品。
核心特点:输入文本,输出一个固定长度的数字向量。
示例:text-embedding-ada-002、BGE等专门生成向量的模型。
1.2 大语言模型
模型对象创建
from langchain_community.llms.tongyi import Tongyi
model=Tongyi(model="qwen-max", api_key=os.getenv("OPENAI_API_KEY"))
一次返回完整结果 invoke
print(model.invoke("请写一个关于机器学习的程序"))
流式输出
res = model.stream("rag的标准流程")
for chunk in res:
print(chunk,end="",flush=True)
1.3 聊天模型
消息类型:
- HumanMessage, # 用户输入(user)
- AIMessage, # AI回复(assistant)
- SystemMessage, # 系统指令(system)
- FunctionMessage, # 函数调用结果
- ToolMessage, # 工具调用结果
- ChatMessage # 自定义角色消息
示例:
chat = ChatTongyi(
model="qwen-max",
api_key=os.getenv("OPENAI_API_KEY")
)
messages = [
SystemMessage(content="你是一个只回答一句话的 Java 专家"),
HumanMessage(content="什么是 JVM?"),
AIMessage(content="JVM 是 Java 程序运行的虚拟机,负责字节码执行。"),
HumanMessage(content="那它和 JDK 的关系是什么?")
]
for chunk in chat.stream(messages):
print(chunk.content, end="", flush=True)
print("\n")
消息简写:
messages = [
("system", "你是一个只回答一句话的 Java 专家"),
("human", "什么是 JVM?"),
("ai", "JVM 是 Java 程序运行的虚拟机,负责字节码执行。"),
("human", "那它和 JDK 的关系是什么?")
]
1.4 文本嵌入模型 embedding Models
文本嵌入模型将文本转换为向量表示(embeddings),用于:
- 语义搜索
- 文档相似度计算
- 聚类分析
- RAG(检索增强生成)中的文档检索
创建模型对象
#创建模型对象,不传model默认为 text-embedding-v1
embeddingModel = DashScopeEmbeddings(dashscope_api_key = os.getenv("DASHSCOPE_API_KEY")))
单次转换 embed_query:
query_vector = embeddingModel.embed_query("only god knows")
print(query_vector)
print(len(query_vector))
批量转换 embed_documents:
texts = [
"only god knows",
"machine learning is interesting",
"artificial intelligence is powerful",
"python programming language"
]
query_vector = embeddingModel.embed_documents(texts)
print(query_vector)
print(len(query_vector))
print(len(query_vector[0]))
2 提示词 PromptsTemplate
2.1 通用提示词模板 PromptTemplate
最基础的提示词模板是 PromptTemplate。它本质上就是一个带变量占位符的字符串模板。
示例:
from langchain_core.prompts import PromptTemplate
from langchain_community.llms.tongyi import Tongyi
import os
from dotenv import load_dotenv
load_dotenv()
model = Tongyi(
model="qwen-max",
api_key=os.getenv("OPENAI_API_KEY")
)
prompt = PromptTemplate.from_template(
"你是一个资深的 {role}。请用通俗易懂的语言解释:{question}"
)
result = prompt.format(role="Java 专家", question="什么是 JVM?")
print(result)
print(model.invoke(result))
链式:
chain = prompt | model
print(chain.invoke({
"role": "Java 后端工程师",
"question": "什么是线程池?"
}))
这里的 | 是 LCEL(LangChain Expression Language)的管道操作符,本质上是把“提示词生成器”输出交给“模型”。
2.2 FewShotPromptTemplate
如果说 PromptTemplate 是“告诉模型要做什么”,那么 Few-Shot Prompt 是“给模型看几个例子,让它照着学”。
Few-shot 的核心思想很简单:
与其告诉模型规则,不如给它样本。
FewShotPromptTemplate类对象构建需要5个核心参数:
- example_prompt:示例数据的提示词模板
- examples:示例数据,list,内套字典
- prefix:组装提示词,示例数据前内容
- suffix:组装提示词,示例数据后内容
- input_variables:列表,注入的变量列表
示例:
from langchain_core.prompts import PromptTemplate,FewShotPromptTemplate
from langchain_community.llms.tongyi import Tongyi
import os
from dotenv import load_dotenv
load_dotenv()
model = Tongyi(
model="qwen-max",
api_key=os.getenv("OPENAI_API_KEY")
)
# 示例样本
examples = [
{"input": "1+1", "output": "3"},
{"input": "2+2", "output": "5"},
{"input": "3+3", "output": "7"},
]
# 示例格式模板
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="问题: {input}\n答案: {output}"
)
# FewShot 模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="请根据示例计算结果:",
suffix="问题: {input}\n答案:",
input_variables=["input"]
)
#获得最终提示词
prompt = few_shot_prompt.format(input="4+4")
print(prompt)
print(model.invoke(prompt))
2.3 ChatPromptTemplate
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages import HumanMessage, AIMessage
import os
from dotenv import load_dotenv
load_dotenv()
model = ChatTongyi(
model="qwen-max",
api_key=os.getenv("OPENAI_API_KEY")
)
# 构建 ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个资深的 Java 架构师,用通俗语言回答问题。"),
MessagesPlaceholder(variable_name="history"),
("human", "{question}")
])
# 构造历史消息
history = [
HumanMessage(content="什么是 JVM?"),
AIMessage(content="JVM 是 Java 虚拟机,用来运行 Java 字节码。"),
HumanMessage(content="那它和 JDK 有什么区别?"),
AIMessage(content="JDK 是开发工具包,包含 JVM。")
]
# 链式调用
chain = chat_prompt | model
result = chain.invoke({
"history": history,
"question": "什么是类加载机制?"
})
print(result)
3 Chain / Runnable
LangChain 管道:
Runnable A → Python 对象 → Runnable B
将组件串联,上一个组件的输出作为下一个组件的输入。