初识 LangChain v1.x Agents

12 阅读12分钟

📖 目录

  1. 什么是 Agent?
  2. Agent 的核心组件
  3. 快速上手:创建你的第一个 Agent
  4. 深入理解:Agent 的工作原理
  5. 高级特性
  6. 实战案例

什么是 Agent?

想象一下,你有一个聪明的助手,它不仅能回答问题,还能主动使用各种工具来完成任务。这就是 Agent(智能代理)!

🎯 Agent vs 普通 LLM

特性普通 LLMAgent
回答问题
使用工具
多步推理有限
自主决策

📊 Agent 的工作流程

用户输入 → LLM 推理 → 选择工具 → 执行工具 → 观察结果 → 再次推理 → 最终答案
         ↑______________________________________________|
                    (循环直到得出答案)

Agent 的核心组件

一个完整的 Agent 系统由三个核心部分组成:

1. 🧠 模型(Model)

模型是 Agent 的"大脑",负责推理和决策。

静态模型配置:

在创建agent的时候配置一次,后续在整个执行过程中保持不变。

from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek

# 方式1:使用模型标识符字符串(简单快捷)
agent = create_agent("deepseek:deepseek-chat", tools=tools)

# 方式2:使用模型实例(更多控制)
model = ChatDeepSeek(
    model="deepseek-chat",
    temperature=0.7,  # 控制创造性
    max_tokens=2000,  # 限制输出长度
    timeout=60        # 超时设置
)
agent = create_agent(model, tools=tools)

动态模型选择:

有时候,我们需要根据不同场景选择不同的模型。比如简单问题用便宜的模型,复杂问题用强大的模型: 我们通过 @wrap_model_call 装饰器来创建中间件的方式来使用动态模型,概中间件会修改请求中的模型。

from langchain.agents.middleware import wrap_model_call

basic_model = ChatDeepSeek(model="deepseek-chat")
advanced_model = ChatDeepSeek(model="deepseek-reasoner")

@wrap_model_call
def smart_model_selection(request, handler):
    """根据对话复杂度智能选择模型"""
    message_count = len(request.state["messages"])
    
    if message_count > 10:
        # 长对话使用推理模型
        model = advanced_model
        print("📈 使用推理模型处理复杂对话")
    else:
        # 短对话使用对话模型节省成本
        model = basic_model
        print("💡 使用对话模型处理简单对话")
    
    return handler(request.override(model=model))

agent = create_agent(
    model=basic_model,
    tools=tools,
    middleware=[smart_model_selection]
)

2. 🔧 工具(Tools)

工具赋予 Agent 行动能力,让它能够与外部世界交互。

定义工具示例:

from langchain.tools import tool

@tool
def search_web(query: str) -> str:
    """在互联网上搜索信息"""
    # 实际项目中这里会调用真实的搜索 API
    return f"搜索结果:{query} 的相关信息..."

@tool
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    # 实际项目中这里会调用天气 API
    weather_data = {
        "北京": "晴天,15°C",
        "上海": "多云,18°C",
        "深圳": "阴天,22°C"
    }
    return weather_data.get(city, "未知城市")

@tool
def calculate(expression: str) -> str:
    """计算数学表达式"""
    try:
        result = eval(expression)
        return f"计算结果:{result}"
    except Exception as e:
        return f"计算错误:{str(e)}"

# 创建 Agent 时传入工具列表
tools = [search_web, get_weather, calculate]

如果提供了一个空的工具列表,智能体将由一个不具备工具调用功能的单个 LLM 节点组成。

工具错误处理:

通过 @wrap_tool_call 中间件自定义工具错误的处理方式。

from langchain.agents.middleware import wrap_tool_call
from langchain.messages import ToolMessage

@wrap_tool_call
def handle_tool_errors(request, handler):
    """优雅地处理工具执行错误"""
    try:
        return handler(request)
    except Exception as e:
        print(f"❌ 工具执行失败:{str(e)}")
        return ToolMessage(
            content=f"工具执行出错,请检查输入后重试。错误信息:{str(e)}",
            tool_call_id=request.tool_call["id"]
        )

agent = create_agent(
    model="deepseek-chat",
    tools=[search_web, get_weather, calculate],
    middleware=[handle_tool_errors]
)

上述示例,会在工具失败时,返回一个自定义的错误消息 ToolMessage

3. 💬 系统提示词(System Prompt)

系统提示词定义了 Agent 的"性格"和行为准则。

# 基础系统提示词
agent = create_agent(
    model="deepseek-chat",
    tools=tools,
    system_prompt="你是一个专业的数据分析助手,擅长用图表和数据说话。"
)

# 动态系统提示词(根据用户角色调整)
from langchain.agents.middleware import dynamic_prompt

@dynamic_prompt
def role_based_prompt(request):
    """根据用户角色生成个性化提示词"""
    user_role = request.runtime.context.get("user_role", "普通用户")
    
    prompts = {
        "专家": "你是技术专家助手,提供深入的技术分析和详细解释。",
        "初学者": "你是新手友好的助手,用简单易懂的语言解释概念,避免术语。",
        "学生": "你是教学助手,通过例子和类比帮助学生理解知识。"
    }
    
    return prompts.get(user_role, "你是一个友好的通用助手。")

agent = create_agent(
    model="deepseek-chat",
    tools=tools,
    middleware=[role_based_prompt]
)

当未提供 system_prompt 时,agent会直接从消息中推断其任务。 @dynamic_prompt 装饰器创建了一个中间件,可以根据模型请求动态生成系统提示


快速上手:创建你的第一个 Agent

🎬 完整示例:天气查询助手

from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek
from langchain.tools import tool

# 步骤1:定义工具
@tool
def get_weather(city: str) -> str:
    """获取城市天气信息
    
    Args:
        city: 城市名称,如"北京"、"上海"
    
    Returns:
        该城市的天气信息
    """
    weather_db = {
        "北京": "☀️ 晴天,温度 15°C,空气质量良好",
        "上海": "⛅ 多云,温度 18°C,有轻微雾霾",
        "深圳": "🌧️ 小雨,温度 22°C,湿度较大",
        "广州": "☀️ 晴天,温度 25°C,适合外出"
    }
    return weather_db.get(city, f"抱歉,暂无 {city} 的天气信息")

@tool
def get_weather_forecast(city: str, days: int = 3) -> str:
    """获取城市未来几天的天气预报
    
    Args:
        city: 城市名称
        days: 预报天数(默认3天)
    
    Returns:
        未来几天的天气预报
    """
    return f"{city} 未来 {days} 天天气:\n第1天:晴 20°C\n第2天:多云 18°C\n第3天:小雨 16°C"

# 步骤2:创建 Agent
weather_agent = create_agent(
    model=ChatDeepSeek(model="deepseek-chat", temperature=0),
    tools=[get_weather, get_weather_forecast],
    system_prompt="""你是一个专业的天气助手。
    
    你的职责:
    1. 准确提供用户查询的城市天气信息
    2. 如果用户询问未来天气,主动使用天气预报工具
    3. 给出贴心的出行建议
    
    回答风格:友好、简洁、实用
    """
)

# 步骤3:使用 Agent
print("🤖 天气助手已启动!\n")

# 示例对话1:查询当前天气
result1 = weather_agent.invoke({
    "messages": [{"role": "user", "content": "北京现在天气怎么样?"}]
})
print("用户:北京现在天气怎么样?")
print(f"助手:{result1['messages'][-1].content}\n")

# 示例对话2:查询未来天气
result2 = weather_agent.invoke({
    "messages": [{"role": "user", "content": "上海这周末天气如何?我想去外滩"}]
})
print("用户:上海这周末天气如何?我想去外滩")
print(f"助手:{result2['messages'][-1].content}")

运行结果:

🤖 天气助手已启动!

用户:北京现在天气怎么样?
助手:北京现在天气很好!☀️ 晴天,温度 15°C,空气质量良好。适合外出活动,建议穿薄外套。

用户:上海这周末天气如何?我想去外滩
助手:上海这周末天气预报:
第1天:晴 20°C
第2天:多云 18°C  
第3天:小雨 16°C

建议周六去外滩,天气最好!周日可能有小雨,记得带伞哦。☔

深入理解:Agent 的工作原理

🔄 ReAct 循环:推理 + 行动

Agent 使用 ReAct(Reasoning + Acting)模式工作:

┌─────────────────────────────────────────────────────────────┐
│                    ReAct 工作流程                            │
└─────────────────────────────────────────────────────────────┘

1️⃣ 用户输入:
   "帮我查询北京和上海的天气,然后告诉我哪个城市更适合旅游"

2️⃣ Agent 推理:
   💭 "我需要先获取两个城市的天气信息,然后进行比较"

3️⃣ Agent 行动:
   🔧 调用工具 get_weather("北京")
   
4️⃣ 观察结果:
   📊 "北京:晴天,15°C,空气质量良好"

5️⃣ Agent 再次推理:
   💭 "好的,已经有北京的天气了,现在获取上海的"

6️⃣ Agent 再次行动:
   🔧 调用工具 get_weather("上海")

7️⃣ 观察结果:
   📊 "上海:多云,18°C,有轻微雾霾"

8️⃣ Agent 最终推理:
   💭 "现在我有两个城市的天气数据,可以进行比较了"

9️⃣ 输出答案:
   ✅ "根据天气情况,北京更适合旅游。北京是晴天且空气质量良好,
       而上海多云且有轻微雾霾。建议选择北京。"

📈 实际执行追踪

# 启用详细追踪模式
agent = create_agent(
    model="deepseek-chat",
    tools=[get_weather, get_weather_forecast],
    system_prompt="你是天气助手"
)

# 流式输出,查看中间步骤
print("=" * 60)
print("🔍 Agent 执行追踪")
print("=" * 60)

for chunk in agent.stream(
    {"messages": [{"role": "user", "content": "比较北京和上海的天气"}]},
    stream_mode="values"
):
    latest_message = chunk["messages"][-1]
    
    if latest_message.content:
        print(f"\n💬 Agent 回复:{latest_message.content}")
    elif hasattr(latest_message, 'tool_calls') and latest_message.tool_calls:
        tool_names = [tc['name'] for tc in latest_message.tool_calls]
        print(f"\n🔧 正在调用工具:{', '.join(tool_names)}")

高级特性

1. 🎯 结构化输出

让 Agent 返回格式化的数据结构,而不是纯文本。LangChain 通过 response_format 参数提供结构化输出策略。

ToolStrategy

ToolStrategy 使用人工工具调用来生成结构化输出。这适用于任何支持工具调用的模型。

from pydantic import BaseModel, Field
from langchain.agents.structured_output import ToolStrategy

class WeatherReport(BaseModel):
    """天气报告数据模型"""
    city: str = Field(description="城市名称")
    temperature: int = Field(description="温度(摄氏度)")
    weather: str = Field(description="天气状况")
    suggestion: str = Field(description="出行建议")

# 创建返回结构化输出的 Agent
structured_agent = create_agent(
    model="deepseek-chat",
    tools=[get_weather],
    response_format=ToolStrategy(WeatherReport)
)

result = structured_agent.invoke({
    "messages": [{"role": "user", "content": "查询北京天气"}]
})

# 获取结构化数据
weather_data = result["structured_response"]
print(f"城市:{weather_data.city}")
print(f"温度:{weather_data.temperature}°C")
print(f"天气:{weather_data.weather}")
print(f"建议:{weather_data.suggestion}")

输出示例:

城市:北京
温度:15°C
天气:晴天
建议:天气晴朗,适合户外活动,建议穿薄外套

ProviderStrategy

使用模型提供者原生的结构化输出生成。这更可靠,但仅适用于支持原生结构化输出的提供者(例如 OpenAI)。

from langchain.agents.structured_output import ProviderStrategy

agent = create_agent(
    model="gpt-4o",
    response_format=ProviderStrategy(ContactInfo)
)

2. 🧠 记忆与状态管理

让 Agent 记住对话上下文和用户偏好。

from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from typing import TypedDict

# 定义自定义状态
class WeatherAgentState(AgentState):
    user_preferences: dict  # 用户偏好
    search_history: list    # 搜索历史

class MemoryMiddleware(AgentMiddleware):
    """带记忆的中间件"""
    state_schema = WeatherAgentState
    
    def before_model(self, state, runtime):
        # 在调用模型前,添加历史记录到上下文
        history = state.get("search_history", [])
        if history:
            print(f"📚 用户历史查询:{', '.join(history[-3:])}")
        return None

# 创建带记忆的 Agent
memory_agent = create_agent(
    model="deepseek-chat",
    tools=[get_weather],
    middleware=[MemoryMiddleware()]
)

# 使用带状态的调用
result = memory_agent.invoke({
    "messages": [{"role": "user", "content": "北京天气"}],
    "user_preferences": {"temperature_unit": "celsius"},
    "search_history": ["上海", "广州", "深圳"]
})

3. 🔀 动态工具选择

根据不同场景动态提供不同的工具集。

from langchain.agents.middleware import wrap_model_call

@wrap_model_call
def permission_based_tools(request, handler):
    """根据用户权限动态选择工具"""
    user_role = request.runtime.context.get("user_role", "guest")
    
    if user_role == "admin":
        # 管理员拥有所有工具
        tools = [get_weather, get_weather_forecast, update_weather_data]
        print("🔐 管理员权限:所有工具可用")
    elif user_role == "vip":
        # VIP 用户可以使用高级功能
        tools = [get_weather, get_weather_forecast]
        print("⭐ VIP 权限:基础 + 预报工具")
    else:
        # 普通用户只能查询基础天气
        tools = [get_weather]
        print("👤 普通权限:仅基础工具")
    
    return handler(request.override(tools=tools))

dynamic_tool_agent = create_agent(
    model="deepseek-chat",
    tools=[get_weather, get_weather_forecast],
    middleware=[permission_based_tools]
)

# 以不同角色调用
result = dynamic_tool_agent.invoke(
    {"messages": [{"role": "user", "content": "查询天气"}]},
    context={"user_role": "vip"}
)

实战案例

🌟 案例1:智能旅游助手

结合多个工具的综合应用。

from langchain.tools import tool
from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek

# 定义多个旅游相关工具
@tool
def get_weather(city: str) -> str:
    """获取城市天气"""
    return f"{city}:晴天,适合旅游"

@tool
def search_attractions(city: str) -> str:
    """搜索城市景点"""
    attractions = {
        "北京": "故宫、长城、颐和园、天坛",
        "上海": "外滩、东方明珠、豫园、迪士尼",
        "杭州": "西湖、灵隐寺、千岛湖、宋城"
    }
    return f"{city}热门景点:{attractions.get(city, '暂无数据')}"

@tool
def estimate_budget(city: str, days: int) -> str:
    """估算旅游预算"""
    daily_cost = {"北京": 800, "上海": 900, "杭州": 700}
    cost = daily_cost.get(city, 800) * days
    return f"{city} {days}天旅游预算约:{cost}元(含住宿、餐饮、门票)"

@tool
def get_transportation(from_city: str, to_city: str) -> str:
    """查询交通方式"""
    return f"{from_city}{to_city}:高铁3小时,飞机1.5小时"

# 创建旅游助手
travel_agent = create_agent(
    model=ChatDeepSeek(model="deepseek-chat", temperature=0.7),
    tools=[get_weather, search_attractions, estimate_budget, get_transportation],
    system_prompt="""你是一个专业的旅游规划助手。

    你的能力:
    1. 查询天气信息,判断是否适合旅游
    2. 推荐热门景点,制定游玩路线
    3. 估算旅游预算,帮助用户做好财务规划
    4. 查询交通方式,提供出行建议
    
    你的风格:
    - 热情友好,充满旅游热情
    - 提供详细实用的建议
    - 考虑用户预算和时间限制
    """
)

# 示例对话
print("🏖️ 智能旅游助手")
print("=" * 60)

query = """我想从北京去杭州玩3天,帮我规划一下:
1. 现在天气怎么样?
2. 有什么好玩的地方?
3. 大概需要多少预算?
4. 怎么去比较方便?
"""

result = travel_agent.invoke({
    "messages": [{"role": "user", "content": query}]
})

print(f"用户提问:\n{query}\n")
print(f"助手回答:\n{result['messages'][-1].content}")

预期输出:

🏖️ 智能旅游助手
============================================================
用户提问:
我想从北京去杭州玩3天,帮我规划一下:
1. 现在天气怎么样?
2. 有什么好玩的地方?
3. 大概需要多少预算?
4. 怎么去比较方便?

助手回答:
太好了!让我为您规划这次杭州之旅 🎉

📍 **目的地天气**
杭州:晴天,非常适合旅游!

🎯 **推荐景点**
杭州的热门景点有:西湖、灵隐寺、千岛湖、宋城
建议第一天游西湖,第二天去灵隐寺,第三天可以去宋城体验文化演出。

💰 **预算估算**
3天旅游预算约:2100元(含住宿、餐饮、门票)
建议多准备500元作为购物和应急资金。

🚄 **交通建议**
北京 → 杭州:高铁3小时,飞机1.5小时
推荐乘坐高铁,舒适便捷,沿途风景也不错!

祝您旅途愉快!✈️

🌟 案例2:客服助手(流式响应)

展示如何实现流式输出,提升用户体验。

@tool
def search_order(order_id: str) -> str:
    """查询订单信息"""
    return f"订单 {order_id}:已发货,预计明天到达"

@tool
def check_inventory(product_id: str) -> str:
    """检查库存"""
    return f"商品 {product_id}:库存充足,可立即发货"

@tool
def process_refund(order_id: str) -> str:
    """处理退款"""
    return f"订单 {order_id} 退款申请已提交,3-5个工作日到账"

customer_service_agent = create_agent(
    model="deepseek-chat",
    tools=[search_order, check_inventory, process_refund],
    system_prompt="你是一个耐心专业的客服助手。"
)

# 流式输出
print("💬 客服对话(流式输出)")
print("=" * 60)

for chunk in customer_service_agent.stream(
    {"messages": [{"role": "user", "content": "我的订单 12345 什么时候到?"}]},
    stream_mode="values"
):
    latest = chunk["messages"][-1]
    if latest.content:
        print(f"客服:{latest.content}", end="\n\n")
    elif hasattr(latest, 'tool_calls') and latest.tool_calls:
        print(f"[正在查询订单信息...]", end="\n")