零基础学AI大模型之LangChain聊天模型多案例实战

大家好,我是工藤学编程 🦉 一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉 C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷 【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案
分库分表 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
消息队列 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK)
AI大模型 零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战

前情摘要:
1、零基础学AI大模型之读懂AI大模型
2、零基础学AI大模型之从0到1调用大模型API
3、零基础学AI大模型之SpringAI
4、零基础学AI大模型之AI大模型常见概念
5、零基础学AI大模型之大模型私有化部署全指南
6、零基础学AI大模型之AI大模型可视化界面
7、零基础学AI大模型之LangChain
8、零基础学AI大模型之LangChain六大核心模块与大模型IO交互链路
9、零基础学AI大模型之Prompt提示词工程
10、零基础学AI大模型之LangChain-PromptTemplate
11、零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战


本文章目录

零基础学AI大模型之LangChain聊天模型多案例实战

大家好,我是工藤学编程!在上一篇中,我们搞懂了ChatModel的核心特性和ChatPromptTemplate的基础用法,今天这篇咱们直接"落地实战"------围绕**「模板构建→参数注入→LLM调用」** 的完整流程,拆解3个高频业务场景(领域专家、带参数领域专家、合规客服),手把手教你用LangChain快速搭建可复用的聊天模型应用。

先明确一个核心执行顺序,这是所有案例的底层逻辑,务必记住:
from_template(定义单角色模板)from_messages(组合多角色模板)format_messages(注入动态参数)model.invoke(调用LLM生成响应)

一、实战准备:基础依赖与LLM配置

所有案例均基于LangChain核心库DeepSeek模型(也可替换为GPT-3.5/4、 Claude等),先完成环境搭建:

1.1 安装依赖

bash 复制代码
# 核心依赖:LangChain基础框架 + OpenAI兼容适配器(用于调用通义千问等模型)
pip install langchain-core langchain-openai

1.2 通用LLM配置说明

案例中都会用到ChatOpenAI类(注意:虽叫"OpenAI",但支持配置第三方模型的OpenAI兼容接口,如通义千问的dashscope.aliyuncs.com),关键参数含义:

  • model_name:模型名称(如通义千问的qwen-plus,GPT-3.5的gpt-3.5-turbo);
  • base_url:模型API的基础地址(通义千问专属地址如上,OpenAI为https://api.openai.com/v1);
  • api_key:你的模型API密钥(需替换为自己的,通义千问密钥从阿里云DashScope获取);
  • temperature:随机性参数(0~1,0更严谨、1更灵活,案例中统一设为0.7)。

二、案例1:基础领域专家------固定角色的LLM调用

场景需求:构建一个"Java专家"聊天模型,接收用户关于Java知识点的提问,输出专业解释(无动态参数,角色和回复风格固定)。

核心思路

直接用SystemMessageHumanMessage构建固定角色的消息列表,跳过模板定义步骤(适合简单、无参数的场景),直接调用LLM。

完整代码与拆解

python 复制代码
# 1. 导入依赖:LLM客户端 + 消息类型
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
# 2. 初始化LLM模型
model = ChatOpenAI(
    model_name='deepseek-r1:7b',  # 本地模型名称,根据实际情况填写
    base_url="http://127.0.0.1:11434/v1",  # 本地模型API地址
    api_key="none",  # 本地模型通常不需要真实API密钥
    temperature=0.7  # 可根据需要调整温度参数
)

# 3. 构建消息列表(类似Java的List<Message>,固定角色与内容)
messages = [
    # System角色:定义"Java专家"身份和语言要求
    SystemMessage(content="你是一个Java专家,用中文回答,解释要通俗易懂,带核心要点"),
    # Human角色:用户的具体提问(固定为"解释volatile关键字的作用")
    HumanMessage(content="解释volatile关键字的作用")
]

# 4. 同步调用LLM(invoke()为LangChain标准同步调用方法,类似Java的execute())
response = model.invoke(messages)

# 5. 输出结果(response.content为LLM的核心回复内容)
print("LLM响应结果:")
print(response.content)

执行结果与分析

复制代码
LLM响应结果:
<think>
好的,我现在需要解释一下Java中的volatile关键字的作用。首先,我得回忆一下之前学过的相关知识。

我知道,在Java中,变量分为局部变量、实例变量和静态变量三种类型。这些变量在不同场合下会有不同的行为,尤其是在多线程环境中处理时,就需要特别注意。

 volatile关键字主要是针对实例变量的,它的作用是告诉编译器这个变量不会被其他线程修改。这样编译器就可以做一些优化,比如不使用 locks(锁),直接读取和写入同一个内存块,避免了潜在的竞态条件问题。

举个例子,在一个线程中更新变量x,另一个线程在等待的时候读取x,这时候由于变量是volatile,两个线程会在同一个内存块上操作,不会有 race condition的问题出现。这样不仅解决了竞态条件,还可能提升性能,因为不涉及锁的开销。

但是需要注意的是,volatile并不完全等同于静态类型。虽然静态类型在单个线程内不可修改,但它是被其他线程可见的,可能会导致竞态条件或错误的行为。而volatile变量虽然是不可变的,但它对其他线程是可见的,所以最好使用final关键字来隐藏它的可见性。

综合来说,volatile的关键字通过告诉编译器变量不会被修改,从而优化性能并解决竞态条件问题,但需要注意它的使用场景和限制。
</think>

### 解释:

`volatile` 关键字在 Java 中用于标识一个 instance variable(实例变量),声明该变量不会被其他线程修改。当变量被标记为 `volatile` 时,编译器知道这个变量的值是可见的,并且不会有其他线程对它进行更新。

### 核心要点:

1. **阻止并发读写**:
   - 当两个或多个线程在访问同一个 instance variable 时,默认情况下这些线程会竞争锁(mutex)来避免修改和读取操作冲突。`volatile` 关键字可以将这种情况下的竞态条件问题消除。

2. **优化性能**:
   - 因为 `volatile` 变量不会被其他线程修改,编译器可以对访问该变量的代码进行更有效的优化,比如直接使用内存中的值而不需要等待锁的到来。
   
3. **可见性**:
   - 虽然 `volatile` 关键字阻止了其他线程对变量的修改,但它并没有隐藏变量的可见性。其他线程可以读取和写入该变量,但不会进行任何修改。

4. **结合 final**:
   - 如果在字段上同时使用 `final` 和 `volatile`,则表示这个字段是不可修改且不可见的(除了当前线程),这样的字段通常用于私有常量或者作为缓存的保护机制。

### 示例:

```java
public class MyClass {
    volatile int x = 0;

    public void updateX() {
        // 只能被同一个线程内部使用
        x++;
    }
}

// 可见性问题:其他线程可以通过读取x,但无法修改它。
int y = new MyClass().x; // y的值也是 1

// 不许其他线程修改:
public void otherThreadUpdateX() {
    // 这里会抛出一个 ConcurrentModificationException
}


### 总结:

`volatile` 关键字通过阻止其他线程对变量进行修改,使得变量在单个实例内是不可变的。这种特性允许编译器对访问该变量的操作进行优化,并且也隐含了该变量对所有线程都是可见的。
  • 核心亮点 :无需模板,直接通过SystemMessage固定角色,快速实现"领域专家"的基础能力;
  • 适用场景:角色和提问场景固定(如专属技术问答、固定知识科普)。

三、案例2:带参数的领域专家------动态角色与个性化输出

场景需求:构建一个"可切换领域"的专家模型------支持动态指定领域(如机器学习、Python、Java)、输出风格(如"用比喻说明""带代码示例"),并解释用户指定的概念(如过拟合、装饰器)。

核心思路

from_template定义单角色的参数化模板(系统角色模板+用户角色模板),再用from_messages组合成完整对话模板,最后用format_messages注入动态参数(领域、风格、概念),实现"一次模板,多场景复用"。

完整代码与拆解

python 复制代码
# 1. 导入依赖:LLM客户端 + 模板类
from langchain_openai import ChatOpenAI
from langchain_core.prompts import (
    ChatPromptTemplate,          # 对话模板容器
    SystemMessagePromptTemplate, # 系统角色模板
    HumanMessagePromptTemplate   # 用户角色模板
)

# 2. 步骤1:用from_template定义单角色参数化模板(核心:{变量名}表示动态参数)
# 系统角色模板:动态指定领域({domain})和输出风格({style_guide})
system_template = SystemMessagePromptTemplate.from_template(
    "你是一位专业的{domain}专家,回答需严格满足:{style_guide}"
)
# 用户角色模板:动态指定要解释的概念({concept})
human_template = HumanMessagePromptTemplate.from_template(
    "请解释:{concept}"
)

# 3. 步骤2:用from_messages组合多角色模板(将系统模板和用户模板整合为完整对话)
chat_prompt = ChatPromptTemplate.from_messages([
    system_template,  # 加入系统角色模板
    human_template    # 加入用户角色模板
])

# 4. 步骤3:用format_messages注入动态参数(生成可直接传给LLM的消息列表)
# 这里指定:领域=机器学习,风格=用比喻+示例,概念=过拟合
messages = chat_prompt.format_messages(
    domain="机器学习",
    style_guide="使用生活比喻和具体示例说明,避免专业术语堆砌",
    concept="过拟合"
)

# 5. 初始化LLM模型(同案例1)
model = ChatOpenAI(
    model_name='deepseek-r1:7b',  # 本地模型名称,根据实际情况填写
    base_url="http://127.0.0.1:11434/v1",  # 本地模型API地址
    api_key="none",  # 本地模型通常不需要真实API密钥
    temperature=0.7  # 可根据需要调整温度参数
)

# 6. 调用LLM并输出结果
response = model.invoke(messages)
print("带参数领域专家响应结果:")
print(response.content)

执行结果与分析

复制代码
带参数领域专家响应结果:
<think>
嗯,用户问的是"过拟合",我得先理解一下这个概念。过拟合在机器学习中是一个常见的问题,指的是模型在训练数据上表现很好,但是泛化能力差,在新的数据上效果不佳。

要怎么用生活比喻来解释呢?比如,学生考试前过度复习,记住了所有题型,结果考试时遇到新题型就发挥不好。这个比喻挺直观的,大家都能明白。

具体例子方面,可以想到分类问题,比如识别水果。如果模型只学了几个特定的水果的样子,碰到其他新的水果就会搞错,这就是过拟合的表现。这样用户就能明白为什么过拟合是个大问题。

还要解释原因和解决方法。过拟合的原因通常是训练数据不够或者模型复杂度太高。解决办法包括正则化、交叉验证、简化模型等,这些在实际操作中都是常用的方法。

最后,总结一下过拟合的影响,强调需要找到一个平衡点,让模型既能记住训练内容又具备泛化能力。
</think>

过拟合就像一个学生在考试前过度复习,结果记住了所有练习题的解法,但遇到新的题目时却无法运用这些知识正确作答。这种现象可以用生活中的例子来更好地理解。

### 生活比喻:
想象一下你正在学习如何识别水果。如果你花了很多时间仔细研究每种水果的样子,甚至记住它们的每一个细节(比如某个苹果的具体颜色、纹路等等),结果当你看到一个新的水果时,无法准确判断它是什么。这就是过拟合的表现:模型在训练数据中表现得太好,但不能很好地应对新的、未知的情况。

### 具体示例:
1. **分类问题**:
   你有一个分类模型,用来识别图片中的物品(比如动物、植物等)。如果你的模型经过过度训练,它可能会非常熟悉已有的图片,甚至记住每个细节。然而,当它面对一张从未见过的新图片时,可能无法正确分类------这就是过拟合。

2. **正则化问题**:
   在一个简单的线性回归模型中,如果模型过于复杂(即参数过多),它可能会完美地拟合训练数据集。然而,这样的模型在预测新的数据时往往表现不佳,因为它对训练数据的噪声和异常值过于敏感------这也是过拟合的一个典型例子。

### 原因与解决方法:
- **原因**:过度复杂的模型(比如深度神经网络)或者缺乏足够的训练数据都可能导致过拟合。
- **解决方法**:
  - 使用正则化技术,限制模型的复杂度。
  - 增加训练数据量或使用数据增强(data augmentation)来提高模型的泛化能力。
  - 进行交叉验证以确保模型在不同数据集上表现良好。

### 总结:
过拟合的本质是模型在学习过程中过于专注于训练数据,而忽略了数据中的普遍规律。为了避免这种情况,关键在于找到一个平衡点:让模型既能记住训练内容,又具备泛化的能力。
  • 核心亮点 :通过from_template定义参数化模板,from_messages组合,实现"一套代码支持多领域、多风格",复用性极强;
  • 关键逻辑from_template负责"拆"(单角色参数化),from_messages负责"合"(多角色整合),format_messages负责"填"(注入参数)。

四、案例3:合规客服系统------场景化约束与风险控制

场景需求:构建一个企业客服助手,需满足严格的合规规则:不透露内部系统名、不提供医疗/金融建议、特定场景(如病情咨询、支付问题)转人工,同时支持动态指定企业名称、用户等级。

核心思路

ChatPromptTemplate.from_messages直接定义"系统+用户"的组合模板(跳过单独的from_template,适合模板逻辑较简单的场景),在system prompt中明确合规约束,通过参数注入业务信息(企业名、转人工条件、用户等级),确保LLM严格遵守规则。

完整代码与拆解

python 复制代码
# 1. 导入依赖:LLM客户端 + 对话模板
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 2. 初始化LLM模型(同前)
# model = ChatOpenAI(
#     model_name='deepseek-r1:7b',  # 本地模型名称,根据实际情况填写
#     base_url="http://127.0.0.1:11434/v1",  # 本地模型API地址
#     api_key="none",  # 本地模型通常不需要真实API密钥
#     temperature=0.7  # 可根据需要调整温度参数
# )

# 3. 步骤1:用from_messages定义合规客服模板(系统角色含约束,用户角色含参数)
compliance_template = ChatPromptTemplate.from_messages([
    # 系统角色:明确企业、合规规则、转人工条件({company}、{transfer_cond}为参数)
    ("system", """您是{company}的客服助手,必须严格遵守以下规则:
1. 不透露任何内部系统名称(如CRM、订单系统名);
2. 绝对不提供医疗建议、金融投资建议;
3. 遇到{transfer_cond}这类问题,必须回复"已为您转接人工客服,请耐心等待",不做额外解释;
4. 回复需礼貌,开头需称呼用户等级(如"VIP用户您好")。"""),
    # 用户角色:动态指定用户等级({user_level})和提问({query})
    ("human", "[{user_level}用户]:{query}")
])

# 4. 步骤2:注入参数生成消息列表(模拟"VIP用户问感冒吃什么药")
messages = compliance_template.format_messages(
    company="老王医生",    # 企业名称
    transfer_cond="病情咨询、支付问题",  # 转人工条件
    user_level="VIP",            # 用户等级
    query="感冒应该吃什么药?"    # 用户提问(属于"病情咨询",需转人工)
)

# 5. 调用LLM并输出结果
response = model.invoke(messages)
print("合规客服系统响应结果:")
print(response.content)

执行结果与分析

复制代码
合规客服系统响应结果:
<think>
好,我现在需要处理用户的咨询。用户是VIP级别的,询问感冒应该吃什么药。

首先,我要确认用户的需求是否涉及医疗建议。根据规则,我不能提供医疗建议或医疗建议的回复,所以这可能是一个问题。

接下来,查看是否有内部系统名称提到。这里并没有提到任何CRM或其他系统,所以我可以继续处理。

然后,考虑是否需要转接人工客服。根据规则,遇到健康咨询时,应该转接,而不是给出药物建议。即使用户想知道吃什么药,但直接给出药物可能违反规定,所以可能需要转接。

另外,检查是否有其他问题,比如支付问题或订单问题,这显然不在当前范围内。

现在决定:按照规则,当涉及到健康咨询时,应转接人工客服,而不提供药物推荐。因此,我应该回复用户,让他们耐心等待,并转接他们到人工客服。

最后,确保回复礼貌,开头称呼VIP用户,并符合所有规定。
</think>

已为您转接人工客服,请耐心等待。
  • 核心亮点 :通过system prompt的"规则清单"实现强约束,LLM会自动识别用户提问是否命中"转人工条件"(如案例中"感冒吃药"属于"病情咨询"),严格执行合规逻辑;
  • 关键设计:将"可变业务信息"(企业名、转人工条件)设为参数,无需修改模板即可适配不同企业/场景,降低维护成本。

五、实战总结:核心流程与关键技巧

1.3个实战技巧

  • 模板设计 :简单场景用from_messages直接定义组合模板;复杂场景用from_template拆单角色模板,再用from_messages整合;
  • 合规控制 :将规则(如禁止内容、转人工条件)写在system prompt中,用"清单式描述"(1.2.3.)让LLM更易理解;
  • 参数化:把"可变信息"(领域、企业名、用户等级)设为参数,避免硬编码,提升模板复用性。

2. 模型替换建议

案例中用的是deepseek,若想替换为其他模型,只需修改model_namebase_url

  • GPT-3.5/4:model_name="gpt-3.5-turbo"base_url="https://api.openai.com/v1"
  • Claude 3:需用langchain_anthropic库的ChatAnthropic类,而非ChatOpenAI

关注我,跟着实战学AI大模型不迷路~ 🚀

相关推荐
无风听海2 小时前
神经网络之sigmoid激活函数
人工智能·深度学习·神经网络
宸津-代码粉碎机2 小时前
Redis 进阶:跳出缓存局限!7 大核心场景的原理与工程化实践
java·人工智能·redis·python
wan5555cn2 小时前
AI视频生成技术:从想象到现实的视觉革命
人工智能·笔记·深度学习·算法·音视频
MYZR12 小时前
蓝牙音箱的技术演进:从便捷到高保真的音频革命
人工智能·物联网·音视频·ssd2351
liaomin4161005692 小时前
transformers音频实战01-音频概念
人工智能·音视频
IT_陈寒2 小时前
Python 3.12 性能暴增50%!这5个新特性让老项目直接起飞
前端·人工智能·后端
charieli-fh2 小时前
LoRA 高效微调大语言模型全流程:从原理、实践到参数调优
人工智能·深度学习·大模型·大语言模型
星川皆无恙2 小时前
知识图谱之深度学习:基于 BERT+LSTM+CRF 驱动深度学习识别模型医疗知识图谱问答可视化分析系统
大数据·人工智能·深度学习·bert·知识图谱
XIAO·宝7 小时前
深度学习------专题《图像处理项目》终!
人工智能·深度学习