您的位置:首页 > 手游攻略 > LangChain大模型开发框架

LangChain大模型开发框架

作者:互联网  时间: 2026-07-09 09:11:16  

一、简述

1 什么是LangChain

LangChain由 Harrison Chase 创建于2022年10月,它是围绕LLMs(大语言模型)建立的一个框架,它的核心理念是为各种LLMs实现通用的接口,把LLMs相关的组件“链接”在一起,简化LLMs应用的开发难度,方便开发者快速地开发复杂的LLMs应用。

LangChain官网:python.langchain.com/docs/introd…

LangChain官网中文版:www.langchain.com.cn/

LangChain 简化了 LLM 应用程序生命周期的每个阶段:

  • 开发:使用 LangChain 的开源组件和第三方集成构建应用程序。使用 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):

二、Models

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

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

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

LangChain支持的三类模型,它们的使用场景不同,输入和输出不同,开发者需要根据项目需要选择相应的模型。

1 LLMs

LLMs(大语言模型)使用场景最多,常用大模型的下载库:

下面Qwen为例进行讲解。

模型调用有2种方式:

  • 通过ChatOpenAI进行调用

from langchain_openai import ChatOpenAIimportos# 实例化模型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进行调用 Ollama支持模型

# from langchain_community.llms import Ollama # Langchain 0.x版本使用from langchain_ollama import OllamaLLM# 实例化模型# model = Ollama(model="qwen2.5:7b") # Langchain 0.x版本使用model = OllamaLLM(model="qwen2.5:7b")# 获取问答结果result = model.invoke("请给我讲个笑话吧")print(result)

2 Chat Models

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

  • AIMessage: 就是 AI 输出的消息,可以是针对问题的回答.

  • HumanMessage: 人类消息就是用户信息,由人给出的信息发送给LLMs的提示信息,比如“实现一个快速排序方法”.

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

  • ChatMessage: Chat 消息可以接受任意角色的参数,但是在大多数时间,我们应该使用上面的三种类型.

LangChain支持大量的chat 模型,可以通过官网查询:

也可以通过langchain源码查看

  • SystemMessage+HumanMessage+AIMessage

from langchain_core.messages import HumanMessage, SystemMessage, AIMessage# from langchain_community.chat_models import ChatOllama # Langchain 0.x版本使用from langchain_ollama import ChatOllama# 实例化模型model = ChatOllama(model="qwen2.5:7b")# 定义提示词messages = [SystemMessage(content="现在你是一个著名的诗人"),HumanMessage(content="给我写一首唐诗")]# 获取问答结果result = model.invoke(messages)# print(result)print(result.content)

3 Embeddings Models

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(大规模文本嵌入基准)排行榜以获取最新模型效果:huggingface.co/spaces/mteb…

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

# from langchain_community.embeddings import OllamaEmbeddings # Langchain 0.x版本使用from langchain_ollama import OllamaEmbeddings# 初始化Ollama嵌入模型,使用mxbai-embed-large模型,温度设置为0model = 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)

运行结果:

三、Prompts

1 通用prompt

Prompt是指当用户输入信息给模型时加入的提示,这个提示的形式可以是zero-shot或者few-shot等方式,目的是让模型理解更为复杂的业务场景以便更好的解决问题。

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

  • zero-shot提示方式

# from langchain import PromptTemplate # Langchain 0.x版本使用from langchain_core.prompts import PromptTemplate# from langchain_community.llms import Ollama# Langchain 0.x版本使用from langchain_ollama import OllamaLLM# model = Ollama(model="qwen2.5:7b") # Langchain 0.x版本使用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)

运行结果:

  • few-shot提示方式

# from langchain import PromptTemplate, FewShotPromptTemplate # Langchain 0.x版本使用from langchain_core.prompts import PromptTemplate, FewShotPromptTemplatefrom langchain_ollama import OllamaLLMmodel = 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 ChatPromptTemplatefrom 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, HumanMessagePromptTemplatefrom langchain_core.messages import SystemMessagefrom 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)# 返回结果出了content外,还有元数据信息print(f'result-->{result}')

运行结果:

大模型开发框架LangChain

  • few-shot提示方式

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderfrom langchain_ollama import OllamaLLM# 实例化模型model = OllamaLLM(model="qwen2.5:7b")# 创建 prompt 模版prompt_template = ChatPromptTemplate.from_messages([ ("system", "给出每个单词的反义词"), MessagesPlaceholder("history"), ("human", "{question}")])# 创建 few-shot prompt# history = [# HumanMessage(content="开心"),# AIMessage(content="难过"),# HumanMessage(content="高"),# AIMessage(content="矮")# ]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) 是一种声明式的方法,用于轻松组合链条。

LCEL的基本语法规则是使用|符号将不同的组件连接起来,形成一个链式结构。|符号类似于Unix的管道操作符,它将一个组件的输出作为下一个组件的输入,从而实现数据的传递和处理。

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

from langchain import PromptTemplatefrom langchain_core.prompts import PromptTemplatefrom 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 PromptTemplatefrom 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_chainprint(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 StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_ollama import OllamaLLM# 实例化模型model = OllamaLLM(model="qwen2.5:7b")# 创建简单链prompt = ChatPromptTemplate.from_template("解释{topic}是什么?回答控制20字以内")chain1 = prompt | modelresult1 = chain1.invoke({"topic": "ai"})print(f"result1-->{result1}")# 添加字符串解析器parser = StrOutputParser()chain2 = prompt | model | parserresult2 = chain2.invoke({"topic": "ai"})print(f"result2-->{result2}")

2 列表解析器

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

from langchain_core.output_parsers import CommaSeparatedListOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom 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 JsonOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_ollama import OllamaLLM# 实例化模型model = OllamaLLM(model="qwen2.5:7b")# 创建JSON解析器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 ChatPromptTemplatefrom langchain_core.output_parsers import PydanticOutputParserfrom pydantic import BaseModel, Fieldfrom typing import Listfrom langchain_ollama import OllamaLLM# 实例化模型model = OllamaLLM(model="qwen2.5:7b")# 定义Pydantic模型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解析器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 BaseOutputParserfrom typing import Dict, Anyfrom langchain_core.prompts import ChatPromptTemplatefrom 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 resultdef 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 ChatMessageHistoryfrom langchain_core.messages import messages_to_dict, messages_from_dictimport json# 1.创建一个ChatMessageHistory对象,用来存储对话信息history = ChatMessageHistory()# 添加用户消息history.add_user_message("在吗?")# 添加大模型消息history.add_ai_message("在")# 打印所有消息print(f'history.messages-->{history.messages}')# 2.可以将history.messages中的信息保存到字典中,然后保存到数据库或者文件中,方便后续读取# 2.1 messages_to_dict()方法将history.messages中的信息转换成字典dicts = messages_to_dict(history.messages)print(f'dicts-->{dicts}')# 2.2 这里将dicts保存到文件中with open('history.json', 'w', encoding='utf-8') as f:f.write(json.dumps(dicts, indent=2, ensure_ascii=False))# 3.从文件中读取出字典,然后将字典转换成消息# 3.1 读取文件messages = json.load(open('history.json', 'r', encoding='utf-8'))# 3.2 然后将字典转换成消息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_agentfrom langgraph.checkpoint.memory import InMemorySaverfrom langchain.messages import HumanMessagefrom langchain_ollama import OllamaLLMimport time# 初始化大模型,这里使用的是 Qwen 的聊天模型model = OllamaLLM(model="qwen2.5:7b")# 创建内存保存器 (Checkpointer)# 这是 LangGraph 的核心概念之一,用于在对话过程中保存和恢复状态(记忆)checkpointer = InMemorySaver()# 定义 Agent 的配置# "thread_id" (线程ID) 非常关键:它相当于对话的 ID,用于区分不同的会话记忆# 使用时间戳作为 ID,确保每次运行脚本时的线程 ID 不同(但在同一次运行中复用)timestamp = time.time()config = {"configurable": {"thread_id": f"{int(timestamp)}"}}# 创建 Agent 实例# model: 指定使用的底层大模型# tools: 工具列表,这里为空,表示 Agent 只能进行对话,不能调用外部工具(如搜索、计算器等)# checkpointer: 传入上面的内存保存器,赋予 Agent 记忆能力# system_prompt: 设定 Agent 的角色和行为模式agent = create_agent(model=model,tools=[],checkpointer=checkpointer,system_prompt="你是一个翻译官,擅长中英互译。")# 第一轮对话输入input_1 = {"messages": [HumanMessage("你好,我叫小呆。")]}# 调用 Agent (Response A)# 使用 config,这意味着这次对话会记录在 thread_id 对应的内存中# Agent 会记住 "我叫小呆" 这个信息response_a = agent.invoke(input=input_1,config=config)# 第二轮对话输入(测试是否记得之前的信息)input_2 = {"messages": [HumanMessage("你好,我叫什么?")]}# 定义一个新的配置 (config_2),使用完全不同的 thread_id# 这代表开启了一个全新的、独立的对话会话config_2 = {"configurable": {"thread_id": f"{int(time.time())}"}# 这里生成了一个新的时间戳 ID}# 调用 Agent (Response B)# 使用新的 config_2,Agent 看不到 config_1 中的历史记录# 因此,Agent 应该不知道用户叫 "小呆",因为它处于一个新的 "线程" 中response_b = agent.invoke(input=input_2,config=config_2)# 调用 Agent (Response C)# 再次使用最初的 config# 这会恢复到第一个会话的记忆中# Agent 应该能回想起用户叫 "小呆",因为它共享同一个 thread_idresponse_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 包,Unstructured 是一个python包,可以把各种类型的文件转换成文本。文档加载器使用起来很简单,只需要引入相应的loader工具。

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

示例代码:

from langchain_unstructured import UnstructuredLoader# 创建 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# 创建 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 ,它按照指定的分隔符(默认“nn”)进行分割,并且考虑文本片段的最大长度。我们看个例子:

from langchain_core.documents import Documentfrom langchain_text_splitters import CharacterTextSplitter# 创建分词器 separator参数指的是分割的分隔符,chunk_size指的是分割出来的每个块的大小,chunk_overlap指的是每个块之间重叠的大小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文档切割器)

其他拓展知识可以参考:blog.csdn.net/qq_28540861…

3 VectorStores

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

LangChain支持的VectorStore有python.langchain.com/docs/integr…,常见的如下:

from langchain_text_splitters import CharacterTextSplitterfrom langchain_chroma import Chromafrom langchain_community.document_loaders import TextLoaderfrom langchain_ollama import OllamaEmbeddings# 1.加载文档# 创建 TextLoader 对象loader = TextLoader('./data/pku.txt', encoding='utf-8')# 加载文档docs = loader.load()# print(f'docs-->{docs}')# 2.将文档进行分块# 创建 CharacterTextSplitter 对象text_splitter = CharacterTextSplitter(separator="nn", chunk_size=200, chunk_overlap=30)# 分块split_docs = text_splitter.split_documents(docs)print(f'split_docs-->{split_docs}')# 3.将分割后的文档存储到向量数据库中# 加载embedding模型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 中负责信息检索的模块,通常与 索引(Indexes) 模块(如向量存储、嵌入模型)结合使用。它的核心功能是:

  • 输入:接收用户查询(通常是文本)。
  • 处理:根据查询从数据源中检索相关内容。
  • 输出:返回一组相关文档或文本片段(通常是 Document 对象列表)。

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

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

4.2 检索器的工作原理

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

  • 查询嵌入:将用户查询通过嵌入模型(如 OpenAIEmbeddings)转为向量表示
  • 相似性搜索:在向量存储中查找与查询向量最相似的文档向量。
  • 文档返回:返回匹配的文档(包含内容、元数据等)。
  • 后处理(可选):对检索结果进行排序、过滤或重新排名。

检索器的核心依赖:

  • 嵌入模型:将文本转为向量(如 OpenAIEmbeddings, HuggingFaceEmbeddings)。
  • 向量存储:存储文档向量(如 Chroma、FAISS、Pinecone)。
  • 相似性度量:如余弦相似度、欧几里得距离

4.3 检索器类型

langchain支持很多检索器python.langchain.com/docs/integr…,部分如下:

此处我们讲解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 则更强调结果之间的差异性})

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

示例代码:

from langchain_chroma import Chromafrom langchain_ollama import OllamaEmbeddingsembedding = OllamaEmbeddings(model="mxbai-embed-large")# 向量数据库已经存在,那么可以直接加载chromadaDB = Chroma(persist_directory='./chroma_db', embedding_function=embedding)# 使用向量数据库进行查询query = "1937年北京大学发生了什么?"# result = chromadaDB.similarity_search(query, k=2)# 使用 as_retriever 方法返回 Retriever 对象,然后调用 invoke 方法进行查询retriever = chromadaDB.as_retriever(search_kwargs={"k":2})result = retriever.invoke(query)print(f'result-->{result}')

运行结果:

拓展:

vectordb.as_retriever()vectordb.similarity_search() 都是用于从向量数据库中检索相关文档的方法,它们有什么异同:

  • 相同

    • 核心功能:两者都基于向量相似度(如余弦相似度)从向量数据库中检索与查询最相关的文档。
    • 底层技术:通常使用相同的嵌入模型和相似度计算方式(如 FAISS、Chroma、Pinecone 等)。
  • 不同

4.4 拓展

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

  • TFIDFRetriever
  • BM25Retriever
  • MultiQueryRetriever
  • EnsembleRetriever
  • ContextualCompressionRetriever
  • Custom Retriever

八、Agents

1 Agent 概念

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

为什么要调用工具?

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

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

工作流程概述:

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

2 Agent关键组成部分

  • 任务规划(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_namesresults = 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 HumanMessagefrom langgraph.checkpoint.memory import MemorySaverfrom langchain.agents import create_agentfrom langchain_community.agent_toolkits.load_tools import load_toolsfrom langchain_openai import ChatOpenAIimportos# 实例化模型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)# Create the agentmemory = MemorySaver()tools = load_tools(['wikipedia', 'llm-math'], llm=model)agent_executor = create_agent(model, tools, checkpointer=memory)# Use the agentconfig = {"configurable": {"thread_id": "abc123"}}for chunk in agent_executor.stream({"messages": [HumanMessage(content="计算一下300的25%是多少?")]}, config):print(chunk)print("----")# for chunk in agent_executor.stream(# {"messages": [HumanMessage(content="大熊猫是哪个国家的国宝?")]}, config# ):# print(chunk)# print("----")

运行结果:

九、LangChain使用场景

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

最新游戏

更多

Copyright©2010-2019. All rights reserved | 波波三国游戏官网|[email protected]

备案编号:湘ICP备2022015115号-4