简介:本教程面向开发者与技术负责人,讲解如何不依赖任何 Agent 编排框架,仅用 Python 和大模型 API 从零实现一个具备工具调用、循环决策、记忆管理与安全终止能力的 AI Agent,内容涵盖选型分析、环境准备、核心代码实现、结果验证、常见问题排查与优化建议,帮助你构建更可控、更轻量、更易维护的智能体应用。
本教程要解决一个很多团队都关心的问题:在真实工程项目中,如果不使用任何主流 Agent 编排框架,仅靠 Python 和大模型 API,能否从零实现一个真正可用的 AI Agent?
答案是肯定的。Agent 的本质并不复杂:它是一个“让大模型在循环中自主决策、调用工具、观察结果,直到完成目标”的程序。只要把这个循环写清楚,一两百行 Python 代码就足以支撑大量真实业务场景。完成本教程后,你将能够:
本教程适合有一定 Python 基础的开发者、负责技术选型的架构师,以及希望对 Agent 核心链路保持完全掌控的技术负责人。
先回答“可不可行”,再回答“值不值得”。
从原理上看,市面上各类 Agent 框架的核心能力都可以归结为四件事:调用大模型接口、管理消息历史、定义并执行工具、控制决策循环。这四件事分别对应 HTTP 请求、一个列表、一个字典和一个循环结构,没有任何一件是某个框架的“专利”。只要你所选的大模型服务支持函数调用能力,纯 Python 实现就没有原理性障碍。
从工程角度看,不引入框架往往带来以下收益:
这套方案尤其适合以下场景:内部工具型助手(订单查询、工单处理、审批流转)、数据查询与分析助手、客服辅助问答、单链路的流程自动化等。需要客观说明的是,如果业务涉及复杂的多角色协作、动态图状编排,或团队希望在极短时间内验证原型,使用成熟框架可以省去部分底层工作。更合理的路径是:先用几十行代码把手搓原型跑通,确认业务形态后再决定是否引入更重的抽象。
动手之前,请确认以下条件已就绪:
写代码之前,先建立整体认知。一个最小可用的 Agent 由四个部分组成:
运行时的数据流可以概括为:
用户输入 → 组装消息与工具描述 → 调用大模型 → 返回的是工具调用请求吗?→ 是:执行对应工具,把结果写回消息历史,进入下一轮循环→ 否:模型输出最终自然语言回答,任务结束
理解了这个闭环,就理解了所有 Agent 框架的骨架。
做什么:编写统一的 call_llm 函数,接收消息列表与工具描述,返回模型输出。
为什么:把接口调用收敛到一个函数里,后续无论更换模型、增加重试还是切换服务,都只需改这一处。
注意什么:必须设置超时;建议在此之上增加带指数退避的重试;密钥一律从环境变量读取。
import json, os, urllib.requestdef call_llm(messages, tools):payload = json.dumps({"model": os.environ["MODEL_NAME"], # 模型名称"messages": messages, # 完整对话历史"tools": tools, # 工具描述列表}).encode("utf-8")req = urllib.request.Request(os.environ["LLM_API_URL"], # 大模型服务接口地址data=payload,headers={"Content-Type": "application/json","Authorization": "Bearer " + os.environ["LLM_API_KEY"],},method="POST",)with urllib.request.urlopen(req, timeout=60) as resp:data = json.loads(resp.read().decode("utf-8"))# 以下为示意性解析,实际返回字段结构请以你所选大模型服务的接口文档为准return data["choices"][0]["message"]
做什么:把业务函数注册到字典中,并为每个工具编写结构化描述(函数调用是当前业界的通用规范)。
为什么:大模型本身不能执行你的业务逻辑,它只能“提出调用请求”。描述写得越清晰——工具做什么、参数含义、什么场景该用——模型选对工具、填对参数的准确率就越高。
注意什么:工具描述本质上属于提示词的一部分,值得像打磨提示词一样反复迭代;所有参数必须在服务端做校验。
def get_order_status(order_id: str) -> str:# 真实场景中,这里会查询数据库或调用内部服务return json.dumps({"order_id": order_id, "status": "已发货"}, ensure_ascii=False)TOOLS = {"get_order_status": get_order_status}TOOL_SCHEMAS = [{"type": "function","function": {"name": "get_order_status","description": "根据订单号查询订单的当前物流状态。当用户询问订单进度时使用。","parameters": {"type": "object","properties": {"order_id": {"type": "string", "description": "订单编号,例如 SO-20240601-001"}},"required": ["order_id"],},},}]
做什么:编写核心循环,处理两种返回情况——工具调用请求与最终文本回答。本步骤依赖步骤一、二的成果。
为什么:这是 Agent 与普通对话机器人的本质区别。普通机器人一问一答即结束;Agent 会把工具结果喂回模型,让它基于真实数据继续推理,直到任务完成。
注意什么:执行工具时必须捕获异常,并把错误信息以工具结果的形式回传给模型,让模型有机会自我修正,而不是让整个进程崩溃。
def run_agent(user_input: str, max_iterations: int = 8) -> str:messages = [{"role": "system", "content":"你是订单助手。涉及订单状态时必须调用工具获取真实数据,不要编造;""拿到结果后用一句话总结,然后立即结束,不要重复调用。"},{"role": "user", "content": user_input},]for _ in range(max_iterations):message = call_llm(messages, TOOL_SCHEMAS)messages.append(message)tool_calls = message.get("tool_calls")if not tool_calls: # 无工具调用,视为任务完成return message.get("content", "")for call in tool_calls:name = call["function"]["name"]args = json.loads(call["function"].get("arguments") or "{}")fn = TOOLS.get(name)if fn is None:result = json.dumps({"error": f"未知工具: {name}"}, ensure_ascii=False)else:try:result = fn(**args)except Exception as e:result = json.dumps({"error": str(e)}, ensure_ascii=False)messages.append({"role": "tool","tool_call_id": call.get("id", ""),"content": result,})return "已达最大轮次,任务未能在限定步数内完成,请缩小问题范围后重试。"
做什么:为消息历史增加容量控制。
为什么:多轮循环会让历史迅速膨胀,一旦超过模型上下文窗口,调用会直接失败,同时 token 成本也会快速上升。
常见做法:始终保留系统提示,仅保留最近若干轮对话;对更早的历史做摘要压缩;工具返回的原始数据较大时,只回传关键字段而非完整报文。是否需要跨会话的长期记忆取决于业务,初版可以不做。
做什么:在最大轮次之外,增加显式终止与行为约束。
为什么:循环失控是 Agent 最典型的事故来源,护栏必须在上线前就位,而不是出事后再补。
建议措施:设置轮次上限(示例为 8);限制单轮工具调用数量;在系统提示中明确“完成即停,同一参数不要重复调用”;对敏感工具增加人工确认开关;逐轮记录模型输出与工具结果,形成完整追踪日志。
将前述代码组合为一个脚本,加入入口函数:
if __name__ == "__main__":print(run_agent("帮我查一下订单 SO-20240601-001 现在到哪了"))
在开发环境中先以最小配置跑通,再逐步接入真实业务工具。
运行后,按以下清单逐项核对,全部通过才算接入成功:
回到最初的问题:不用框架,纯 Python 手搓 AI Agent 可行吗?不仅可行,而且在依赖控制、链路透明、深度定制等方面,在许多真实工程场景下就是更优选择。本教程带你完成了从可行性分析、环境准备,到四大核心组件(大模型调用封装、工具注册表、消息历史、主循环)的实现,再到终止护栏、结果验证、问题排查与持续优化的完整闭环。
后续你可以在此基础上继续演进:引入流式输出改善交互体验、增加结构化追踪提升可观测性、探索多 Agent 协作模式,或建立自动化评估集来量化每次提示词与工具调整的效果。当你真正理解了“循环 + 工具 + 记忆”这个最小内核,无论未来使用哪种框架或平台,你都会清楚它们在替你做什么,以及什么情况下值得自己动手。