
1. 先搞清楚“Agent Skill”到底在解决什么问题如果你最近在关注AI应用开发尤其是想做一个能自己调用工具、处理复杂任务的智能体Agent那“Skill”这个概念你一定绕不开。很多人一上来就去看各种框架和代码结果被一堆术语搞晕Agent、Skill、Tool、Action、RAG……它们之间到底是什么关系为什么我的Agent只会聊天一让它干点实际的比如查个天气、发封邮件就报错“Agent Skill”要解决的就是这个“让智能体具备实际做事能力”的核心问题。你可以把它理解为智能体的“技能包”。一个只会对话的Agent是“大脑”但它没有“手”和“脚”。Skill就是为这个大脑安装的“手”和“脚”让它能执行具体的操作比如调用一个API、操作一个数据库、运行一段脚本。现在很多教程一上来就讲大模型微调、讲RAG检索增强生成这当然重要但那是解决“知识”和“记忆”的问题。而Skill解决的是“行动”的问题。一个真正有用的AI助手必然是既懂知识通过RAG又能行动通过Skill的。所以这个主题最适合两类人已经会用大模型API做对话但想让AI自动执行任务的人比如自动整理会议纪要并发送邮件、监控数据异常并触发告警。在评估或使用LangChain、AutoGen、CrewAI等Agent框架的开发者想弄明白如何在这些框架里自定义和扩展功能。最关键的价值在于掌握了Skill的设计和集成方法你就能把任何现有的API、函数或脚本变成AI可以理解和调用的能力从而构建出真正能落地的自动化流程而不是停留在演示阶段。2. 动手之前理清概念、选好环境在写第一行代码之前必须把几个关键概念和它们之间的关系掰扯清楚不然看任何框架的文档都会一头雾水。2.1 Agent、Skill、Tool、Action 到底是什么关系这是最让人混乱的地方。不同框架的叫法可能不同但核心逻辑是相通的。我们可以这样理解Agent智能体这是总指挥。它拥有一个“大脑”通常是LLM大语言模型负责理解用户意图、制定计划、决定下一步该调用哪个技能并解析技能返回的结果。你可以把它看作一个项目经理。Skill / Tool技能/工具这是可被调用的能力单元。一个Skill通常对应一个具体的、可执行的操作。在大多数上下文中Skill和Tool是等同的概念。比如“发送邮件”是一个Skill“查询数据库”也是一个Skill。Action动作这是Skill/Tool内部的具体执行步骤。有时一个复杂的Skill可能包含多个Action。但在简单场景下一个Skill可能只包含一个Action。你可以认为Action是Skill的实现细节。它们的关系链是用户请求 - Agent大脑分析- 决定调用某个 Skill - Skill 执行内部 Action - 返回结果给 Agent - Agent 组织语言回复用户。举个例子用户说“帮我查一下北京明天的天气然后发邮件提醒我带伞”。Agent理解后制定计划先调用“天气查询Skill”再调用“邮件发送Skill”。Agent调用“天气查询Skill”该Skill执行“调用天气API”这个Action返回“北京明天小雨15-20°C”。Agent将结果组织成文本调用“邮件发送Skill”该Skill执行“连接SMTP服务器并发送”这个Action。Agent最终告诉用户“已查询天气并发送提醒邮件。”2.2 RAG 和 Skill 有什么区别这也是高频问题。简单说RAG检索增强生成解决“知道什么”的问题。它让Agent能从外部知识库如文档、数据库中查找信息并用这些信息来生成更准确的回答。重点是信息获取和增强。Skill解决“能做什么”的问题。它让Agent能执行操作改变外部状态如发送邮件、创建工单、控制设备。重点是行动和执行。一个强大的Agent往往会同时使用两者用RAG来获取必要的知识用Skill来执行具体的任务。2.3 环境与框架选择对于入门和实战我不建议一开始就追求最火、最复杂的框架。从简单、易理解、文档清晰的开始更容易建立直觉。1. 基础环境准备Python3.8或以上版本。这是绝大多数AI框架的语言。包管理使用pip即可。强烈建议使用虚拟环境venv或conda避免包冲突。# 创建虚拟环境 python -m venv agent_skill_env # 激活Windows agent_skill_env\Scripts\activate # 激活Mac/Linux source agent_skill_env/bin/activateLLM API Key你需要一个大型语言模型的API访问权限这是Agent的“大脑”。国内场景可以考虑百度文心、阿里通义千问、智谱GLM等国际场景OpenAI的GPT系列、Anthropic的Claude是常见选择。准备好你的API Key。2. 框架选择建议对于学习Skill开发我推荐按以下路径第一阶段理解概念使用LangChain。它是目前生态最丰富、文档最全的框架之一对Tool/Skill的定义非常标准。虽然它组件繁多显得复杂但正是通过它你能最清晰地看到Tool是如何被定义、描述和调用的。第二阶段实战开发可以继续用LangChain深化或者尝试AutoGen。AutoGen由微软推出特别擅长多Agent协作其UserProxyAgent与AssistantAgent的对话模式能让你非常直观地看到Agent如何自动调用你提供的Tool。第三阶段生产考虑研究CrewAI、Semantic Kernel或LangGraph。它们提供了更结构化的任务编排、工作流和状态管理适合更复杂的业务场景。本篇教程我们将以LangChain为核心进行讲解因为它是最佳的教学样板。理解了它的模式迁移到其他框架会非常容易。3. 核心实战从零定义一个可用的Skill我们跳过理论直接动手。目标是创建一个能让Agent使用的“天气查询Skill”。3.1 第一步安装与最小化启动首先安装必要的库。我们使用OpenAI的模型作为Agent大脑你需要有自己的API Key。pip install langchain langchain-openai requestsrequests库用于我们的Skill中调用外部天气API。接下来我们先不写Skill而是测试一下最基本的LangChain调用LLM的能力确保大脑能工作。import os from langchain_openai import ChatOpenAI # 设置你的API Key这里以OpenAI为例其他模型类似 os.environ[OPENAI_API_KEY] 你的-api-key-here # 初始化LLM llm ChatOpenAI(modelgpt-3.5-turbo) # 测试简单对话 response llm.invoke(你好请简单介绍一下你自己。) print(response.content)如果这一步能正常输出模型自我介绍说明你的LLM环境配置成功了。这是所有Agent工作的基础。3.2 第二步创建你的第一个ToolSkill在LangChain中Skill就是Tool。创建一个Tool最基本的方式是定义一个函数然后用tool装饰器来装饰它。我们来创建一个查询指定城市天气的Tool。import requests from langchain.tools import tool # 使用一个免费的天气API示例例如 openweathermap需要注册获取免费API Key # 这里仅作演示请替换为你自己的API Key或使用其他稳定API WEATHER_API_KEY 你的-天气api-key BASE_URL http://api.openweathermap.org/data/2.5/weather tool def get_current_weather(city: str) - str: 获取指定城市的当前天气情况。输入应为城市名例如北京。 try: # 构造请求参数 params { q: city, appid: WEATHER_API_KEY, units: metric, # 使用摄氏度 lang: zh_cn } response requests.get(BASE_URL, paramsparams, timeout10) response.raise_for_status() # 检查请求是否成功 data response.json() # 解析返回的JSON数据 city_name data[name] temp data[main][temp] weather_desc data[weather][0][description] humidity data[main][humidity] result f{city_name}的当前天气{weather_desc}温度 {temp}°C湿度 {humidity}%。 return result except requests.exceptions.RequestException as e: return f请求天气API时出错{e} except KeyError: return 无法解析天气API返回的数据请检查API Key或城市名。 except Exception as e: return f获取天气时发生未知错误{e} # 测试一下这个Tool本身是否工作 print(get_current_weather.invoke(北京))关键点解释tool装饰器这是LangChain将普通函数标记为Tool的关键。它会让LangChain自动为这个函数生成描述以便LLM理解何时调用它。函数文档字符串Docstring获取指定城市的当前天气情况...这部分极其重要LLMAgent的大脑就是靠阅读这个描述来决定是否以及如何调用这个Tool的。描述必须清晰、准确。参数类型提示city: str和- str帮助框架理解输入输出格式。健壮性处理Tool内部必须有完善的错误处理try...except因为外部API可能失败。一个总是崩溃的Skill会让整个Agent瘫痪。运行上面的代码你应该能看到打印出的北京天气信息如果API Key有效。这说明你的Skill本身逻辑是通的。3.3 第三步将Tool交给Agent让它自主调用现在我们有了“大脑”LLM和“手”Weather Tool。接下来就是用LangChain把两者连接起来创建一个能自动决定何时使用这只“手”的Agent。LangChain提供了多种创建Agent的方式create_react_agent是一个经典且易于理解的选择它基于ReActReasoning Acting范式。from langchain.agents import create_react_agent, AgentExecutor from langchain import hub # 用于拉取预设的提示词 # 1. 准备Tools列表 tools [get_current_weather] # 把我们刚定义的Tool放进去 # 2. 拉取一个专门为ReAct Agent设计好的提示词模板 # 这个模板会告诉LLM如何思考、何时使用工具 prompt hub.pull(hwchase17/react) # 3. 创建ReAct Agent agent create_react_agent(llm, tools, prompt) # 4. 创建Agent执行器它负责运行Agent的循环思考-行动-观察-再思考... agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # 5. 运行测试 result agent_executor.invoke({ input: 请问上海和北京的天气怎么样 }) print(\n--- Agent最终回答 ---) print(result[output])运行过程解读注意看verboseTrue输出的日志当你运行这段代码时控制台会打印出详细的思考过程类似这样 Entering new AgentExecutor chain... 我需要比较上海和北京的天气。我应该分别查询这两个城市的天气。 行动get_current_weather 行动输入上海 观察上海的当前天气多云温度 22°C湿度 65%。 我需要再查询北京的天气。 行动get_current_weather 行动输入北京 观察北京的当前天气晴温度 18°C湿度 40%。 现在我有两个城市的信息可以给出比较后的回答。 思考上海多云22度北京晴18度。北京更凉爽干燥。 最终答案上海目前多云气温22°C湿度65%。北京天气晴朗气温18°C湿度40%。相比之下北京更凉爽干燥一些。 Finished chain.这就是SkillTool工作的核心魔法时刻AgentLLM自动识别出问题需要查询天气自动选择了正确的Toolget_current_weather自动生成了正确的输入参数“上海”、“北京”并最终将Tool返回的结果组织成了通顺的回答。3.4 第四步技能进阶——让Skill更强大可靠一个能跑通的Skill只是开始。要用于实际项目必须考虑更多。1. 结构化输出上面的Tool返回的是字符串。但有时后续步骤需要结构化的数据。我们可以让Tool返回字典Dict。from typing import Dict, Any from pydantic import BaseModel, Field from langchain.tools import StructuredTool # 定义输出数据的结构 class WeatherOutput(BaseModel): city: str Field(description城市名称) temperature: float Field(description温度单位摄氏度) description: str Field(description天气描述) humidity: int Field(description湿度百分比) def get_weather_structured(city: str) - Dict[str, Any]: 获取指定城市的结构化天气信息。 # ... 内部调用API的逻辑与之前类似 ... # 假设从API获取到数据后 return { city: 北京, temperature: 18.5, description: 晴朗, humidity: 40 } # 使用StructuredTool进行包装 structured_weather_tool StructuredTool.from_function( funcget_weather_structured, nameget_structured_weather, description获取城市天气的结构化数据, args_schemaNone, # 可以定义输入schema return_schemaWeatherOutput )结构化输出便于其他Tool或程序进一步处理例如筛选温度高于20度的城市。2. 异步支持如果Skill执行的是网络请求等IO密集型操作使用异步可以显著提升Agent在并发时的效率。import asyncio import aiohttp from langchain.tools import tool tool async def get_weather_async(city: str) - str: 异步获取城市天气。 async with aiohttp.ClientSession() as session: async with session.get(BASE_URL, params{q: city, appid: WEATHER_API_KEY}) as resp: data await resp.json() # ... 解析数据 ... return f{city}天气是...对应的Agent执行器也需要使用ainvoke异步方法调用。3. 技能依赖与管理当你有几十个Skill时需要管理。常见的做法是分类按领域分类如data_tools、communication_tools、system_tools。懒加载不是一次性加载所有Tool而是根据Agent的任务类型动态加载所需的Tool集合。权限控制某些敏感Skill如删除数据、发送消息需要对调用者进行权限校验。这通常在Tool函数内部或Agent调用前的中介层实现。4. 避坑指南与效能提升在实际开发和调试中你会遇到比教程更复杂的情况。下面是我从实际项目中总结的几个关键点和避坑经验。4.1 为什么我的Agent不调用Tool—— 描述与提示词工程这是新手最常见的问题。你写好了Tool但Agent就是无视它总是用自己的知识瞎编答案。问题通常出在两方面Tool的描述Docstring不够清晰LLM根据描述决定是否调用。描述必须准确说明功能、输入格式和输出内容。差描述“获取天气。”好描述“获取指定城市的当前天气情况包括温度、天气状况和湿度。输入应为城市名称字符串例如‘北京’或‘New York’。如果城市不存在会返回错误信息。”技巧在描述中自然地包含可能的关键词。如果用户问“今天下雨吗”你的Tool描述里有“天气状况”LLM就更容易关联上。提示词Prompt没有充分激发Agent使用Tool我们之前用的hwchase17/react提示词模板已经内置了使用Tool的指令。但如果你自定义提示词必须明确告诉LLM它可以且应该使用提供的工具。一个简单的模板应该包含系统角色设定如“你是一个有帮助的助手可以调用工具来回答问题。”工具列表及其描述。指令如“如果问题需要查询实时信息或执行操作请务必调用合适的工具。”思考格式如“思考... 行动... 行动输入... 观察...”。调试方法开启verboseTrue观察Agent的“思考”链。如果它根本没进入“行动”步骤说明它不认为需要调用工具优先检查上述两点。4.2 处理复杂任务与多技能协作单个Skill很简单但现实任务往往需要多个Skill按顺序或条件执行。这就是Agent规划能力的体现。场景用户说“查一下北京天气如果温度低于10度就发邮件提醒我加衣服。”分析这需要get_weatherSkill和send_emailSkill。Agent需要先调用前者根据结果温度值做判断再决定是否调用后者。LangChain的create_react_agent本身具备一定的顺序推理能力。但对于更复杂的工作流如循环、并行你需要更强大的编排工具使用LangGraph这是LangChain官方的工作流库可以用图的方式定义Agent和Tool的执行流程支持循环、分支、并行。使用CrewAI的Task在CrewAI中你可以定义多个Task每个Task指定一个Agent和一系列Tool并设置Task之间的依赖关系。手动控制流在最底层你可以自己写逻辑根据一个Tool的输出决定下一个调用什么。但这失去了Agent自动规划的意义。建议先从简单的多Tool场景开始依赖ReAct Agent的推理能力。当逻辑过于复杂且不稳定时再考虑引入LangGraph等编排框架。4.3 错误处理与稳定性保障一个脆弱的Agent是没用的。你必须为Skill和Agent本身设计容错机制。Skill内部错误处理如前所述每个Tool函数内部必须有try...except返回明确的错误信息而不是抛出异常导致整个Agent崩溃。超时控制网络请求必须设置超时timeout参数避免一个慢速API拖死整个Agent。Agent执行器的错误处理AgentExecutor的handle_parsing_errorsTrue参数很重要它能处理LLM输出不符合Tool调用格式的解析错误。你还可以自定义一个错误回调函数。重试机制对于可能因网络抖动失败的Tool可以加入简单的重试逻辑如tenacity库。验证输入在Tool函数开头验证输入参数是否合法如城市名是否为空、邮箱格式是否正确。4.4 性能与成本考量Token消耗Agent的每一步“思考”和“行动”都会消耗LLM的Token。复杂的思考链和频繁的Tool调用会显著增加成本。在verbose模式下观察如果Agent为了一个简单问题进行了过多无用的“思考”可能需要优化提示词或Tool描述。并发与速率限制如果你部署的Agent服务会同时处理多个用户请求要注意LLM API的速率限制避免并发请求超过配额。下游Skill API的速率限制比如天气API可能有每分钟调用次数限制。解决方案在Agent服务层实现请求队列、限流和缓存例如对同一城市天气的查询5分钟内缓存结果。4.5 从开发到部署的最后一公里本地跑通只是第一步。要让别人能用你需要封装为API使用FastAPI或Flask将你的Agent和Skill封装成HTTP接口。接收用户问题返回Agent的回答。技能注册与发现建立一个技能注册中心新的Skill可以通过配置文件或API动态注册而不需要重启主服务。日志与监控记录每一次用户交互、Agent的思考链、Tool的调用和结果。这对于调试和优化至关重要。监控Token消耗、响应时间和错误率。安全性输入过滤防止用户输入恶意指令导致Tool执行危险操作如“删除所有文件”。Tool权限对不同用户或角色暴露不同的Tool集合。敏感信息Tool中使用的API Key等敏感信息必须通过环境变量或密钥管理服务获取绝不能硬编码在代码中。5. 总结Skill开发的本质是“能力封装”与“意图理解”回过头看开发Agent Skill的过程本质上在做两件事能力封装将一段确定性的、可执行的功能函数、API调用、脚本包装成一个标准化的、有清晰描述的接口Tool。这是工程活考验的是代码健壮性和设计能力。意图理解与路由通过精心设计的提示词和Tool描述引导LLMAgent准确理解用户意图并路由到正确的Skill上。这是提示词工程和AI产品设计的活考验的是对人机交互和LLM能力的理解。因此一个优秀的Agent Skill开发者需要同时具备软件工程和AI产品的思维。不要只埋头写Tool函数更要不断测试和优化Agent调用这些Tool的准确性和效率。最后给一个最实在的建议不要一开始就追求大而全的技能库。从一个你最熟悉的、最有把握的领域比如查询你公司的内部知识库、操作一个你负责的云服务开始打造一个极其稳定、可靠的Skill。把这个流程跑通、跑稳包括开发、测试、部署、监控、迭代。这个过程中积累的经验远比你看十篇教程更有价值。之后再沿着这个模式去扩展第二个、第三个Skill你会顺利得多。