简介:不使用第三方智能体框架,仅用 Python 与 LLM API 手动实现 AI Agent,不仅能加深对底层机制的理解,还能在调试、成本控制与灵活性上获得更大主动权。本文从官方建议与真实项目经验出发,系统拆解纯 Python 实现 Agent 的目标、前置准备、核心模块、实施步骤、验证方法与排查思路,帮助开发者构建结构清晰、易于维护的轻量级智能体系统。
本教程旨在帮助开发者完成以下任务:
本教程适合以下读者:
阅读完成之后,你将能够独立搭建一个结构清晰、可控性强、易于调试的纯 Python AI Agent,并具备将其用于生产环境的判断能力。
在讨论具体实现之前,需要先建立一个基本判断:LLM 应用的本质是什么?
从工程角度看,一个基于大语言模型的应用,其核心交互过程通常由三部分组成:
这三部分的核心操作,在 Python 中都可以用非常简单的方式完成:字符串拼接、HTTP 请求、条件判断和循环。换句话说,Python 原生能力已经覆盖了大多数 Agent 的基础需求。
行业中的一些长期实践也验证了这一判断。有团队在生产环境中使用某类智能体框架长达一年之后,最终选择完全移除,理由是框架带来的调试成本与灵活性限制超过了其便利性。官方文档中也有明确建议:开发者在入门阶段可以先从直接调用 LLM API 开始,很多模式只需要几行代码即可实现;框架在简化低级任务的同时,也可能遮蔽提示词与响应内容,使得调试更加困难。
因此,纯 Python 实现 Agent 并非一种“简化版”或“临时方案”,在很多场景下反而是更直接、更透明、更可控的工程选择。
纯 Python 手搓 Agent 特别适合以下场景:
如果任务可以拆解为固定的几个步骤,例如“读取数据 → 分析内容 → 调用工具查询 → 汇总结果”,用 Python 直接组织流程会非常直观。
当 Agent 行为异常时,直接查看提示词内容、API 响应原文、每一步的函数调用参数和返回值,通常比在框架的抽象层中翻找要高效得多。
如果 Agent 只需要访问两三个内部接口,且调用方式稳定,那么自行维护一个简单的工具注册表就足够了。
纯 Python 方案只需依赖 HTTP 客户端和 JSON 处理能力,部署包更小,环境兼容性更好。
通过手写实现,开发者可以逐步理解 Agent 的规划、执行、反馈闭环是如何建立的。
在开始编码之前,需要准备以下内容。
你需要一个能够通过 HTTP 接口访问的大模型服务。该服务应当至少支持以下能力:
在具体接入时,建议将 API 地址、密钥、模型名称等配置项独立出来,避免硬编码。
建议使用 Python 3.10 及以上版本。基础依赖很少,通常只需要一个 HTTP 请求库和 JSON 标准库即可。开发环境与生产环境应保持 Python 版本一致。
为了演示完整的 Agent 循环,建议准备一个实际可用的函数,例如:
工具的功能不需要复杂,但应当具备明确的输入参数和可预期的返回结果。
你需要了解以下概念:
一个纯 Python 手写的 Agent,通常可以拆分为以下五个模块。每个模块的职责清晰,便于单独测试和替换。
负责与 LLM API 通信。建议封装一个统一函数:
def chat(messages, tools=None):# 构造请求体# 发送 HTTP 请求# 解析并返回模型响应pass
该函数接收对话历史和可选工具列表,返回模型生成的内容。如果模型支持工具调用,响应中还会包含工具调用请求。
负责将任务说明、可用工具描述、上下文信息、用户输入等内容组织为模型可理解的文本。提示词的设计直接影响 Agent 的行为质量。
一个完整的 Agent 提示词通常包含:
工具注册表用于维护可用工具的基本信息,包括:
调度逻辑负责根据模型返回的工具调用请求,找到对应函数,执行并获取结果。
Agent 的核心在于循环。每一轮循环的基本逻辑如下:
负责维护对话历史、工具调用结果,并在必要时进行裁剪或摘要,防止上下文超长。
下面按照一个完整的最小实现来拆解步骤。
首先,准备一个真实的 Python 函数,例如查询日期:
from datetime import datetimedef get_current_date():return datetime.now().strftime("%Y-%m-%d")
然后为它定义工具描述:
tools_meta = [{"name": "get_current_date","description": "获取当前日期。当用户询问今天几号、当前日期等信息时使用。","parameters": {}}]
工具描述会被放入提示词中,帮助模型判断什么时候应该调用这个工具。
模型客户端需要完成三件事:构造请求、发送请求、解析响应。
示意性代码如下:
import requestsdef chat(messages, tools=None):payload = {"messages": messages,"tools": tools or []}response = requests.post(API_URL, headers=HEADERS, json=payload)return response.json()
实际项目中还需要处理超时、重试、错误码以及流式响应等情况。
核心循环的逻辑可以表示为:
def run_agent(user_input, max_turns=5):messages = [{"role": "system", "content": SYSTEM_PROMPT},{"role": "user", "content": user_input}]for _ in range(max_turns):result = chat(messages, tools_meta)tool_calls = result.get("tool_calls")if not tool_calls:return result.get("content")for call in tool_calls:tool_name = call["name"]arguments = call.get("arguments", {})tool_result = execute_tool(tool_name, arguments)messages.append({"role": "tool","tool_call_id": call["id"],"content": tool_result})return "已达到最大循环次数,但 Agent 尚未给出最终结果。"
这里的关键点在于:只有当模型不再请求调用工具时,才认为它给出了最终答案。
工具执行器需要保证:
def execute_tool(name, arguments):tool_map = {"get_current_date": get_current_date}fn = tool_map.get(name)if not fn:return "错误:未找到对应工具。"return fn(**arguments)
系统提示词是决定 Agent 行为质量的核心。一个典型的结构如下:
你是一个智能助手,可以调用工具来回答用户问题。可用工具:- get_current_date:获取当前日期。规则:1. 当用户询问日期相关信息时,先调用工具。2. 获取工具返回结果后,用自然语言回答用户。3. 如果问题不需要工具,直接回答。
将这段文本作为系统消息放在对话开头,可以有效约束模型行为。
完成以上步骤后,就可以进行本地测试:
if __name__ == "__main__":answer = run_agent("今天是几号?")print(answer)
运行之后,应当看到模型先调用日期工具,然后基于返回结果生成自然语言回答。
一个纯 Python Agent 是否构建成功,可以从以下几个方面验证。
建议在每一轮循环中记录:
这些信息对于排查行为异常至关重要。
验证以下异常场景:
系统应当能对这些情况给出可理解的反馈,而不是直接崩溃。
原因分析:提示词对工具使用的要求不够明确,或者工具描述不够清晰。
解决思路:在系统提示词中明确要求“当遇到需要实时信息或内部数据的问题时,必须先调用工具,不得猜测”。同时细化每个工具的触发条件。
原因分析:工具返回内容被截断、格式不易理解,或者模型没有收到工具结果消息。
解决思路:检查工具结果是否完整回传;将工具返回内容整理为结构化文本;在消息中明确标注该内容来自工具执行。
原因分析:模型反复调用同一工具,却未能收敛到最终答案。
解决思路:设置最大循环轮次;在提示词中加入“如果同一工具已被连续调用两次,请停止调用并给出当前已知信息”;增加工具调用去重逻辑。
原因分析:模型幻觉或工具描述歧义。
解决思路:在工具描述中使用准确、无歧义的名称;在代码层对工具名做规范化和容错匹配;对未知工具名返回明确错误信息。
原因分析:多轮循环中的中间结果被完整保留。
解决思路:在每轮结束后评估上下文长度;对较旧的中间步骤进行摘要或裁剪;只保留关键信息。
完成最小实现之后,可以从以下方向逐步增强。
如果业务需要稳定提取字段,可以要求模型以 JSON 格式返回结果,并在代码层进行解析和校验。这有助于降低后续处理逻辑的复杂度。
对于网络抖动、接口限流、模型超时等情况,建议加入指数退避重试。对于非关键工具,可提供降级返回内容,避免整个 Agent 流程中断。
当对话历史过长时,可以定期使用模型对历史信息进行摘要,或者仅保留最近 N 轮完整消息,更早的消息以摘要形式存在。
对于复杂任务,可以将 Agent 分为两个阶段:先生成执行计划,再逐步调用工具执行。这样可以让每一步的意图更加清晰,也便于日志审计。
在生产环境中,建议记录以下指标:
这些数据可以作为后续优化的基础,例如调整提示词、裁剪上下文或增加缓存。
对工具调用增加权限校验,避免模型调用到高风险操作。对于敏感工具,应在执行前进行人工确认或二次验证。
纯 Python 手写 AI Agent 完全可行,并且在许多场景下比直接引入框架更加清晰和高效。LLM 应用的核心无非是提示词构造、API 调用、工具执行和循环控制,这些都可以用 Python 原生能力很好地完成。
框架的价值在于标准化与加速开发,但同时也带来了额外抽象层,可能增加调试难度和灵活性限制。对于逻辑明确、工具数量有限、需要高度可控的项目,纯 Python 方案是一种值得优先考虑的工程选择。
通过本教程,你应当已经掌握了:
在此基础上,你可以根据业务需要逐步扩展工具集、优化提示词、增强上下文管理与监控能力,构建出稳定、可维护、低依赖的智能体系统。