夜雨聆风学习资料网

ARTICLE · 1092921

从零构建一个带工具的 AI Agent

从零构建一个带工具的 AI Agent
学习笔记 · LANGCHAIN

一篇给自己复盘的实战笔记 · 整理自当日学习记录

▲ 一个模型“大脑”为核心,向外连接各类工具“手脚”

大家好。今天在学习大模型应用开发时,完整走了一遍“构建一个带工具的 AI Agent”的流程:从理论架构到代码落地,再到和网络环境、版本兼容性斗智斗勇,过程曲折但收获很扎实。这篇文章把当天的学习心得和踩坑记录整理出来,希望能帮到同样在入门 LangChain 的你。

今天的学习路线(五站)

1核心概念:Agent 的“大脑”与“手脚”
2定义工具:@tool 与 Pydantic
3组装 Agent:LangChain 1.x 的巨变
4踩坑实录:从 API Key 到网络超时
5总结与展望
PART 01核心概念:大脑与手脚

在写代码之前,先理清 Agent(智能体)的基本构成。一个完整的 Agent,至少包含两个关键部分:

模型 Model · 大脑

负责推理、分析,规划任务的步骤。

工具 Tools · 手脚

负责执行具体任务,与外界交互。

二者不是各干各的,而是在一个循环里不断协作。

▲ 大脑指挥手脚,手脚把结果反馈给大脑,循环往复

它们如何协作:一个循环

1用户提问:给出一个问题或目标(Input)。
2模型分析:要不要调用工具?调哪个?现有结果够不够回答?
3调用工具:执行动作(Action),拿到执行结果(Observation)。
4再次交给模型:把结果喂回去,判断是否继续。
5最终输出:信息足够时,生成回答(Output)。
PART 02动手:如何定义工具

从零搭建 Agent 的第一步,是定义工具(Tools)。在 LangChain 里,工具本质上是一个可调用的函数,但它不是给我们自己调用的,而是给模型调用的。所以必须用清晰的语言描述它,让模型知道“它叫什么”“有什么用”“需要什么参数”。

从最简单的 @tool 装饰器开始:

from langchain_core.tools import tool

@tool

defget_current_time(timezone: str) -> str:

    """获取指定时区的当前时间。当用户询问现在几点、

    时间、日期时,使用此工具。"""

    # ... 逻辑代码

    returnf"{timezone}的当前时间是..."

不写装饰器参数时:函数名默认成为工具名,文档注释(Docstring)默认成为工具作用的描述。

进阶:用 Pydantic 描述复杂参数

参数较多、较复杂时,直接写在函数里会很乱。这时建议引入 Pydantic 模型,把参数结构化:

from pydantic import BaseModel, Field

classWeatherInput(BaseModel):

    """查询天气所需的输入参数"""

    location: str = Field(description="城市名称或经纬度坐标")

    units: str = Field(default="celsius", description="温度单位")

    include_forecast: bool = Field(default=False, description="是否包含未来天气预测")

通过 @tool(args_schema=WeatherInput) 绑定后,模型就能非常精准地理解并提取参数,减少参数错传、漏传。

PART 03组装 Agent:1.x 的巨变

定义好工具后,初始化模型、创建 Agent。这里遇到了今天最大的坑:版本兼容性。很多旧教程还在用 AgentExecutor 和 create_tool_calling_agent,但在 LangChain 1.x 中这些 API 已被弃用,强行导入会报 ImportError。现在的正确姿势是全新的 create_agent。

旧教程写法
1.x 状态
现在用什么
AgentExecutor
已弃用
create_agent
create_tool_calling_agent
已弃用
create_agent
agent.run("问题")
已弃用
invoke({"messages": [...]})

from langchain.agents import create_agent

llm = ChatOpenAI(

    model="deepseek-chat", temperature=0,

    base_url="https://api.deepseek.com/v1",

    api_key=os.getenv("DEEPSEEK_API_KEY")

)

agent = create_agent(

    model=llm, tools=tools,

    system_prompt="你是一个智能助手,请根据问题决定是否调用工具。"

)

response = agent.invoke({

"messages": [{"role": "user", "content": "今天天气怎么样?"}]

})

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

两个 1.x 要点:调用时必须传入 messages 列表,而不是直接传一句话;最终回答从 response["messages"][-1].content 取。
PART 04踩坑实录:三连暴击

理论很丰满,现实很骨感。运行代码时,报错一个接一个,正好把常见网络坑都过了一遍。

坑 1Missing credentials:缺少凭证

根因:ChatOpenAI 默认会去环境变量里找 OPENAI_API_KEY,没读到就报缺凭证。

解法:确认 .env 配置正确,或在代码里显式传入 api_key;改完务必重启 Jupyter 内核,否则旧环境变量不会刷新。

坑 2ConnectError:getaddrinfo failed

根因:DNS 解析失败,连不上服务器。部分内网环境(如校园网、公司网络)会屏蔽外部大模型 API。

解法:更换网络环境,或直接改用国内直连模型(见下方方案)。

坑 3APITimeoutError:请求超时

根因:即使没有被屏蔽,直连海外服务器在国内也可能极不稳定,请求迟迟无响应。

解法:设置超时与重试,或改用国内直连、网络更稳的模型。

终极方案:换国内直连模型

与其在网络上死磕,不如换成直连稳定的通义千问(Qwen)。它完全兼容 OpenAI 接口,只需改几行配置,换上后代码即可顺利跑通。

llm = ChatOpenAI(

    model="qwen-turbo",

    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",

    api_key=os.getenv("DASHSCOPE_API_KEY"), # 在阿里云百炼平台申请

    temperature=0

)

PART 05总结与展望

● 理解 Agent 的基础架构:模型“大脑” + 工具“手脚”;

● 学会用 @tool、Pydantic 清晰地定义工具与参数;

● 掌握 LangChain 1.x 的新范式 create_agent;

● 在复杂网络下,灵活切换到国内直连大模型。

如果你在配置时也遇到了类似报错,希望这篇笔记能帮你省下一点 debug 的时间。我们下期见。

相关学习资料