1. 项目概述从零构建AI智能体的核心价值最近在GitHub上看到一个挺有意思的项目叫pguso/ai-agents-from-scratch。光看名字很多朋友可能就心动了——“从零开始构建AI智能体”听起来就像是把那些神秘的大模型应用开发黑盒给彻底拆开让你亲手从螺丝钉开始组装一台能思考、能行动的机器。我花了些时间深入研究了这个仓库的代码和设计思路发现它确实提供了一个绝佳的实践窗口尤其适合那些已经对大型语言模型LLM有基本了解但困惑于如何将其转化为一个能持续运行、具备记忆和工具调用能力的“智能体”的开发者。这个项目的核心价值在于“解耦”与“教学”。它没有直接给你一个封装好的、参数繁多的重型框架而是将智能体最核心的几个模块——推理循环、记忆系统、工具使用、任务规划——用清晰、简洁的Python代码实现出来。你可以像看一本优秀的源码剖析书一样逐行理解每个决策背后的逻辑为什么这里要用一个while循环记忆列表是如何被管理和裁剪的工具调用的结果如何反馈给模型以进行下一步思考对于中级开发者而言这种透明性比直接调用某个Agent.run()方法要宝贵得多。你不仅能学会“怎么做”更能透彻理解“为什么这么做”以及当需求变化时“该如何改造”。它解决的核心痛点是理论与实操之间的鸿沟。我们都知道智能体Agent是当前AI应用的前沿但相关论文和博客往往侧重于高层架构描述。当你真正动手时会面临一堆具体问题如何设计提示词Prompt才能让模型更好地规划记忆的上下文窗口满了怎么办工具调用失败该如何优雅地处理这个项目通过一个可运行的代码基底直接带你穿越这些“魔鬼细节”。无论是想为自己的产品添加一个自动化的客服助手还是构建一个能自动分析数据并撰写报告的研究员亦或是创建一个游戏内的NPC你都能从这个“从零开始”的范式中获得扎实的起点和清晰的扩展思路。2. 智能体基础架构与核心循环拆解2.1 智能体的基本构成要素一个能够自主运作的AI智能体远不止是一个简单的大模型API调用。在ai-agents-from-scratch项目中我们可以清晰地看到一个最小可行智能体Minimum Viable Agent所必需的几个核心组件它们共同构成了智能体的“身体”与“大脑”。首先是最核心的推理引擎Reasoning Engine通常就是一个大型语言模型LLM。它负责理解输入、进行思考、做出决策并生成输出。但仅仅有LLM是不够的它就像一个只有瞬时记忆的天才不知道之前说过什么也无法操作外部世界。因此我们需要记忆系统Memory System。这个项目里通常实现为一个会话历史列表保存了用户与智能体之间的多轮对话。更高级的记忆可能包括向量数据库存储的长期记忆用于记住跨会话的关键信息。为了让智能体能“动手”工具集Toolkit必不可少。工具可以是任何函数查询数据库、调用搜索引擎、执行计算、操作文件系统。智能体需要知道它有哪些工具可用每个工具是做什么的通过描述并学会在合适的时机调用正确的工具。最后还需要一个控制流Control Flow或调度器Orchestrator也就是项目中最核心的那个循环。它负责粘合以上所有部分从用户或系统获取目标管理记忆的读写决定何时调用模型进行思考何时执行工具并处理执行结果直到任务完成或达到停止条件。2.2 核心循环ReAct模式的实践ai-agents-from-scratch项目典型地实现了ReActReasoning Acting模式。这是一种让模型交替进行“思考”和“行动”的范式极大地提升了任务完成的可靠性和可解释性。让我们拆解这个核心循环的每一步。循环始于一个用户查询或任务目标比如“查询北京今天的天气并建议我是否该带伞”。这个目标会被添加到记忆会话历史中。然后循环开始生成提示Prompt Generation系统会将当前的任务描述、完整的会话历史记忆、以及所有可用工具的描述名称、功能、参数格式组合成一个结构化的提示发送给LLM。这里的提示词设计非常关键它必须明确指示模型按照“Thought: ... Action: ... Action Input: ...”的格式进行输出。模型推理LLM InferenceLLM接收提示进行“思考”。它需要理解历史上下文分析当前任务状态然后决定下一步该做什么。输出会被严格解析。解析与决策Parsing Decision系统解析模型的输出。如果输出中包含Action:字段就意味着模型决定要使用一个工具。系统会提取工具名和输入参数。工具执行Tool Execution根据解析出的工具名找到对应的函数并传入参数执行。例如调用get_weather(location北京)。观察结果Observation工具执行的结果成功或失败会被格式化为一个观察语句例如Observation: 北京今天晴转多云最高气温25度降水概率10%。更新记忆与循环Update Loop将模型的“思考”Thought、“行动”Action和得到的“观察”Observation全部追加到会话历史中。这样在下一轮循环模型就能基于包含了之前所有步骤的完整上下文进行新的推理。循环重复直到模型输出Final Answer:字段表示它认为任务已完成可以给出最终答案。这个循环的精妙之处在于它将模型的“内部思考过程”外部化、步骤化了。你不仅能得到答案还能看到智能体得出答案的完整逻辑链它先想了什么为什么决定查天气查到结果后又如何推理出“不需要带伞”的结论。这对于调试和构建用户信任至关重要。注意在实现解析时一定要做好健壮性处理。模型输出可能不严格遵循格式可能拼错工具名可能提供非法参数。代码中必须有相应的异常捕获和重试机制例如当解析失败时可以将错误信息作为“观察”反馈给模型让它自我纠正。3. 记忆系统的设计与实现策略3.1 短期记忆会话历史的管理在基础实现中记忆通常就是一个Python列表按顺序存储所有的消息用户输入、模型思考、工具观察。但这带来了两个立即的问题上下文长度限制和信息冗余。所有LLM都有上下文窗口限制如4K、8K、128K tokens。如果我们的会话历史无限制增长很快就会超出限制导致最开始的对话被“遗忘”。ai-agents-from-scratch项目需要演示如何处理这个问题。一种简单策略是滑动窗口只保留最近N条消息或最近N个token的对话。虽然会丢失早期信息但对于许多短期对话任务已经足够。更精细的策略涉及摘要Summarization。当历史记录达到一定长度时可以触发一个“摘要”步骤将早期的对话内容发送给LLM要求其生成一个简洁的段落来总结之前讨论的关键事实和结论然后用这个摘要替换掉大段的原始历史。这样智能体保留了“要点”而不占用大量token。例如在进行了十轮关于旅行计划的讨论后记忆可以被摘要为“用户计划在六月去日本东京为期一周对美食和博物馆感兴趣预算中等。已讨论过签证和航班时间。”3.2 长期记忆的扩展思路对于更复杂的智能体需要长期甚至永久的记忆。这通常通过引入外部存储来实现比如向量数据库Vector Database。其核心思想是将信息记忆片段转换为向量嵌入存储起来。当需要回忆时将当前上下文或问题也转换为向量在数据库中进行相似性搜索找出最相关的记忆片段然后注入到当前提示中。例如你构建一个个人学习助手智能体。当用户问“我之前读过的关于神经网络正则化的那篇文章主要观点是什么”时智能体可以将这个问题转换为向量然后从其向量数据库中检索出之前存储的关于“读《...》文章笔记Dropout和权重衰减可以结合使用...”的記憶片段从而给出精准回答。在ai-agents-from-scratch的基础上你可以添加一个save_to_memory(text)函数将文本嵌入并存入向量库和一个recall_from_memory(query, k3)函数根据查询检索前k个相关记忆。这使得智能体具备了跨会话的、基于语义的記憶能力。实操心得管理记忆的“新鲜度”很重要。不是所有东西都值得记入长期记忆。可以设计一些规则例如只有包含具体事实数据、用户明确偏好或重要结论的对话才触发长期存储。同时为记忆片段添加时间戳和元数据如“类型事实”、“类型用户偏好”便于更精细的检索和过滤。4. 工具使用赋予智能体“手脚”4.1 工具的定义与封装工具的本质是智能体可以调用的函数。在项目中工具通常被定义为一个字典或一个类包含name工具名、description给模型看的描述、parameters参数JSON Schema和function实际执行的函数。例如一个计算器的工具可能这样定义{ “name”: “calculator”, “description”: “执行数学计算。支持加()、减(-)、乘(*)、除(/)、乘方(**)等运算。”, “parameters”: { “type”: “object”, “properties”: { “expression”: {“type”: “string”, “description”: “数学表达式例如 ‘(3 4) * 2’“} }, “required”: [“expression”] }, “function”: lambda **kwargs: str(eval(kwargs[“expression”])) # 注意实际使用中eval需谨慎此处仅为示例 }工具描述必须清晰、无歧义因为LLM完全依赖这个描述来理解工具用途。参数的模式Schema定义要尽可能详细这能极大提高模型调用工具的准确性。4.2 工具的选择与调用流程当LLM决定使用工具时它需要从一长串可用工具列表中做出选择。这个过程依赖于提示词工程。你的系统提示中需要清晰地列出所有工具及其描述。一种有效的格式是你有以下工具可供使用 {{tool_list}} 请严格按照以下格式响应 Thought: 我需要分析当前问题... Action: 工具名 Action Input: 符合工具参数JSON Schema的输入模型在Thought部分进行推理解释为什么选择这个工具然后在Action和Action Input中给出具体指令。系统收到响应后需要验证检查Action指定的工具是否存在。解析将Action Input解析为字典通常是JSON格式。校验根据该工具的parametersschema校验输入字典的合法性类型、必填字段等。执行调用工具函数传入解析后的参数。处理结果捕获执行结果或异常。如果成功将结果格式化为Observation: ...如果失败如工具异常、参数错误则格式化错误信息为Observation: 工具执行失败原因...。这个Observation会被加回记忆驱动下一轮循环。如果工具执行失败模型有机会在下一轮思考中尝试其他方案或纠正参数这体现了智能体的容错和自适应能力。注意事项工具的安全性至关重要。绝对不要让模型直接调用可以执行任意代码如os.system、删除文件或访问敏感数据的函数除非在高度受控的环境下。所有工具函数都应进行输入验证和权限控制。例如一个文件读取工具应该限制可访问的目录路径。5. 任务规划与分解的实现5.1 让智能体学会“分步走”对于复杂任务如“为我制定一份为期三天的北京旅游计划包括景点、餐饮和交通”直接要求模型一次性输出完美结果往往效果不佳。更好的方法是让智能体自己进行任务规划与分解。这可以通过在提示词中明确要求模型先制定计划来实现。一种简单有效的技术是思维链Chain-of-Thought, CoT提示的升级应用。你可以在系统提示中加入“对于复杂任务请先制定一个分步计划然后逐步执行。”在ai-agents-from-scratch的循环中这可以体现为模型的第一轮输出不是一个具体的行动而是一个计划列表。Thought: 这是一个复杂的旅游规划任务。我需要先确定核心需求时间、兴趣、预算然后分别查找景点、餐厅和交通信息最后整合成一份日程表。我的计划是 1. 询问用户对景点类型的偏好历史、现代、自然等。 2. 根据偏好搜索北京的推荐景点。 3. 根据景点位置搜索周边的餐厅。 4. 查询景点间的交通方式。 5. 将以上信息按天编排成日程。 现在我开始执行第一步。 Action: ask_user Action Input: {question: “您对哪些类型的景点更感兴趣例如历史古迹、现代建筑、博物馆、公园自然风光等”}然后智能体按照自己制定的计划一步步与用户交互或调用工具。这种“先计划后执行”的方式使得任务处理更加结构化也更容易调试。5.2 动态规划与重规划计划并非一成不变。在执行过程中可能会出现意外工具调用失败、用户提供了新信息、发现了更好的方案。因此智能体需要具备动态重规划的能力。这可以通过在每一轮循环中都让模型“评估当前状态和计划”来实现。在提示词中可以加入“请基于当前的对话历史和上一步的结果评估剩余任务并决定是继续执行原计划的下一步还是调整计划。”例如智能体原计划搜索“王府井附近的餐厅”但工具返回“未找到结果”。在下一轮模型观察到这个失败后可能会输出Thought: 搜索王府井附近餐厅失败。可能该区域餐厅数据暂时缺失。我应该调整计划改为搜索用户提到的另一个区域‘三里屯’的餐厅。 Action: search_restaurants Action Input: {location: “三里屯”}实现这一机制的关键是将“当前目标”、“已执行步骤”、“最新结果”都清晰地呈现在模型的上下文中并鼓励其进行状态评估。这使智能体从简单的“指令-执行”模式进化到更高级的“目标导向-动态调整”模式。6. 提示词工程与模型高效沟通的艺术6.1 系统提示的设计原则系统提示System Prompt是智能体的“宪法”它定义了智能体的角色、行为准则、可用资源和响应格式。一个设计良好的系统提示是项目成功的一半。首先明确角色和边界。开头就要定调“你是一个高效、准确的AI助手专门帮助用户完成信息查询和任务处理。你必须使用提供的工具来获取信息不能编造知识。”这设定了预期并减少了模型的“幻觉”。其次清晰说明格式要求。这是实现稳定解析的基础。必须用明确、无歧义的语言规定输出格式最好给出例子你必须用以下格式回应 Thought: [在此处清晰描述你对当前情况和下一步行动的思考] Action: [工具名必须是从以下列表中选择的一个] Action Input: [工具的输入参数必须是严格的JSON格式] 或 Final Answer: [当任务完成时直接给出最终答案]第三结构化地呈现工具和信息。将工具列表、当前目标、会话历史等不同部分用分隔符如###、---清晰分开帮助模型理解上下文结构。6.2 迭代优化与少样本学习提示词很少能一次写完美。你需要像调试代码一样调试提示词。基于ai-agents-from-scratch项目搭建起基础循环后就可以开始系统的提示词优化。收集失败案例运行智能体处理一系列测试任务记录下所有格式错误、工具选择错误、逻辑混乱的案例。分析根因是工具描述不清还是格式指令不明确或者是模型对任务理解有偏差修改提示针对性地增强提示。例如如果模型总选错工具可以在工具描述中加入更鲜明的对比“search_web用于查找实时通用信息query_database用于查找内部结构化数据。”引入少样本示例Few-shot Examples在系统提示中直接包含1-3个完整的、正确的输入输出示例。这是最强大的提示优化技术之一。示例展示了你期望的完整推理过程模型会强烈地倾向于模仿这种模式。例如在提示词中加入示例 用户上海现在的温度是多少 Thought: 用户询问实时天气信息。我需要使用天气查询工具。 Action: get_weather Action Input: {city: “上海”} Observation: 上海当前气温22度多云。 Thought: 我已获得天气信息可以回答用户。 Final Answer: 上海现在的气温是22度天气多云。通过这种迭代优化智能体的稳定性和准确性会得到显著提升。7. 项目实战构建一个多功能研究助手7.1 定义场景与工具集让我们基于ai-agents-from-scratch的框架动手构建一个实用的“多功能研究助手”。这个智能体的目标是帮助用户快速调研一个主题例如“对比TensorFlow和PyTorch在自然语言处理任务上的优缺点”。首先我们需要为它装备一套工具网络搜索工具调用SerpAPI或类似服务获取最新的博客文章、新闻、论坛讨论。学术搜索工具连接Google Scholar或Semantic Scholar的API查找相关论文和引用。内容摘要工具一个本地函数调用LLM API对长篇文章进行摘要提取核心观点。信息对比工具另一个本地函数接收多个摘要或要点生成结构化的对比表格。文件写入工具将最终的研究报告保存为Markdown或PDF文件。每个工具都需要精心编写描述。例如学术搜索工具的描述可以是“使用此工具搜索学术论文。输入应包含研究主题的关键词并可选择性地包含发表年份范围。返回论文标题、作者、摘要和引用链接。”7.2 实现与测试流程我们按照项目框架搭建智能体并编写核心循环。然后用我们的研究主题进行测试。智能体的理想执行流程应该是接收任务“对比TensorFlow和PyTorch在自然语言处理任务上的优缺点。”制定计划模型思考后可能计划先进行网络搜索获取业界实践观点再进行学术搜索获取研究数据然后分别摘要最后对比综合。执行与迭代调用网络搜索工具关键词“TensorFlow PyTorch NLP comparison 2024”。观察到返回了10条结果。调用内容摘要工具对前3篇最相关的长文进行摘要。调用学术搜索工具关键词“TensorFlow PyTorch benchmark NLP”。对找到的论文摘要进行提取。调用信息对比工具输入网络摘要和学术摘要要求从“易用性”、“性能”、“社区支持”、“部署”等维度生成对比。最后调用文件写入工具将对比报告保存。在整个过程中我们会密切观察模型的“Thought”部分看其推理是否合理观察其工具选择是否精准观察其如何处理海量、有时矛盾的信息。我们可能会发现模型在整合信息时遇到困难或者对比维度不够全面。这时我们就需要回到提示词工程优化系统指令例如明确要求“在对比时请至少从以下五个维度进行分析...”或者在工具层面进行改进例如让摘要工具额外提取“优点”、“缺点”字段。通过这个实战项目你会深刻体会到构建一个可靠的智能体是一个系统工程需要反复在模型能力、提示词设计、工具功能、流程编排之间进行调试和权衡。ai-agents-from-scratch提供的正是这样一个可以让你亲手进行所有调试的沙盒其价值远超过直接使用一个成熟但黑盒的框架。
从零构建AI智能体:核心架构、ReAct模式与实战指南
发布时间:2026/5/19 1:21:17
1. 项目概述从零构建AI智能体的核心价值最近在GitHub上看到一个挺有意思的项目叫pguso/ai-agents-from-scratch。光看名字很多朋友可能就心动了——“从零开始构建AI智能体”听起来就像是把那些神秘的大模型应用开发黑盒给彻底拆开让你亲手从螺丝钉开始组装一台能思考、能行动的机器。我花了些时间深入研究了这个仓库的代码和设计思路发现它确实提供了一个绝佳的实践窗口尤其适合那些已经对大型语言模型LLM有基本了解但困惑于如何将其转化为一个能持续运行、具备记忆和工具调用能力的“智能体”的开发者。这个项目的核心价值在于“解耦”与“教学”。它没有直接给你一个封装好的、参数繁多的重型框架而是将智能体最核心的几个模块——推理循环、记忆系统、工具使用、任务规划——用清晰、简洁的Python代码实现出来。你可以像看一本优秀的源码剖析书一样逐行理解每个决策背后的逻辑为什么这里要用一个while循环记忆列表是如何被管理和裁剪的工具调用的结果如何反馈给模型以进行下一步思考对于中级开发者而言这种透明性比直接调用某个Agent.run()方法要宝贵得多。你不仅能学会“怎么做”更能透彻理解“为什么这么做”以及当需求变化时“该如何改造”。它解决的核心痛点是理论与实操之间的鸿沟。我们都知道智能体Agent是当前AI应用的前沿但相关论文和博客往往侧重于高层架构描述。当你真正动手时会面临一堆具体问题如何设计提示词Prompt才能让模型更好地规划记忆的上下文窗口满了怎么办工具调用失败该如何优雅地处理这个项目通过一个可运行的代码基底直接带你穿越这些“魔鬼细节”。无论是想为自己的产品添加一个自动化的客服助手还是构建一个能自动分析数据并撰写报告的研究员亦或是创建一个游戏内的NPC你都能从这个“从零开始”的范式中获得扎实的起点和清晰的扩展思路。2. 智能体基础架构与核心循环拆解2.1 智能体的基本构成要素一个能够自主运作的AI智能体远不止是一个简单的大模型API调用。在ai-agents-from-scratch项目中我们可以清晰地看到一个最小可行智能体Minimum Viable Agent所必需的几个核心组件它们共同构成了智能体的“身体”与“大脑”。首先是最核心的推理引擎Reasoning Engine通常就是一个大型语言模型LLM。它负责理解输入、进行思考、做出决策并生成输出。但仅仅有LLM是不够的它就像一个只有瞬时记忆的天才不知道之前说过什么也无法操作外部世界。因此我们需要记忆系统Memory System。这个项目里通常实现为一个会话历史列表保存了用户与智能体之间的多轮对话。更高级的记忆可能包括向量数据库存储的长期记忆用于记住跨会话的关键信息。为了让智能体能“动手”工具集Toolkit必不可少。工具可以是任何函数查询数据库、调用搜索引擎、执行计算、操作文件系统。智能体需要知道它有哪些工具可用每个工具是做什么的通过描述并学会在合适的时机调用正确的工具。最后还需要一个控制流Control Flow或调度器Orchestrator也就是项目中最核心的那个循环。它负责粘合以上所有部分从用户或系统获取目标管理记忆的读写决定何时调用模型进行思考何时执行工具并处理执行结果直到任务完成或达到停止条件。2.2 核心循环ReAct模式的实践ai-agents-from-scratch项目典型地实现了ReActReasoning Acting模式。这是一种让模型交替进行“思考”和“行动”的范式极大地提升了任务完成的可靠性和可解释性。让我们拆解这个核心循环的每一步。循环始于一个用户查询或任务目标比如“查询北京今天的天气并建议我是否该带伞”。这个目标会被添加到记忆会话历史中。然后循环开始生成提示Prompt Generation系统会将当前的任务描述、完整的会话历史记忆、以及所有可用工具的描述名称、功能、参数格式组合成一个结构化的提示发送给LLM。这里的提示词设计非常关键它必须明确指示模型按照“Thought: ... Action: ... Action Input: ...”的格式进行输出。模型推理LLM InferenceLLM接收提示进行“思考”。它需要理解历史上下文分析当前任务状态然后决定下一步该做什么。输出会被严格解析。解析与决策Parsing Decision系统解析模型的输出。如果输出中包含Action:字段就意味着模型决定要使用一个工具。系统会提取工具名和输入参数。工具执行Tool Execution根据解析出的工具名找到对应的函数并传入参数执行。例如调用get_weather(location北京)。观察结果Observation工具执行的结果成功或失败会被格式化为一个观察语句例如Observation: 北京今天晴转多云最高气温25度降水概率10%。更新记忆与循环Update Loop将模型的“思考”Thought、“行动”Action和得到的“观察”Observation全部追加到会话历史中。这样在下一轮循环模型就能基于包含了之前所有步骤的完整上下文进行新的推理。循环重复直到模型输出Final Answer:字段表示它认为任务已完成可以给出最终答案。这个循环的精妙之处在于它将模型的“内部思考过程”外部化、步骤化了。你不仅能得到答案还能看到智能体得出答案的完整逻辑链它先想了什么为什么决定查天气查到结果后又如何推理出“不需要带伞”的结论。这对于调试和构建用户信任至关重要。注意在实现解析时一定要做好健壮性处理。模型输出可能不严格遵循格式可能拼错工具名可能提供非法参数。代码中必须有相应的异常捕获和重试机制例如当解析失败时可以将错误信息作为“观察”反馈给模型让它自我纠正。3. 记忆系统的设计与实现策略3.1 短期记忆会话历史的管理在基础实现中记忆通常就是一个Python列表按顺序存储所有的消息用户输入、模型思考、工具观察。但这带来了两个立即的问题上下文长度限制和信息冗余。所有LLM都有上下文窗口限制如4K、8K、128K tokens。如果我们的会话历史无限制增长很快就会超出限制导致最开始的对话被“遗忘”。ai-agents-from-scratch项目需要演示如何处理这个问题。一种简单策略是滑动窗口只保留最近N条消息或最近N个token的对话。虽然会丢失早期信息但对于许多短期对话任务已经足够。更精细的策略涉及摘要Summarization。当历史记录达到一定长度时可以触发一个“摘要”步骤将早期的对话内容发送给LLM要求其生成一个简洁的段落来总结之前讨论的关键事实和结论然后用这个摘要替换掉大段的原始历史。这样智能体保留了“要点”而不占用大量token。例如在进行了十轮关于旅行计划的讨论后记忆可以被摘要为“用户计划在六月去日本东京为期一周对美食和博物馆感兴趣预算中等。已讨论过签证和航班时间。”3.2 长期记忆的扩展思路对于更复杂的智能体需要长期甚至永久的记忆。这通常通过引入外部存储来实现比如向量数据库Vector Database。其核心思想是将信息记忆片段转换为向量嵌入存储起来。当需要回忆时将当前上下文或问题也转换为向量在数据库中进行相似性搜索找出最相关的记忆片段然后注入到当前提示中。例如你构建一个个人学习助手智能体。当用户问“我之前读过的关于神经网络正则化的那篇文章主要观点是什么”时智能体可以将这个问题转换为向量然后从其向量数据库中检索出之前存储的关于“读《...》文章笔记Dropout和权重衰减可以结合使用...”的記憶片段从而给出精准回答。在ai-agents-from-scratch的基础上你可以添加一个save_to_memory(text)函数将文本嵌入并存入向量库和一个recall_from_memory(query, k3)函数根据查询检索前k个相关记忆。这使得智能体具备了跨会话的、基于语义的記憶能力。实操心得管理记忆的“新鲜度”很重要。不是所有东西都值得记入长期记忆。可以设计一些规则例如只有包含具体事实数据、用户明确偏好或重要结论的对话才触发长期存储。同时为记忆片段添加时间戳和元数据如“类型事实”、“类型用户偏好”便于更精细的检索和过滤。4. 工具使用赋予智能体“手脚”4.1 工具的定义与封装工具的本质是智能体可以调用的函数。在项目中工具通常被定义为一个字典或一个类包含name工具名、description给模型看的描述、parameters参数JSON Schema和function实际执行的函数。例如一个计算器的工具可能这样定义{ “name”: “calculator”, “description”: “执行数学计算。支持加()、减(-)、乘(*)、除(/)、乘方(**)等运算。”, “parameters”: { “type”: “object”, “properties”: { “expression”: {“type”: “string”, “description”: “数学表达式例如 ‘(3 4) * 2’“} }, “required”: [“expression”] }, “function”: lambda **kwargs: str(eval(kwargs[“expression”])) # 注意实际使用中eval需谨慎此处仅为示例 }工具描述必须清晰、无歧义因为LLM完全依赖这个描述来理解工具用途。参数的模式Schema定义要尽可能详细这能极大提高模型调用工具的准确性。4.2 工具的选择与调用流程当LLM决定使用工具时它需要从一长串可用工具列表中做出选择。这个过程依赖于提示词工程。你的系统提示中需要清晰地列出所有工具及其描述。一种有效的格式是你有以下工具可供使用 {{tool_list}} 请严格按照以下格式响应 Thought: 我需要分析当前问题... Action: 工具名 Action Input: 符合工具参数JSON Schema的输入模型在Thought部分进行推理解释为什么选择这个工具然后在Action和Action Input中给出具体指令。系统收到响应后需要验证检查Action指定的工具是否存在。解析将Action Input解析为字典通常是JSON格式。校验根据该工具的parametersschema校验输入字典的合法性类型、必填字段等。执行调用工具函数传入解析后的参数。处理结果捕获执行结果或异常。如果成功将结果格式化为Observation: ...如果失败如工具异常、参数错误则格式化错误信息为Observation: 工具执行失败原因...。这个Observation会被加回记忆驱动下一轮循环。如果工具执行失败模型有机会在下一轮思考中尝试其他方案或纠正参数这体现了智能体的容错和自适应能力。注意事项工具的安全性至关重要。绝对不要让模型直接调用可以执行任意代码如os.system、删除文件或访问敏感数据的函数除非在高度受控的环境下。所有工具函数都应进行输入验证和权限控制。例如一个文件读取工具应该限制可访问的目录路径。5. 任务规划与分解的实现5.1 让智能体学会“分步走”对于复杂任务如“为我制定一份为期三天的北京旅游计划包括景点、餐饮和交通”直接要求模型一次性输出完美结果往往效果不佳。更好的方法是让智能体自己进行任务规划与分解。这可以通过在提示词中明确要求模型先制定计划来实现。一种简单有效的技术是思维链Chain-of-Thought, CoT提示的升级应用。你可以在系统提示中加入“对于复杂任务请先制定一个分步计划然后逐步执行。”在ai-agents-from-scratch的循环中这可以体现为模型的第一轮输出不是一个具体的行动而是一个计划列表。Thought: 这是一个复杂的旅游规划任务。我需要先确定核心需求时间、兴趣、预算然后分别查找景点、餐厅和交通信息最后整合成一份日程表。我的计划是 1. 询问用户对景点类型的偏好历史、现代、自然等。 2. 根据偏好搜索北京的推荐景点。 3. 根据景点位置搜索周边的餐厅。 4. 查询景点间的交通方式。 5. 将以上信息按天编排成日程。 现在我开始执行第一步。 Action: ask_user Action Input: {question: “您对哪些类型的景点更感兴趣例如历史古迹、现代建筑、博物馆、公园自然风光等”}然后智能体按照自己制定的计划一步步与用户交互或调用工具。这种“先计划后执行”的方式使得任务处理更加结构化也更容易调试。5.2 动态规划与重规划计划并非一成不变。在执行过程中可能会出现意外工具调用失败、用户提供了新信息、发现了更好的方案。因此智能体需要具备动态重规划的能力。这可以通过在每一轮循环中都让模型“评估当前状态和计划”来实现。在提示词中可以加入“请基于当前的对话历史和上一步的结果评估剩余任务并决定是继续执行原计划的下一步还是调整计划。”例如智能体原计划搜索“王府井附近的餐厅”但工具返回“未找到结果”。在下一轮模型观察到这个失败后可能会输出Thought: 搜索王府井附近餐厅失败。可能该区域餐厅数据暂时缺失。我应该调整计划改为搜索用户提到的另一个区域‘三里屯’的餐厅。 Action: search_restaurants Action Input: {location: “三里屯”}实现这一机制的关键是将“当前目标”、“已执行步骤”、“最新结果”都清晰地呈现在模型的上下文中并鼓励其进行状态评估。这使智能体从简单的“指令-执行”模式进化到更高级的“目标导向-动态调整”模式。6. 提示词工程与模型高效沟通的艺术6.1 系统提示的设计原则系统提示System Prompt是智能体的“宪法”它定义了智能体的角色、行为准则、可用资源和响应格式。一个设计良好的系统提示是项目成功的一半。首先明确角色和边界。开头就要定调“你是一个高效、准确的AI助手专门帮助用户完成信息查询和任务处理。你必须使用提供的工具来获取信息不能编造知识。”这设定了预期并减少了模型的“幻觉”。其次清晰说明格式要求。这是实现稳定解析的基础。必须用明确、无歧义的语言规定输出格式最好给出例子你必须用以下格式回应 Thought: [在此处清晰描述你对当前情况和下一步行动的思考] Action: [工具名必须是从以下列表中选择的一个] Action Input: [工具的输入参数必须是严格的JSON格式] 或 Final Answer: [当任务完成时直接给出最终答案]第三结构化地呈现工具和信息。将工具列表、当前目标、会话历史等不同部分用分隔符如###、---清晰分开帮助模型理解上下文结构。6.2 迭代优化与少样本学习提示词很少能一次写完美。你需要像调试代码一样调试提示词。基于ai-agents-from-scratch项目搭建起基础循环后就可以开始系统的提示词优化。收集失败案例运行智能体处理一系列测试任务记录下所有格式错误、工具选择错误、逻辑混乱的案例。分析根因是工具描述不清还是格式指令不明确或者是模型对任务理解有偏差修改提示针对性地增强提示。例如如果模型总选错工具可以在工具描述中加入更鲜明的对比“search_web用于查找实时通用信息query_database用于查找内部结构化数据。”引入少样本示例Few-shot Examples在系统提示中直接包含1-3个完整的、正确的输入输出示例。这是最强大的提示优化技术之一。示例展示了你期望的完整推理过程模型会强烈地倾向于模仿这种模式。例如在提示词中加入示例 用户上海现在的温度是多少 Thought: 用户询问实时天气信息。我需要使用天气查询工具。 Action: get_weather Action Input: {city: “上海”} Observation: 上海当前气温22度多云。 Thought: 我已获得天气信息可以回答用户。 Final Answer: 上海现在的气温是22度天气多云。通过这种迭代优化智能体的稳定性和准确性会得到显著提升。7. 项目实战构建一个多功能研究助手7.1 定义场景与工具集让我们基于ai-agents-from-scratch的框架动手构建一个实用的“多功能研究助手”。这个智能体的目标是帮助用户快速调研一个主题例如“对比TensorFlow和PyTorch在自然语言处理任务上的优缺点”。首先我们需要为它装备一套工具网络搜索工具调用SerpAPI或类似服务获取最新的博客文章、新闻、论坛讨论。学术搜索工具连接Google Scholar或Semantic Scholar的API查找相关论文和引用。内容摘要工具一个本地函数调用LLM API对长篇文章进行摘要提取核心观点。信息对比工具另一个本地函数接收多个摘要或要点生成结构化的对比表格。文件写入工具将最终的研究报告保存为Markdown或PDF文件。每个工具都需要精心编写描述。例如学术搜索工具的描述可以是“使用此工具搜索学术论文。输入应包含研究主题的关键词并可选择性地包含发表年份范围。返回论文标题、作者、摘要和引用链接。”7.2 实现与测试流程我们按照项目框架搭建智能体并编写核心循环。然后用我们的研究主题进行测试。智能体的理想执行流程应该是接收任务“对比TensorFlow和PyTorch在自然语言处理任务上的优缺点。”制定计划模型思考后可能计划先进行网络搜索获取业界实践观点再进行学术搜索获取研究数据然后分别摘要最后对比综合。执行与迭代调用网络搜索工具关键词“TensorFlow PyTorch NLP comparison 2024”。观察到返回了10条结果。调用内容摘要工具对前3篇最相关的长文进行摘要。调用学术搜索工具关键词“TensorFlow PyTorch benchmark NLP”。对找到的论文摘要进行提取。调用信息对比工具输入网络摘要和学术摘要要求从“易用性”、“性能”、“社区支持”、“部署”等维度生成对比。最后调用文件写入工具将对比报告保存。在整个过程中我们会密切观察模型的“Thought”部分看其推理是否合理观察其工具选择是否精准观察其如何处理海量、有时矛盾的信息。我们可能会发现模型在整合信息时遇到困难或者对比维度不够全面。这时我们就需要回到提示词工程优化系统指令例如明确要求“在对比时请至少从以下五个维度进行分析...”或者在工具层面进行改进例如让摘要工具额外提取“优点”、“缺点”字段。通过这个实战项目你会深刻体会到构建一个可靠的智能体是一个系统工程需要反复在模型能力、提示词设计、工具功能、流程编排之间进行调试和权衡。ai-agents-from-scratch提供的正是这样一个可以让你亲手进行所有调试的沙盒其价值远超过直接使用一个成熟但黑盒的框架。