大家好我是专注于AI技术分享的博主。最近在跟进大模型应用开发时发现很多开发者对“Agent Skills”这个概念既熟悉又陌生知道它很重要是让大模型从“聊天工具”升级为“智能助手”的关键但具体到如何设计、如何实现、如何集成到业务中又感觉无从下手。网上的资料要么过于理论要么是零散的代码片段缺乏一个从原理到落地的完整闭环。本文将以实战为导向系统拆解Agent Skills的技术内核、设计模式与工程实践。无论你是想快速上手LangChain、AutoGen等框架还是希望自研一个业务Agent这篇文章都将为你提供清晰的路径和可复用的代码。学完你将能独立设计并实现具备规划、工具调用、记忆等核心能力的智能体大幅提升开发效率。1. Agent Skills 核心概念从“聊天”到“行动”在深入代码之前我们必须厘清几个核心概念。这能帮你建立正确的认知避免后续开发中的概念混淆。什么是Agent简单来说Agent是一个能够感知环境、进行决策并执行行动以实现目标的智能实体。在大模型语境下Agent通常指一个以大语言模型LLM为“大脑”具备使用工具Tools、访问记忆Memory和进行规划Planning能力的系统。它不再只是回答一个问题而是为了完成一个复杂任务如分析数据、预订行程而自主调用一系列技能。什么是SkillSkill即技能是Agent能够执行的一个具体、原子化的操作。它是Agent与外部世界交互的“手”和“脚”。一个Skill通常对应一个工具函数Tool Function。例如网络搜索Skill调用搜索引擎API获取实时信息。代码执行Skill在安全沙箱中运行一段Python代码并返回结果。数据库查询Skill连接数据库执行SQL查询。文件读写Skill读取本地文件内容或写入结果。Agent与Skills的关系你可以把Agent想象成一个项目经理LLM而Skills就是他手下的各个专家团队。项目经理Agent负责理解客户用户的复杂需求如“帮我分析上季度销售数据并生成报告”然后进行任务分解和规划Planning接着协调调用数据分析专家数据库查询Skill、报告撰写专家文本生成Skill和图表制作专家画图Skill来完成最终目标。Skills是具体的执行者Agent是决策和调度中心。为什么需要Agent Skills突破模型局限大模型的知识可能过时且无法直接操作外部系统。Skills让模型能获取实时信息并执行具体操作。处理复杂任务单一问答无法解决多步骤问题。Agent通过组合多个Skills以链式或循环的方式解决复杂问题。实现业务闭环将大模型能力嵌入现有工作流如自动处理客服工单、智能数据分析等创造实际业务价值。2. 环境准备与核心工具选型工欲善其事必先利其器。构建Agent应用选择合适的框架和工具链至关重要。下面以当前最主流的Python技术栈为例进行说明。2.1 基础环境操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04)。本文示例在macOS/Linux环境下演示Windows用户请注意路径差异。Python版本 3.8。推荐使用3.9或3.10以获得最佳的库兼容性。包管理工具使用pip或更推荐的poetry/conda管理虚拟环境。2.2 核心框架选择目前社区主要有两大流派LangChain / LangGraph生态最丰富、文档最全的“全家桶”式框架。提供了大量现成的工具、链和Agent模板适合快速原型开发和入门。AutoGen由微软推出专注于多智能体协作。擅长构建多个Agent对话、协作完成任务的场景设计理念更贴近分布式系统。对于初学者和大多数单Agent应用从LangChain入手学习成本更低。本文主要基于LangChain进行演示但其设计思想是通用的。2.3 安装依赖创建一个新的项目目录并初始化虚拟环境。# 创建项目目录 mkdir agent-skills-demo cd agent-skills-demo # 创建并激活虚拟环境 (以venv为例) python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate # 安装核心库 pip install langchain langchain-community langchain-openai # 安装可能用到的工具依赖 pip install duckduckgo-search # 用于网络搜索 pip install sqlalchemy # 用于数据库操作 pip install python-dotenv # 用于管理API密钥2.4 配置API密钥你需要一个LLM的API密钥作为Agent的“大脑”。这里以OpenAI为例也支持Azure OpenAI、Anthropic、本地模型等。在项目根目录创建.env文件来安全存储密钥。# .env 文件内容 OPENAI_API_KEY你的OpenAI API密钥然后在Python代码中加载# config.py from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的环境变量 OPENAI_API_KEY os.getenv(OPENAI_API_KEY) assert OPENAI_API_KEY, 请在 .env 文件中设置 OPENAI_API_KEY3. Skill设计原理与实现模式Skill是Agent的基石。一个设计良好的Skill应该是功能单一、接口明确、安全可靠的。3.1 Skill的基本结构在LangChain中Skill通过Tool类来定义。一个Tool需要具备名称nameAgent识别和调用该技能的唯一标识。描述description用自然语言清晰描述该技能的功能、输入和输出。描述至关重要LLM依靠它来决定是否以及如何调用该工具。执行函数func具体的实现逻辑。# skills/basic_skills.py from langchain.tools import Tool import math from datetime import datetime def get_current_time(*args, **kwargs) - str: 获取当前的日期和时间。此工具不需要任何输入参数。 now datetime.now() return now.strftime(%Y-%m-%d %H:%M:%S) def calculate_sqrt(number: str) - str: 计算一个数的平方根。输入应该是一个数字字符串。 try: num float(number) if num 0: return 错误输入不能为负数。 result math.sqrt(num) return f{number} 的平方根是 {result:.4f} except ValueError: return 错误请输入有效的数字。 # 将函数包装成LangChain Tool time_tool Tool( nameGetCurrentTime, funcget_current_time, description当需要知道当前时间或日期时使用此工具。输入应为空。 ) sqrt_tool Tool( nameCalculator_SquareRoot, funccalculate_sqrt, description用于计算一个非负数的平方根。输入应该是一个数字字符串例如 25。 ) # 工具列表 BASIC_TOOLS [time_tool, sqrt_tool]3.2 高级Skill示例网络搜索与数据查询让Agent获取实时信息或查询内部数据是核心场景。# skills/advanced_skills.py from langchain.tools import Tool from langchain_community.tools import DuckDuckGoSearchRun from langchain_community.utilities import SQLDatabase from sqlalchemy import create_engine, text import json # 1. 网络搜索Skill (使用 DuckDuckGo) search DuckDuckGoSearchRun() search_tool Tool( nameWebSearch, funcsearch.run, description在互联网上搜索最新信息。当问题涉及实时新闻、未知事实或需要最新数据时使用。 输入应该是一个明确的搜索查询字符串。 ) # 2. 数据库查询Skill (示例连接SQLite) # 假设我们有一个简单的用户数据库 def setup_demo_db(): import sqlite3 conn sqlite3.connect(demo.db) cursor conn.cursor() cursor.execute(CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)) cursor.execute(INSERT OR IGNORE INTO users VALUES (1, 张三, zhangsanexample.com)) cursor.execute(INSERT OR IGNORE INTO users VALUES (2, 李四, lisiexample.com)) conn.commit() conn.close() setup_demo_db() # 创建数据库引擎和LangChain SQLDatabase对象 engine create_engine(sqlite:///demo.db) db SQLDatabase(engine) def query_database(query: str) - str: 执行SQL查询并返回结果。仅用于查询禁止执行INSERT/UPDATE/DELETE。 # 简单的安全过滤只允许SELECT操作生产环境需要更严格的权限控制 if not query.strip().upper().startswith(SELECT): return 错误此工具仅支持SELECT查询。 try: with engine.connect() as conn: result conn.execute(text(query)) rows result.fetchall() columns result.keys() # 将结果格式化为易读的字符串 if not rows: return 查询成功但未找到数据。 # 简单格式化 formatted_rows [] for row in rows: formatted_rows.append(dict(zip(columns, row))) return json.dumps(formatted_rows, ensure_asciiFalse, indent2) except Exception as e: return f数据库查询出错{str(e)} db_tool Tool( nameQueryDatabase, funcquery_database, description查询用户数据库以获取信息。可以回答关于用户数据的问题。 输入必须是一个有效的SQL SELECT查询语句例如 SELECT name FROM users WHERE id1。 注意不要修改数据。 ) ADVANCED_TOOLS [search_tool, db_tool]3.3 Skill设计的最佳实践描述要精准描述是LLM的“使用说明书”。要写明功能、输入格式、输出格式和适用场景。例如“当用户需要计算两个数的乘积时使用。输入应为两个用逗号分隔的数字如 ‘5,3’。返回它们的乘积。”功能要单一一个Skill只做一件事。不要设计一个“万能工具”这会让LLM困惑。输入要验证在Skill函数内部务必对输入参数进行类型检查和有效性验证防止错误输入导致系统崩溃。错误要处理Skill必须能处理异常并返回对人友好的错误信息而不是抛出Python异常。考虑安全性对于执行代码、访问文件、操作数据库的Skill必须实施严格的权限控制和输入过滤遵循最小权限原则。4. 构建你的第一个智能体从零到一有了Skills我们就可以组装Agent了。LangChain提供了多种Agent类型我们从一个最简单的ReActAgent开始。4.1 初始化LLM与工具首先引入LLM作为Agent的推理核心。# agent_basic.py from langchain_openai import ChatOpenAI from langchain.agents import initialize_agent, AgentType from skills.basic_skills import BASIC_TOOLS from skills.advanced_skills import ADVANCED_TOOLS from config import OPENAI_API_KEY import warnings warnings.filterwarnings(ignore) # 忽略一些警告 # 1. 初始化LLM # 使用gpt-3.5-turbo性价比高gpt-4能力更强但成本也高 llm ChatOpenAI( modelgpt-3.5-turbo, temperature0, # 温度设为0使输出更确定、更可靠 openai_api_keyOPENAI_API_KEY ) # 2. 组合所有工具 ALL_TOOLS BASIC_TOOLS ADVANCED_TOOLS print(f已加载工具: {[tool.name for tool in ALL_TOOLS]})4.2 创建并运行Agent使用initialize_agent函数来创建Agent。AgentType.ZERO_SHOT_REACT_DESCRIPTION是一种通用且强大的Agent类型它基于ReAct推理行动范式。# 接上段代码 # 3. 初始化Agent agent initialize_agent( toolsALL_TOOLS, llmllm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, # 使用ReAct代理 verboseTrue, # 设置为True可以看到Agent的思考过程 handle_parsing_errorsTrue, # 优雅地处理解析错误 max_iterations5, # 限制最大迭代次数防止死循环 early_stopping_methodgenerate # 当认为任务完成时提前停止 ) # 4. 运行Agent测试简单任务 print( 测试1: 基础计算 ) result1 agent.run(36的平方根是多少) print(f答案: {result1}\n) print( 测试2: 结合知识与工具 ) result2 agent.run(今天是几月几号顺便告诉我圆周率的前五位。) print(f答案: {result2}\n) print( 测试3: 使用网络搜索 ) # 注意网络搜索可能较慢且结果可能随时间变化 result3 agent.run(搜索一下今天科技圈最重要的新闻是什么) print(f答案: {result3}\n) print( 测试4: 使用数据库查询 ) result4 agent.run(从数据库中查询所有用户的姓名。) print(f答案: {result4})运行这个脚本你会看到类似以下的输出verbose模式 Entering new AgentExecutor chain... 我需要计算36的平方根。我有一个计算平方根的工具。 Action: Calculator_SquareRoot Action Input: 36 Observation: 36 的平方根是 6.0000 Thought: 我已经得到了答案。 Final Answer: 36的平方根是6。 答案: 36的平方根是6.verboseTrue让你能透视Agent的“思考链”Thought-Action-Observation这对于调试和理解Agent行为至关重要。4.3 Agent的核心工作流程通过上面的输出我们可以清晰地看到ReAct Agent的工作循环Thought思考LLM根据当前任务和之前的观察分析下一步该做什么。Action行动LLM决定调用哪个Tool并生成调用参数Action Input。Observation观察Tool被执行返回结果。循环LLM接收Observation再次进行Thought直到它认为任务完成输出Final Answer。这个循环使得Agent能够处理多步骤任务例如“搜索杭州的天气如果下雨就查一下从杭州到三亚的机票。” Agent会先调用天气搜索根据结果再决定是否调用机票查询。5. 进阶实战构建具备记忆与规划的专属业务Agent基础Agent只能处理单次对话。在实际业务中我们需要Agent能记住对话历史Memory并能处理更复杂的规划任务Planning。下面我们构建一个更强大的“数据分析助手”Agent。5.1 为Agent添加记忆Memory记忆使Agent能进行多轮对话记住上下文。LangChain提供了多种记忆后端。# agent_with_memory.py from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain.agents import initialize_agent, AgentType from langchain.chains import LLMChain from langchain.prompts import PromptTemplate from skills.advanced_skills import ADVANCED_TOOLS import pandas as pd from io import StringIO # 自定义一个技能分析CSV数据 def analyze_csv_data(csv_string: str, instruction: str) - str: 根据指令分析提供的CSV格式数据。输入的第一个参数是CSV字符串第二个参数是分析指令。 try: # 解析输入的参数LangChain有时会将两个参数合并为一个字符串传递 if | in csv_string: parts csv_string.split(|, 1) csv_content parts[0].strip() instruction parts[1].strip() if len(parts) 1 else instruction else: csv_content csv_string df pd.read_csv(StringIO(csv_content)) # 根据指令进行简单分析这是一个简化示例 if 描述 in instruction or summary in instruction.lower(): buffer StringIO() df.info(bufbuffer) info buffer.getvalue() desc df.describe().to_string() return f数据概览\n{info}\n\n统计描述\n{desc} elif 前几行 in instruction or head in instruction.lower(): return f数据前5行\n{df.head().to_string()} else: return f成功加载数据共 {len(df)} 行 {len(df.columns)} 列。列名{list(df.columns)}。请提供更具体的分析指令。 except Exception as e: return f数据分析出错{str(e)} from langchain.tools import Tool csv_tool Tool( nameAnalyzeCSV, funcanalyze_csv_data, description分析用户提供的CSV格式数据。输入应该包含两部分用竖线|分隔 第一部分是CSV格式的文本数据第二部分是分析指令如‘显示前几行’、‘数据描述’。 例如name,age\\nAlice,30\\nBob,25|显示前几行 ) # 创建带记忆的Agent llm ChatOpenAI(modelgpt-3.5-turbo, temperature0, openai_api_keyOPENAI_API_KEY) # 关键初始化记忆 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 创建Agent tools [csv_tool] ADVANCED_TOOLS agent_with_memory initialize_agent( toolstools, llmllm, agentAgentType.CONVERSATIONAL_REACT_DESCRIPTION, # 专为对话设计的Agent类型 verboseTrue, memorymemory, max_iterations5, handle_parsing_errorsTrue ) # 测试多轮对话 print( 第一轮对话 ) response1 agent_with_memory.run(你好我叫小明。) print(fAgent: {response1}\n) print( 第二轮对话Agent应该记得我的名字) response2 agent_with_memory.run(我刚才说我叫什么名字) print(fAgent: {response2}\n) # 测试数据分析 sample_csv product,sales,region Laptop,150,North Phone,200,South Tablet,120,North Monitor,80,East print( 第三轮对话数据分析 ) response3 agent_with_memory.run(f请分析这份销售数据{sample_csv}|数据描述) print(fAgent: {response3})5.2 实现复杂规划Planning与执行对于“写一份报告”、“制定旅行计划”这类复杂任务需要先规划步骤再执行。我们可以通过LLM 提示工程来实现一个简单的规划器。# planning_agent.py from langchain.schema import SystemMessage, HumanMessage import json class PlanningAgent: def __init__(self, llm, tools): self.llm llm self.tools {tool.name: tool for tool in tools} # 工具字典便于查找 self.planner_prompt SystemMessage(content你是一个任务规划专家。请将用户的复杂请求分解为一系列清晰的、可执行的步骤。 每个步骤必须对应一个可用的工具。输出一个JSON数组每个元素是一个步骤对象包含 step步骤序号、tool工具名称和 input工具输入。 可用的工具名称{tool_names}。 如果任务无法用现有工具完成请输出 []。 示例输入“查一下北京天气然后计算如果温度是25度相当于多少华氏度” 示例输出[ {{step: 1, tool: WebSearch, input: 北京今天天气}}, {{step: 2, tool: Calculator, input: (25 * 9/5) 32}} ] 请只输出JSON不要有其他文字。) def plan(self, user_query): # 1. 规划阶段 plan_prompt self.planner_prompt.format(tool_nameslist(self.tools.keys())) messages [plan_prompt, HumanMessage(contentuser_query)] response self.llm.invoke(messages).content try: steps json.loads(response.strip()) if not isinstance(steps, list): steps [] except json.JSONDecodeError: print(f规划器返回了非JSON内容{response}) steps [] return steps def execute(self, user_query): print(f用户请求: {user_query}) steps self.plan(user_query) if not steps: return 抱歉我无法用现有技能完成这个任务。 print(f规划步骤: {json.dumps(steps, ensure_asciiFalse, indent2)}) results [] for step in steps: tool_name step.get(tool) tool_input step.get(input, ) if tool_name not in self.tools: results.append(f步骤{step[step]}: 错误 - 未知工具 {tool_name}) continue print(f执行步骤{step[step]}: 调用 {tool_name}输入: {tool_input}) try: tool_result self.tools[tool_name].run(tool_input) results.append(f步骤{step[step]} ({tool_name}): {tool_result}) except Exception as e: results.append(f步骤{step[step]} ({tool_name}): 执行出错 - {str(e)}) return \n.join(results) # 使用示例 from langchain_openai import ChatOpenAI from skills.basic_skills import BASIC_TOOLS from skills.advanced_skills import ADVANCED_TOOLS llm ChatOpenAI(modelgpt-3.5-turbo, temperature0, openai_api_keyOPENAI_API_KEY) all_tools BASIC_TOOLS ADVANCED_TOOLS planner PlanningAgent(llm, all_tools) # 测试一个需要多步规划的任务 complex_task 先获取当前时间然后搜索‘人工智能最新突破’最后告诉我搜索结果的条数大概有多少。 result planner.execute(complex_task) print(\n 最终结果 ) print(result)这个PlanningAgent展示了“规划-执行”的经典模式。LLM首先作为规划器将复杂任务分解为顺序步骤然后作为执行器按步骤调用工具。这种模式比单一的ReAct Agent在处理复杂、线性任务时更具可控性。6. 工程化与生产环境最佳实践将原型Agent转化为稳定、可维护的生产系统需要关注以下方面6.1 技能Tool的管理与注册统一注册中心创建一个中心化的模块来注册和管理所有Skills避免散落在各处。版本控制对Skill进行版本管理记录变更。依赖隔离每个Skill应尽可能独立减少全局依赖考虑使用子进程或Docker容器隔离高风险技能如代码执行。# skill_registry.py class SkillRegistry: def __init__(self): self._tools {} self._categories {} def register(self, tool, categorygeneral): 注册一个技能 if tool.name in self._tools: raise ValueError(f工具名称 {tool.name} 已存在。) self._tools[tool.name] tool self._categories.setdefault(category, []).append(tool.name) print(f已注册技能: {tool.name} - {category}) def get_tool(self, name): return self._tools.get(name) def get_tools_by_category(self, category): return [self._tools[name] for name in self._categories.get(category, [])] def get_all_tools(self): return list(self._tools.values()) # 使用注册中心 registry SkillRegistry() registry.register(time_tool, categoryutility) registry.register(search_tool, categoryweb) registry.register(db_tool, categorydata)6.2 提示工程Prompt Engineering优化Agent的表现极大程度依赖于给LLM的提示Prompt。系统提示词System Prompt明确Agent的角色、能力和约束。system_prompt 你是一个专业的数据分析助手。你的核心能力是使用工具来获取和分析信息。 你必须遵守以下规则 1. 在回答用户问题前先思考是否需要使用工具。 2. 一次只使用一个工具。 3. 如果工具返回错误尝试理解错误原因并调整输入或告知用户。 4. 对于涉及个人隐私、数据库修改或危险操作的请求必须拒绝。 5. 最终答案应清晰、简洁并引用数据来源。工具描述优化持续迭代工具的描述使其更精准减少LLM的误调用。少样本学习Few-shot在Prompt中提供几个正确调用工具的示例能显著提升Agent表现。6.3 稳定性与错误处理超时控制为每个工具调用设置超时防止长时间阻塞。重试机制对于可能因网络波动失败的技能如API调用实现指数退避重试。优雅降级当某个技能不可用时Agent应能跳过或寻找替代方案而不是完全崩溃。解析错误处理LangChain Agent可能因为LLM输出格式不符合预期而抛出解析错误。务必使用handle_parsing_errorsTrue参数并准备一个后备响应。6.4 可观测性与日志记录完整链保存每次交互的Thought-Action-Observation链这是调试和优化Agent的黄金数据。性能监控记录每个工具调用的耗时、成功率。成本监控记录每次LLM调用的Token消耗特别是使用GPT-4等昂贵模型时。6.5 安全与权限这是生产部署的生命线。输入过滤与消毒对所有用户输入和工具输入进行严格检查防止注入攻击。工具权限分级将工具分为“安全”、“受限”、“危险”等级别。根据用户身份或上下文动态加载工具集。沙箱环境对于执行代码、访问文件系统的技能必须在安全的沙箱环境如Docker容器中运行。审计日志记录谁、在什么时候、使用了哪个工具、输入输出是什么。7. 常见问题与排查指南在开发Agent过程中你一定会遇到各种问题。以下是高频问题及解决方案。7.1 Agent不调用工具总是直接回答问题现象LLM无视可用工具试图用自己的知识回答问题。可能原因工具描述不清LLM无法理解工具用途。需要优化description明确使用场景和输入格式。系统提示词太弱没有在系统提示中强调“必须使用工具”。LLM温度Temperature过高导致输出随机性大。尝试将temperature设为0。解决方案在工具描述中使用“当需要...时使用此工具”、“输入应该是...”等明确句式。强化系统提示“你必须使用提供的工具来回答问题。禁止仅凭自身知识猜测。”在initialize_agent中尝试使用AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION它对工具调用的支持更好。7.2 Agent陷入死循环或重复调用同一工具问题现象Agent在Thought和Action间无限循环或反复执行相同操作。可能原因工具返回的结果无法让LLM推进任务结果格式混乱或信息不足。最大迭代次数max_iterations设置过高。任务本身无法用现有工具完成但LLM不愿承认。解决方案检查工具返回的结果是否清晰、结构化。确保错误信息明确。合理设置max_iterations通常5-10次足够。在系统提示中加入“如果你认为现有工具无法完成任务请直接告知用户不要无限尝试。”7.3 工具调用参数格式错误问题现象Action Input不是工具函数期望的格式导致工具执行失败。可能原因LLM没有正确理解工具所需的输入格式。解决方案在工具描述中用示例明确输入格式。例如“输入应为‘城市名’如‘北京’。”使用StructuredTool或Tool.from_function并指定args_schemaPydantic模型可以强制LLM生成结构化参数。from pydantic import BaseModel, Field class SearchInput(BaseModel): query: str Field(description搜索关键词) search_tool Tool.from_function( funcsearch.run, nameWebSearch, description搜索网络信息, args_schemaSearchInput # 指定参数模式 )7.4 处理复杂、模糊的用户请求问题现象用户提问“分析一下我们的数据”过于模糊。解决方案实现一个“澄清”技能。当LLM认为输入信息不足时可以调用一个特殊的“AskUserForClarification”工具该工具并不执行具体操作而是将问题返回给用户引导用户提供更具体的信息。这需要设计更复杂的Agent流程如使用LangGraph。7.5 性能与成本优化缓存对频繁且结果不变的查询如某些数据库查询、内部API调用实施缓存减少LLM和工具调用。流式输出对于长文本生成使用流式响应提升用户体验。模型选择在非核心推理步骤使用更小、更快的模型如gpt-3.5-turbo在需要深度思考时切换到大模型如gpt-4。构建高效的Agent系统是一个持续迭代的过程。从最小可行产品MVP开始聚焦核心流程然后逐步增加技能、优化提示、完善错误处理。始终以解决实际业务问题为导向避免陷入对“通用人工智能”的过度追求。希望这篇从原理到实战的长文能为你打下坚实的基础助你在AI应用开发的道路上少走弯路。