AI智能体开发实战:三大主流框架对比与项目构建指南
1. 从零到一为什么你需要系统学习AI智能体如果你最近在关注AI领域尤其是大语言模型的应用那么“智能体”这个词一定已经刷爆了你的信息流。从能自动写代码、调试程序的Devin到能帮你处理复杂工作流的各种AI助手智能体似乎正在成为下一代人机交互的核心范式。但当你真正想动手构建一个属于自己的智能体时往往会发现教程要么是零散的博客讲个概念就没了要么是某个框架的官方文档读起来像天书要么就是一些“5分钟速成”的视频结果连环境都配不通。这正是Hugging Face推出这门《智能体课程》的初衷。它不是一个简单的工具说明书合集而是一套由浅入深、从理论到实战的完整学习路径。我花了几天时间完整跟了一遍感觉就像有个经验丰富的同事坐在旁边手把手带你拆解智能体的每一个核心部件。这门课最大的价值在于它没有把你局限在某个单一的框架里而是让你同时掌握smolagents、LangGraph和LlamaIndex这三种主流工具的核心思想和用法。这相当于给了你一张地图让你知道在什么场景下该走哪条路而不是盲目地跟着某一个“网红”框架走到黑。无论你是想为自己的产品增加一个智能的对话接口还是想构建一个能自动处理文档、分析数据的内部工具甚至是探索游戏AI这类有趣的应用这门课程提供的知识框架和实战项目都能让你快速上手。接下来我就结合自己的学习体验和项目经验为你详细拆解这门课的精髓并补充一些官方课程里没细说但在实际开发中至关重要的“坑”和技巧。2. 课程核心架构与学习路径解析2.1 单元设计逻辑从认知到创造的递进之旅这门课程的结构设计得非常巧妙它遵循了“是什么 - 怎么用 - 怎么选 - 怎么做好”的经典学习曲线而不是一上来就扔给你一堆代码。第0单元开营准备。这部分看似简单但千万别跳过。它明确了学习本课程需要的基础Python和LLM的基本知识。如果你对Python的异步编程async/await不熟或者对调用OpenAI或开源LLM的API感到陌生我建议你先花点时间补上这两块。课程本身不会从头教你Python语法但它后续的许多高级示例特别是在LangGraph中处理复杂工作流时会大量用到这些概念。一个实用的建议是在开始前先用Hugging Face的InferenceClient或OpenAI的库写一个最简单的聊天程序确保你的API密钥和环境配置都是通的这能避免你卡在第一步。第1单元智能体基础概念。这是构建认知框架的关键。课程清晰地定义了“智能体”是什么一个能感知环境输入、进行思考LLM推理、执行动作调用工具/函数并基于结果进行下一步决策的循环系统。它重点讲解了LLM的“函数调用”能力这是智能体的基石。我特别喜欢它对“模型族谱”的梳理帮你理解ChatGPT、Claude、Llama等模型在函数调用支持上的异同。一个常见的误区是很多人以为只有GPT-4才能做好函数调用实际上经过特定微调Fine-tuning的Llama 3等开源模型在此任务上表现已经非常出色成本却低得多。第一单元的Bonus部分就专门教你如何微调一个属于自己的函数调用模型这部分含金量极高。第2单元三大框架实战。这是课程的核心干货部分。它没有武断地说哪个框架最好而是并列介绍了三种不同哲学的设计smolagentsHugging Face自家出品的轻量级框架。它的理念是“简单够用”API设计非常直观如果你需要快速构建一个功能明确、逻辑相对简单的智能体比如一个根据用户描述生成SQL并执行的工具smolagents可能是最快上手的。它的代码就像Python本身一样易读。LangGraph来自LangChain主打“可控的工作流”。它的核心是“图”Graph你可以把智能体的每一步LLM调用、工具执行、条件判断定义成节点用线边连接起来形成一个可视化的流程图。这对于构建有复杂状态转移、需要严格步骤控制的商业流程如客户工单处理、多步骤数据分析来说是无可替代的。学习曲线较陡但能力上限也最高。LlamaIndex最初以“为LLM提供数据索引”闻名现在其智能体框架更侧重于数据感知。如果你的智能体核心任务是深入理解和处理你自己的私有数据公司文档、知识库、数据库那么LlamaIndex提供的各种索引器、查询引擎以及与智能体的无缝集成会让你事半功倍。关键选择建议不要试图用一个框架解决所有问题。对于新手我建议的路径是先用smolagents完成第一个能跑通的智能体建立信心和基本概念当你的智能体需要处理“如果A失败就尝试B”这类复杂逻辑时引入LangGraph当你的任务核心是问答、总结、分析大量自有文档时重点钻研LlamaIndex。第3单元与第4单元高级应用与毕业设计。第3单元深入探讨了“智能体检索增强生成”。这不是简单的RAG而是让智能体自己决定何时检索、检索什么、如何整合检索结果进行回答智能性大大提升。第4单元的最终项目则是一个完整的闭环从零创建一个解决特定问题的智能体然后使用课程教你的方法去自动评估它比如测试它的回答准确率、工具调用正确率最后可以提交到一个排行榜上。这个过程模拟了一个真实的AI产品开发迭代流程价值远超一个简单的Demo。2.2 隐藏的学习资源与社区价值除了明面的课程内容这个仓库和相关的社区本身就是巨大的宝藏。Discord社区课程推荐加入的Discord频道非常活跃。这里不仅有课程作者和助教答疑更多的是来自全球的学习者和开发者。我在这里看到过有人分享用智能体自动化管理云服务器成本的复杂方案也看到过关于“工具描述怎么写LLM才能更好理解”的激烈讨论。很多在文档中找不到的“坑”比如LangGraph在持久化状态Persistence时的序列化问题或者LlamaIndex在处理特定PDF格式时的性能调优都能在社区找到前人的经验。强烈建议你在学习过程中把遇到的问题和最终的解决方案也分享出去。项目代码与协作GitHub仓库的代码是最新的而且结构清晰。更重要的是它展示了如何为一个大型开源课程项目做贡献。从修复一个错别字到提议增加一个全新的单元比如关于多模态智能体或智能体安全都有明确的指南。参与其中哪怕只是提交一个小的PR也是你技术履历上漂亮的一笔并能让你更深入地理解项目结构。3. 三大框架深度对比与选型指南学完第二单元后你可能会对这三个框架有点选择困难。下面我结合几个具体的场景帮你做一次深入的对比和选型分析。3.1 Smolagents轻快灵巧的“瑞士军刀”核心哲学极简主义降低使用门槛。smolagents的API设计几乎是声明式的。你定义一个工具一个Python函数加上清晰的文档字符串把它给智能体智能体就能在对话中尝试使用它。from smolagents import Agent, tool tool def get_weather(city: str) - str: 获取指定城市的当前天气。 # 这里模拟一个API调用 return f{city}的天气是晴朗25摄氏度。 agent Agent(modelgpt-4o, tools[get_weather]) response agent.run(北京天气怎么样)它的工作流是线性的用户输入 - LLM思考是否调用工具调用哪个- 执行工具 - 将结果返回给LLM生成最终回答。对于不需要复杂记忆、分支判断的场景这种简单性就是最大的优势。适用场景原型验证快速验证一个智能体想法是否可行。简单任务自动化如数据查询、内容格式化、发送通知等单一或少量工具组合的任务。教育演示由于其代码极其简洁非常适合用于教学让学生聚焦于智能体逻辑而非框架复杂性。实操心得与坑点工具描述是关键tool装饰器会读取函数的文档字符串docstring和参数类型注解将其转化为给LLM的“工具说明书”。这份说明书必须清晰、无歧义。例如参数city最好注明“请输入完整的城市名如‘北京市’”否则LLM可能会生成“北京”或“Beijing”导致你的后端服务无法识别。处理模糊请求当用户说“帮我查下天气”但没有指明城市时简单的smolagents智能体可能会直接调用get_weather(cityNone)而报错。更好的做法是在工具函数内部或之前增加一层校验和澄清逻辑或者使用更高级的“规划”能力但这已接近LangGraph的领域。会话状态管理smolagents的默认Agent在多次run()调用间不会自动保持上下文。如果你需要多轮对话记忆需要使用ConversationalAgent或手动管理对话历史并传入。3.2 LangGraph绘制智能体的“交通蓝图”核心哲学将智能体工作流建模为有状态图。在LangGraph中一切皆节点Node节点之间通过边Edge连接数据状态沿着边在节点间流动。一个经典的“旅行规划”智能体可能包含以下节点LLM节点解析用户请求“我想去杭州玩三天”。工具节点调用天气查询API。工具节点调用航班搜索API。条件判断边如果航班价格太高则流向“推荐高铁”节点否则流向“生成行程”节点。LLM节点汇总信息生成最终行程建议。你可以通过代码或可视化编辑器清晰地看到这个逻辑图这对于调试复杂流程至关重要。适用场景多步骤商业流程例如客户服务智能体需要1. 理解问题2. 查询知识库3. 若未解决创建工单4. 通知相关人员。具备复杂逻辑判断的任务例如“如果股票价格低于X则买入如果高于Y则卖出否则持有”。需要严格保证执行顺序和错误处理的任务LangGraph可以定义错误处理节点和回滚逻辑。实操心得与坑点状态State设计是灵魂在定义图之前必须仔细设计你的状态对象通常是一个Pydantic模型。它应该包含工作流所需的所有信息。设计不良的状态会导致节点间传递数据困难或者状态变得臃肿。原则是状态应尽量扁平只包含必要数据。理解“循环”LangGraph的END和continue是关键。一个节点执行完后会返回下一个要去的节点名。通常LLM节点会返回一个包含next字段的字典。你需要清晰地定义在什么条件下工作流结束END什么条件下继续循环例如LLM认为还需要更多信息。持久化与检查点对于长时间运行的工作流如处理一个可能需要数小时的分析任务LangGraph的持久化功能可以将图的状态保存到数据库。这涉及到序列化问题。确保你的状态对象中所有字段都是可序列化的如避免复杂的自定义类。使用Pydantic模型作为状态基类能很好地解决这个问题。调试工具一定要利用好LangGraph的追踪Tracing功能。它可以将每一步的输入、输出、下一个节点都记录下来这对于排查“为什么智能体走到了这个分支”的问题不可或缺。第二单元的Bonus章节“可观测性与评估”会详细讲解这部分。3.3 LlamaIndex专精于数据的“领域专家”核心哲学智能体应与数据深度集成。LlamaIndex的强项在于它提供了一整套工具将你的数据文本、PDF、数据库、API转换成LLM能够高效查询和推理的格式。它的智能体通常是这样的你首先为你的数据建立索引Index比如一个包含所有公司产品手册的向量索引。然后你创建一个“查询引擎”Query Engine或“聊天引擎”Chat Engine。最后你将这个引擎作为一个超级工具暴露给智能体。当用户问“我们的旗舰产品支持哪些加密协议”时智能体会自动调用这个查询引擎工具引擎会在索引中检索相关内容并将检索到的片段作为上下文给LLM最终生成准确回答。适用场景企业知识库问答这是最典型的场景让智能体成为公司内部文档的“活字典”。复杂数据分析与报告生成智能体可以调用LlamaIndex的SQL查询引擎从数据库中提取数据然后让LLM进行分析和总结。研究助手针对某个研究课题上传大量论文智能体可以帮你进行跨文档的综合、对比和问答。实操心得与坑点索引构建质量决定上限“垃圾进垃圾出”。如果原始文档格式混乱、分块Chunking策略不合理、嵌入模型Embedding Model选得不好那么检索结果的质量会很差再聪明的智能体也无力回天。需要花时间调试分块大小、重叠度以及嵌入模型例如中文文档用BAAI/bge系列通常比OpenAI的text-embedding-3效果更好。检索策略的权衡LlamaIndex提供了多种检索器如向量检索、关键词检索BM25、混合检索等。对于事实性强的查询混合检索Hybrid Search通常更鲁棒。你需要根据你的数据特性进行配置和测试。智能体与引擎的协作模式LlamaIndex的智能体框架ReActAgent和查询引擎可以紧密耦合。你需要决定是让智能体“完全自主”地决定何时检索还是设计一个更受控的流程。通常对于开放域问答前者更灵活对于需要保证信息准确性的场景后者更可靠。处理长上下文当检索返回很多片段时可能会超出LLM的上下文窗口。LlamaIndex提供了“重排序”Re-ranking和“上下文压缩”Context Compression等高级功能来筛选出最相关的信息这部分需要额外学习和调优。4. 实战构建一个跨框架的智能体项目理论说得再多不如动手做一遍。我们设计一个综合性的实战项目尝试融合多个框架的优势。项目目标构建一个“技术调研助手”智能体。需求用户输入一个技术名词如“向量数据库Qdrant”智能体需要从网络如维基百科、技术博客获取基本信息。从本地知识库你存储的已读论文/技术报告PDF中查找相关深度分析。综合以上信息生成一份结构化的调研摘要包括概述、核心特性、优缺点、适用场景。如果信息不足能主动提出澄清性问题例如“您是想了解Qdrant在云原生环境下的部署吗”。4.1 架构设计与工具定义我们将采用“主从”架构主控智能体使用LangGraph实现负责管理整个调研流程做出决策是否需要网络搜索是否需要查询本地知识库信息是否足够。工具执行器使用smolagents和LlamaIndex来构建具体的工具因为它们各自在简单工具调用和复杂数据查询上更高效。第一步用smolagents风格定义基础工具我们创建两个基础工具网络搜索和总结。为了简化我们用duckduckgo-search模拟网络搜索。# tools.py from smolagents import tool import requests from duckduckgo_search import DDGS tool def search_web(query: str, max_results: int 5) - str: 使用搜索引擎在互联网上搜索最新信息。 Args: query: 搜索查询关键词应具体明确。 max_results: 返回的最大结果数量默认为5。 Returns: 一个包含搜索结果的字符串每个结果包括标题和摘要。 try: with DDGS() as ddgs: results list(ddgs.text(query, max_resultsmax_results)) formatted [] for r in results: formatted.append(f标题: {r[title]}\n摘要: {r[body]}\n) return \n---\n.join(formatted) if formatted else 未找到相关信息。 except Exception as e: return f搜索过程中出错: {e} tool def generate_summary(context: str, format: str markdown) - str: 根据提供的上下文材料生成一份结构化的总结报告。 Args: context: 需要被总结的原始文本材料。 format: 输出格式可选 markdown 或 plain。 Returns: 结构化的总结报告。 # 在实际应用中这里会调用LLM。此处为示例我们模拟一个简单总结。 # 真实场景应调用如 agent.run(f请总结以下内容{context})但注意避免循环调用。 # 这里我们假设有一个独立的LLM调用函数。 summary f基于提供的{len(context.split())}个单词的上下文生成的关键要点如下... if format markdown: return f## 调研摘要\n\n{summary} return summary第二步用LlamaIndex构建本地知识库工具假设我们有一个pdfs/文件夹里面存放了很多技术白皮书和报告。# knowledge_tool.py from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.llms.openai import OpenAI import os # 初始化设置实际使用时应配置你的API Key Settings.embed_model OpenAIEmbedding(modeltext-embedding-3-small) Settings.llm OpenAI(modelgpt-4o-mini) class KnowledgeBaseTool: def __init__(self, data_pathpdfs/): self.data_path data_path self.index None self._initialize_index() def _initialize_index(self): 加载文档并创建索引如果尚未创建 if not os.path.exists(self.data_path): print(f知识库路径 {self.data_path} 不存在将跳过本地查询。) return try: documents SimpleDirectoryReader(self.data_path).load_data() self.index VectorStoreIndex.from_documents(documents) print(本地知识库索引构建完成。) except Exception as e: print(f构建知识库索引失败: {e}) self.index None def query(self, question: str) - str: 查询本地知识库。 Args: question: 需要查询的问题。 Returns: 从本地知识库中检索到的相关信息。如果索引未初始化或未找到结果返回提示信息。 if self.index is None: return 本地知识库未就绪或为空。 try: query_engine self.index.as_query_engine(similarity_top_k3) response query_engine.query(question) return str(response) except Exception as e: return f查询本地知识库时出错: {e} # 创建工具实例 knowledge_base KnowledgeBaseTool() # 为了能被smolagents/LangGraph调用我们将其包装成一个函数 def query_local_knowledge(question: str) - str: return knowledge_base.query(question)第三步用LangGraph组装主控智能体现在我们用LangGraph来编排整个工作流。状态State需要包含用户问题、收集到的信息、当前步骤等。# research_agent.py from typing import TypedDict, Annotated, List import operator from langgraph.graph import StateGraph, END from langgraph.prebuilt import ToolExecutor from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, SystemMessage from tools import search_web, generate_summary from knowledge_tool import query_local_knowledge # 1. 定义状态结构 class ResearchState(TypedDict): question: str # 原始问题 gathered_info: List[str] # 收集到的信息片段 current_step: str # 当前步骤描述 needs_clarification: bool # 是否需要澄清 clarification_question: str # 需要澄清的问题 final_answer: str # 最终答案 # 2. 初始化LLM和工具执行器 llm ChatOpenAI(modelgpt-4o) tools [search_web, generate_summary, query_local_knowledge] tool_executor ToolExecutor(tools) # 3. 定义各个节点函数 def plan_step(state: ResearchState): 规划步骤分析问题决定下一步行动 messages [ SystemMessage(content你是一个技术调研助手。请分析用户的问题决定需要采取哪些步骤来收集信息。可能的步骤有SEARCH_WEB搜索网络、QUERY_KB查询本地知识库、SUMMARIZE生成总结、ASK_CLARIFY需要用户澄清。), HumanMessage(contentf用户的问题是{state[question]}。当前已收集的信息{state.get(gathered_info, [])}。请只输出下一步动作的名称。) ] response llm.invoke(messages) next_step response.content.strip() return {current_step: next_step} def execute_web_search(state: ResearchState): 执行网络搜索 if not state[question]: return {gathered_info: state[gathered_info] [错误问题为空]} result tool_executor.invoke({tool: search_web, tool_input: {query: state[question]}}) new_info f[网络搜索结果]{result} return {gathered_info: state[gathered_info] [new_info]} def execute_kb_query(state: ResearchState): 查询本地知识库 result tool_executor.invoke({tool: query_local_knowledge, tool_input: {question: state[question]}}) new_info f[本地知识库结果]{result} return {gathered_info: state[gathered_info] [new_info]} def decide_next(state: ResearchState): 决策节点根据已有信息判断是否足够或是否需要澄清 info_str \n.join(state[gathered_info]) messages [ SystemMessage(content请评估当前收集到的信息是否足以回答用户问题。如果信息充分输出SUFFICIENT如果信息不足且问题模糊输出NEED_CLARIFY并附上一个澄清问题否则输出CONTINUE。), HumanMessage(contentf问题{state[question]}\n已收集信息{info_str}) ] response llm.invoke(messages) decision response.content.strip() if decision.startswith(NEED_CLARIFY): # 简单解析实际应用中需要更鲁棒的解析 parts decision.split() if len(parts) 1: clarification parts[1] else: clarification 您能更具体地说明一下您的需求吗 return {needs_clarification: True, clarification_question: clarification, current_step: ask_user} elif SUFFICIENT in decision: return {current_step: generate_final} else: # 默认继续收集信息这里可以设计更复杂的路由逻辑比如交替搜索 # 简单起见我们设定一个条件如果已有网络和本地信息则总结否则继续搜索网络。 has_web any([网络搜索结果] in info for info in state[gathered_info]) has_kb any([本地知识库结果] in info for info in state[gathered_info]) if has_web and has_kb: return {current_step: generate_final} else: return {current_step: search_web} # 默认继续搜索 def generate_final_answer(state: ResearchState): 生成最终答案 all_info \n\n.join(state[gathered_info]) result tool_executor.invoke({tool: generate_summary, tool_input: {context: all_info, format: markdown}}) return {final_answer: result, current_step: end} def ask_user_clarification(state: ResearchState): 向用户请求澄清这是一个特殊节点在实际应用中可能需要中断工作流或等待外部输入 # 在实际部署中这里可能将澄清问题发送给用户界面并暂停图执行等待回调。 # 为演示我们假设用户会立即提供澄清并更新问题。 print(f[智能体请求澄清]{state[clarification_question]}) # 模拟用户提供了更具体的问题在实际中这来自外部输入 clarified_question state[question] (专注于其存储引擎原理) return {question: clarified_question, needs_clarification: False, current_step: plan} # 4. 构建图 workflow StateGraph(ResearchState) # 添加节点 workflow.add_node(plan, plan_step) workflow.add_node(search_web, execute_web_search) workflow.add_node(query_kb, execute_kb_query) workflow.add_node(decide, decide_next) workflow.add_node(generate_final, generate_final_answer) workflow.add_node(ask_user, ask_user_clarification) # 设置入口点 workflow.set_entry_point(plan) # 定义边路由逻辑 workflow.add_conditional_edges( plan, lambda state: state[current_step], { search_web: search_web, QUERY_KB: query_kb, # 注意这里演示了从LLM输出直接路由实际需要清洗和映射 ask_user: ask_user, generate_final: generate_final } ) workflow.add_edge(search_web, decide) workflow.add_edge(query_kb, decide) workflow.add_edge(decide, generate_final) # 简化路由决定后直接生成最终答案 workflow.add_edge(generate_final, END) workflow.add_edge(ask_user, plan) # 获得澄清后重新规划 # 编译图 app workflow.compile() # 5. 运行智能体 initial_state ResearchState(question什么是Qdrant向量数据库, gathered_info[], current_step, needs_clarificationFalse, clarification_question, final_answer) final_state app.invoke(initial_state, config{recursion_limit: 10}) print(final_state[final_answer])这个项目示例展示了如何将三个框架的优势结合用smolagents的简洁方式定义原子工具用LlamaIndex高效处理私有数据再用LangGraph的强大编排能力将它们串联成一个能自主决策的复杂工作流。在实际开发中你还需要完善错误处理、状态持久化、以及更精细的路由逻辑。5. 避坑指南与效能优化实战录在实际开发和部署智能体的过程中你会遇到许多官方教程不会提及的挑战。以下是我从多个项目中总结出的核心经验。5.1 工具设计与描述的黄金法则智能体表现不佳十有八九问题出在工具描述上。LLM并不理解你的代码它只“看”你给的工具描述。反面教材tool def process_data(input_data): 处理数据。 # ... 实现这个描述等于没说。LLM不知道什么时候该调用它也不知道input_data应该是什么。最佳实践功能描述具体化清晰说明工具的目的、适用场景和限制。tool def calculate_monthly_loan_payment(principal: float, annual_rate: float, years: int) - float: 计算等额本息贷款的每月还款金额。 适用于房贷、车贷等固定利率贷款的计算。 Args: principal: 贷款本金总额单位为元。 annual_rate: 年化利率单位为百分比例如5.5表示5.5%。 years: 贷款年限整数。 Returns: 每月应还款金额单位为元保留两位小数。 monthly_rate annual_rate / 100 / 12 months years * 12 payment principal * monthly_rate * (1 monthly_rate) ** months / ((1 monthly_rate) ** months - 1) return round(payment, 2)参数描述示例化在描述中给出例子能极大提高LLM理解和使用工具的准确率。“例如city参数应输入‘北京市’、‘Shanghai’这样的完整城市名。”处理边界情况在工具函数内部做好校验和错误处理并返回对LLM友好的错误信息。不要抛出晦涩的异常而是返回如“错误未找到名为‘XX’的城市请检查拼写。”这样的字符串LLM能将其融入对话。5.2 控制成本与延迟智能体必须考虑的经济学智能体频繁调用LLM和外部API成本尤其是使用GPT-4这类模型时和响应延迟会迅速成为问题。策略一缓存与记忆对话历史缓存对于多轮对话不要每次都把全部历史扔给LLM。可以使用LangChain的ConversationSummaryBufferMemory或ConversationTokenBufferMemory自动将长历史压缩成摘要或限制在token数以内。工具结果缓存对于幂等性工具如查询天气、获取股票价格将其结果缓存一段时间例如5分钟。可以使用functools.lru_cache或外部缓存如Redis。策略二模型分级调用并非所有步骤都需要最强的模型。可以设计一个“路由智能体”先用一个快速廉价的小模型如gpt-3.5-turbo或claude-haiku分析用户意图判断任务复杂度。简单任务直接由小模型处理复杂任务再“召唤”大模型如GPT-4o或Claude-3.5-Sonnet进行深度推理和规划。LangGraph的图结构非常适合实现这种路由。策略三减少不必要的工具调用在工具描述中明确其开销和限制例如“注意此工具调用外部API可能有延迟”。让LLM在调用工具前进行“思考链”Chain-of-Thought评估是否真的有必要。你可以在系统提示词中强调“在调用任何工具前请先简要思考这个工具是否能提供解决问题所必需的新信息。”5.3 评估与监控你的智能体真的在好好工作吗课程第4单元和Bonus单元强调了评估的重要性。上线一个没有评估的智能体如同闭眼开车。基础评估维度任务完成率给定一组测试问题智能体能正确完成的比例。工具调用准确率智能体在需要时是否调用了正确的工具并传入了正确的参数。响应质量最终答案的准确性、相关性和完整性。可以使用更强大的LLM如GPT-4作为裁判进行评分。效率指标平均响应时间、平均token消耗、平均工具调用次数。搭建简易评估流水线import asyncio from typing import List, Dict from langsmith import Client from langsmith.evaluation import evaluate # 1. 准备测试数据集 test_cases [ {input: 计算100万贷款利率4.5%贷30年月供多少, expected_tool: calculate_monthly_loan_payment}, {input: 今天北京天气如何, expected_tool: get_weather}, ] # 2. 定义运行智能体的函数 async def run_agent(question: str) - Dict: # ... 你的智能体调用逻辑返回结果和追踪信息 pass # 3. 定义评估函数 def correctness_evaluator(run_outputs: Dict, test_case: Dict) - Dict: 评估工具调用是否正确 predicted_tool run_outputs.get(called_tool) expected test_case[expected_tool] score 1.0 if predicted_tool expected else 0.0 return {key: tool_correctness, score: score} # 4. 使用LangSmith或类似平台进行批量评估和可视化 # client Client() # evaluate(...)Hugging Face也提供了evaluate库和平台可以方便地对生成内容进行自动评估。5.4 安全与可靠性不可忽视的底线智能体因为能自主调用工具也带来了新的风险。风险一无限循环与资源耗尽在LangGraph中务必设置recursion_limit如上例所示防止因为逻辑错误导致无限循环。为工具调用设置超时timeout和重试次数上限。风险二工具滥用严格限制智能体可访问的工具范围。一个面向内部的文档分析智能体不应该有发送邮件或访问数据库的权限。对于执行写操作或敏感操作的工具如“发送邮件”、“创建数据库条目”可以设计一个“确认节点”。在LangGraph中在执行前增加一个节点将操作详情发给人工或一个确认流程只有获得批准后才继续。风险三提示词注入与越狱用户输入可能包含试图覆盖系统提示词的指令。缓解方法包括在将用户输入传递给LLM前进行清洗使用强硬的系统提示词明确告知模型忽略任何试图改变其行为的指令在架构上将工具调用权限与用户输入进行隔离。构建一个真正可靠、有用的智能体是一个持续迭代和优化的过程。这门课程给了你一套强大的工具和清晰的路线图但真正的精通来自于在具体项目中不断地踩坑、填坑和反思。从今天开始选一个你工作中小而具体的问题尝试用smolagents自动化它你会发现自己打开了一扇新的大门。