1. 项目概述今天我们来聊聊如何从零开始构建一个具备工具调用能力的Agent系统。作为一名长期从事AI工程化落地的开发者我发现很多初学者在学习Agent开发时容易陷入两个极端要么停留在理论层面纸上谈兵要么直接复制粘贴代码却不明就里。这篇文章将带你通过渐进式实战亲手构建一个天气查询助手Agent掌握从零到一的完整开发流程。这个项目特别适合已经了解Python基础语法想进入AI应用开发领域的工程师对LangChain等框架感兴趣但缺乏实战经验的学习者需要将大模型能力集成到现有系统的开发者我们将采用Linux开发环境这也是生产环境的主流选择使用LangChain框架构建一个基于ReAct架构的Agent。这个Agent不仅能理解自然语言查询还能正确调用天气查询工具并返回结构化的响应。更重要的是我会分享在实际工程化过程中积累的那些教科书不会告诉你的经验和技巧。2. 环境准备与项目初始化2.1 开发环境配置在开始编码前我们需要搭建一个隔离的Python环境。这里我强烈推荐使用virtualenv而不是conda因为在生产环境中virtualenv的体积更小、启动更快也更符合Linux服务器的部署习惯。# 创建并激活虚拟环境 python -m venv ~/agent-env source ~/agent-env/bin/activate安装依赖时有个重要细节必须固定版本号。这是因为LangChain等框架更新频繁不同版本间API可能有破坏性变更。下面是经过我实际验证能完美配合的版本组合pip install langchain0.1.16 langchain-community0.0.34 \ langchain-core0.1.46 requests2.31.0 \ python-dotenv1.0.0 tqdm4.66.1注意如果你打算使用本地模型比如Ollama还需要额外安装ollama包。但为了教程的普适性我们先以API方式为例。2.2 项目结构设计良好的项目结构是工程化的第一步。我推荐采用以下模块化结构my-first-agent/ ├── tools/ # 工具模块 ├── agents/ # Agent实现 ├── config/ # 配置文件 ├── logs/ # 日志文件 ├── .env # 环境变量 ├── .gitignore # 版本控制忽略规则 └── requirements.txt # 依赖声明这样设计有几个好处功能模块清晰分离便于维护配置文件与代码分离符合12-Factor应用原则日志集中管理方便问题排查初始化这个结构只需几条命令mkdir -p my-first-agent/{tools,agents,config,logs} cd my-first-agent touch __init__.py tools/__init__.py agents/__init__.py .env .gitignore requirements.txt3. 核心工具开发3.1 天气查询工具实现在tools/weather_tool.py中我们将实现一个安全的天气查询工具。这里有几个工程化要点需要注意输入校验防止Prompt Injection攻击错误隔离避免工具异常导致整个Agent崩溃模拟数据教程中使用mock数据实际项目可替换为真实APIimport requests from langchain.tools import Tool from dotenv import load_dotenv import os load_dotenv() def get_weather(city: str) - str: 安全封装天气查询模拟 API实际项目替换为真实服务 安全设计城市名校验 超时控制 错误隔离 # 白名单校验防 Prompt Injection allowed_cities [beijing, shanghai, guangzhou, shenzhen, hangzhou] city_clean city.strip().lower() if city_clean not in allowed_cities: return f❌ 仅支持查询: {, .join(allowed_cities)}。您输入了: {city} try: # 实际项目替换为和风天气/彩云天气 API # 此处用 mock 数据避免依赖外部服务 mock_data { beijing: ️ 北京: 晴, 28°C, 微风, shanghai: ️ 上海: 小雨, 26°C, 东南风3级, guangzhou: ⛈️ 广州: 雷阵雨, 31°C, 南风2级 } return mock_data.get(city_clean, f️ {city_clean.capitalize()}: 晴, 25°C) except Exception as e: return f⚠️ 天气服务异常: {str(e)[:50]} # 注册为 LangChain Tool weather_tool Tool( nameget_weather, funcget_weather, description( 查询中国主要城市的实时天气。 参数: 城市英文名小写如 beijing。 注意: 仅支持 beijing/shanghai/guangzhou/shenzhen/hangzhou ) )3.2 安全设计考量在实际项目中工具的安全性往往被忽视。这里我特别强调几个关键点输入白名单只允许预定义的城市名防止恶意输入错误信息脱敏异常消息只返回前50个字符避免泄露敏感信息超时控制虽然没有在mock中体现但真实API调用必须设置timeout经验分享我曾经在一个生产项目中遇到过因为未做输入校验导致用户输入北京; rm -rf /这样的恶意命令。虽然Python解释器会阻止这种操作但良好的安全习惯应该从一开始就培养。4. Agent核心实现4.1 ReAct Agent架构在agents/weather_agent.py中我们将实现基于ReAct架构的Agent。ReActReasoning and Acting是一种让LLM能够动态决定何时以及如何使用外部工具的框架。from langchain.agents import create_react_agent, AgentExecutor from langchain.prompts import PromptTemplate from langchain_community.llms import Ollama # 本地模型无需网络 from tools.weather_tool import weather_tool import logging # 配置日志Linux 工程师熟悉的方式 logging.basicConfig( levellogging.INFO, format%(asctime)s | %(levelname)s | %(message)s, handlers[ logging.FileHandler(logs/agent.log), logging.StreamHandler() ] ) logger logging.getLogger(__name__) def create_weather_agent(): # 1. 选择本地模型适配 Linux 环境 llm Ollama( modelqwen:7b, # 需提前 ollama pull qwen:7b temperature0.3, # 降低随机性提升工具调用稳定性 timeout120 ) # 2. 定制 ReAct Prompt关键注入领域知识 template 你是一个严谨的天气查询助手严格遵守以下规则 1. 用户问天气时必须调用 get_weather 工具 2. 城市名必须转为小写英文如北京→beijing) 3. 若工具返回错误明确告知用户限制范围 4. 最终回答需包含emoji和实用建议如适合带伞 工具描述 {tools} 使用以下格式 Question: 用户问题 Thought: 分析需求 Action: 工具名 参数 Observation: 工具返回 ...可重复 Final Answer: 清晰结论 当前问题: {input} {agent_scratchpad} prompt PromptTemplate.from_template(template) # 3. 创建 Agent agent create_react_agent(llm, [weather_tool], prompt) executor AgentExecutor( agentagent, tools[weather_tool], verboseTrue, # 关键输出思考过程 handle_parsing_errorsTrue, # 防止 LLM 格式错误崩溃 max_iterations5 # 防止无限循环 ) logger.info(✅ Weather Agent 初始化成功) return executor4.2 Prompt工程技巧这个模板中有几个关键设计点明确的规则约束前三条规则强制Agent必须使用工具避免直接编造答案输出格式化要求包含emoji和实用建议提升用户体验错误处理明确要求处理工具返回的错误踩坑记录在早期版本中我没有明确要求城市名转换导致Agent有时会直接传递中文城市名给工具引发错误。这个细节告诉我们Prompt中的约束条件要尽可能明确具体。4.3 执行器配置AgentExecutor的几个关键参数verboseTrue开发阶段建议开启方便调试handle_parsing_errorsTrue防止LLM输出格式错误导致程序崩溃max_iterations5限制最大迭代次数避免无限循环5. 交互界面与测试5.1 CLI交互实现我们采用简单的命令行交互方式这是Linux环境下最通用的形式# CLI 入口Linux 工程师熟悉的交互方式 if __name__ __main__: agent create_weather_agent() print(️ 天气助手已启动 (输入 quit 退出)) print(- * 50) while True: try: user_input input(\n 你的问题: ).strip() if user_input.lower() in [quit, exit]: break if not user_input: continue result agent.invoke({input: user_input}) print(f\n 助手: {result[output]}) except KeyboardInterrupt: print(\n⚠️ 用户中断) break except Exception as e: logger.error(fAgent 执行异常: {e}) print(f❌ 系统错误: {str(e)[:100]}) print(\n 感谢使用日志已保存至 logs/agent.log)5.2 测试案例让我们测试几个典型场景正常查询输入: 上海明天天气如何 输出: ️ 上海: 小雨, 26°C, 东南风3级 → 建议携带雨具不在白名单的城市输入: 纽约天气怎么样 输出: ❌ 仅支持查询: beijing, shanghai, guangzhou, shenzhen, hangzhou。您输入了: 纽约中文城市名输入: 北京今天天气 输出: ️ 北京: 晴, 28°C, 微风 → 适合户外活动6. 工程化进阶技巧6.1 日志与监控完善的日志系统对Agent调试至关重要。我们的配置实现了同时输出到文件和终端包含时间戳和日志级别关键操作都有日志记录logging.basicConfig( levellogging.INFO, format%(asctime)s | %(levelname)s | %(message)s, handlers[ logging.FileHandler(logs/agent.log), logging.StreamHandler() ] )6.2 性能优化LLM参数调优temperature0.3平衡创造性和稳定性timeout120给大模型足够的响应时间工具调用优化限制最大迭代次数添加解析错误处理6.3 安全加固环境变量管理 所有敏感配置都通过.env文件管理不要硬编码在代码中命令执行限制 如果Agent需要执行系统命令务必设置白名单ALLOWED_LINUX_COMMANDSls,pwd,cat,df,du COMMAND_TIMEOUT57. 常见问题排查7.1 工具未被调用现象Agent直接回答天气情况而不调用工具排查步骤检查Prompt中是否明确要求调用工具验证工具描述是否清晰准确检查LLM的temperature是否过高建议0.3-0.57.2 无限循环现象Agent不断重复相似操作解决方案设置max_iterations通常3-5次足够在Prompt中明确终止条件7.3 格式解析错误现象Agent输出不符合ReAct格式处理方案启用handle_parsing_errors在Prompt中提供更明确的格式示例8. 扩展方向这个基础Agent可以进一步扩展多工具集成添加日历、交通等工具记忆功能保存对话历史Web界面用FastAPI封装成服务生产部署Docker容器化我在实际项目中发现一个设计良好的基础Agent架构可以节省后期大量的重构时间。建议在初期就考虑好扩展性比如采用工厂模式创建Agent使用依赖注入管理工具等。
企业数字化 ERP 产品动态
相关推荐
深入解析bthread协程库:从高性能并发原理到C++大厂面试实战 1. 项目概述:一次关于并发编程与求职准备的深度拆解最近在整理技术笔记,翻到了之前分析百度brpc框架中bthread协程库的旧文,又恰好有朋友在准备搜狐新闻客户端这类大厂的C/C岗位面试,跑来问我有没有什么“新鲜出炉”的干货。这让我… · 2026/9/25 11:39:21
C++未初始化变量:从内存原理到实战排查与防御 1. 项目概述:从“幽灵值”到程序崩溃的元凶在C的世界里摸爬滚打,你迟早会遇到一个看似简单却暗藏杀机的报错:Use of Uninitialized Variable(使用了未初始化的变量)。这行编译器警告或运行时调试器抛出的错误信息&… · 2026/9/25 11:39:20
当Markdown解析器不再“简单“:Simple-Markdown如何重新定义可扩展性 当Markdown解析器不再"简单":Simple-Markdown如何重新定义可扩展性 【免费下载链接】simple-markdown JavaScript markdown parsing, made simple 项目地址: https://gitcode.com/gh_mirrors/si/simple-markdown
你是否曾遇到过这样的困境… · 2026/9/18 16:15:07
DeskcommCRM实战:从数据建模到权限体系的客户管理系统设计 从最初接到DeskcommCRM这个项目开始,我就在心里给它定了个调子:它不是市面上那种功能堆到溢出的通用CRM,而是要给一群天天被客户信息和管理报表折磨的销售、售前、实施人员,提供一个真正能用得起来的协作工具。项目落地之后&#… · 2026/9/25 11:41:36
Atlas 300V 24G推理加速卡深度解析:从定位到YOLOv5部署实践 先说个有意思的现象:atlas 300v 24g 是运算加速卡吗这个搜索词,我最近在好几个技术社群里都看到有人在问。有人拿它和T4比,有人把它当成显卡,甚至还有人在纠结能不能用它跑通YOLO训练。说实话,这些问题的背后其实是对昇… · 2026/9/25 11:41:30
如何实现闲鱼批量抓取采集自动化?20核并发不抢焦,单机跑通百店零报错 如何实现闲鱼批量抓取采集自动化?20核并发不抢焦,单机跑通百店零报错
老店群人都有个体会:闲鱼的批量抓取采集,是店群运营中最耗人力也最容易出错的环节。
采集竞品数据是店群运营的命脉。但各大平台的反爬系统越来越强࿰… · 2026/9/25 11:41:24
如何实现闲鱼批量抓取采集自动化?DOM透视突破大促弹窗,毫秒级响应 如何实现闲鱼批量抓取采集自动化?DOM透视突破大促弹窗,毫秒级响应
搞店群运营这行,闲鱼的批量抓取采集,是店群运营中最耗人力也最容易出错的环节。
采集竞品数据是店群运营的命脉。但各大平台的反爬系统越来越强,普通爬… · 2026/9/25 11:41:18
MikroORM 自定义数据库驱动开发指南:从 Platform 到 Driver 的四层架构与完整实现 后端 【免费下载链接】mikro-orm TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases. 项目地址: https://gitcode.com/gh_mir… · 2026/9/25 11:41:05
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37