LangChain:构建 LLM 驱动应用的框架

FreeGuideOnline 最新 2026-07-02

bash pip install langchain langchain-openai


**API 密钥配置**  
LangChain 本身不限制模型提供商。这里以 OpenAI 为例,你需要申请一个 API Key,并建议将其设置为环境变量:

```bash
export OPENAI_API_KEY="your-api-key-here"

在代码中也可以直接传入,但推荐使用环境变量以保持安全。

1.2 发起第一个 LLM 请求

用最少的代码体验 LangChain 的调用模式:

from langchain_openai import ChatOpenAI

# 初始化模型(默认使用 gpt-3.5-turbo)
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.9)

response = llm.invoke("你好,请用一句话介绍你自己。")
print(response.content)

invoke 方法是 LangChain 的标准执行接口,几乎适用于所有组件。你已经迈出了第一步


2. 核心概念:Prompt Template 与 Chain

直接拼接字符串会让代码难以维护。LangChain 提供了 Prompt Template 来系统化管理提示词。

2.1 使用 PromptTemplate

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_template("请将以下英文翻译成中文:{text}")

# 填充变量后生成一个消息对象
message = prompt.format_messages(text="The future belongs to those who believe in the beauty of their dreams.")
print(message)

2.2 构建第一个 Chain

Chain 是 LangChain 的核心抽象,它将多个步骤串联为一个可执行的整体:

chain = prompt | llm

result = chain.invoke({"text": "Artificial Intelligence is reshaping every industry."})
print(result.content)

| 操作符使用 LCEL(LangChain 表达式语言)将组件连接起来。数据从左向右流动:先经过 prompt 格式化成模型可理解的输入,再交给 llm 生成回复。


3. 让应用拥有记忆:ConversationBufferMemory

LLM 本身是无状态的,每次调用都是独立的。要让应用拥有对话记忆,LangChain 提供了多种记忆管理类。

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain

memory = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True  # 打印中间过程,便于调试
)

# 连续对话
conversation.predict(input="我叫小明。")
conversation.predict(input="我叫什么名字?")

此时模型会回答“你叫小明”。ConversationBufferMemory 简单地将整个对话历史存储在列表中,并在每次调用时作为上下文注入 prompt。对于长对话,你可能需要更高级的记忆类型(如 ConversationSummaryMemory),以避免 token 超限。


4. 工具集成:让 LLM 与外部世界互动

LLM 的强项在于语言理解,但无法直接访问实时数据或执行操作。工具(Tool) 机制为模型提供了“手和眼”。

4.1 自定义一个天气工具

假设我们有一个天气查询函数。我们将其包装为 LangChain 的 Tool:

from langchain.tools import tool

@tool
def get_weather(city: str) -> str:
    """查询指定城市的实时天气(模拟)"""
    # 实际项目可替换为真实 API 调用
    weather_data = {
        "北京": "晴,25°C",
        "上海": "多云,28°C",
    }
    return weather_data.get(city, "暂无该城市天气数据。")

4.2 绑定工具到模型

llm_with_tools = llm.bind_tools([get_weather])

现在模型可以根据用户输入自动决定是否调用工具。但要真正执行工具并处理返回结果,我们需要一个完整的 Agent 流程。


5. Agent:自主推理与行动的智能体

Agent 是 LangChain 中的高级组件,它利用 LLM 的推理能力来决定“何时使用哪个工具,以及如何解读工具返回的结果”。

5.1 创建 Agent

from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有用的助手,可以使用工具获取信息。"),
    ("user", "{input}"),
    ("placeholder", "{agent_scratchpad}"),  # 必须包含,用于记录中间步骤
])

agent = create_tool_calling_agent(llm, [get_weather], prompt)
agent_executor = AgentExecutor(
    agent=agent,
    tools=[get_weather],
    verbose=True,
    handle_parsing_errors=True,
)

5.2 运行 Agent

response = agent_executor.invoke({"input": "现在北京的天气怎么样?"})
print(response['output'])

在 verbose 模式下,你会看到模型的思考过程:它识别出需要调用 get_weather 工具,并将“北京”作为参数传入,拿到结果后生成自然语言回复。

5.3 多工具协同

你可以添加更多工具,例如计算器、搜索引擎或数据库查询工具。Agent 会根据上下文自动选择并组合使用它们:

@tool
def calculate(expression: str) -> str:
    """计算数学表达式,例如 '2 + 2'"""
    try:
        return str(eval(expression))
    except:
        return "计算错误"

tools = [get_weather, calculate]
# 后续创建 agent 时使用 tools 即可

当用户问“北京的温度除以2是多少?”时,Agent 会先查天气,再用计算器处理结果。


6. 构建完整的端到端应用:带记忆的天气助理

综合以上知识,我们创建一个能记住对话历史的天气助理。

6.1 初始化带记忆的 Agent

AgentExecutor 本身没有记忆。我们需要将对话历史手动传入 prompt。LangChain 提供了 MessagesPlaceholder 来注入历史消息。

from langchain_core.messages import AIMessage, HumanMessage
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

# 使用内存存储对话历史(生产环境可换为 Redis 等)
store = {}

def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

# 重构 prompt,加入历史消息占位
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是个天气助手,可以使用工具获取天气信息。"),
    ("placeholder", "{chat_history}"),
    ("user", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 包装为带消息历史的 Runnable
conversational_agent = RunnableWithMessageHistory(
    agent_executor,
    get_session_history,
    input_messages_key="input",
    history_messages_key="chat_history",
)

6.2 进行多轮对话

session_id = "user_123"

response1 = conversational_agent.invoke(
    {"input": "我叫小明,北京天气如何?"},
    config={"configurable": {"session_id": session_id}}
)
print(response1['output'])

response2 = conversational_agent.invoke(
    {"input": "我刚才说我叫什么名字?"},
    config={"configurable": {"session_id": session_id}}
)
print(response2['output'])  # 会输出“小明”

记忆功能通过会话 ID 隔离,不同用户可以并发访问。


7. 进阶主题与最佳实践

7.1 流式输出

在 Web 应用中,通常需要逐词显示回复以提升体验。使用 astream_events 方法:

async for event in agent_executor.astream_events(
    {"input": "北京天气如何?"}, version="v1"
):
    if event["event"] == "on_chat_model_stream":
        content = event["data"]["chunk"].content
        print(content, end="", flush=True)

7.2 选择正确的记忆类型

  • BufferMemory:适合短对话,简单直接。
  • SummaryMemory:自动对历史做摘要,控制 token 消耗。
  • ConversationTokenBufferMemory:按 token 数量限制历史长度。
  • VectorStoreRetrieverMemory:将历史存入向量数据库,按相关度检索——适合需要长期记忆的场景。

7.3 结构化输出

利用 with_structured_output 可以让模型返回 JSON 等格式化数据,便于后续代码处理:

from pydantic import BaseModel, Field

class WeatherResponse(BaseModel):
    city: str = Field(description="城市名")
    summary: str = Field(description="天气梗概")

structured_llm = llm.with_structured_output(WeatherResponse)
res = structured_llm.invoke("今天北京的天气是晴天,25°C")
print(res)  # WeatherResponse(city='北京', summary='晴天,25°C')