langchain学习笔记

(备注:所有字体标红的笔记模块暂时没有用到或者没来得及看)

2026-02-24

Runable与LCEL(一下的五种链式调用仅代表常见场景)

Runable

是什么:是langchain核心抽象接口(定义在langchain_core.runnables)统一组件的调用方式,支持LCEL组合,可以适配同步/异步、流式、批量等场景,是构建工作流的基础。通俗一点就是为所有可执行组件都提供统一的接口,案例如下

python 复制代码
from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from loguru import logger
import os
# 创建聊天提示模板,包含系统角色设定和用户问题输入
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请简短回答我提出的问题"),
    ("human", "请回答:{question}")
])

# 使用具体参数实例化提示模板并记录日志
prompt = chat_prompt.invoke({"role": "AI助手", "question": "什么是LangChain,简洁回答100字以内"})
logger.info(prompt)

# 初始化模型
model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)


# 调用模型获取原始响应并记录日志
result = model.invoke(prompt)
logger.info(f"********>模型原始输出:\n{result}")

# 创建字符串输出解析器,用于处理模型输出
parser = StrOutputParser ()

# 解析模型输出为结构化结果并记录日志
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
# 记录解析结果的数据类型
logger.info(f"结果类型: {type(response)}")

解决什么问题:

1、在使用runnable之前,不同的AI组件各有各的调用方式。比如,提示模板用.format(),语言模型用.generate(),解析器用.parse()。开发者需要手动处理这些差异,代码既冗长又难以维护,使用这种可以解决接口混乱问题

2、使用runnable实现了无缝的组合,通过lcel, 可以结合管道符|把多个runnable像流水线一样串联起来

python 复制代码
chain = chat_prompt | model | parser

3、支持多种执行模式,AI应用场景中,有的时候需要获取单个答案invoke,有的时候需要批量处理数据batch,有的时候需要流式处理stream,runnable原生支持这些模式,IT工作中不需要为不同的场景编排不同的代码

为什么需要:

1、降低学习成本:只需要学习一套接口就可以操作所有AI组件

2、提升开发效率:runnable的可组合性让快速迭代成为了可能,可以先搭建简单的测试核心功能,然后逐步增加组件,不需要重写整个系统

3、增强系统可靠性:内置有企业级功能增强

4、实现了更好的可观测性:可以通过astream_events等方法追踪每个步骤的执行情况

LCEL

是什么:组合runnable组件的声明式语法,通俗说类似于Linux的管道符|

解决什么问题:

1、代码冗长且难以维护

2、可读性差

3、缺乏灵活性:传统链式调用的结构固定难以动态调整

4、调试困难:所有步骤耦合在一起,出现异常时难以快速定位异常位置

为什么需要:

灵活性和可组合性,可以拼接多个runnable为复杂工作流,支持条件分支和并行执行

RunnableSequence-顺序链

RunnableSequence按照顺序链接多个可执行对象,其中的一个对象的输出作为下一个对象的输入,代码案例如下

python 复制代码
"""
顺序链
LangChain 的一个典型链条由Prompt、Model、OutputParser (可没有)组成,
然后可以通过 链(Chain) 把它们顺序组合起来,让一个任务的输出成为下一个任务的输入
意思等价于Linux里面的管道符
"""
from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from loguru import logger
import os

# 创建聊天提示模板,包含系统角色设定和用户问题输入
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请简短回答我提出的问题"),
    ("human", "请回答:{question}")
])

# 使用具体参数实例化提示模板并记录日志
prompt = chat_prompt.invoke({"role": "AI助手", "question": "什么是LangChain,简洁回答100字以内"})
logger.info(prompt)

# 初始化模型
model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)


# 调用模型获取原始响应并记录日志
result = model.invoke(prompt)
logger.info(f"********>模型原始输出:\n{result}")

# 创建字符串输出解析器,用于处理模型输出
parser = StrOutputParser ()

# 解析模型输出为结构化结果并记录日志
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
# 记录解析结果的数据类型
logger.info(f"结果类型: {type(response)}")


print()
print("*" * 60)
print()


# 构建处理链:提示模板 -> 模型 -> 输出解析器
chain = chat_prompt | model | parser

# 执行处理链并记录最终结果及数据类型
result_chain = chain.invoke({"role": "AI助手", "question": "什么是LangChain,简洁回答100字以内"})
logger.info(f"Chain执行结果:\n {result_chain}")
logger.info(f"Chain执行结果类型: {type(result_chain)}")

print()

print(type(chain))

RunnableBranch-分支链

用条件分支判断 (条件,Runnable) 对列表和默认分支进行初始化。就是if-else if-else

在langchain中提供类RunnableBranch来完成LCEL中的条件分支判断,可以根据输入的不同采用不同的处理逻辑

python 复制代码
'''
分支链
在langchain中提供类RunnableBranch来完成LCEL中的条件分支判断,可以根据输入的不同采用不同的处理逻辑
具体实例如下
会根据用户输入中是否包含英文、韩文等关键词,来选择对应的提示词进行处理。根据判断结果
再执行不同的逻辑分支
'''

from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from loguru import logger
from langchain_core.runnables import RunnableBranch
import os

# 创建提示词
english_prompt = ChatPromptTemplate.from_messages([
    ('system', '你是一个英语翻译,你叫小英'),
    ('human', '{query}')
])

japanese_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个日语翻译专家,你叫小日"),
    ("human", "{query}")
])

korean_prompt = ChatPromptTemplate.from_messages([
    ('system', '你是一个韩语翻译,你叫小韩'),
    ('human', '{query}')
])

def determine_language(inputs):
    '''判断语言种类'''
    query = inputs['query']
    if '日语' in query:
        return 'japanese'
    elif '韩语' in query:
        return 'korean'
    return 'english'


# 初始化模型
model = init_chat_model(
    model='qwen-plus',
    model_provider='openai',
    # 硬编码写死key
    api_key=os.getenv('aliQwen-api'),  # 平台提供的API-KEY
    base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)

# 创建字符输出解析器,用于处理模型输出
parser = StrOutputParser()


# 创建一个可执行的分支链,根据输入文本语言类型选择响应的处理流程
# 返回值:RunnableBranch对象,可根据输入动态选择执行路径的可运行链
chain = RunnableBranch(
    (lambda x: determine_language(x)=='japanese',japanese_prompt|model|parser),
    (lambda x: determine_language(x)=='korean',korean_prompt|model|parser),
    (english_prompt|model|parser)
)

# 测试查询
test_queries = [
    {'query': '请你用韩语翻译这句话:"见到你很高兴"'},
    {'query': '请你用日语翻译这句话:"见到你很高兴"'},
    {'query': '请你用英语翻译这句话:"见到你很高兴"'}
]


for query_input in test_queries:
    # 判断使用哪个词
    lang = determine_language(query_input)
    logger.debug(f'检测到语言类型:{lang}')

    # 根据语言类型选择对应的提示词并格式化
    if lang == 'english':
        chatPromptTemplate = english_prompt
    elif lang == 'korean':
        chatPromptTemplate = korean_prompt
    else:
        chatPromptTemplate = japanese_prompt

    # print(query_input) # {'query': '请你用英语翻译这句话:"见到你很高兴"'}

    # 格式化提示词并打印
    formatted_messages = chatPromptTemplate.format_messages(**query_input)
    logger.info(f"格式化后的提示词:{formatted_messages}")
    for msg in formatted_messages:
        logger.info(f"[{msg.type}]: {msg.content}")

    # 执行链
    result = chain.invoke(query_input)
    logger.info(f"输出结果: {result}\n")

RunnableSerializable-串行链

子链叠加串行,假如我们需要多次调用大模型,将多个步骤串联起来实现功能,案例如下

python 复制代码
'''
RunnableSerializable-串行链
子链叠加串联,假如我们需要多次调用大模型,需要多个步骤串联起来实现功能
'''

from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from loguru import logger
import os

# 初始化模型
model = init_chat_model(
    model='qwen-plus',
    model_provider='openai',
    # 硬编码写死key
    api_key=os.getenv('aliQwen-api'),  # 平台提供的API-KEY
    base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)

# 子链1提示词
prompt1 = ChatPromptTemplate.from_messages([
    ('system', '你是一个知识渊博的计算机专家,请用中文简短回答我提出的问题'),
    ('human', '请简短介绍什么是{topic}')
])
# 子链1解析器
parser1 = StrOutputParser()
# 子链1:生成内容
chain1 = prompt1 | model | parser1

result1 = chain1.invoke({'topic':'langchain'})
logger.info(result1)


# 子链2提示词
prompt2 = ChatPromptTemplate.from_messages([
    ('system', '你是一个翻译助手,请将用户输入内容翻译为英文'),
    ('human', '{input}')
])
# 子链2解析器
parser2 = StrOutputParser()
# 子链1:翻译内容
chain2 = prompt2 | model | parser2

# 组合一个复合chain,使用lambda函数将chain1执行结果content内容添加input键作为参数传递给chain2
full_chain = chain1 | (lambda content:{'input':content})|chain2
full_chain1 = chain1 |chain2

# 调用复合链
result = full_chain.invoke({'topic':'langchain'})

result1 = full_chain1.invoke({'topic':'langchain'})

logger.info(result)
print('*'*100)
logger.info(result1)

RunnableParallel-并行链

在 Langchain 中,创建并行链(Parallel Chains),是指同时运行多个子链(Chain),

并在它们都完成后汇总结果。

python 复制代码
'''
RunnableParallel-并行链
在langchain中,创建并行链(Parallel Chains),是指同时运行多个子链(chain),并在他们都完成后汇总结果
**作用**,同时执行多个runnable,合并结果
'''

from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel
from loguru import logger
import os

# 初始化模型
model = init_chat_model(
    model='qwen-plus',
    model_provider='openai',
    # 硬编码写死key
    api_key=os.getenv('aliQwen-api'),  # 平台提供的API-KEY
    base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)

# 并行链1提示词
prompt1 = ChatPromptTemplate.from_messages([
    ('system', '你是一个知识渊博的计算机专家,请用中文简短回答我提出的问题'),
    ('human', '请简短介绍什么是{topic}')
])
# 并行链1解析器
parser1 = StrOutputParser()
# 并行链1:生成中文结果
chain1 = prompt1 | model | parser1

# 并行链2提示词
prompt2 = ChatPromptTemplate.from_messages([
    ('system', '你是一个知识渊博的计算机专家,请用英文简短回答我提出的问题'),
    ('human', '请简短介绍什么是{topic}')
])
# 子链2解析器
parser2 = StrOutputParser()
# 子链1:生成英文结果
chain2 = prompt2 | model | parser2

# 创建并行链,用于同时处理多个语言处理链
parallel_chain = RunnableParallel({
    'chinese': chain1,
    'english': chain2
})

# 调用复合链
result = parallel_chain.invoke({'topic': 'langchain'})
logger.info(result)

RunnableLambda-函数链

函数转可执行链,

将普通Python函数融入Runnable流程

记忆缓存(和Runnable相关)

是什么:上下文记忆缓存,存储之前对话的内容,从而提供连贯和个性化回复

能解决什么问题:前面说的话和后面的话语相关联,即前言搭后语

为什么要使用:解决固有的上下文遗忘问题,实现连贯且智能

内存版本:(生产上用不上,自行查找文档)

持久化版本:此处以RedisStack为例

|------|-----------------------------|--------------|
| 组件 | RedisStack | 原生Redis |
| 数据结构 | 增加JSON、图、时间序列、概率结构等高级类型 | 字符串、列表、集合、哈希 |
| 查询能力 | 支持全文搜索、向量搜索、图查询、JSON查询 | 仅限键值查询 |
| 使用场景 | 实时推荐、时序分析、知识图谱、文档数据库、AI向量检索 | 缓存、消息队列、计数器等 |
| 开发体验 | 提供RedisInsight和对象映射库,开发效率更高 | 命令行操作,手动拼接逻辑 |

Redis核心组件:RedisSearch、RedisJSON、RedisGraph、RedisBloom

RedisStack = 原生Redis + 搜索 + 图 + 时间序列 + JSON + 概率结构 + 可视化工具 + 开发框架支持

代码案例

环境验证

python 复制代码
# pip install redis==7.2.0

# 尝试导入 redis 包
import redis

# 验证包版本(无报错即为导入成功)
print(redis.__version__)

# 极简 redis 导入测试脚本
try:
    # 导入 redis 包
    import redis
    print("✅ redis 包导入成功!")
    print(f"✅ redis 包版本:{redis.__version__}")
except ModuleNotFoundError:
    print("❌ 未找到 redis 包,请先安装!")
except Exception as e:
    print(f"❌ redis 包导入异常:{e}")

"""
7.2.0
✅ redis 包导入成功!
✅ redis 包版本:7.2.0
"""
python 复制代码
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableConfig
from langchain.chat_models import init_chat_model
import os
import redis # 导入原生Redis库
from loguru import logger

REDIS_URL = 'redis://117.72.80.97:6379'
# 创建原生Redis客户端,decode_responses 控制Redis返回数据的类型:False返回字节串,True返回字符串
redis_client = redis.Redis.from_url(REDIS_URL,decode_responses=True)


# 初始化模型
model = init_chat_model(
    model='qwen-plus',
    model_provider='openai',
    api_key=os.getenv('aliQwen-api'),  # 平台提供的API-KEY
    temperature=0.0,
    base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)


# 创建提示词模板
prompt = ChatPromptTemplate.from_messages([
    MessagesPlaceholder('history'),
    ('human', '{question}')
])


def get_session_history(session_id: str) ->RedisChatMessageHistory:
    '''创建或者获取历史会话(使用Redis)'''
    # 创建Redis历史对象
    history = RedisChatMessageHistory(
        session_id=session_id,
        url=REDIS_URL,
        # ttl=3600 # 注释:关闭自动过期,避免重启后数据被清洗
    )

    return history

# 创建带历史的链
chain = RunnableWithMessageHistory(
    prompt | model | StrOutputParser(),
    get_session_history,
    input_messages_key='question',
    history_messages_key='history'
)

# 配置
# session_id 就是登录大模型的各自账号,类似登录手机号码,各不相同
config = RunnableConfig(configurable={'session_id': 'user-001'})

# 主循环
print('开始对话(输入"quit"退出)')
while True:
    question = input('\n输入问题:')
    if question.lower() in ['quit', 'exit', 'q']:
        break

    response = chain.invoke({'question': question},config)
    logger.info(f'AI回答{response}')
    # 等同于redis-cli的save命令,强制写入dump.rdb
    redis_client.save()

Tools (Function Calling)工具调用

是什么:通过tool工具机制可以使得模型具有'调用外部函数'的能力,是的其可以与外部系统、API或者自定义函数进行交互,从而完成仅靠文本生成无法完成的任务(LLM本身不执行函数,只是知道调用哪个函数和如何调用),简单来说就是LLM的外部工具类

能解决什么问题:可以解决大模型不具备访问数据库、调用API的能力,不执行代码或者文件操作,无法实时访问互联网或者动态数据的问题

为什么要使用:比如希望通过大模型获取某地实时的天气,大模型是基于过往数据的预训练,对于之后的数据则不知道,可以结合tool工具获取最新的数据,可以使用工具访问数据库,调用API,执行文件和代码

|---------------|-------------------|-----------------------------------------------|
| 属性 | 类型 | 描述 |
| name | str | 必选,在提供给LLM或者Agent工具中必须是唯一的 |
| description | str | 可选但建议,描述工具的功能,LLM或Agent将使用此描述作为上下文工具的使用 |
| args_schema | PydanticBaseModel | 可选但建议,可用于提供更多信息(例如few-shot实例)或验证预期参数 |
| return_direct | boolean | 仅对Agent相关,当为True时,在调用给工具后,Agent将停止并将结果直接返回给用户 |
[Tool常用属性]

相关推荐
2501_918126912 小时前
怎么接usb转杜邦线到stm32上
stm32·单片机·嵌入式硬件·学习·个人开发
linux_cfan2 小时前
第四篇:像敏捷开发一样迭代人生——控制论与真正的高级智能
学习·敏捷流程
炽烈小老头2 小时前
【每天学习一点算法 2026/02/24】矩阵置零
学习·算法·矩阵
●VON2 小时前
HarmonyOS应用开发实战(基础篇)Day12 -《打造专业级底部导航栏》
学习·华为·harmonyos·von
有为少年2 小时前
Monarch矩阵:从设计直觉到数学推导与实际应用
人工智能·深度学习·学习·线性代数·机器学习·计算机视觉·矩阵
2501_918126912 小时前
stm32四条线,红绿黑白分别对应什么
stm32·单片机·学习·个人开发
左左右右左右摇晃2 小时前
SpringBoot 实现「新增班级 + 批量关联教师」多对多业务实战
笔记
健忘的派大星4 小时前
需求激增800%!2025年第一硬通货:懂大模型、云计算和硬件的“前沿部署工程师”!
人工智能·算法·架构·langchain·云计算·大模型学习·大模型教程
小付同学呀10 小时前
C语言学习(五)——输入/输出
c语言·开发语言·学习