Langchain 最近更新的 Agent Skills 机制,值得所有做 Agent 应用的人重新看一遍。它不是又加了一个 API,而是把“写死工具列表 + 写死 Prompt”那套玩法,升级成了“给 Agent 一个技能包,让它自己决定怎么用”。这个转变,对开发方式的冲击比想象中更大。
先说判断:Agent Skills 真正解决的问题,是 Agent 应用里最头疼的“组合爆炸”。以前每增加一个能力,你要改 system prompt、改工具注册表、改任务路由逻辑,功能越多代码越碎。现在官方把这层抽象成了 Skills 架构,Agent 自身负责调用、编排和决策,开发者只需要把“技能”描述清楚。这意味着,写 Agent 的姿势正在从“写程序”变成“写说明书 + 配技能包”。
这篇文章会用 12 个实际案例,带你拆解这套架构到底是什么,能解决什么问题,有哪些坑。内容偏实操,建议边读边试。
1. 为什么 Agent Skills 突然火起来了
先说背景。Langchain 在 Agent 方向已经迭代了很多版本,从最早期单纯的 Chain 串联,到后来引入 ReAct、Plan-and-Execute 等多种 Agent 范式,再到 Langgraph 做图状态编排。能力在变强,但开发者始终面临同一个尴尬:构建一个稍微像样的 Agent,要把 Prompt 工程、工具定义、记忆策略、路由逻辑全部揉在一起。
没有 Agent Skills 时,你想让 Agent 具备“数据库查询”的能力,通常要经历这些步骤:
- 在 system prompt 里描述数据库有哪些表、字段含义。
- 写几个 Tool 函数,比如
query_db、get_schema,注册到 Agent 的工具列表。 - 处理 Tool 返回的原始结果,再拼装成自然语言。
- 如果数据库类型变了,或者换了业务场景,又得重新调 prompt 和工具参数。
这个过程不难,但非常琐碎。问题在于:Agent 的核心价值是自主决策,但开发者却在替它把每一步都规定死。
Agent Skills 的思路是:把一组相关的指令、工具、模板、校验逻辑打包成一个“技能”。Agent 收到用户请求后,自己判断需要哪些技能,再加载这个技能的上下文和工具来执行。
用生活中的类比来理解:传统开发方式是你请了一个员工,然后给他一本极其详细的 SOP,每一步都写清楚。Agent Skills 的方式是,你告诉员工“你具备数据分析、报告生成、可视化三种能力”,具体怎么组合完成目标,员工自己决定。
这个转变真正解决的是Agent 能力的标准化封装与复用。技能包可以在不同 Agent 之间共享,可以在社区分发,也可以按场景组合。
2. 核心概念:Agent、Tool、Skill 的区别
开始写案例之前,必须先厘清三组概念,否则后面容易混。
2.1 Tool 与 Skill 的关系
Tool(工具)是 Agent 可以直接调用的函数,通常是独立、原子性的,比如“执行 SQL”“调用天气 API”“计算两个日期差值”。
Skill(技能)是一个更高层的抽象,它将多个工具、指令模板、上下文说明、验证逻辑组合在一起。你可以理解为:
Tool = 一个会做某件事的函数 Skill = 一套完成某类任务的能力包(包含工具、规则、步骤、校验和常见错误处理)一个 Skill 内部可以包含多个 Tool。Skill 不只是工具的集合,还包括如何使用这些工具的知识。比如“生成数据分析报告”这个技能,里面要有数据库查询工具、Markdown 模板、图表生成工具,还要有告诉模型“先了解表结构、再写查询、最后生成结论”的指令。
2.2 Skill 与 Prompt 的关系
很多人会问:这不就是把 Prompt 写长一点吗?
区别在于:Skill 不只是 Prompt 文本,它附带了可执行的工具定义、输入输出约束、验证逻辑、示例数据。Prompt 只影响模型“怎么想”,Skill 还决定了模型“能做什么”。换个角度说,Prompt 是给模型的提示,Skill 是给 Agent 的完整能力模块。
2.3 Langchain 与 Langgraph 的定位差异
Langchain 是构建 Agent 应用的综合框架,提供了模型接入、Prompt 管理、Tool 封装、RAG、记忆等能力。Langgraph 专注于状态化、可编排的 Agent 工作流,适用于需要多轮状态管理、条件跳转、复杂分支的 Agent。
Agent Skills 不是一个独立的框架,而是 Langchain 层面的能力抽象。它和 Langgraph 的关系是:Langgraph 负责编排 Agent 的整体流程,Skills 负责定义 Agent 在某一步调用的具体能力。
做一个简单的对比表:
| 维度 | Tool | Skill | Langgraph 节点 |
|---|---|---|---|
| 粒度 | 最小可调用单元 | 一组能力的封装 | 工作流中的一个执行步骤 |
| 是否包含指令 | 否,只有函数逻辑 | 是,包含指令和使用说明 | 否,包含状态转移逻辑 |
| 典型例子 | 查询天气的函数 | 完整的数据分析技能包 | 对话管理、任务分发节点 |
理解到这层,后面的 12 个案例才看得明白。
3. Agent Skills 的整体架构
先看架构层面。一个完整的 Agent Skills 方案,通常由 5 个层次组成:
- 模型层:底层大语言模型,负责理解用户请求、调用技能、生成回复。
- 技能注册层:维护一个技能清单,记录每个技能的 ID、名称、描述、所需工具、适用场景。
- 技能加载层:根据用户输入动态选择技能,并将技能内的指令模板、工具定义注入模型上下文。
- 工具执行层:实际执行技能内部的工具调用,完成数据获取、参数计算等操作。
- 校验与反馈层:校验执行结果是否符合预期,出错时负责重试或降级。
在 Langchain 中,一个 Agent Skill 的典型设计包括以下部分:
- name:技能名称,如
data_analysis_skill - description:技能描述,Agent 根据描述决定是否使用该技能
- instructions:如何使用该技能的指令,注入 system prompt
- tools:技能执行时用到的工具列表
- templates:输入输出模板
- validators:参数或输出校验器
用户的请求进来后,Agent 会先判断需要哪些技能,然后按需加载。
3.1 架构上的变化:从“代码驱动”到“声明式驱动”
过去你用 Langchain 构建 Agent,核心代码是:
agent = create_react_agent(llm, tools=[tool1, tool2, tool3])所有工具对 Agent 来说都是平铺的,Agent 只能根据描述自行选择。一旦工具多了,模型容易选错工具,或者不知道该先用哪个。
有了 Agent Skills 后,架构变成:
agent = create_agent_with_skills(llm, skills=[skill_a, skill_b])Agent 先选择技能,再在技能范围内选择工具。这相当于把“工具选择空间”先缩小到“技能选择空间”,再在技能内部执行工具,显著降低了模型决策难度。
3.2 为什么说这套架构是分水岭
传统 Agent 是“模型 + 工具 + 提示词”的三明治结构,所有逻辑都暴露在开发者的代码里。而 Skills 架构把任务能力从主流程中抽离,变成了可插拔的模块。
这带来三个直接好处:
- 复用性提升:一个“数据分析技能”可以在客服 Agent、运营 Agent、研发辅助 Agent 中复用。
- 维护成本下降:修改某个技能内部逻辑时,不需要动主 Agent 代码。
- 协作边界清晰:擅长 Prompt 的成员负责写技能指令,擅长工程的同学负责写技能内部工具,互不阻塞。
4. 环境准备与前置条件
进入实操前先准备好环境。以下步骤主要针对 Langchain 的新版本,具体版本号以你实际安装为准。
4.1 创建 Python 虚拟环境
python -m venv agent_skills_env source agent_skills_env/bin/activate # Windows 系统使用 agent_skills_env\Scripts\activate4.2 安装 Langchain
pip install --upgrade langchain langchain-openai langchain-core如果你需要用到 Langgraph 来做复杂的 Agent 编排,再安装:
pip install langgraph4.3 准备模型 API Key
本文中的示例以 OpenAI 兼容接口为例。你可以在环境变量中配置:
export OPENAI_API_KEY="your-api-key"如果你的模型服务不是 OpenAI,而是国内大模型平台或其他兼容接口,只需要替换 Langchain 中的模型实例即可,案例的 Agent Skills 逻辑是通用的。
4.4 验证环境是否正常
python -c "import langchain; print(langchain.__version__)"打印出版本号说明安装成功。接下来我们进入案例环节。
5. 12 个案例拆解:从入门到进阶
接下来是全文最核心的部分。12 个案例按难度递增排列,从最简单的最小技能,到复杂的数据分析、多 Agent 协同、工具类技能组合。建议每个案例都自己跑一遍,再修改参数测试效果。
案例 1:定义一个最基础的 Skill
以“代码注释生成器”为例,演示如何定义一个最小可用的 Skill。
from langchain_core.tools import tool from langchain_core.language_models.chat_models import BaseChatModel from langchain_openai import ChatOpenAI from langchain.agents import create_agent @tool def get_function_code(func_name: str) -> str: """根据函数名称获取项目中该函数的源代码。""" # 实际项目中这里会从代码仓库读取 return """ def add(a, b): return a + b """ code_comment_skill = { "name": "code_comment_generator", "description": "为指定函数生成注释,输入为函数名,输出为带注释的代码。", "instructions": """ 当用户要求为函数生成注释时: 1. 使用 get_function_code 获取函数源代码。 2. 分析函数逻辑。 3. 在函数定义的下一行插入功能说明、参数说明、返回值说明。 """, "tools": [get_function_code], } llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) # 将技能中的 tools 平铺给 agent,并将 instructions 注入 system prompt agent = create_agent(llm, tools=[get_function_code], system_prompt=code_comment_skill["instructions"]) response = agent.invoke({"input": "请为 add 函数生成注释"}) print(response["output"])这个案例有三个关键点:
- Skill 是 Python 字典对象,最重要的是
description和instructions。description用于 Agent 判断何时使用该技能,instructions是技能内部的使用方法。 - 本例没有用官方的“技能注册/加载”高级 API,而是先把技能手动平铺到 agent 中。目的是让你理解技能的本质,不是魔法,而是“指令 + 工具 + 逻辑的组合”。
- 输出结果时,模型会根据 instructions 中的步骤顺序执行,先拿代码,再写注释。
案例 2:多工具组合技能
单个工具太简单,真实场景往往需要多个工具配合。以“项目周报生成”为例,这个技能需要两个工具:获取 Git 提交记录、获取需求列表。
from langchain_core.tools import tool from datetime import datetime, timedelta @tool def get_git_commits(repo_path: str) -> str: """获取指定仓库最近一个工作日的 git 提交记录。""" # 真实场景中会执行 git log 命令 return "feat: 添加登录功能\nfix: 修复订单超时问题\nrefactor: 重构用户模块" @tool def get_task_list(project_id: str) -> str: """获取指定项目的任务完成情况。""" return "已完成: 3个任务\n进行中: 2个任务\n待开始: 1个任务" week_report_skill = { "name": "weekly_report", "description": "根据 git 提交记录和项目任务列表,生成周报。", "instructions": """ 生成周报时: 1. 先调用 get_git_commits 获取代码提交记录。 2. 再调用 get_task_list 获取任务完成情况。 3. 将两者组织成周报格式:本周完成 / 存在问题 / 下周计划。 """, "tools": [get_git_commits, get_task_list], } agent = create_agent( llm, tools=[get_git_commits, get_task_list], system_prompt=week_report_skill["instructions"], ) response = agent.invoke({"input": "生成项目 PROJ-1001 的本周周报"}) print(response["output"])这个案例想说明的是:技能内部可以有多个工具,且工具之间通常有执行顺序。在这个设计里,指令模板就是告诉模型“你先查代码,再查需求,最后汇总”。相比让模型自己摸索顺序,这种显式规定成功率更高。
案例 3:带输入校验的 Skill
实际生产中,技能参数经常会被传错。比如用户让 Agent“查询上周的数据”,但技能只支持“按日期查”。如果没有校验机制,Agent 会拿一个模糊的时间范围去调工具,然后返回一堆脏数据。
我们可以在技能中加入参数校验逻辑:
from pydantic import BaseModel, Field class DateQueryInput(BaseModel): start_date: str = Field(description="开始日期,格式 YYYY-MM-DD") end_date: str = Field(description="结束日期,格式 YYYY-MM-DD") @tool(args_schema=DateQueryInput) def query_sales(start_date: str, end_date: str) -> str: """查询指定日期范围内的销售数据。""" # 模拟查询结果 return f"销售数据: {start_date} 至 {end_date}, 总销售额 100000 元" data_query_skill = { "name": "sales_query", "description": "查询销售数据,只支持按日期范围查询。", "instructions": """ 当用户查询销售数据时: 1. 必须先确认开始日期和结束日期。 2. 如果用户没有提供日期,询问用户。 3. 日期格式必须是 YYYY-MM-DD。 """, "tools": [query_sales], }这个案例的价值点是:args_schema让工具具备结构化的参数约束。模型在调用工具之前,会先按 Pydantic 模型校验参数。参数不对时,Langchain 会要求模型重新生成符合要求的参数。
实际开发中,不要偷懒省掉参数校验。AI 生成的内容再聪明,也可能出现错误格式。
案例 4:使用模板引擎生成结构化输出
很多技能的输出需要固定格式,比如 JSON、Markdown、HTML。只靠模型“自觉”遵守格式会不稳定,比较可靠的做法是给它一个模板,让它“填空式”输出。
下面这个案例是“生成数据库表设计文档”:
table_doc_template = """ ## 表名: {table_name} ### 字段说明 | 字段名 | 类型 | 是否必填 | 说明 | | --- | --- | --- | --- | {field_rows} ### 索引设计 {index_rows} ### 备注 {notes} """ @tool def get_table_meta(table_name: str) -> str: """获取数据库表结构元数据。""" return [ {"field": "id", "type": "bigint", "nullable": "否", "comment": "主键"}, {"field": "name", "type": "varchar(64)", "nullable": "否", "comment": "用户名"}, ] table_doc_skill = { "name": "table_doc_generator", "description": "根据表名生成数据库表结构说明文档。", "instructions": """ 1. 使用 get_table_meta 工具获取表结构元数据。 2. 将元数据填充到 table_doc_template 模板中。 3. 最终输出完整的 Markdown 文档。 """, "tools": [get_table_meta], }模板方式的核心价值是减少生成式输出的不确定性。只要模板约束了结构,模型输出的部分就只有内容,格式是稳定可控的。如果你正在做报表、合同、代码生成、API 文档等场景,建议都采用模板方案。
案例 5:带记忆的 Skill
Agent 的上下文记忆问题,一直是被问得最多的问题之一。Langchain 中记忆组件五花八门,但在技能架构里,记忆应该如何设计?
推荐的做法是:把记忆设计成技能内部的一个工具,而不是全局的一团状态。
from langchain_core.tools import tool memory_store = {} @tool def save_note(key: str, content: str) -> str: """保存一条笔记到长期记忆。""" memory_store[key] = content return "已保存" @tool def get_note(key: str) -> str: """读取指定键的笔记。""" return memory_store.get(key, "未找到相关笔记") note_skill = { "name": "meeting_memory", "description": "记录会议中的关键结论和待办事项,并在后续对话中调用。", "instructions": """ 当用户提到会议、结论、待办事项时: 1. 如果是第一次提到,使用 save_note 保存。 2. 如果用户后续询问,使用 get_note 查询。 3. 注意区分不同会议,key 建议使用 会议名称_日期。 """, "tools": [save_note, get_note], }这里的关键是:记忆不再是黑盒,而是显式的“保存”和“读取”工具。这有 3 个好处:
- Agent 知道自己在什么时候“记住了东西”,什么时候该“调用记忆”。
- 调试容易,你可以直接查看 memory_store 里的内容。
- 后续可以无缝替换成 Redis、向量数据库,只需要改工具内部实现。
案例 6:数据分析类技能(多步骤编排)
数据分析是 Agent 场景里最常见的需求之一。一个完整的数据分析技能,至少包含以下步骤:
- 获取数据表结构。
- 生成 SQL 并执行。
- 对结果做聚合计算。
- 输出分析结论。
用一个简化示例展示:
from langchain_core.tools import tool @tool def get_schema() -> str: """获取数据库所有表的结构。""" return """ table: orders columns: order_id, customer_id, amount, created_at table: customers columns: customer_id, name, city """ @tool def run_sql(sql: str) -> str: """执行 SQL 查询,只允许 SELECT 语句。""" # 生产环境需要严格校验 SQL,防止注入 return "北京, 1500\n上海, 1200\n广州, 900" analysis_skill = { "name": "sales_analysis", "description": "分析销售数据,输出结论和趋势。", "instructions": """ 数据分析步骤: 1. 先调用 get_schema 了解表结构。 2. 根据用户问题编写 SQL,关键:只允许 SELECT。 3. 调用 run_sql 执行查询。 4. 根据结果总结趋势、指出异常,最后给出建议。 """, "tools": [get_schema, run_sql], }这个案例真正体现了 Agent 结合技能和执行能力的价值。模型负责拆解问题、编写 SQL、解读结果;工具负责真实的数据访问。你自己看数据可能半天才能得出结论,Agent 在几秒内就能输出一份包含结论的回复。实际项目中,需要注意的地方是 run_sql 的实现必须要做安全过滤,不能让模型拼接出DROP TABLE这类危险语句。
案例 7:RAG 检索问答技能
Langchain 最经典的场景之一就是 RAG。把 RAG 做成技能,好处是可以针对不同知识库配置不同的检索策略。
from langchain_community.vectorstores import FAISS from langchain_openai import OpenAIEmbeddings from langchain_core.tools import tool # 假设已有一个向量数据库 vectorstore = FAISS.load_local("faiss_index", OpenAIEmbeddings(), allow_dangerous_deserialization=True) retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) @tool def search_docs(query: str) -> list: """在知识库中检索与问题相关的内容。""" docs = retriever.invoke(query) return [doc.page_content for doc in docs] rag_skill = { "name": "internal_docs_qa", "description": "基于内部知识库回答员工问题,适用于制度、流程、产品文档。", "instructions": """ 当用户询问内部制度或流程时: 1. 调用 search_docs 检索相关文档片段。 2. 优先基于检索内容回答,不要编造。 3. 如果检索内容不足以回答,告诉用户“该问题暂未找到相关信息”。 """, "tools": [search_docs], }这个技能值得注意的地方是第 3 条指令。如果不加这条,模型很容易在检索不到信息时强行编造答案。加上了,就引导模型保守回答。做企业知识库问答时,这几乎是必须的设计。
案例 8:代码生成 + 自动执行技能
代码类 Agent 很受欢迎,但实际使用中最怕代码生成错误、运行报错。可以把代码生成、执行、报错修复三个步骤封装在一个技能中。
import subprocess @tool def write_and_run_code(code: str) -> str: """将生成的 Python 代码保存并运行,返回执行结果或报错信息。""" with open("generated_code.py", "w", encoding="utf-8") as f: f.write(code) result = subprocess.run( ["python", "generated_code.py"], capture_output=True, text=True, timeout=30, ) if result.returncode == 0: return f"运行成功:\n{result.stdout}" return f"运行失败:\n{result.stderr}" coding_skill = { "name": "python_coder", "description": "编写并运行 Python 代码,帮助用户解决编程问题。", "instructions": """ 1. 根据用户需求编写完整 Python 代码。 2. 调用 write_and_run_code 执行代码。 3. 如果执行失败,根据报错信息修改代码后再次运行。 4. 最终将运行结果反馈给用户。 """, "tools": [write_and_run_code], }这个技能模式下,Agent 成为一个简单的“自动编程执行器”。测试环境可以这么玩,但生产环境要非常谨慎,因为让模型直接执行生成的代码有安全风险。只建议在沙箱环境、测试环境中开启。
案例 9:工作流路由技能
一个复杂的 Agent,往往内部有多个技能。技能之间不是相互独立的,而是根据用户意图做路由分发。
用“需求分析助手”举例,它既能写 PRD,也能面 SQL,还能生成原型描述。路由怎样做?
@tool def route_request(query: str) -> str: """判断用户请求属于哪个技能。""" if "prd" in query.lower() or "需求文档" in query: return "write_prd" elif "sql" in query.lower() or "数据库" in query: return "write_sql" else: return "unknown" router_skill = { "name": "request_router", "description": "将用户请求路由到合适的技能。", "instructions": """ 当用户提出需求时: 1. 先调用 route_request 判断属于哪个技能。 2. 如果路由结果是 write_prd,调用 write_prd_skill。 3. 如果路由结果是 write_sql,调用 write_sql_skill。 """, "tools": [route_request], }这个路由方案在实现上还可以升级为向量相似度匹配。把每个技能的描述向量化,用户输入进来后用余弦相似度找最合适的技能。Langchain 里可以用VectorStoreToolkit做类似的事。
案例 10:组合式技能:一个技能调用另一个技能
高级场景下,技能之间也需要协作。比如“生成数据分析报告”技能内部,要调用“数据查询”技能和“图表生成”技能。
@tool def get_report_data(metric: str) -> str: """获取某个指标的数据序列。""" return f"{metric}: 10, 15, 23, 42, 56" @tool def generate_chart(data: str) -> str: """将数据序列转换为图表 Markdown 代码。""" images = [""] return images[0] composite_skill = { "name": "data_report", "description": "生成一份完整的数据分析报告。", "instructions": """ 生成数据分析报告的步骤: 1. 使用 get_report_data 获取原始数据。 2. 使用 generate_chart 生成趋势图。 3. 综合数据和图表,输出 Markdown 格式的报告。 """, "tools": [get_report_data, generate_chart], }这种设计把“查询数据”和“生成图表”拆成两个可复用的工具,但组合逻辑依然由 Agent 完成。如果你有很多报表需求,可以基于这个思路构建一个报表技能族。
案例 11:多 Agent 协同下的 Skills
规模再大一点,就需要 Langgraph 来编排多个 Agent,每个 Agent 拥有不同的 Skills。比如一个“项目复盘助手”系统:
- 数据收集 Agent:拥有
git_log_skill、task_query_skill - 分析 Agent:拥有
metrics_calculation_skill - 报告生成 Agent:拥有
report_template_skill
Langgraph 负责 Flow,每个节点是 Agent,每个 Agent 有自己的 Skills。
下面是一个极简示意:
from langgraph.graph import StateGraph class AgentState(dict): messages: list def collect_node(state): # 调用数据收集 Agent,内部使用 git_log_skill return state def analyze_node(state): # 调用分析 Agent,内部使用 metrics_calculation_skill return state def report_node(state): # 调用报告 Agent,内部使用 report_template_skill return state graph = StateGraph(AgentState) graph.add_node("collect", collect_node) graph.add_node("analyze", analyze_node) graph.add_node("report", report_node) graph.add_edge("collect", "analyze") graph.add_edge("analyze", "report") graph.set_entry_point("collect") graph.set_finish_point("report") app = graph.compile()这个案例说明了一个重要架构判断:单 Agent + 单技能的思路只能做 Demo;生产中复杂任务,要靠 Langgraph 编排多个 Agent,每个 Agent 拥有专职技能。这样每个 Agent 的上下文更短、决策更准确,调试也更容易。
案例 12:对外发布一个可复用的技能包
最后一个案例,是把自己开发的技能做成可复用的包,分享给团队或社区。
Langchain 支持自定义工具和技能封装。一个典型技能包目录如下:
my_agent_skills/ ├── pyproject.toml ├── my_agent_skills/ │ ├── __init__.py │ ├── analysis_skill.py │ ├── report_skill.py │ └── utils.py └── examples/ └── demo.py其中pyproject.toml声明依赖:
[project] name = "my-agent-skills" version = "0.1.0" dependencies = [ "langchain-core>=0.2", "langchain-openai>=0.1" ]技能模块里,把 Skill 定义导出:
# my_agent_skills/analysis_skill.py from langchain_core.tools import tool @tool def analyze_text(text: str) -> dict: """分析文本的情感倾向和关键词。""" return { "sentiment": "positive", "keywords": ["高效", "稳定", "易用"], } analysis_skill = { "name": "text_analysis", "description": "分析用户文本的关键词和情感。", "instructions": "当用户请求分析文本时,使用 analyze_text 工具。", "tools": [analyze_text], }团队成员可以直接引用这个模块:
from my_agent_skills.analysis_skill import analysis_skill这个案例的核心价值是工程化。技能的封装和发布,最终会决定团队协作效率。规范接口、版本管理、依赖声明,都是实际落地中会让你少踩很多坑的细节。
6. 运行结果与效果验证
上面 12 个案例,每个都可以独立运行。但运行只是第一步,如何验证 Agent 真的“拥有”了技能,才是关键。
6.1 验证技能是否生效
最简单的验证方式是直接输入一个覆盖技能场景的问题:
response = agent.invoke({"input": "请分析项目 PROJ-1001 的周报"}) print(response["output"])预期应该看到 Agent 按 Skill 中 instructions 规定的顺序执行工具:先获取 git 记录,再获取任务列表,最后输出周报。
6.2 调试手段
如果 Agent 没有按预期执行技能,建议做这几步检查:
- 查看模型原始调用链:Langchain 支持回调回调机制,通过
LangSmithTracer或自定义BaseCallbackHandler来看每一步究竟调用了哪个工具。 - 检查系统提示词:确认
system_prompt确实注入了技能的instructions。 - 单测每个工具:直接用 Python 调用工具函数,看返回值是否符合预期。工具本身出错,Agent 再聪明也没用。
# 验证工具 print(get_git_commits.invoke({"repo_path": "/tmp/repo"}))6.3 失败时的第一排查思路
如果技能完全没有被调用,优先检查技能的description是否清晰。description直接决定了模型是否会在正确场景触发该技能。
比如,"查询销售数据,只支持按日期范围查询"这样的描述,模型很容易理解。如果写成"sales_data_query_function",模型大概率不会触发。
7. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Agent 不调用技能 | description 不清晰,或没有触发场景 | 检查技能描述是否包含用户常见的说法 | 重写 description,加入同义词和典型问法 |
| 工具参数传错 | args_schema 未定义,或定义过于宽泛 | 查看 Langchain 日志中的 tool call 参数 | 用 Pydantic 定义严格的参数模型 |
| 技能内部工具执行顺序混乱 | instructions 步骤不够明确 | 在 instructions 中增加“先…再…最后…” | 显式规定工具调用顺序 |
| 模型回答与工具返回结果不符 | system prompt 和工具输出之间缺少衔接指令 | 检查 tool 结果是否被截断 | 加长工具返回的上下文,或让模型完整引用工具结果 |
| 并发执行时内存溢出 | 技能内部缓存/store 设计不当 | 查看进程内存占用 | 将存储迁移到 Redis 等独立中间件 |
| 生产环境技能更新不生效 | 技能代码被缓存 | 检查 Agent 启动方式 | 改为动态加载技能配置,支持热更新 |
| 工具执行报错,Agent 无法恢复 | 缺少错误恢复指令 | 观察重试次数 | 在 instructions 中加入“如果工具报错,请尝试修复参数后重试,或告知用户失败原因” |
| 数据泄露风险 | 工具未做权限隔离 | 审核工具对应的数据范围 | 为不同场景配置独立的数据访问控制 |
8. 最佳实践与工程建议
8.1 技能拆分原则
一个技能不应该太大,也不应该太小。判断标准是:
- 技能是否具备完整的目标闭环?
- 技能是否可以被多个场景复用?
- 技能内部工具是否高度内聚?
比如“生成数据分析报告”可以作为一个技能;但“查询数据库” + “生成图表” + “生成文字结论”如果拆成三个独立技能,会让 Agent 面对不必要的路由压力;如果硬放在一个技能里,复用性又差。
推荐的折中方案是:把“查询数据库”做成底层能力,把“生成图表”做成另一个底层能力,然后再封装一个“数据分析报告”组合技能。
8.2 指令模板设计建议
写instructions时要避免模糊表述。看两个对比:
错误示范:
当用户查询数据时,你应该分析数据并给出答案。正确示范:
当用户查询数据时: 1. 使用 get_schema 获取表结构。 2. 编写 SQL,校验 SQL 只包含 SELECT 关键字。 3. 调用 run_sql 执行查询。 4. 如果结果为空,告知用户“暂无数据”,不要凭空编造。 5. 输出结论时,列出关键数据指标。Agent 对确定性步骤的执行成功率,远高于模糊指示。把步骤拆细,是成本最低也最有效的提升 Agent 性能的方法。
8.3 安全与权限控制
技能内部工具具有真实的执行能力,必须遵循最小权限原则:
- 数据库工具只开放 SELECT 或指定表,禁止 DDL、DML。
- 文件操作工具限制在指定目录内,防止路径穿越。
- 外部 API 调用需要在网关层限制域名和频次。
- 涉及隐私数据查询时,需要接入权限校验,不能让模型权限成为权限后门。
安全边界是 Agent 应用落地中最严肃的部分,不要因为“只是 Demo”而放松。
8.4 监控与日志
日志至少要覆盖:
- 用户问题原文
- Agent 选择了哪个技能
- 技能内部调用了哪些工具
- 工具执行结果摘要
- 模型最终输出
这些日志不仅是调试的依据,也是你判断技能是否好用的数据来源。如果某个技能总是触发失败,从日志里能很快看出来。
8.5 多技能时的路由策略
技能数量超过 5 个后,一次把全部技能的描述都塞给模型,会拉长上下文,也会影响决策准确率。两种方案:
- 显式路由:先用一个小的分类器或关键词规则判断意图,再加载对应的技能包。
- 向量检索路由:将技能描述向量化,用户请求进来后用相似度匹配 TopN 技能。Langchain 的
create_retriever_tool可以辅助实现。
在实战场景里,显式路由通常比完全依赖模型做技能选择更稳定。
8.6 版本管理与治理
技能也是代码。团队协作时要纳入版本管理,遵循以下规范:
- 一个技能一个目录,目录内包含描述文件、工具代码、测试用例。
- 技能变更走 MR 流程,附带变更说明。
- 对技能做版本标记,Agent 端固定引用指定版本,防止“昨天还能用,今天不行了”。
9. 对 Langchain 与 Langgraph 架构选型的建议
很多读者纠结:到底应该直接用 Langchain 的 Agent,还是用 Langgraph 自己编排?
谈谈判断标准:
- 如果你的 Agent 只有 1 到 3 个技能,任务链路短,直接用 Langchain Agent + Skills 完全够用。
- 如果你的 Agent 需要处理多轮状态、条件分支、人工审核、超时重试,使用 Langgraph 编排,把每个环节做成一个节点,技能放在各节点内部。
还要提一下 Langchain 和 Langgraph 的关系。Langgraph 更底层的定位是“Agent 工作流引擎”,Langchain 提供的是“构建 Agent 的组件库”。两者不是二选一,而是可以并存:Langgraph 做流程控制,Langchain 提供工具、技能、模型接入能力。
从当前 Langchain 的迭代趋势看,Agent Skills 正在成为核心抽象层。它解决的是 Agent 开发中最痛的问题:能力如何标准化?如何复用?如何治理?这也是这篇文章最想让你理解的点:Agent Skills 不是一个新功能,而是一套关于 Agent 能力组织方式的架构设计。沿着这个思路做下去,不只是使用一个框架的某个 API,而是在建立你自己的 Agent 工程化方法论。
10. 总结与后续学习方向
这 12 个案例从最小技能定义、工具组合、参数校验、模板输出,一直讲到多 Agent 协同和技能包发布。核心想传达的判断是:
Agent Skills 把“Agent 的能力”从一个抽象概念,变成了一个可定义、可组合、可复用、可治理的工程对象。有了这套抽象,开发 Agent 的方式会从“写死一切逻辑”变成“定义能力边界,让模型在边界内自主决策”。
建议你的下一步实践路径:
- 从案例 1 开始,先定义一个属于自己业务场景的最简技能。
- 跑通之后,逐步增加工具、校验、指令模板。
- 当你觉得技能变多了,再引入 Langgraph 做流程编排。
- 关注 Langchain 官方仓库中关于 Agent Skills 的更新,架构还在快速迭代。
如果想深入,优先看这几个方向:
- Langchain 官方文档中 Agent 与 Tool 的部分。
- Langgraph 教程里的多 Agent 协作例子。
- Pydantic 官方文档,掌握参数校验工具。
收藏这篇文章,找个周末跑通前 5 个案例,你对 Agent Skills 的理解会超过大部分人。