LangChain学习笔记(一)

LangChain学习第一天

一、核心思想

提示词系统的本质是构建可复用、可维护、可扩展的输入输出闭环,而非简单的文本拼接。在 LangChain 中,所有能力都围绕「标准化输入→标准化调用→标准化输出」的核心链路展开:

三大核心组件

组件 核心作用 核心类
Prompt 定义输入结构与交互规则 PromptTemplate/ChatPromptTemplate
Model 对接大模型并控制生成行为 ChatOpenAI/ChatAnthropic
Parser 标准化模型输出,适配业务场景 StrOutputParser/PydanticOutputParser

完整执行链路(LCEL 核心)

Plain 复制代码
原始变量 → PromptTemplate(填充) → 结构化输入 → Model(调用) → 原始输出 → Parser(解析) → 业务可用结果

抽象为 LCEL 表达式(LangChain 官方推荐):

Python 复制代码
chain = prompt | model | parser  # 管道符串联,左到右执行

这条链路是所有 LangChain 应用的基础,支持并行执行、条件分支、错误处理等高级能力,是后续所有代码的核心框架。


二、PromptTemplate 详解(参数+场景+避坑)

PromptTemplate 是单轮文本交互的基础模板类,核心是「模板字符串 + 变量管理」,解决硬编码提示词的复用性问题。

1. 核心构造参数(全维度解析)

参数 类型 必选 作用 示例
template str 提示词模板,变量用 {变量名} 包裹 "你是{domain}专家,回答:{question}"
input_variables list[str] 声明必填变量(from_template 可自动识别) ["domain", "question"]
partial_variables dict 声明默认变量(固定值),format 时无需传入 {"domain": "机器学习"}
template_format str 模板解析格式,支持 f-string/jinja2(默认 f-string) jinja2
validate_template bool 是否校验模板变量与 input_variables 一致性(默认 True) False

2. 基础使用方式(分场景)

方式1:手动实例化(精准控制)
Python 复制代码
from langchain.prompts import PromptTemplate

# 基础用法
prompt = PromptTemplate(
    template="你是{domain}专家,请用{language}回答:{question}",
    input_variables=["domain", "language", "question"],
    validate_template=True  # 开启变量校验,避免漏写
)

# 带默认值(partial_variables)
prompt_with_default = PromptTemplate(
    template="你是{domain}专家,请用{language}回答:{question}",
    input_variables=["language", "question"],  # 仅声明必填项
    partial_variables={"domain": "机器学习"}     # 固定值
)
方式2:from_template(简化开发)

自动解析模板中的变量,无需手动声明 input_variables,推荐简单场景使用:

Python 复制代码
# 自动识别变量「topic」
prompt = PromptTemplate.from_template("请用通俗易懂的语言解释:{topic}")
print(prompt.input_variables)  # 输出:['topic']

# 结合jinja2模板(支持条件、循环等高级语法)
jinja_prompt = PromptTemplate.from_template(
    """
    {% if length == "short" %}
    用1句话解释:{topic}
    {% else %}
    详细解释:{topic}
    {% endif %}
    """,
    template_format="jinja2"  # 指定解析格式
)
# 使用时传入条件变量
print(jinja_prompt.format(topic="Python", length="short"))

3. 核心方法(必掌握)

方法 作用 返回值 示例
format(**kwargs) 填充变量,生成最终提示词字符串 str prompt.format(domain="AI", language="中文", question="什么是大模型")
format_prompt(**kwargs) 填充变量,返回 PromptValue 对象(兼容模型调用) PromptValue prompt_val = prompt.format_prompt(...)
partial(**kwargs) 动态设置默认值(替代 partial_variables) PromptTemplate prompt.partial(domain="深度学习")

4. 避坑要点

  • 变量名必须与模板中的 {变量名} 完全一致(大小写敏感);

  • 使用 jinja2 模板时,注意语法错误(如缺少 {% endif %});

  • 避免模板中出现多余的 {}(非变量),如需保留需转义:{{ 代表 {}} 代表 }


三、ChatPromptTemplate(对话场景专用)

适用于多轮对话、带角色的交互场景(如 System/Human/AI 对话),核心区别是:

  • PromptTemplate 输出字符串

  • ChatPromptTemplate 输出消息对象列表(符合大模型的对话接口规范)。

1. 核心概念:Message 类型

LangChain 定义了标准化的消息类型,适配所有主流大模型的对话接口:

消息类型 作用 示例
SystemMessage 定义模型角色、行为准则(优先级最高) SystemMessage(content="你是专业的翻译助手,仅输出翻译结果")
HumanMessage 用户输入(人类消息) HumanMessage(content="你好")
AIMessage 模型输出(AI 回复) AIMessage(content="Hello")
FunctionMessage 工具调用结果(进阶) FunctionMessage(name="search", content="搜索结果...")

2. 构建方式(分场景)

方式1:快速构建(推荐简单对话)
Python 复制代码
from langchain_core.prompts import ChatPromptTemplate

# 直接定义角色+模板
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{role},仅用{language}回答,答案不超过{length}个字"),  # system角色
    ("human", "{question}"),                                           # 用户输入
    ("ai", "示例回答:{example_answer}")                               # 示例(Few-shot)
])

# 填充变量,生成消息列表
messages = chat_prompt.format_messages(
    role="数学老师",
    language="中文",
    length="50",
    question="什么是勾股定理",
    example_answer="勾股定理是直角三角形两直角边的平方和等于斜边的平方"
)
print(messages)
# 输出:[SystemMessage(content='你是数学老师...'), HumanMessage(content='什么是勾股定理'), AIMessage(content='示例回答:...')]
方式2:分模块构建(复杂项目/组件化)

适合将 System/Human 模板拆分管理,便于复用:

Python 复制代码
from langchain_core.prompts import SystemMessagePromptTemplate, HumanMessagePromptTemplate

# 拆分构建System模板
system_template = SystemMessagePromptTemplate.from_template(
    "你是{role},请遵循以下规则:{rules}"
)
# 拆分构建Human模板
human_template = HumanMessagePromptTemplate.from_template(
    "问题:{question}\n要求:{requirements}"
)

# 组合为ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages([
    system_template,
    human_template
])

# 填充变量
messages = chat_prompt.format_messages(
    role="客服",
    rules="1. 语气友好 2. 回答简洁",
    question="如何退款",
    requirements="用1句话说明"
)

3. 核心方法

方法 作用 返回值
format_messages(**kwargs) 填充变量,生成消息对象列表 list[BaseMessage]
format_prompt(**kwargs) 填充变量,返回 ChatPromptValue 对象 ChatPromptValue
partial(**kwargs) 动态设置默认变量 ChatPromptTemplate

四、Model 模型调用(ChatOpenAI 全参数解析)

ChatOpenAI 是对接 OpenAI 兼容接口的核心类(支持通义千问、讯飞星火等兼容 OpenAI 接口的模型),以下是全参数详解+最佳实践

1. 核心导入与初始化

Python 复制代码
from langchain_openai import ChatOpenAI
from pydantic import SecretStr  # 安全存储密钥

# 基础初始化(通义千问示例)
model = ChatOpenAI(
    # 核心参数
    model="qwen-plus",                # 模型名称(不同平台不同:gpt-3.5-turbo/qwen-plus/ERNIE-4.0)
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",  # 自定义接口地址
    api_key=SecretStr("your-api-key"),  # 密钥(用SecretStr避免日志泄露)
    # 生成控制参数
    temperature=0.7,                 # 随机性:0(最稳定)~2(最发散),推荐0.1~1.0
    max_tokens=1024,                 # 最大生成token数(防止输出过长)
    top_p=0.9,                       # 采样阈值:0~1,越小越聚焦
    frequency_penalty=0.0,           # 重复惩罚:0~2,越大越避免重复
    presence_penalty=0.0,            # 主题惩罚:0~2,越大越鼓励新主题
    # 执行参数
    streaming=False,                 # 是否流式输出(实时返回内容)
    timeout=30,                      # 超时时间(秒)
    max_retries=3,                   # 失败重试次数
    # 高级参数
    n=1,                             # 每次调用生成n个结果
    stop=["\n\n"],                   # 停止符:生成到该字符时停止
)

2. 核心参数详解(必掌握)

参数 取值范围 核心作用 最佳实践
temperature 0~2 控制生成随机性,值越高,回答越发散;值越低,回答越固定。 事实类问答:0.10.3;创作类:0.71.0
max_tokens 正整数 限制模型输出的最大token数(输入+输出通常有总上限)。 根据业务场景设置(如客服:500,创作:2000)
streaming bool 是否开启流式输出(逐字返回)。 前端交互场景开启,批量处理关闭
max_retries 0~5 接口调用失败时的重试次数。 生产环境设置3~5次,避免网络波动导致失败
stop list[str] 生成停止符,模型遇到该字符立即停止输出。 ["###", "\n\n"],用于截断多余内容

3. 核心调用方法

方法 作用 使用场景
invoke(input) 同步调用,返回完整结果 简单场景、批量处理
stream(input) 流式调用,返回生成器(逐块返回) 实时交互(如聊天界面)
batch(inputs, batch_size=5) 批量调用,处理多个输入 批量问答、数据处理
调用示例
Python 复制代码
# 1. 同步调用(字符串输入)
response = model.invoke("解释一下Python")
print(response.content)  # 输出模型回答字符串

# 2. 同步调用(消息列表输入,推荐)
from langchain_core.messages import SystemMessage, HumanMessage
messages = [
    SystemMessage(content="你是Python专家,回答简洁"),
    HumanMessage(content="解释一下Python")
]
response = model.invoke(messages)
print(response.content)

# 3. 流式调用(实时输出)
model_stream = ChatOpenAI(
    model="qwen-plus",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key=SecretStr("your-api-key"),
    streaming=True  # 开启流式
)
for chunk in model_stream.stream("用100字介绍Python"):
    print(chunk.content, end="", flush=True)  # 逐字输出

五、OutputParser 输出解析(标准化输出)

模型返回的是 AIMessage 对象,OutputParser 用于将其转换为业务可用的格式(字符串/JSON/自定义结构)。

1. 基础解析器(必掌握)

(1)StrOutputParser:提取纯字符串
Python 复制代码
from langchain_core.output_parsers import StrOutputParser

parser = StrOutputParser()
# 解析AIMessage对象
response = model.invoke("解释一下Python")
result = parser.invoke(response)
print(result)  # 纯字符串结果
(2)JSONOutputParser:解析JSON格式输出

需在提示词中明确要求模型输出JSON,否则会解析失败:

Python 复制代码
from langchain_core.output_parsers import JsonOutputParser

# 1. 定义提示词(强制JSON输出)
prompt = PromptTemplate.from_template(
    """
    分析以下产品名称:{product}
    要求:
    1. 输出JSON格式
    2. 包含字段:category(类别)、brand(品牌)、price_range(价格区间)
    """
)
# 2. 初始化解析器
json_parser = JsonOutputParser()
# 3. 构建链并执行
chain = prompt | model | json_parser
result = chain.invoke({"product": "苹果iPhone 15 Pro Max"})
print(result)  # 输出字典:{"category": "手机", "brand": "苹果", "price_range": "高端"}
(3)PydanticOutputParser:结构化解析(推荐)

通过 Pydantic 定义数据模型,强制模型输出符合结构的内容,支持自动校验:

Python 复制代码
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List

# 1. 定义数据模型(Pydantic V2)
class ProductAnalysis(BaseModel):
    category: str = Field(description="产品类别")
    brand: str = Field(description="品牌名称")
    price_range: str = Field(description="价格区间:低端/中端/高端")
    tags: List[str] = Field(description="产品标签列表")

# 2. 初始化解析器
parser = PydanticOutputParser(pydantic_object=ProductAnalysis)

# 3. 定义提示词(包含解析器的格式说明)
prompt = PromptTemplate.from_template(
    """
    分析以下产品:{product}
    {format_instructions}
    """
)
# 4. 填充格式说明(解析器自动生成)
prompt = prompt.partial(format_instructions=parser.get_format_instructions())

# 5. 构建链并执行
chain = prompt | model | parser
result = chain.invoke({"product": "华为Mate 70 Pro"})
print(result.category)  # 输出:手机
print(result.tags)      # 输出:["鸿蒙系统", "高端", "拍照"]

2. 解析器异常处理

Python 复制代码
from langchain_core.output_parsers import OutputParserException

try:
    result = chain.invoke({"product": "华为Mate 70 Pro"})
except OutputParserException as e:
    print(f"解析失败:{e}")
    # 降级处理:返回原始字符串
    raw_result = StrOutputParser().invoke(e.raw_output)
    print(f"原始输出:{raw_result}")

六、LCEL 链式表达(终极推荐)

LCEL(LangChain Expression Language)是 LangChain 最新的链式编程范式,核心是「管道符串联组件」,支持灵活扩展和高级操作。

1. 基础用法(核心链路)

Python 复制代码
# 1. 导入依赖
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from pydantic import SecretStr

# 2. 定义组件
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{role},回答简洁明了"),
    ("human", "{question}")
])
model = ChatOpenAI(
    model="qwen-plus",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key=SecretStr("your-api-key"),
    temperature=0.3
)
parser = StrOutputParser()

# 3. 构建链(核心:管道符串联)
chain = prompt | model | parser

# 4. 执行链
result = chain.invoke({
    "role": "Python工程师",
    "question": "什么是装饰器"
})
print(result)

2. 高级用法(扩展能力)

(1)添加日志(中间件)
Python 复制代码
from langchain_core.runnables import RunnableLambda

# 定义日志函数
def log_input(inputs):
    print(f"输入:{inputs}")
    return inputs

def log_output(outputs):
    print(f"输出:{outputs}")
    return outputs

# 构建带日志的链
chain_with_log = (
    RunnableLambda(log_input)  # 输入日志
    | prompt 
    | model 
    | parser 
    | RunnableLambda(log_output)  # 输出日志
)

chain_with_log.invoke({"role": "测试", "question": "hello"})
(2)分支链(条件执行)
Python 复制代码
from langchain_core.runnables import RunnableBranch

# 定义不同场景的prompt
simple_prompt = ChatPromptTemplate.from_messages([("human", "简单回答:{question}")])
detailed_prompt = ChatPromptTemplate.from_messages([("human", "详细回答:{question}")])

# 定义分支规则:根据「detail_level」选择不同prompt
branch_chain = RunnableBranch(
    (lambda x: x["detail_level"] == "simple", simple_prompt),
    (lambda x: x["detail_level"] == "detailed", detailed_prompt),
    simple_prompt  # 默认分支
) | model | parser

# 执行不同分支
print(branch_chain.invoke({"question": "什么是Python", "detail_level": "simple"}))
print(branch_chain.invoke({"question": "什么是Python", "detail_level": "detailed"}))
(3)批量执行
Python 复制代码
# 批量输入
inputs = [
    {"role": "数学老师", "question": "什么是质数"},
    {"role": "语文老师", "question": "什么是文言文"}
]
# 批量执行(返回列表)
results = chain.batch(inputs, batch_size=2)
for res in results:
    print(res)

七、传统链 LLMChain(兼容说明)

LLMChain 是 LangChain 早期的链式实现,现已被 LCEL 替代,仅作兼容说明:

Python 复制代码
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

prompt = PromptTemplate.from_template("你是{role},回答:{question}")
model = ChatOpenAI(model="qwen-plus", api_key=SecretStr("your-api-key"))

# 构建LLMChain
chain = LLMChain(prompt=prompt, llm=model)

# 执行
result = chain.invoke({"role": "医生", "question": "如何预防感冒"})
print(result["text"])  # 结果在「text」字段中

# 缺点:扩展性差,不支持流式/批量/分支等高级操作

八、最佳实践(生产环境规范)

1. 代码结构规范(可复用)

Python 复制代码
# langchain_demo.py
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from pydantic import SecretStr
import os

# 1. 配置抽离(环境变量/配置文件)
def get_model():
    return ChatOpenAI(
        model=os.getenv("LLM_MODEL", "qwen-plus"),
        base_url=os.getenv("LLM_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"),
        api_key=SecretStr(os.getenv("LLM_API_KEY")),
        temperature=float(os.getenv("LLM_TEMPERATURE", 0.7)),
        max_tokens=int(os.getenv("LLM_MAX_TOKENS", 1024)),
        max_retries=3
    )

# 2. 模板封装(组件化)
def get_chat_prompt(role: str = "通用助手"):
    return ChatPromptTemplate.from_messages([
        ("system", f"你是{role},遵循以下规则:1. 回答准确 2. 语气友好 3. 拒绝敏感内容"),
        ("human", "{question}")
    ])

# 3. 链构建(统一入口)
def build_chain(role: str = "通用助手"):
    prompt = get_chat_prompt(role)
    model = get_model()
    parser = StrOutputParser()
    return prompt | model | parser

# 4. 业务调用
if __name__ == "__main__":
    # 加载环境变量(推荐使用python-dotenv)
    from dotenv import load_dotenv
    load_dotenv()  # 从.env文件加载配置
    
    chain = build_chain(role="Python工程师")
    result = chain.invoke({"question": "如何调试代码"})
    print(result)

2. 环境变量配置(.env 文件)

Plain 复制代码
# .env 文件(添加到.gitignore)
LLM_MODEL=qwen-plus
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_API_KEY=your-real-api-key
LLM_TEMPERATURE=0.3
LLM_MAX_TOKENS=1024
相关推荐
羸弱的穷酸书生4 小时前
跟AI学一手之运维Agent
运维·人工智能·agent
阿杜杜不是阿木木4 小时前
从0到1构建像Claude Code那样的Agent(二):工具
前端·chrome·agent·ai编程·cluade code
x-cmd4 小时前
[x-cmd] Chrome DevTools MCP 更新:支持 coding agent 直接接管当前的浏览器窗口
前端·chrome·ai·agent·chrome devtools·x-cmd·mcp
arvin_xiaoting4 小时前
AI Agent行为约束失效深度分析:为何SOUL.md无法完全控制Agent行为
人工智能·ai·agent·soul·约束系统·行为约束·偏离分析
Y君5 小时前
在我当开发工程师的第10年,我完成了一次转向
前端·agent
HIT_Weston5 小时前
16、【Agent】【OpenCode】源码构建(Bun介绍)
人工智能·agent·opencode
阿杜杜不是阿木木5 小时前
从0到1构建像Claude Code那样的Agent(三):行动前先计划
java·服务器·windows·agent·ai编程·claudecode
吴佳浩5 小时前
OpenClaw Windows 完整卸载
人工智能·llm·agent
Shawn_Shawn12 小时前
mcp学习笔记(三)-Mcp传输协议代码示例
llm·agent·mcp