LangChain 快速入门:从零开始构建 AI 应用

154 阅读9分钟

在 AI 应用开发中,你是否遇到过这些问题:

  • 想要切换不同的 LLM 模型,却需要重写大量代码?

  • 需要处理复杂的 Prompt 工程,但缺乏统一的模板管理?

  • 想要实现 RAG(检索增强生成),但不知道如何整合向量数据库?

LangChain正是为了解决这些问题而生的开发框架。本文将带你快速入门 LangChain,掌握构建 AI 应用的核心技能。

LangChain 是什么?

  • LangChain 是一套面向大模型的开发框架(SDK)
  • LangChain 是 AGI 时代软件工程的一个探索和原型
  • 简化了创建 LLM 应用的过程,提供了统一的接口和丰富的工具链

项目地址github.com/langchain-a…

LangChain 的核心组件

1.功模型I/O封装

  • Chat Models:对语言模型接口的封装
  • PromptTemple:提示词模板
  • OutputParser:解析输出

2.数据连接封装

  • Document Loaders:各种格式文件的加载器
  • Document Transformers:对文档的常用操作,如:split, filter, translate, extract metadata, etc
  • Text Embedding Models:文本向量化表示,用于检索等操作
  • Verctorstores & Retrievers:向量数据库与向量检索

3.架构封装

  • Chain/LCEL:实现一个功能或者一系列顺序功能组合

  • Agent:根据用户输入,自动规划执行步骤,自动选择每步需要的工具,最终完成用户指定的功能

  • Tools:调用外部功能的函数,例如:调 google 搜索、文件 I/O、Linux Shell 等等

  • LangGraph:工作流开发框架

  1. LangSmith:过程监控与调试框架

img_1.jpg

快速开始示例

from langchain.prompts import PromptTemplate
from langchain_community.llms import Tongyi  # 导入通义千问Tongyi模型
import dashscope
import os
# 从环境变量获取 dashscope 的 API Key
api_key = os.environ.get('DASHSCOPE_API_KEY')
dashscope.api_key = api_key
# 加载 Tongyi 模型
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)  # 使用通义千问qwen-turbo模型
# 创建Prompt Template
prompt = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)
# 新推荐用法:将 prompt 和 llm 组合成一个"可运行序列"
chain = prompt | llm
# 使用 invoke 方法传入输入
result1 = chain.invoke({"product": "colorful socks"})
print(result1)
result2 = chain.invoke({"product": "广告设计"})
print(result2)

说明:PromptTemplate是 LangChain 的提示词模板类chain = prompt | llm可以直接将 prompt 的输出作为 llm 的输入,形成一个可运行的链式结构,简化了原先 LLMChain 的写法

官方文档(以 Python 版为例)

功能模块python.langchain.com/docs/tutori… 文档**python.langchain.com/api_referen… HowTo**python.langchain.com/docs/how_to…

1. 模型 I/O 封装

把不同的模型,统一封装成一个接口,方便更换模型而不用重构代码。

1.1 模型 API: ChatModel

1.1.1 模型初始化

安装依赖

    # !pip install -U langchain
    # !pip install -U langchain-openai
    # !pip install -U langchain-deepseek

代码示例

from langchain.chat_models import init_chat_model
model = init_chat_model(model="deepseek-chat", model_provider="deepseek")
response = model.invoke("你是谁")
print(response.content)

💡 划重点:通过模型封装,实现不同模型的统一接口调用

1.1.2 多轮对话 Session 封装

LangChain 提供了统一的消息类型,可以方便地构建多轮对话:

    from langchain.schema import (
        AIMessage,  # 等价于OpenAI接口中的assistant role
        HumanMessage,  # 等价于OpenAI接口中的user role
        SystemMessage  # 等价于OpenAI接口中的system role
    )
    messages = [
        SystemMessage(content="你是一名客服人员"),
        HumanMessage(content="我是张三"),
        AIMessage(content="欢迎!"),
        HumanMessage(content="我是谁?")
    ]
    ret = model.invoke(messages)
    print(ret.content)

输出结果

你是张三。很高兴与你交流!有什么问题或者需要帮助的地方吗?

1.1.3 流式输出

对于长文本生成,流式输出可以提升用户体验,让用户实时看到生成内容:

for token in model.stream("你是谁"):    
    print(token.content, end="")

1.2 模型的输入与输出

img_2.jpg

1.2.1 Prompt 模板封装

1)PromptTemplate 可以在模板中自定义变量
from langchain.prompts import PromptTemplate
template = PromptTemplate.from_template("给我讲个关于{subject}的笑话")
print("===Template===")
print(template)
print("===Prompt===")
print(template.format(subject='小明'))

输出结果

    ===Template===
    input_variables=['subject'] input_types={} partial_variables={} template='给我讲个关于{subject}的笑话'
    ===Prompt===
    给我讲个关于小明的笑话

调用 LLM

from langchain.chat_models import init_chat_model
# 定义 LLM
llm = init_chat_model("deepseek-chat", model_provider="deepseek")
# 通过 Prompt 调用 LLM
ret = llm.invoke(template.format(subject='小明'))
# 打印输出
print(ret.content)

输出示例

    小明去参加考试,监考老师叮嘱:"遇到不会的题目可以跳过去。"
    结果考到一半,整个考场的人都听见小明开始做广播体操:"第一节,跳跃运动!"
    老师怒吼:"你干嘛呢?"
    小明一脸无辜:"不是你说不会的题目就跳吗?我正跳着呢!"
2)ChatPromptTemplate 用模板表示的对话上下文
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    SystemMessagePromptTemplate,
)
from langchain.chat_models import init_chat_model
# llm = init_chat_model("gpt-4o-mini", model_provider="openai")
llm = init_chat_model("deepseek-chat", model_provider="deepseek")
template = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate.from_template("你是{product}的客服助手。你的名字叫{name}"),
        HumanMessagePromptTemplate.from_template("{query}")
    ]
)
prompt = template.format_messages(
    product="XX店铺",
    name="小A",
    query="你是谁"
)
print(prompt)
ret = llm.invoke(prompt)
print(ret.content)

输出结果

[SystemMessage(content='你是XX店铺的客服助手。你的名字叫小A', additional_kwargs={}, response_metadata={}), HumanMessage(content='你是谁', additional_kwargs={}, response_metadata={})]
我是小A,XX店铺的客服助手。如果你有任何问题或者需要帮助,随时可以问我!
3)MessagesPlaceholder 把多轮对话变成模板
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    MessagesPlaceholder,
)
human_prompt = "Translate your answer to {language}."
human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)
chat_prompt = ChatPromptTemplate.from_messages(
    # variable_name 是 message placeholder 在模板中的变量名
    # 用于在赋值时使用
    [MessagesPlaceholder("history"), human_message_template]
)

使用示例

from langchain_core.messages import AIMessage, HumanMessage
human_message = HumanMessage(content="Who is Elon Musk?")
ai_message = AIMessage(
    content="Elon Musk is a billionaire entrepreneur, inventor, and industrial designer"
)
messages = chat_prompt.format_prompt(
    # 对 "history" 和 "language" 赋值
    history=[human_message, ai_message], language="中文"
)
print(messages.to_messages())

调用 LLM

result = llm.invoke(messages)
print(result.content)

💡 划重点:把 Prompt 模板看作带有参数的函数

1.2.2 从文件加载 Prompt 模板

from langchain.prompts import PromptTemplate
template = PromptTemplate.from_file("example_prompt_template.txt")
print("===Template===")
print(template)
print("===Prompt===")
print(template.format(topic='黑色幽默'))

1.3 结构化输出

1.3.1 直接输出 Pydantic 对象

定义输出对象

from pydantic import BaseModel, Field
# 定义你的输出对象
class Date(BaseModel):
    year: int = Field(description="Year")
    month: int = Field(description="Month")
    day: int = Field(description="Day")
    era: str = Field(description="BC or AD")

使用结构化输出

from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from langchain.chat_models import init_chat_model
llm = init_chat_model("deepseek-chat", model_provider="deepseek")
# 定义结构化输出的模型
structured_llm = llm.with_structured_output(Date)
template = """提取用户输入中的日期。
用户输入:
{query}"""
prompt = PromptTemplate(
    template=template,
)
query = "2025年十二月20日天气晴..."
input_prompt = prompt.format_prompt(query=query)
structured_llm.invoke(input_prompt)

输出结果

    Date(year=2025, month=12, day=20, era='AD')

1.3.2 输出指定格式的 JSON

# OpenAI 模型的JSON格式
json_schema = {
    "title": "Date",
    "description": "Formated date expression",
    "type": "object",
    "properties": {
        "year": {
            "type": "integer",
            "description": "year, YYYY",
        },
        "month": {
            "type": "integer",
            "description": "month, MM",
        },
        "day": {
            "type": "integer",
            "description": "day, DD",
        },
        "era": {
            "type": "string",
            "description": "BC or AD",
        },
    },
}
structured_llm = llm.with_structured_output(json_schema)
structured_llm.invoke(input_prompt)

输出结果

{'year': 2025, 'month': 12, 'day': 20, 'era': 'AD'}

1.3.3 使用 OutputParser

OutputParser可以按指定格式解析模型的输出

使用 JsonOutputParser

from langchain_core.output_parsers import JsonOutputParser
parser = JsonOutputParser(pydantic_object=Date)
prompt = PromptTemplate(
    template="提取用户输入中的日期。\n用户输入:{query}\n{format_instructions}",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()},
)
input_prompt = prompt.format_prompt(query=query)
output = llm.invoke(input_prompt)
print("原始输出:\n"+output.content)
print("\n解析后:")
parser.invoke(output)

使用 PydanticOutputParser

from langchain_core.output_parsers import PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Date)
input_prompt = prompt.format_prompt(query=query)
output = llm.invoke(input_prompt)
print("原始输出:\n"+output.content)
print("\n解析后:")
parser.invoke(output)

使用 OutputFixingParser 自动纠错

OutputFixingParser利用大模型做格式自动纠错:

from langchain.output_parsers import OutputFixingParser
from langchain.chat_models import init_chat_model
llm = init_chat_model(model="deepseek-chat", model_provider="deepseek")
# 纠错能力与大模型能力相关
new_parser = OutputFixingParser.from_llm(parser=parser, llm=llm)
bad_output = output.content.replace("4","四")
print("PydanticOutputParser:")
try:
    parser.invoke(bad_output)
except Exception as e:
    print(e)
print("OutputFixingParser:")
new_parser.invoke(bad_output)

1.4 Function Calling

定义工具函数

from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
    """Add two integers.
    Args:
        a: First integer
        b: Second integer
    """
    return a + b
@tool
def multiply(a: float, b: float) -> float:
    """Multiply two integers.
    Args:
        a: First integer
        b: Second integer
    """
    return a * b

绑定工具并调用

import json
from langchain_core.messages import HumanMessage
llm_with_tools = llm.bind_tools([add, multiply])
query = "3.5的4倍是多少?"
messages = [HumanMessage(content=query)]
output = llm_with_tools.invoke(messages)
print(json.dumps(output.tool_calls, indent=4))

回传 Function Call 的结果

messages.append(output)
available_tools = {"add": add, "multiply": multiply}
for tool_call in output.tool_calls:
    selected_tool = available_tools[tool_call["name"].lower()]
    tool_msg = selected_tool.invoke(tool_call)
    messages.append(tool_msg)
new_output = llm_with_tools.invoke(messages)
for message in messages:
    print(json.dumps(message.model_dump(), indent=4, ensure_ascii=False))
print(new_output.content)

1.5 小结

  1. LangChain 统一封装了各种模型的调用接口,包括补全型和对话型两种2. LangChain 提供了 PromptTemplate 类,可以自定义带变量的模板3. LangChain 提供了一系列输出解析器,用于将大模型的输出解析成结构化对象4. LangChain 提供了 Function Calling 的封装5. 上述模型属于 LangChain 中较为实用的部分

2. 数据连接封装

img_3.jpg

2.1 文档加载器:Document Loaders

安装依赖

    # !pip install -U langchain-community pymupdf

代码示例

from langchain_community.document_loaders import PyMuPDFLoader
loader = PyMuPDFLoader("./data/deepseek-v3-1-4.pdf")
pages = loader.load_and_split()
print(pages[0].page_content)

2.2 文档处理器

2.2.1 TextSplitter

安装依赖

    # !pip install --upgrade langchain-text-splitters

代码示例

from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=200, 
    length_function=len,
    add_start_index=True,
)
paragraphs = text_splitter.create_documents([pages[0].page_content])
for para in paragraphs:
    print(para.page_content)
    print('-------')

2.3 向量数据库与向量检索

安装依赖

    # !pip install dashscope# !pip install faiss-cpu

完整示例

import os
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_community.document_loaders import PyMuPDFLoader
# 加载文档
loader = PyMuPDFLoader("./data/deepseek-v3-1-4.pdf")
pages = loader.load_and_split()
# 文档切分
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=200,
    length_function=len,
    add_start_index=True,
)
texts = text_splitter.create_documents(
    [page.page_content for page in pages[:1]]
)
# 入库
embeddings = DashScopeEmbeddings(
    model="text-embedding-v1", dashscope_api_key=os.getenv("DASHSCOPE_API_KEY")
)
index = FAISS.from_documents(texts, embeddings)
# 检索 top-5 结果
retriever = index.as_retriever(search_kwargs={"k": 5})
docs = retriever.invoke("deepseek v3有多少参数")
for doc in docs:
    print(doc.page_content)
    print("----")

2.4 小结

1.文档处理部分,建议在实际应用中详细测试后使用2.与向量数据库的连接部分本质是接口封装,向量数据库需要自己选型

📚 下期预告:LCEL(LangChain Expression Language)

在本文中,我们已经初步接触了 LangChain 的核心功能,包括:

  • ✅ 模型 I/O 封装(统一接口调用)
  • ✅ Prompt 模板管理
  • ✅ 结构化输出
  • ✅ Function Calling
  • ✅ 数据连接与向量检索

你可能已经注意到,在快速开始示例中我们使用了这样的写法:

chain = prompt | llmresult = chain.invoke({"product": "colorful socks"})

这种简洁优雅的链式语法,正是**LCEL(LangChain Expression Language)**的体现!

🎯 下期内容预告

在下一篇文章中,我们将深入探讨LCEL,包括:

  1. 什么是 LCEL?
  2. LCEL 核心语法
  3. 实战应用
  4. 最佳实践

💡 为什么学习 LCEL?

  • 更简洁的代码用更少的代码实现更复杂的功能
  • 更好的可维护性清晰的链式结构,易于理解和修改
  • 更强的扩展性轻松组合不同的组件,构建复杂的 AI 应用
  • 官方推荐LangChain 官方推荐使用 LCEL 作为主要开发方式

📌 提示:如果你对本文内容有任何疑问,或者想提前了解 LCEL 的某个方面,欢迎在评论区留言!