1. 本章目标 #

上一章讲清了 Agent = Model + Harness。本章目标:

跑通一个可调用工具的天气助手,并看懂它的执行轨迹。

学完你应能:

参考文档:

2. 第一个 Agent:天气助手 #

核心路径是:定义工具 → create_agentinvoke

2.1. 1.weather_agent.py #

# 创建智能体的工厂函数
from langchain.agents import create_agent
# 从 .env 加载密钥等环境变量
from dotenv import load_dotenv

load_dotenv(override=True)


def get_weather(city: str) -> str:
    """获取指定城市的天气信息。"""
    return f"{city} 今天晴,气温 25°C。"


# model:provider:model 字符串;tools:普通函数也可;system_prompt:人设与约束
agent = create_agent(
    model="deepseek:deepseek-v4-flash",
    tools=[get_weather],
    system_prompt="你是一个简洁、可靠的中文助手。需要天气信息时请调用工具,不要编造。",
)

# 输入是状态字典;messages 是对话消息列表
result = agent.invoke(
    {"messages": [{"role": "user", "content": "北京今天天气怎么样?"}]}
)

# 最后一条通常是助手的最终回复
print(result["messages"][-1].content)

预期类似:

北京今天晴,气温 25°C。

2.2. 这段代码在做什么 #

用户:「北京今天天气怎么样?」
        │
        ▼
   create_agent 循环
        │
        ├─ 模型判断:需要天气 → 调用 get_weather(city="北京")
        ├─ 工具返回:"北京 今天晴,气温 25°C。"
        ├─ 模型根据工具结果组织自然语言回答
        └─ 结束循环,返回完整 messages

要点回顾:

参数 含义
model "deepseek:deepseek-v4-flash" 或已初始化的模型实例
tools 可调用对象列表;docstring + 类型注解帮助模型选对工具
system_prompt 系统行为设定
invoke({...}) 同步执行一轮(内部可能多步工具调用)

3. 看懂返回的消息轨迹 #

只打印最后一句不够。调试时要看清中间发生了什么。

3.1. inspect_messages.py #

from langchain.agents import create_agent
from dotenv import load_dotenv

load_dotenv(override=True)


def get_weather(city: str) -> str:
    """获取指定城市的天气信息。"""
    return f"{city} 今天晴,气温 25°C。"


agent = create_agent(
    model="deepseek:deepseek-v4-flash",
    tools=[get_weather],
    system_prompt="你是一个简洁、可靠的中文助手。需要天气信息时请调用工具。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "上海天气如何?"}]}
)

# 遍历完整消息轨迹,观察角色与是否含 tool_calls
for i, msg in enumerate(result["messages"]):
    # 消息类型名:HumanMessage / AIMessage / ToolMessage 等
    msg_type = type(msg).__name__
    print(f"\n===== [{i}] {msg_type} =====")

    # 文本内容(工具结果、最终回答等多在这里)
    content = getattr(msg, "content", None)
    if content:
        print("content:", content)

    # 模型发起的工具调用请求(若有)
    tool_calls = getattr(msg, "tool_calls", None)
    if tool_calls:
        print("tool_calls:", tool_calls)

典型轨迹(简化):

[0] HumanMessage     → 用户问题
[1] AIMessage        → 带 tool_calls:get_weather(city="上海")
[2] ToolMessage      → 工具返回字符串
[3] AIMessage        → 最终自然语言回答

这就是 harness 帮你自动完成的「模型 ↔ 工具」循环。第 4 章会系统讲消息类型。

4. 多工具助手 #

真实项目中很少只有一个工具。下面加「天气 + 加法」,看模型如何按需选择。

4.1. multi_tools_agent.py #

from langchain.agents import create_agent
from langchain.tools import tool
from dotenv import load_dotenv

load_dotenv(override=True)


# 使用 @tool 装饰器,把下方函数注册为可供 Agent 调用的工具
@tool
# 定义获取天气的工具函数:参数 city 为城市名,返回值为字符串
def get_weather(city: str) -> str:
    # 工具说明(docstring),会作为工具描述提供给模型
    """获取指定城市的天气信息。"""
    return f"{city} 今天晴,气温 25°C。"


# 使用 @tool 装饰器,把下方函数注册为可供 Agent 调用的工具
@tool
# 定义整数加法工具:接收两个整数 a、b,返回它们的和
def add(a: int, b: int) -> int:
    # 工具说明(docstring),会作为工具描述提供给模型
    """计算两个整数之和。"""
    # 返回 a 与 b 的加法结果
    return a + b


agent = create_agent(
    model="deepseek:deepseek-v4-flash",
    tools=[get_weather, add],
    system_prompt=(
        "你是办公助手。"
        "查天气时调用 get_weather;"
        "做整数加法时调用 add,不要心算。"
    ),
)

# 一次提问里同时触发两类工具
result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "北京天气怎么样?另外帮我算 128 + 256。",
            }
        ]
    }
)

print(result["messages"][-1].content)

@tool 会把函数名、参数 schema、docstring 整理成模型可见的工具描述。

5. 流式输出 #

长回答时,用流式边生成边打印体验更好。Agent 也支持 stream

5.1. stream_agent.py #

from langchain.agents import create_agent
from dotenv import load_dotenv

load_dotenv(override=True)


def get_weather(city: str) -> str:
    """获取指定城市的天气信息。"""
    return f"{city} 今天晴,气温 25°C。"


agent = create_agent(
    model="deepseek:deepseek-v4-flash",
    tools=[get_weather],
    system_prompt="你是一个简洁的中文助手。",
)

# stream_mode="updates":按节点更新推送;也可用 "values" 看完整状态快照
for chunk in agent.stream(
    {"messages": [{"role": "user", "content": "深圳今天天气?"}]},
    stream_mode="updates",
):
    print(chunk)

第一次看 updates 可能较碎:会看到模型节点、工具节点逐步产出。

若只想快速拿到最终文本,继续用 invoke 即可。

6. 常见问题排查 #

现象 可能原因 处理
模型直接编造天气、不调工具 系统提示太弱,或 docstring 不清晰 system_prompt 明确「必须调用工具」;补全工具说明
AuthenticationError / 401 密钥无效或过期 检查 .env 中的 DEEPSEEK_API_KEY
create_agent 导入失败 LangChain 版本过旧 pip install -U langchain
LangSmith 无数据 未开启追踪或 key 错误 确认 LANGSMITH_TRACING=true 与 API Key

7. 练习 #

  1. 改城市:把用户问题换成「广州和杭州天气分别怎么样?」观察是否多次调用 get_weather
  2. 加工具:再写一个 get_time(city: str) -> str(可返回固定字符串),让助手能回答「现在几点」。
  3. 收紧人设:把 system_prompt 改成「只回答天气;其他问题礼貌拒绝」,测一句无关问题。
  4. 对照轨迹:用 inspect_messages.py 打印完整 messages,标出哪一步是 tool_calls。

9. 本章小结 #

  1. 最小闭环:定义工具 → create_agentinvoke
  2. 工具可以是普通函数;写清 类型注解 + docstring
  3. 调试看 完整 messages,不要只看最后一句。
  4. 多工具时靠系统提示 + 工具描述引导模型选择。
  5. 尽早打开 LangSmith,为后面复杂 Agent / RAG 打底。

下一章:Chat Models 聊天模型——统一用 init_chat_model 切换供应商、调参数、做流式输出。