从零开始构建AI Agent框架:小白友好版,收藏学习必备!
从零开始构建AI Agent框架:小白友好版,收藏学习必备!
本文将带你一步步构建具备工具调用能力的AI Agent框架,内容涵盖大模型适配层、对话记忆系统、工具调用能力、标准化消息格式及整合形成完整ToolAgent的五个步骤。采用ReAct模式,让Agent能推理并调用工具完成任务,适合编程新手学习,最终实现具备Google搜索等功能的智能助手。
什么是 Agent?
🤖 概念理解
Agent(智能体) = 大模型(大脑)+ 记忆系统 + 工具调用能力 + 任务规划能力
比喻:
- 大模型
= 大脑(思考、理解、决策)
* 记忆系统
= 记忆(记住对话历史)
* 工具调用
= 手脚(执行实际任务,如搜索、计算)
* 任务规划
= 规划能力(分解复杂任务)
🎯 我们的实现目标
构建一个简单的 Agent,具备以下能力:
-
✅ 与用户对话并保持上下文记忆
-
✅ 调用 Google 搜索工具获取实时信息
-
✅ 自动决定何时调用工具
-
✅ 综合工具结果生成最终答案
准备工作
1 创建项目目录
# 在你的桌面创建项目目录cd ~/Desktopmkdir agentcd agent
2 创建依赖管理文件
创建 requirements.txt 文件:
openai>=1.0.0python-dotenv>=1.0.0google-search-results>=2.4.2
3 安装依赖
pip3 install -r requirements.txt
4 配置环境变量
创建 .env 文件(不要提交到 Git):
# 方案1:使用 DeepSeek(推荐,有免费额度)API_KEY=sk-your-deepseek-api-keyBASE_URL=xxxxxMODEL_NAME=deepseek-chat# 方案2:使用 OpenAI(需要 API Key)# API_KEY=sk-your-openai-api-key# BASE_URL=xxxxx# MODEL_NAME=gpt-3.5-turbo# Google 搜索 API(用于工具功能)SERPAPI_API_KEY=your-serpapi-key
第一步:构建"大脑"- 统一的大模型适配层
🎯 目标
创建一个统一的大模型调用接口,屏蔽不同厂商的 API 差异。
📝 创建文件:llm.py
# llm.pyfrom openai import OpenAIimport osfrom dotenv import load_dotenvload_dotenv() # 加载环境变量class LLMClient: def __init__(self): # 通过环境变量配置,轻松切换不同厂商 self.client = OpenAI( api_key=os.getenv("API_KEY"), base_url=os.getenv("BASE_URL") ) self.model = os.getenv("MODEL_NAME", "gpt-4o") def chat(self, messages, tools=None): """ 统一的对话入口,屏蔽底层差异 参数: messages: 对话历史列表 tools: 工具定义列表(可选) 返回: OpenAI API 的响应对象 """ params = { "model": self.model, "messages": messages, } if tools: params["tools"] = tools # 这里为了演示简洁,暂不开启流式输出 return self.client.chat.completions.create(params)
💡 代码解释
核心设计思想:
- 环境变量配置
api_key=os.getenv("API_KEY")base_url=os.getenv("BASE_URL")
将敏感信息(API Key)放在 .env 文件中
避免硬编码在代码里,提高安全性
- 统一接口
def chat(self, messages, tools=None): return self.client.chat.completions.create(params)
封装 OpenAI API 的调用细节
提供简单易用的 chat() 方法
支持 tools 参数,让 Agent 能调用工具
- 易于切换厂商
只需修改 .env 中的 BASE_URL 和 MODEL_NAME
代码完全不需要改动
🔍 为什么需要这个适配层?
❌ 没有适配层
# 硬编码,不安全,难以维护import openairesponse = openai.ChatCompletion.create( model="gpt-4o", messages=[...], api_key="sk-xxx" # 暴露在代码中)
✅ 使用适配层
# 简洁、安全、易切换from llm import LLMClientllm = LLMClient()response = llm.chat([{"role": "user", "content": "你好"}])
第二步:实现基础 Agent - 对话记忆系统
🎯 目标
创建一个能记住对话历史的 Agent,实现多轮对话。
📝 创建文件:agent.py
# agent.py (基础版)from llm import LLMClientclass SimpleAgent: def __init__(self): self.llm = LLMClient() # 初始化记忆,设定基础背景 self.messages = [{"role": "system", "content": "你是一个乐于助人的AI助手。"}] def chat(self, user_input): # 1. 接收:将用户输入存入记忆 self.messages.append({"role": "user", "content": user_input}) # 2. 思考:带着所有历史记录去请求 LLM response = self.llm.chat(self.messages) content = response.choices[0].message.content # 3. 闭环:将 AI 的回答也存入记忆 self.messages.append({"role": "assistant", "content": content}) return content
💡 代码解释
核心概念:消息角色
# system: 设定 AI 的身份和行为规则{"role": "system", "content": "你是一个乐于助人的AI助手。"}# user: 用户的输入{"role": "user", "content": "我叫小明"}# assistant: AI 的回答{"role": "assistant", "content": "你好小明,很高兴认识你!"}
工作流程(三步闭环):
📥 用户输入 → 💾 存入记忆 → 🧠 调用 LLM(带上完整历史)→ 📤 获取回答 → 💾 存入记忆 → ✅ 返回给用户
为什么需要记忆?
- 大模型本身是无状态的,每次调用都是独立的
- 通过传递历史消息,让 AI 理解上下文
- 实现多轮对话和连贯性
🧪 测试基础 Agent
创建测试文件 test_agent.py:
# test_agent.pyfrom agent import SimpleAgentdef main(): agent = SimpleAgent() print("=== 简单的AI助手 ===") print("输入'quit'退出/n") while True: user_input = input("你: ") if user_input.lower() == 'quit': break response = agent.chat(user_input) print(f"Agent: {response}/n")if __name__ == "__main__": main()
运行测试:
python3 test_agent.py
示例对话:
=== 简单的AI助手 === 输入'quit'退出 你: 我叫susie Agent: 你好susie!我是SimpleAgent,有什么我可以帮助你的吗? 你: 你记得我叫什么吗? Agent: 当然记得,你叫susie! 你: quit
第三步:装备工具 - 让 Agent 能"做事"
🎯 目标
实现工具注册和调用系统,让 Agent 能执行实际任务(如 Google 搜索)。
📝 创建文件:tools.py
# tools.pyimport inspectimport jsonimport osfrom functools import wrapsfrom google_search_results import GoogleSearchclass ToolRegistry: """工具注册中心:管理所有可用工具""" def __init__(self): self.tools = {} # 存函数实体 self.schemas = [] # 存函数说明书(JSON Schema) def register(self, func): """ 魔法装饰器:自动将 Python 函数转换为 OpenAI Tool Schema """ name = func.__name__ # 函数名 doc = func.__doc__ or "No description" # 函数文档字符串 # 解析函数签名 sig = inspect.signature(func) params = {"type": "object", "properties": {}, "required": []} # 遍历参数,生成 JSON Schema for param_name, param in sig.parameters.items(): params["properties"][param_name] = { "type": "string", "description": f"参数 {param_name}" } if param.default == inspect.Parameter.empty: params["required"].append(param_name) # 1. 生成说明书(给 LLM 看) self.schemas.append({ "type": "function", "function": { "name": name, "description": doc, "parameters": params } }) # 2. 存储函数(实际执行) self.tools[name] = func @wraps(func) def wrapper(*args, kwargs): return func(*args, kwargs) return wrapper def execute(self, name, args_json): """执行器:根据 LLM 的指令运行代码""" if name in self.tools: try: args = json.loads(args_json) # 将 JSON 字符串转为字典 print(f"⚙️ [System] 正在调用工具: {name} 参数: {args}") return self.tools[name](args) # 执行函数,解包参数 except Exception as e: return f"Error: {str(e)}" return "Tool not found"# 创建全局注册表registry = ToolRegistry()# ========== 定义工具 ==========@registry.registerdef google_search(query: str): """ 当用户询问当前事件、新闻、天气或不知道的信息时,使用此工具进行搜索。 """ try: search = GoogleSearch({ "q": query, "api_key": os.getenv("SERPAPI_API_KEY"), }) # 数据清洗:只提取前两条结果的标题和摘要,节省 Token results = search.get_dict().get("organic_results", [])[:2] return "/n".join([ f"- {r.get('title')}: {r.get('snippet')}" for r in results ]) except Exception as e: return f"搜索失败: {e}"
💡 代码解释
核心设计:装饰器模式
@registry.registerdef google_search(query: str): """函数描述""" pass
装饰器做了什么?
- 提取函数信息
- 名称:
google_search - 描述:函数的文档字符串
- 参数:从类型注解
query: str中提取
- 生成 JSON Schema(给 LLM 看的"说明书")
{ "type": "function", "function": { "name": "google_search", "description": "当用户询问当前事件、新闻、天气或不知道的信息时,使用此工具进行搜索。", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "参数 query" } }, "required": ["query"] } } }
- 存储函数(实际执行用的)
self.tools['google_search'] = google_search # 存储真实的 Python 函数
为什么用装饰器?
没有装饰器时,需要手动写一遍函数,再写一遍 JSON Schema,容易出错。
使用装饰器后,只需写一次函数,自动生成说明书。
第四步:消息标准化 - 统一通信格式
🎯 目标
创建消息辅助函数,确保消息格式标准化,避免手动构造字典出错。
📝 创建文件:message.py
# message.pydef user_msg(content): """用户消息""" return {"role": "user", "content": content}def assistant_msg(content=None, tool_calls=None): """ 助手消息 - content: 文本回复(可选) - tool_calls: 工具调用请求(可选) """ msg = {"role": "assistant"} if content: msg["content"] = content if tool_calls: msg["tool_calls"] = tool_calls return msgdef tool_msg(tool_call_id, content): """ 工具消息 - tool_call_id: 工具调用 ID(关键!) - content: 工具返回结果 """ return { "role": "tool", "tool_call_id": tool_call_id, "content": str(content) }
💡 代码解释
为什么需要标准化?
❌ 手动构造消息
# 容易出错messages.append({"role": "user", "content": "你好"})messages.append({"rol": "assistant", "content": "你好"}) # 拼写错误!messages.append({"role": "tool", "content": "结果"}) # 缺少 tool_call_id!
✅ 使用辅助函数
# 标准化,不易出错messages.append(user_msg("你好"))messages.append(assistant_msg(content="你好"))messages.append(tool_msg("call_123", "搜索结果"))
核心概念:tool_call_id(快递单号)
LLM: “帮我搜索北京天气” → 生成单号 call_abc123
↓
调用搜索工具
↓
工具返回结果,附上单号 call_abc123
↓
LLM 看到单号,知道这是北京天气的搜索结果
消息类型总结:
| 函数 | role | 必需字段 | 可选字段 | 用途 |
|---|---|---|---|---|
user_msg() |
“user” | content | - | 用户输入 |
assistant_msg() |
“assistant” | - | content, tool_calls | LLM 的回复(文本或工具调用) |
tool_msg() |
“tool” | tool_call_id, content | - | 工具执行结果 |
第五步:整合一切 - 完整的 ToolAgent
🎯 目标
将前面所有组件整合,实现具备工具调用能力的完整 Agent。
📝 创建文件:tool_agent.py
# tool_agent.pyimport jsonfrom llm import LLMClientfrom tools import registry # 导入工具注册表from message import user_msg, assistant_msg, tool_msgclass ToolAgent: def __init__(self): self.llm = LLMClient() # 大脑 self.tools = registry # 工具箱 # self.messages 记忆系统 self.messages = [{ "role": "system", "content": "你是一个全能助手,可以调用工具获取实时信息。如果觉得已经足够回复用户了,就不用再调用工具了。" }] def chat(self, user_input): """ 支持工具调用的 ReAct 循环入口 注意:为了演示逻辑清晰,这里暂时使用非流式 """ # 1. 存入用户问题 self.messages.append(user_msg(user_input)) # 设置最大循环次数,防止 Agent 陷入死循环 max_turns = 5 turn_count = 0 while turn_count < max_turns: turn_count += 1 # 2. 调用 LLM(带上 tools 定义) print(f"/n🤖 [Thinking] 第 {turn_count} 轮思考...") response = self.llm.chat( messages=self.messages, tools=self.tools.schemas # 关键:把工具说明书发给 LLM ) response_msg = response.choices[0].message # 3. 判断 LLM 的意图 tool_calls = response_msg.tool_calls if tool_calls: # === 情况 A: LLM 想要调用工具 === # A1. 先把 LLM 的"调用指令"存入记忆(这步不能省!) ai_msg_dict = assistant_msg( content=response_msg.content, tool_calls=tool_calls ) self.messages.append(ai_msg_dict) # A2. 遍历所有工具调用请求(LLM 可能一次想调多个工具) for tool_call in tool_calls: func_name = tool_call.function.name func_args = tool_call.function.arguments call_id = tool_call.id print(f"✋ [Action] 正在调用工具: {func_name} ...") # A3. 执行真正的 Python 代码 tool_result = self.tools.execute(func_name, func_args) # A4. 构建 Tool Message(观察结果) # 关键:一定要带上 call_id,否则 LLM 不认账 tm = tool_msg(tool_call_id=call_id, content=tool_result) self.messages.append(tm) print(f"👀 [Observation] 工具返回: {tool_result[:50]}...") # A5. 循环继续 -> 回到 while 开头,把结果发给 LLM else: # === 情况 B: LLM 没调工具,直接回复 === content = response_msg.content self.messages.append(assistant_msg(content=content)) return content return "❌ 任务太复杂,超过最大循环次数。"# --- 演示代码 ---if __name__ == "__main__": # 确保 .env 里配置了 SERPAPI_API_KEY agent = ToolAgent() while True: try: user_input = input("/n👤 你:").strip() # 检查用户输入 if user_input.lower() in ['exit', 'q', '退出']: print("/n👏再见!") break # 如果用户输入为空,跳过 if not user_input: continue final_answer = agent.chat(user_input) print("/n" + "=" * 30) print(f"🤖 Final Answer:/n{final_answer}") print("=" * 30) except KeyboardInterrupt: print("/n/n 🙏 检测到中断,退出程序") break except Exception as e: print(f"/n❌ 发生错误: {e}") import traceback traceback.print_exc() # 打印详细的错误信息
💡 代码解释
核心设计:ReAct 模式
ReAct = Reasoning + Acting(推理 + 行动)
用户:今天北京天气怎么样?
↓
LLM 思考:我需要查询天气信息
↓
LLM 行动:调用搜索工具
↓
观察结果:北京今天晴天,25度
↓
LLM 思考:现在我有了信息,可以回答用户了
↓
LLM 行动:生成最终回复
为什么需要循环?
一次对话可能需要多次工具调用:
用户:帮我规划北京一日游
↓
第1轮:LLM 决定先了解北京天气 → 调用搜索工具
↓
第2轮:LLM 得到天气信息,继续思考需要知道景点 → 再次调用搜索
↓
第3轮:LLM 得到景点信息,综合所有信息 → 生成完整旅游规划
关键设计点:
- 存储调用指令(A1)
- 必须将 LLM 的工具调用请求存入记忆
- 否则下次调用时 LLM 会忘记
- tool_call_id(A4)
- 必须带上调用 ID,让 LLM 知道结果对应哪个工具
- 防止死循环
- 最多 5 轮工具调用,避免无限循环
运行与测试
🚀 运行 ToolAgent
python3 tool_agent.py
📝 示例对话
场景1:询问天气(需要调用工具)
👤 你:今天北京天气怎么样? 🤖 [Thinking] 第 1 轮思考... ✋ [Action] 正在调用工具: google_search ... ⚙️ [System] 正在调用工具: google_search 参数: {'query': '北京天气'} 👀 [Observation] 工具返回: - 北京今天天气预报: 晴天,气温25°C... 🤖 [Thinking] 第 2 轮思考... ============================== 🤖 Final Answer: 根据搜索结果,北京今天是个好天气!晴天,气温25°C,非常适合外出活动。 ==============================
场景2:简单对话(不需要工具)
👤 你:你好 🤖 [Thinking] 第 1 轮思考... ============================== 🤖 Final Answer: 你好!我是全能助手,有什么可以帮助你的吗? ==============================
场景3:退出
👤 你:q 👏再见!
或使用 Ctrl+C(Mac 上是 Cmd+C)
👤 你:^C 🙏 检测到中断,退出程序
常见问题排查
❌ 问题1:ModuleNotFoundError
错误信息:
ModuleNotFoundError: No module named 'openai'
解决方法:
pip3 install -r requirements.txt
❌ 问题2:API Key 错误
错误信息:
Error code: 401 - Unauthorized
解决方法:
-
检查
.env文件中的API_KEY是否正确 -
确认没有多余空格或引号
-
重启脚本
❌ 问题3:余额不足
错误信息:
Error code: 402 - Insufficient Balance
解决方法:
-
充值 DeepSeek 账户
-
或切换到其他 API(如 Ollama 本地模型)
❌ 问题4:搜索失败
错误信息:
搜索失败: Invalid API Key
解决方法:
-
在
.env文件中配置SERPAPI_API_KEY -
访问 SerpAPI 官网注册获取免费 Key
❌ 问题5:无法退出
现象: 输入 q 后程序不退出
解决方法:
-
检查代码中是否有
break语句 -
确保保存了文件并重启脚本
-
使用
Ctrl+C强制退出
总结与进阶
🎯 我们实现了什么?
-
✅ 统一的大模型适配层 - 轻松切换不同厂商
-
✅ 对话记忆系统 - 实现多轮对话
-
✅ 工具注册和执行 - 让 Agent 能"做事"
-
✅ 消息标准化 - 确保通信规范
-
✅ ReAct 循环 - 推理+行动的智能决策
🚀 可以继续扩展的方向
- 添加更多工具
@registry.registerdef get_weather(city: str): """获取天气信息""" pass@registry.registerdef calculate(expression: str): """计算数学表达式""" pass
- 记忆优化
- 实现记忆窗口(限制历史长度)
- 重要信息提取和总结
- 长期记忆存储(数据库)
- 任务规划
- 分解复杂任务
- 多步骤执行
- 目标导向
- 流式输出
- 实时显示 LLM 回复
- 提升用户体验
- 多模态能力
- 图像处理
- 语音交互
- 文件操作
## 最后
近期科技圈传来重磅消息:行业巨头英特尔宣布大规模裁员2万人,传统技术岗位持续萎缩的同时,另一番景象却在AI领域上演——AI相关技术岗正开启“疯狂扩招”模式!据行业招聘数据显示,具备3-5年大模型相关经验的开发者,在大厂就能拿到50K×20薪的高薪待遇,薪资差距肉眼可见!

业内资深HR预判:不出1年,“具备AI项目实战经验”将正式成为技术岗投递的硬性门槛。在行业迭代加速的当下,“温水煮青蛙”式的等待只会让自己逐渐被淘汰,与其被动应对,不如主动出击,抢先掌握AI大模型核心原理+落地应用技术+项目实操经验,借行业风口实现职业翻盘!
深知技术人入门大模型时容易走弯路,我特意整理了一套全网最全最细的大模型零基础学习礼包,涵盖入门思维导图、经典书籍手册、从入门到进阶的实战视频、可直接运行的项目源码等核心内容。这份资料无需付费,免费分享给所有想入局AI大模型的朋友!

👇👇扫码免费领取全部内容👇👇

部分资料展示
1、 AI大模型学习路线图

2、 全套AI大模型应用开发视频教程
从入门到进阶这里都有,跟着老师学习事半功倍。

3、 大模型学习书籍&文档

4、 AI大模型最新行业报告
2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

5、大模型大厂面试真题
整理了百度、阿里、字节等企业近三年的AI大模型岗位面试题,涵盖基础理论、技术实操、项目经验等维度,每道题都配有详细解析和答题思路,帮你针对性提升面试竞争力。


6、大模型项目实战&配套源码
学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
- 👇👇扫码免费领取全部内容👇👇

这些资料真的有用吗?
这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

更多推荐

所有评论(0)