首页 > 教程攻略 > ai教程 >大模型开发框架LangChain

大模型开发框架LangChain

来源:互联网 时间:2026-07-09 07:26:19

如果你想快速上手一个能让大模型应用开发事半功倍的框架,LangChain绝对是首选。它由 Harrison Chase 于2022年10月创建,核心思路是为各种大语言模型(LLMs)提供统一的接口,把相关的组件像搭乐高一样“链接”起来,从而大幅降低开发门槛,让复杂应用的构建变得高效。

一、简述

1 什么是LangChain

LangChain围绕LLMs建立了一个框架,核心理念是为各种LLMs实现通用接口,将LLMs相关的组件“链接”在一起,简化开发难度,方便开发者快速开发复杂的LLMs应用。

LangChain官网提供了完整的入门文档。LangChain在LLM应用的每个生命周期阶段都做了简化:

  • 开发

    :使用开源组件和第三方集成构建应用,通过LangGraph构建支持一流流式和人机交互的状态智能体。
  • 生产化

    :借助LangSmith检查、监控和评估应用,方便持续优化和部署。
  • 部署

    :利用LangGraph平台将应用转变为可用于生产的API和助手。

2 主要组件

  • Models

    :模型,各种类型的模型和模型集成,比如GPT-4。
  • Prompts

    :提示,包括提示管理、提示优化和提示序列化。
  • Chains

    :链,一系列对各种组件的调用。
  • Memory

    :记忆,用来保存和模型交互时的上下文状态。
  • Indexes

    :索引,用来结构化文档,以便和模型交互。
  • Agents

    :智能体,决定模型采取哪些行动,执行并观察流程,直到完成为止。

3 LangChain核心包

  • langchain-core

    :聊天模型和其他组件的基础抽象。
  • 集成包

    (例如 langchain-openai、langchain-anthropic 等):重要的集成被拆分为轻量级的独立包,由LangChain团队和集成方共同维护。
  • langchain

    :包含链(chains)、智能体(agents)和检索策略,构成应用的认知架构。
  • langchain-community

    :由社区维护的第三方集成。
  • langgraph

    :一个编排框架,用于将LangChain组件组合成可用于生产的应用,支持持久化、流式处理及其他关键特性。

4 环境准备

本课程以LangChain+Qwen进行学习,需要提前安装相关依赖。借助阿里云-百炼平台(需要申请API Key 以及Secret Key)来调用Qwen模型。

二、Models

现在市面上的模型多如牛毛,各种新模型层出不穷。LangChain模型组件提供了与各种模型的集成,并为所有模型提供一个精简的统一接口。

LangChain目前支持三种类型的模型:LLMs、Chat Models(聊天模型)、Embeddings Models(嵌入模型)。

  • LLMs

    :大语言模型接收文本字符作为输入,返回的也是文本字符。
  • 聊天模型

    :基于LLMs,不同的是它接收聊天消息(一种特定格式的数据)作为输入,返回的也是聊天消息。
  • 文本嵌入模型

    :接收文本作为输入,返回的是浮点数列表。

这三类模型的使用场景、输入和输出各不相同,开发者需要根据项目需求选择相应的模型。

1 LLMs

LLMs的应用场景最为广泛。下面以Qwen为例进行讲解。

模型调用有两种方式:

  • 通过ChatOpenAI调用

from langchain_openai import ChatOpenAI
import os

# 实例化模型
model = ChatOpenAI(
    base_url=os.environ.get('base_url','https://dashscope.aliyuncs.com/compatible-mode/v1'),
    model='qwen-plus',
    openai_api_key=os.environ.get('api_key','sk-XXXXXX'),
    max_tokens=1000,
    temperature=0
)
# 获取问答结果
result = model.invoke("帮我讲个笑话吧")
print(result.content)
  • 通过Ollama调用

# from langchain_community.llms import Ollama # Langchain 0.x版本使用
from langchain_ollama import OllamaLLM

# 实例化模型
model = OllamaLLM(model="qwen2.5:7b")
# 获取问答结果
result = model.invoke("请给我讲个笑话吧")
print(result)

2 Chat Models

聊天模型接收的聊天消息包含以下几种类型,使用时需要按约定传入合适的值:

  • AIMessage

    :AI输出的消息,可以是针对问题的回答。
  • HumanMessage

    :人类消息,由人给出的提示信息,比如“实现一个快速排序方法”。
  • SystemMessage

    :用于指定模型所处的环境和背景,如角色扮演。你可以在这里给出具体指示,比如“作为一个代码专家”,或者“返回json格式”。
  • ChatMessage

    :Chat消息可以接受任意角色的参数,但大多数情况下应使用上面三种类型。

LangChain支持大量的聊天模型,可以通过官方文档或LangChain源码查看所有支持的模型。

  • SystemMessage + HumanMessage + AIMessage

from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_ollama import ChatOllama

# 实例化模型
model = ChatOllama(model="qwen2.5:7b")
# 定义提示词
messages = [
    SystemMessage(content="现在你是一个著名的诗人"),
    HumanMessage(content="给我写一首唐诗")
]
# 获取问答结果
result = model.invoke(messages)
print(result.content)

3 Embeddings Models

嵌入模型的特点是:将字符串作为输入,返回一个浮点数列表。在NLP中,Embedding的作用就是将数据进行文本向量化。

不同的Embedding模型在多语言支持和文本类型上有不同特点:

  • 多语言支持

    • text-embedding-ada-002:支持多种语言,但对中文等亚洲语言的支持相对较弱。
    • bge-large-zh:对中文有很好的支持。
    • multilingual-e5-large:对多语言都有较好的支持。
    • mxbai-embed-large:也是一种选择。
  • 文本类型适用性

    • 代码文本:建议使用专门的代码Embedding模型,如 CodeBERT
    • 通用文本:可以使用 text-embedding-ada-002bge-large-zh
    • 专业领域文本:建议使用该领域的专门模型。

可以参考MTEB(大规模文本嵌入基准)排行榜获取最新模型效果。

接下来以一个文本嵌入模型的例子进行说明:

# from langchain_community.embeddings import OllamaEmbeddings # Langchain 0.x版本使用
from langchain_ollama import OllamaEmbeddings

# 初始化Ollama嵌入模型,使用mxbai-embed-large模型,温度设置为0
model = OllamaEmbeddings(model="mxbai-embed-large", temperature=0)

# 对单个查询文本进行嵌入编码
res1 = model.embed_query('这是第一个测试文档')
print(f'result1->{res1}')
print(f'result1的长度->{len(res1)}')

# 对多个文档进行批量嵌入编码
res2 = model.embed_documents(['这是第一个测试文档', '这是第二个测试文档'])
print(res2)

运行结果:

大模型开发框架LangChain

三、Prompts

1 通用prompt

Prompt是指用户输入信息时加入的提示,形式可以是zero-shot或few-shot等,目的是让模型理解更复杂的业务场景,从而更好地解决问题。

提示模板:如果你已经有了一个起作用的提示,你可能想把它作为模板用于解决其他问题。LangChain提供了PromptTemplates组件,帮助更方便地构建提示。

  • zero-shot提示方式

from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

# 定义模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
prompt = PromptTemplate(input_variables=["lastname"], template=template)
prompt_text = prompt.format(lastname="王")
print(prompt_text)
# result: 我的邻居姓王,他生了个儿子,给他儿子起个名字
result = model.invoke(prompt_text)
print(result)

运行结果:

大模型开发框架LangChain

  • few-shot提示方式

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

examples = [
    {"word": "开心", "antonym": "难过"},
    {"word": "高", "antonym": "矮"}
]

example_template = """
单词: {word}
反义词: {antonym}\n
"""
example_prompt = PromptTemplate(input_variables=["word", "antonym"], template=example_template)

few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="给出每个单词的反义词",
    suffix="单词: {input}\n反义词:",
    input_variables=["input"],
    example_separator="\n",
)

prompt_text = few_shot_prompt.format(input="粗")
print(model.invoke(prompt_text))
# 细

2 ChatPrompts

适合交互式对话应用,如聊天机器人、智能客服等,这些应用需要处理用户和LLM之间的多轮对话。

  • 直接提问

提示模板就是把常见的提示整理成模板,用户只需要修改模板中特定的词语,就能快速准确地告诉模型自己的需求。看个例子:

from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

template_str = "帮我讲个关于{name}笑话吧"
prompt_template = ChatPromptTemplate.from_template(template_str)
prompt = prompt_template.format_messages(name="气球")
print(f'prompt-->{prompt}')
result = model.invoke(prompt)
print(f'result-->{result}')
  • zero-shot提示方式

from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.messages import SystemMessage
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

system_prompt = SystemMessage("你是取名专家。")
human_str = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字。"
human_template = HumanMessagePromptTemplate.from_template(human_str)

chat_template = ChatPromptTemplate.from_messages([system_prompt, human_template])
prompt = chat_template.format_messages(lastname="王")
print(f'prompt-->{prompt}')
result = model.invoke(prompt)
print(f'result-->{result}')
  • few-shot提示方式

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "给出每个单词的反义词"),
    MessagesPlaceholder("history"),
    ("human", "{question}")
])

history = [("human", "开心"), ("ai", "难过"), ("human", "高"), ("ai", "矮")]
prompt = prompt_template.format_messages(history=history, question="富有")
print(f"prompt-->{prompt}")
result = model.invoke(prompt)
print(f'result-->{result}')

四、Chains

在LangChain中,Chains描述了将LLM与其他组件结合起来完成一个应用程序的过程。针对上一小节的提示模版例子(zero-shot),我们可以用链来连接提示模版组件和模型,从而实现代码的更改。主要使用LCEL方法。

LCEL(Lang Chain Expression Language)是一种声明式的方法,用于轻松组合链条。基本语法规则是使用|符号将不同的组件连接起来,形成一个链式结构。|符号类似于Unix的管道操作符,将一个组件的输出作为下一个组件的输入,实现数据的传递和处理。

上一个组件的输出作为下一个组件的输入,输出和输入的类型必须保持一致,否则不能连接。

from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM

# 定义模板
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
prompt = PromptTemplate(input_variables=["lastname"], template=template)

# 实例化模型
llm = OllamaLLM(model="qwen2.5:7b")

chain = prompt | llm

# 执行链
print(chain.invoke("王"))

如果你想将第一个模型输出的结果直接作为第二个模型的输入,直接使用管道符:

from langchain_core.prompts import PromptTemplate
from langchain_ollama import OllamaLLM

# 创建第一条链
template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字"
first_prompt = PromptTemplate(input_variables=["lastname"], template=template)
llm = OllamaLLM(model="qwen2.5:7b")
first_chain = first_prompt | llm

# 创建第二条链
second_prompt = PromptTemplate(
    input_variables=["child_name"],
    template="邻居的儿子名字叫{child_name},给他起一个小名"
)
second_chain = second_prompt | llm

# 链接两条链
overall_chain = first_chain | second_chain
print(overall_chain)
print('*'*80)

# 执行链,只需要传入第一个参数
catchphrase = overall_chain.invoke("王")
print(catchphrase)

五、output_parsers

LLM的输出是自然语言文本,但在应用开发中,我们经常需要将这些文本转换为结构化的数据格式,如列表、字典或对象。LangChain输出解析器负责获取LLM的输出并将其转换为更合适的格式。

解析器名称核心功能输出的 Python 类型工业级应用场景
StrOutputParser默认解析器。将 LLM 的输出直接解析为字符串。str只需要原始回答时(如问答任务、对话场景)
CommaSeparatedListParser将 LLM 输出的、用逗号分隔的文本解析为列表。list[str]列表/枚举型输出
JsonOutputParser极其常用。将 LLM 输出的 JSON 字符串解析为 Python 字典。dict结构化 JSON 输出
PydanticOutputParser极其常用。将 LLM 输出解析为预先定义的 Pydantic 对象,提供类型安全和数据验证。自定义的 pydantic.BaseModel 对象输出需要严格结构化(JSON-like)数据时
DatetimeOutputParser从文本中智能地解析出日期和时间信息。datetime.datetime需要时间格式时

1 字符串解析器

StrOutputParser,最简单的解析器,用于提取模型返回的原始文本:

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

prompt = ChatPromptTemplate.from_template("解释{topic}是什么?回答控制20字以内")
chain1 = prompt | model
result1 = chain1.invoke({"topic": "ai"})
print(f"result1-->{result1}")

parser = StrOutputParser()
chain2 = prompt | model | parser
result2 = chain2.invoke({"topic": "ai"})
print(f"result2-->{result2}")

2 列表解析器

CommaSeparatedListOutputParser,将逗号分隔的文本转换为Python列表:

from langchain_core.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

parser = CommaSeparatedListOutputParser()
format_instructions = parser.get_format_instructions()
prompt = ChatPromptTemplate.from_template("用中文列出{topic}的五个最重要特点。\n{format_instructions}")

chain = prompt | model | parser
result = chain.invoke({"topic": "大模型", "format_instructions": format_instructions})
print(result)

3 JSON解析器

JsonOutputParser,将JSON格式文本转换为Python字典或列表:

from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

json_parser = JsonOutputParser()
json_format_instructions = json_parser.get_format_instructions()
json_prompt = ChatPromptTemplate.from_template(
    "生成一个包含{person}基本信息的JSON。应包括姓名、职业、年龄和技能列表, 不要包含任何注释或额外说明。\n{format_instructions}"
)

json_chain = json_prompt | model | json_parser
result = json_chain.invoke({"person": "雷军", "format_instructions": json_format_instructions})
print(result)

4 Pydantic解析器

PydanticOutputParser,使用Pydantic模型定义输出结构:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

class Movie(BaseModel):
    title: str = Field(description="电影标题")
    director: str = Field(description="导演姓名")
    year: int = Field(description="上映年份")
    genre: List[str] = Field(description="电影类型")
    rating: float = Field(description="评分(1-10)")

pydantic_parser = PydanticOutputParser(pydantic_object=Movie)
format_instructions = pydantic_parser.get_format_instructions()
pydantic_prompt = ChatPromptTemplate.from_template("生成一部{genre}电影的信息。\n{format_instructions}")

pydantic_chain = pydantic_prompt | model | pydantic_parser
movie_data = pydantic_chain.invoke({"genre": "科幻", "format_instructions": format_instructions})
print(movie_data)

5 自定义解析器

创建自定义输出解析器:

from langchain_core.output_parsers import BaseOutputParser
from typing import Dict, Any
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen2.5:7b")

class CustomKeyValueParser(BaseOutputParser[Dict[str, Any]]):
    """解析形如'key: value'的文本"""
    def parse(self, text: str) -> Dict[str, Any]:
        """从文本中解析键值对"""
        result = {}
        lines = text.strip().split('\n')
        for line in lines:
            if ':' in line:
                key, value = line.split(':', 1)
                result[key.strip()] = value.strip()
        return result

    def get_format_instructions(self) -> str:
        """提供格式指导给模型"""
        return """请以'键: 值'的格式返回信息,每行一个键值对。例如:
名称: 爱因斯坦
职业: 物理学家
贡献: 相对论"""

custom_parser = CustomKeyValueParser()
custom_prompt = ChatPromptTemplate.from_template("提供关于{person}的基本信息。\n{format_instructions}")

custom_chain = custom_prompt | model | custom_parser
result = custom_chain.invoke({"person": "屠呦呦", "format_instructions": custom_parser.get_format_instructions()})
print(result)

六、Memory

大模型本身不具备上下文的概念,它并不保存上次交互的内容。ChatGPT之所以能够和人正常对话,是因为它进行了一层封装,将历史记录回传给了模型。因此LangChain也提供了Memory组件。Memory分为两种类型:短期记忆和长期记忆。短期记忆一般指单一会话时传递数据,长期记忆则是处理多个会话时获取和更新信息。

  • 使用 ChatMessageHistory 手动添加上下文

from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import messages_to_dict, messages_from_dict
import json

# 1.创建一个ChatMessageHistory对象,用来存储对话信息
history = ChatMessageHistory()
history.add_user_message("在吗?")
history.add_ai_message("在")
print(f'history.messages-->{history.messages}')

# 2.可以将history.messages中的信息保存到字典中,然后保存到数据库或者文件中
dicts = messages_to_dict(history.messages)
print(f'dicts-->{dicts}')

# 2.2 保存到文件
with open('history.json', 'w', encoding='utf-8') as f:
    f.write(json.dumps(dicts, indent=2, ensure_ascii=False))

# 3.从文件中读取并转换回消息
messages = json.load(open('history.json', 'r', encoding='utf-8'))
chat_messages = messages_from_dict(messages)
print(f'chat_messages-->{chat_messages}')

LangChain v1.0版本对Memory组件进行了深度优化与工程化重构,使其不仅支持多轮对话上下文管理,更成为构建生产级智能体(Agent)不可或缺的核心能力之一。在LangChain从“实验性框架”迈向“企业级平台”的关键转型中,Memory模块被赋予了更清晰的职责边界、更灵活的策略机制以及更强的可扩展性,从而支撑复杂任务场景下的长期记忆、状态追踪与个性化交互。

1 短期记忆(Short-term Memory)

短期记忆的本质是线程级状态管理。在LangGraph中:

(1)状态(State)


通常是一个包含 messages 字段的字典或 Pydantic 模型(如 MessagesState 或自定义 CustomState),用于存储当前会话的所有消息、中间变量、工具调用结果等。

(2)检查点器(Checkpointer)


负责将状态序列化并持久化到内存、SQLite、PostgreSQL 等后端。每次状态变更(如新增一条消息)都会触发一次检查点保存。

(3)会话ID(thread_id)


作为会话的唯一标识符,确保不同用户或不同对话之间的状态完全隔离。即使多个用户并发交互,也不会发生记忆混淆。

from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySa ver
from langchain.messages import HumanMessage
from langchain_ollama import OllamaLLM
import time

model = OllamaLLM(model="qwen2.5:7b")
checkpointer = InMemorySa ver()
timestamp = time.time()
config = {"configurable": {"thread_id": f"{int(timestamp)}"}}

agent = create_agent(
    model=model,
    tools=[],
    checkpointer=checkpointer,
    system_prompt="你是一个翻译官,擅长中英互译。"
)

input_1 = {"messages": [HumanMessage("你好,我叫小呆。")]}
response_a = agent.invoke(input=input_1, config=config)

input_2 = {"messages": [HumanMessage("你好,我叫什么?")]}
config_2 = {"configurable": {"thread_id": f"{int(time.time())}"}}
response_b = agent.invoke(input=input_2, config=config_2)
response_c = agent.invoke(input=input_2, config=config)

print("Response A (第一次对话):")
print(response_a)
print("\nResponse B (新线程,无记忆):")
print(response_b)
print("\nResponse C (回到原线程,有记忆):")
print(response_c)

代码运行逻辑:

  • checkpointer (记忆核心)

    :这是LangGraph区别于传统简单API调用的关键。它允许Agent在多次invoke调用之间保存状态。
  • thread_id (记忆索引)

    :你可以把thread_id想象成数据库中的主键。Response A向ID为100的记录里写入了名字;Response B向ID为200的新记录提问,因为200是空的,所以Agent不知道名字;Response C又回到ID为100的记录提问,Agent读取了历史记录,所以知道名字。
  • System Prompt

    :虽然输入是在对话,但因为设定了“你是一个翻译官”,Agent可能会试图在回答的同时进行翻译,或者在回复格式上符合翻译官的身份。

2 长期记忆

对于需要长期运行和可靠记忆的应用,推荐使用数据库进行持久化。详见后面阶段LangGraph部分。

七、Indexes

Indexes组件的目的是让LangChain具备处理文档处理的能力,包括:文档加载、检索等。注意,这里的文档不局限于txt、pdf等文本类内容,还涵盖email、区块链、视频等内容。

Indexes组件主要包含类型:

  • 文档加载器
  • 文本分割器
  • VectorStores
  • 检索器

1 文档加载器

文档加载器主要基于Unstructured 包,它是把各种类型的文件转换成文本的Python包。使用起来很简单,只需要引入相应的loader工具。

LangChain支持的文档加载器(部分):

大模型开发框架LangChain

示例代码:

from langchain_unstructured import UnstructuredLoader
loader = UnstructuredLoader('./data/衣服属性.txt', encoding='utf8')
docs = loader.load()
print(f'docs-->{docs}')
print(f'len-->{len(docs)}')
print(f'第一行数据-->{docs[0].page_content}')
print('*' * 100)

from langchain_community.document_loaders import TextLoader
loader = TextLoader('./data/衣服属性.txt', encoding='utf8')
docs = loader.load()
print(f'docs-->{docs}')
print(f'len-->{len(docs)}')
print('第一行数据-->{}'.format(docs[0].page_content.split('\n')[0]))

2 文档分割器

由于模型对输入的字符长度有限制,我们在碰到很长的文本时,需要把文本分割成多个小的文本片段。

文本分割最简单的方式是按照字符长度进行分割,但这样会带来很多问题,比如如果文本是一段代码,一个函数被分割到两段之后就成了没有意义的字符,所以整体的原则是把语义相关的文本片段放在一起。

LangChain中最基本的文本分割器是CharacterTextSplitter,它按照指定的分隔符(默认“\n\n”)进行分割,并且考虑文本片段的最大长度。看个例子:

from langchain_core.documents import Document
from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter(separator=" ", chunk_size=5, chunk_overlap=1)
result1 = text_splitter.split_text("a b c d e f")
print(f'result1--->{result1}')

result2 = text_splitter.create_documents(["a b c d e f", "e f g h"])
print(f'result2--->{result2}')

result3 = text_splitter.split_documents([Document(page_content="a b c d e f", metadata={"id": "1"})])
print(f'result3--->{result3}')

除了CharacterTextSplitter,LangChain还支持其他文档分割器(部分):

分割器名称功能描述类型工业场景应用
CharacterTextSplitter简单按指定分隔符(如换行、逗号)直接分割。基础字符解析简单字符串或CSV数据处理,如传感器数据日志。
RecursiveCharacterTextSplitter递归按字符分割,先尝试自然边界(如段落、句子),太大则继续细分。通用字符解析通用文本处理,如日志、报告、PDF文档分割,便于RAG检索。
TokenTextSplitter按 token(词元)分割,支持LLM token计数。Token 基于解析LLM输入优化,如处理API响应或长查询,控制token限制。
SentenceTextSplitter按句子边界分割,使用NLP识别句子(包括标点)。语义解析自然语言文本,如文章或对话分析,保持句子完整。
SpacyTextSplitter使用SpaCy NLP库按句子或实体分割(需安装SpaCy)。语义解析高级NLP场景,如实体提取或生物医学文本。
NLTKTextSplitter使用NLTK库按句子或词分割(需安装NLTK)。语义解析文本研究或分析,如时间序列数据描述。
MarkdownHeaderTextSplitter按Markdown结构(如标题、列表)智能分割。结构化解析Markdown文档分割,保留语义结构,用于知识库构建。
HTMLSplitter按HTML标签(如

)分割网页内容。

结构化解析网页数据爬取,如在线技术文档或新闻提取。
LatexTextSplitter按LaTeX结构(如章节、公式)分割。结构化解析学术论文或数学文档处理。
PythonCodeTextSplitter按Python代码结构(如函数、类)分割。代码解析源代码文件分析,如脚本调试或代码库管理。

下面就几个重要的分割器进行讲解。

  • 递归字符文本分割器(RecursiveCharacterTextSplitter)

  • 语义文档分割器(SemanticChunker)

  • MarkdownHeaderTextSplitter(Markdown文档切割器)

其他拓展知识可以在实际使用中参考更多资料。

3 VectorStores

VectorStores是一种特殊类型的数据库,它的作用是存储由嵌入创建的向量,提供相似查询等功能。

LangChain支持的VectorStore种类丰富,常见的如下:

大模型开发框架LangChain

from langchain_text_splitters import CharacterTextSplitter
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_ollama import OllamaEmbeddings

# 1.加载文档
loader = TextLoader('./data/pku.txt', encoding='utf-8')
docs = loader.load()

# 2.将文档进行分块
text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=200, chunk_overlap=30)
split_docs = text_splitter.split_documents(docs)
print(f'split_docs-->{split_docs}')

# 3.将分割后的文档存储到向量数据库中
embedding = OllamaEmbeddings(model="mxbai-embed-large")
chromadaDB = Chroma.from_documents(documents=split_docs, embedding=embedding, persist_directory='./chroma_db')

# 假如你的向量数据库已经存在,那么可以直接加载
# chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)

# 4.使用向量数据库进行查询
query = "1937年北京大学发生了什么?"
result = chromadaDB.similarity_search(query, k=2)
print(f'result-->{result}')

4 检索器

4.1 LangChain的检索器定义

检索器是 LangChain 中负责信息检索的模块,通常与索引模块(如向量存储、嵌入模型)结合使用。它的核心功能是:

  • 输入

    :接收用户查询(通常是文本)。
  • 处理

    :根据查询从数据源中检索相关内容。
  • 输出

    :返回一组相关文档或文本片段(通常是 Document 对象列表)。

检索器在以下场景中扮演关键角色:

  • 问答系统:从文档或知识库中检索答案的上下文。
  • 语义搜索:根据查询的语义返回相关结果。
  • 上下文增强:为语言模型提供外部知识,解决其知识局限。

4.2 检索器的工作原理

检索器通常与向量存储配合,通过嵌入模型将查询和文档转为向量,基于相似性进行检索。工作流程可以分为以下步骤:

  • 查询嵌入

    :将用户查询通过嵌入模型转为向量表示。
  • 相似性搜索

    :在向量存储中查找与查询向量最相似的文档向量。
  • 文档返回

    :返回匹配的文档(包含内容、元数据等)。
  • 后处理(可选)

    :对检索结果进行排序、过滤或重新排名。

检索器的核心依赖:

  • 嵌入模型

    :将文本转为向量(如 OpenAIEmbeddings, HuggingFaceEmbeddings)。
  • 向量存储

    :存储文档向量(如 Chroma、FAISS、Pinecone)。
  • 相似性度量

    :如余弦相似度、欧几里得距离。

4.3 检索器类型

LangChain支持很多检索器,部分如下:

大模型开发框架LangChain

此处我们讲解VectorStoreRetriever。

在 LangChain 中,as_retriever() 方法的 search_type 参数决定了向量检索的具体算法和行为。

retriever = vector_store.as_retriever(
    search_type="similarity",  # 可选 "similarity"|"mmr"|"similarity_score_threshold"
    search_kwargs={
        "k": 5,
        "score_threshold": 0.7,  # 仅当search_type="similarity_score_threshold"时有效
        "filter": {"source": "重要文档.pdf"},  # 元数据过滤
        "lambda_mult": 0.25  # 仅MMR搜索有效:接近0强调相关性,接近1强调差异性
    }
)

以下是三种搜索类型的对比:

大模型开发框架LangChain

示例代码:

from langchain_chroma import Chroma
from langchain_ollama import OllamaEmbeddings

embedding = OllamaEmbeddings(model="mxbai-embed-large")
chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)

query = "1937年北京大学发生了什么?"
retriever = chromadaDB.as_retriever(search_kwargs={"k":2})
result = retriever.invoke(query)
print(f'result-->{result}')

4.4 拓展

其他几种常用的检索器介绍如下。

  • TFIDFRetriever

  • BM25Retriever

  • MultiQueryRetriever

  • EnsembleRetriever

  • ContextualCompressionRetriever

  • Custom Retriever

八、Agents

1 Agent 概念

Agent(智能体)是一种能够感知环境、进行决策和执行动作的智能实体。不同于传统的人工智能,Agent具备通过主动思考、调用工具去逐步完成给定目标的能力。

为什么要调用工具?因为大模型虽然非常强大,但也存在局限性,比如不能回答实时信息、处理数学逻辑问题仍然很初级等。因此,可以借助第三方工具来辅助大模型的应用。

从大模型的角度来看,Agent其实就是基于大模型的语义理解和推理能力,让大模型拥有解决复杂问题时的任务规划能力,并调用外部工具来执行各种任务,利用向量数据库保留“记忆”的一个智能体。

工作流程概述:

  • 用户提出任务。
  • Agent 启动:将用户输入与预设的“提示词模板”结合,并结合当前的“上下文”和“变量”,形成一个完整的输入发送给大模型。
  • 大模型思考与决策(循环):
    • 大模型接收输入后,根据内置的逻辑和提示词的指导,进行“思考”。
    • 判断完成当前任务是否需要继续使用工具来获取更多信息/执行操作,还是已经可以直接生成最终答案。
    • 如果需要工具:大模型会根据任务需求和对工具的描述,选择合适的工具,并生成执行该工具所需的输入参数。
    • 工具执行:选定的工具被调用,执行其功能。
    • 结果反馈:工具执行的结果返回给Agent,并用来更新“上下文”和“变量”。
    • 循环:Agent将更新后的“上下文”、“变量”以及工具执行结果再次反馈给大模型,大模型继续新一轮的“思考-行动”循环,直到任务完成。
    • 如果直接回答:当大模型判断任务已完成,或无需额外工具即可回答时,它会生成最终的答案。
  • 用户输出:最终答案被呈现给用户。

2 Agent关键组成部分

大模型开发框架LangChain

  • 任务规划(Planning)

    :Agent需要提前将一项复杂任务拆解为多个更小、更易于处理的子任务,从而实现对复杂任务的高效处理。
  • 长短期记忆(Memory)

    :聊天上下文,长期保留和回忆信息。
  • 工具&执行(Tools&Action)

    :根据拆分好的子任务,调用外部提供好的专业API解决专业问题,完成一个个具体的子任务,并把处理结果返回给大模型。

3 LangChain实现Agent

LangChain提供了不同类型的智能体(主要罗列以下三种):

  • Zero-shot ReAct Description

    • 基于 ReAct 框架(推理 + 行动),仅依赖工具的

      描述

      来决定调用哪个工具。
    • 特点:无需额外示例(zero-shot),但

      不具备记忆能力

      ,每次推理都独立进行。
    • 使用场景:简单任务,工具选择完全靠工具描述即可。
  • Structured Chat Zero-shot ReAct Description

    • 同样基于 ReAct 框架,但可以处理

      结构化输入

      ,即支持带多个参数的工具(类似函数调用)。
    • 特点:不仅能像第一种智能体那样根据描述选择工具,还能正确组织并传递复杂参数。
    • 使用场景:调用接口类工具、需要多参数输入的任务。
  • Conversational ReAct Description

    • 在 ReAct 框架基础上,增强了

      对话记忆能力

    • 特点:能根据上下文对话历史来做出工具选择和回应,更适合持续性对话场景。
    • 使用场景:多轮对话,用户可能引用之前的内容或需要长期上下文跟踪。

LangChain中集成了很多工具,可以通过下面的方式查询:

from langchain_community.agent_toolkits.load_tools import get_all_tool_names
results = get_all_tool_names()
print(results)

运行结果:

['sleep', 'wolfram-alpha', 'google-search', 'google-search-results-json', 'searx-search-results-json', 'bing-search', 'metaphor-search', 'ddg-search', 'google-books', 'google-lens', 'google-serper', 'google-scholar', 'google-finance', 'google-trends', 'google-jobs', 'google-serper-results-json', 'searchapi', 'searchapi-results-json', 'serpapi', 'dalle-image-generator', 'twilio', 'searx-search', 'merriam-webster', 'wikipedia', 'arxiv', 'golden-query', 'pubmed', 'human', 'awslambda', 'stackexchange', 'sceneXplain', 'graphql', 'openweathermap-api', 'dataforseo-api-search', 'dataforseo-api-search-json', 'eleven_labs_text2speech', 'google_cloud_texttospeech', 'read_file', 'reddit_search', 'news-api', 'tmdb-api', 'podcast-api', 'memorize', 'llm-math', 'open-meteo-api', 'requests', 'requests_get', 'requests_post', 'requests_patch', 'requests_put', 'requests_delete', 'terminal']

接下来,通过一个示例来学习Agent的基本使用。

  • 问题1:计算一下300的25%是多少?
  • 问题2:请帮我介绍一下故宫

示例代码:

from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySa ver
from langchain.agents import create_agent
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain_openai import ChatOpenAI
import os

model = ChatOpenAI(
    base_url=os.environ.get('base_url','https://dashscope.aliyuncs.com/compatible-mode/v1'),
    model='qwen-plus',
    openai_api_key=os.environ.get('api_key','sk-XXXXXXXX'),
    max_tokens=1000,
    temperature=0
)

memory = MemorySa ver()
tools = load_tools(['wikipedia', 'llm-math'], llm=model)
agent_executor = create_agent(model, tools, checkpointer=memory)

config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="计算一下300的25%是多少?")]}, config
):
    print(chunk)
    print("----")

九、LangChain使用场景

  • 个人助手
  • 基于文档的问答系统
  • 聊天机器人
  • Tabular数据查询
  • API交互
  • 信息提取
  • 文档总结