从零开始自建智能体让你的程序学会思考和行动你是否想过让你的程序不仅能执行固定的指令还能像人一样理解你的意图、自主决定下一步做什么、调用各种工具完成任务这就是智能体Agent的魅力。今天我们将一起动手从零搭建一个属于自己的智能体让它能回答你的问题、执行系统命令甚至帮你完成复杂的自动化任务。无论你是编程小白还是想深入理解AI原理这篇文章都会带你一步步走进智能体的世界。1. 智能体是什么先来打个比方想象你有一个全能助手小明。你告诉他“帮我查一下明天的天气然后设个提醒。”小明会怎么做理解你的话他知道你要查询天气和设置提醒。分解任务他先打开天气应用查明天天气然后打开日历应用创建提醒。执行动作他动手操作手机完成两个步骤。反馈结果他告诉你“明天晴天已经设好早上8点的提醒”。智能体就是程序世界里的“小明”。它由三个核心部分组成大脑一个大语言模型如GPT、Llama负责理解、思考和决策。眼睛和耳朵接收你的输入文本、语音等。手和脚各种工具如计算器、搜索引擎、系统命令用来执行具体动作。当你说一句话智能体的大脑会思考该怎么做然后指挥手脚去执行最后把结果反馈给你。整个过程是循环的大脑根据手脚的反馈决定下一步做什么直到任务完成。2. 极速体验一个最简单的智能体我们先写一个最简单的智能体它能调用三个工具获取当前时间、计算数学表达式、模拟网页搜索。为了让你快速上手我们使用本地运行的Ollama模型当然也可以换成OpenAI。准备工作安装Ollama从ollama.com下载并拉取一个模型比如llama3.1ollama pull llama3.1确保Ollama服务在运行ollama serve。完整代码只需几十行importrequestsimportjsonimportdatetime# ---------- 定义工具 ----------defget_current_time(locationNone):returnf当前时间是{datetime.datetime.now()}defcalculator(expression):try:returnf计算结果{expression}{eval(expression)}except:return计算错误defweb_search(query):# 模拟搜索结果mock{天气:今天晴天,python:Python是一种编程语言}returnmock.get(query.lower(),没有找到信息)tools{get_current_time:get_current_time,calculator:calculator,web_search:web_search}# 系统提示告诉模型如何调用工具system_prompt你是一个智能助手可以调用工具。需要工具时请输出 ACTION: 工具名称 ACTION_INPUT: {参数: 值} 然后根据返回结果给出最终答案。defcall_llm(messages):resprequests.post(http://localhost:11434/api/chat,json{model:llama3.1,messages:messages,stream:False})returnresp.json()[message][content]defrun_agent(user_input):messages[{role:system,content:system_prompt},{role:user,content:user_input}]for_inrange(5):# 最多5步replycall_llm(messages)print(助手:,reply)ifreply.startswith(ACTION:):linesreply.split(\n)actionlines[0].replace(ACTION:,).strip()input_strlines[1].replace(ACTION_INPUT:,).strip()iflen(lines)1else{}try:action_inputjson.loads(input_str)except:action_input{}ifactionintools:resulttools[action](**action_input)messages.append({role:assistant,content:reply})messages.append({role:system,content:f工具返回{result}})else:messages.append({role:system,content:f未知工具{action}})else:breakif__name____main__:run_agent(现在几点)运行这段代码你会看到智能体调用get_current_time工具并给出答案。尝试问“123*456等于多少”或“搜索一下python”它都能应对。这个demo虽小但包含了智能体的核心骨架理解→决策→执行→反馈的循环。3. 这个简易智能体有什么问题与主流差距在哪虽然能跑起来但你会发现它有点“笨”无法记住上下文每次提问都是独立的不能连续对话。输出格式太死板模型必须严格按ACTION:格式输出稍微变化就解析失败。没有错误处理如果工具调用失败程序可能崩溃。不能规划复杂任务只会单步调用不会根据结果调整后续计划。与主流框架如LangChain、AutoGPT相比差距明显维度我们的demo主流智能体上下文每轮重置维护完整历史甚至长期记忆工具调用文本解析原生函数调用API如OpenAI functions规划能力无ReAct、任务分解、动态调整错误恢复简单记录自动重试、回退策略扩展性硬编码工具动态注册、工具选择器别灰心接下来我们就一步步改造让它变得更“聪明”。4. 改造之路让智能体真正“活”起来4.1 添加跨轮对话能力我们用一个类来保存消息历史每次用户输入后追加这样智能体就能记住之前说了什么。classAgent:def__init__(self,modelllama3.1):self.modelmodel self.messages[{role:system,content:system_prompt}]defrun(self,user_input):self.messages.append({role:user,content:user_input})# ... 循环处理 ...# 最后将助手回复加入 self.messages现在你可以连续提问“我叫小明”“我的名字是什么”——智能体都能答对。4.2 采用ReAct格式让思考更清晰ReAct是一种提示词技巧让模型输出“思考→行动→观察”的链条。这样模型更容易遵循我们也更容易解析。修改系统提示你是一个智能助手请按以下格式输出 思考你现在需要做什么 行动工具名称 行动输入{参数: 值} 观察工具返回的结果 ...可重复多次... 最终答案...解析时用正则提取“行动”和“行动输入”不再依赖固定行号importre patternr行动\s*(\w)\s*\n行动输入\s*(\{.*?\})matchre.search(pattern,reply,re.DOTALL)ifmatch:actionmatch.group(1)input_strmatch.group(2)# ...4.3 增加错误容忍和重试机制如果模型输出不规范我们将其视为普通回答避免程序中断。同时如果工具调用失败将错误信息作为“观察”返回给模型让它决定下一步比如重新尝试或换一种方式。4.4 实现多步推理主循环会持续运行直到模型输出“最终答案”或达到最大步数。每一步的“观察”都会加入历史供模型参考。改造后的智能体类完整代码较长但核心就是上述几点。你可以参考我们之前提供的完整代码在文中附链接或代码块。现在它已经能进行多轮对话并自主决定多次调用工具。5. 扩展能力让智能体执行系统命令自动化任务智能体最强大的地方是能调用任意工具。比如我们可以让它执行系统命令从而实现自动化运维、文件操作等。但务必注意安全我们通过白名单限制允许执行的命令。添加run_command工具importsubprocessimportshlex ALLOWED_COMMANDS{ls:列出目录,echo:输出文本,pwd:显示当前目录,uname:显示系统信息,df:查看磁盘空间}defrun_command(command_string):partsshlex.split(command_string)ifnotparts:return错误空命令cmdparts[0]ifcmdnotinALLOWED_COMMANDS:returnf错误命令{cmd}不在白名单中try:resultsubprocess.run([cmd]parts[1:],capture_outputTrue,textTrue,timeout10)returnresult.stdoutorresult.stderror执行成功exceptExceptionase:returnf执行出错{str(e)}将这个工具注册到智能体更新工具描述智能体就能执行白名单内的命令了。例如问它“当前目录是什么”它会调用pwd问“系统信息”会调用uname -a。安全红线永远不要允许rm、wget、sudo等危险命令生产环境建议在沙箱如Docker中运行。6. 原理深潜当你说“当前系统信息”智能体内部发生了什么让我们一步步拆解看智能体如何完成这个任务。第1步接收输入你输入“当前系统信息”。Agent将这条消息加入历史然后调用大模型。第2步大模型第一次思考模型根据提示输出思考用户想获取系统信息我可以先执行uname命令查看内核版本。 行动run_command 行动输入{command_string: uname -a}第3步解析并执行工具Agent解析出run_command和参数执行命令得到输出如“Linux myhost 5.15.0…”。然后将原始回复和观察观察Linux myhost...加入历史。第4步第二次调用模型模型看到历史中有了uname的输出可能认为还需要磁盘信息于是继续思考已经得到内核信息现在看看磁盘使用情况。 行动run_command 行动输入{command_string: df -h}Agent再次执行df -h得到结果加入历史。第5步第三次调用模型模型现在拥有内核和磁盘信息整合后输出最终答案思考信息收集齐全可以回答了。 最终答案系统内核版本为Linux 5.15.0磁盘根分区使用率30%。Agent检测到“最终答案”输出结果本轮结束。整个过程就像一个有思考能力的人先决定查什么查完再看还需要什么最后汇总报告。7. 自动化任务的本质程序视角从代码层面看自动化任务的本质是一个基于大模型驱动的状态机。核心组件包括状态管理self.messages记录了所有历史包括用户输入、模型思考、工具返回这是智能体的“记忆”。意图解析器大模型将用户模糊需求转化为结构化指令如“行动工具名行动输入{…}”。工具抽象层每个工具都是一个函数有明确的输入输出通过tools字典动态调用。控制循环for step in range(max_steps):不断驱动“思考-执行-反馈”的闭环。错误处理解析失败、工具异常时通过加入错误观察让模型自行调整。所以subprocess.run只是末端执行器真正的“大脑”是那个循环和大模型。你完全可以替换大模型比如用GPT-4或者增加更多工具如发送邮件、操作数据库智能体就能完成越来越复杂的任务。8. 总结与展望通过这篇文章我们从零搭建了一个智能体并逐步改进它让它具备上下文记忆、稳健的工具调用、多步推理甚至能安全执行系统命令。这个过程中你不仅学会了代码更理解了智能体的核心原理用大模型做决策用工具做执行用循环做反馈。当然这只是一个开始。真正的智能体还可以拥有长期记忆用向量数据库存储重要信息。自主规划将复杂任务分解成子任务并排序执行。联网搜索实时获取最新信息。多模态能力理解图片、生成图像等。现在轮到你动手了试着给智能体添加更多工具比如天气API、数据库查询、文件读写让它成为你的私人助理。记住安全第一尤其是涉及系统命令时。智能体的世界充满可能愿你享受创造的乐趣附 如果你有任何问题欢迎留言讨论。