1. 项目背景与需求分析
最近在开发基于LangChain的智能体系统时,发现一个痛点:LangChain原生并不支持AgentSkills功能。这让我在构建需要特定技能组合的智能体时遇到了不少麻烦。经过调研发现,虽然DeepAgent等框架提供了相关能力,但如果我们想要一个更轻量、更可控的解决方案,从零开始实现可能是更好的选择。
AgentSkills本质上是一组可组合、可复用的能力模块,它允许智能体根据任务需求动态加载不同的技能组合。想象一下,你的智能体就像一个工具箱,而各种技能就是不同的工具——螺丝刀、锤子、扳手等。当需要修理家具时,拿出锤子和螺丝刀;当需要修理水管时,拿出扳手和密封胶。这种模块化设计让智能体更加灵活和可扩展。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心设计思路
2.1 技能定义规范
首先我们需要定义技能的标准化格式。参考行业实践,一个技能至少包含以下几个部分:
yaml复制# SKILL.md 示例
---
name: weather-query
description: 查询指定城市的天气情况
parameters:
city: 城市名称,如"北京"
output:
format: json
fields:
temperature: 当前温度(℃)
condition: 天气状况
humidity: 湿度(%)
---
这个YAML头定义了技能的基本元信息。接下来是技能的详细说明和使用示例:
markdown复制## 使用说明
1. 用户需提供有效的城市名称
2. 系统将返回当前天气数据
3. 示例请求: "查询北京的天气"
4. 示例响应:
```json
{
"temperature": 25,
"condition": "晴",
"humidity": 60
}
2.2 技能目录结构
合理的目录结构能让技能管理更清晰:
code复制skills/
├── weather/
│ ├── SKILL.md
│ ├── scripts/
│ │ └── query_weather.py
│ └── assets/
│ └── city_codes.json
└── translation/
├── SKILL.md
└── scripts/
└── translate_text.py
这种结构将技能描述、执行脚本和辅助资源分开存放,便于维护和扩展。
3. 实现细节
3.1 技能加载器实现
技能加载器是核心组件,负责发现和加载可用技能。以下是Python实现示例:
python复制import os
import yaml
from pathlib import Path
from typing import Dict, Any
class SkillLoader:
def __init__(self, skills_dir: str = "skills"):
self.skills_dir = Path(skills_dir)
self.skills = {}
def load_skills(self):
"""加载所有技能"""
for skill_dir in self.skills_dir.iterdir():
if skill_dir.is_dir():
skill_file = skill_dir / "SKILL.md"
if skill_file.exists():
with open(skill_file, 'r', encoding='utf-8') as f:
content = f.read()
# 分离YAML和Markdown
parts = content.split('---', 2)
if len(parts) >= 3:
meta = yaml.safe_load(parts[1])
meta['description'] = parts[2].strip()
self.skills[meta['name']] = meta
self.skills[meta['name']]['path'] = skill_dir
return self.skills
def get_skill(self, name: str) -> Dict[str, Any]:
"""获取特定技能"""
return self.skills.get(name)
3.2 技能执行引擎
技能执行需要处理不同类型的操作,这里我们实现一个基础版本:
python复制import subprocess
import json
from typing import Optional
class SkillExecutor:
@staticmethod
def execute_python_script(script_path: str, args: dict) -> Optional[dict]:
"""执行Python脚本形式的技能"""
try:
result = subprocess.run(
['python', script_path, json.dumps(args)],
capture_output=True,
text=True,
check=True
)
return json.loads(result.stdout)
except (subprocess.CalledProcessError, json.JSONDecodeError) as e:
print(f"执行技能失败: {e}")
return None
@staticmethod
def execute_skill(skill_name: str, args: dict, skills: dict) -> Optional[dict]:
"""执行指定技能"""
skill = skills.get(skill_name)
if not skill:
return None
script_dir = skill['path'] / 'scripts'
if script_dir.exists():
for script in script_dir.iterdir():
if script.suffix == '.py':
return SkillExecutor.execute_python_script(str(script), args)
return None
4. 与LangChain集成
4.1 自定义Tool实现
为了让技能能在LangChain中使用,我们需要将其包装成Tool:
python复制from langchain.tools import BaseTool
from typing import Optional, Type
class SkillTool(BaseTool):
name: str
description: str
skill_executor: SkillExecutor
skills_info: dict
def _run(self, query: str) -> str:
"""执行技能"""
args = {'query': query}
result = self.skill_executor.execute_skill(self.name, args, self.skills_info)
return json.dumps(result, ensure_ascii=False)
async def _arun(self, query: str) -> str:
raise NotImplementedError("异步执行暂不支持")
4.2 动态Tool加载
根据当前任务需求动态加载相关技能:
python复制from langchain.agents import initialize_agent, AgentType
from langchain.llms import OpenAI
def setup_agent(skill_names: list, llm=OpenAI(temperature=0)):
"""初始化带技能的Agent"""
loader = SkillLoader()
skills = loader.load_skills()
executor = SkillExecutor()
tools = []
for name in skill_names:
if name in skills:
tools.append(SkillTool(
name=name,
description=skills[name]['description'],
skill_executor=executor,
skills_info=skills
))
return initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
5. 高级功能实现
5.1 技能组合与管道
有时需要将多个技能串联使用,比如先翻译再查询天气:
python复制class SkillPipeline:
def __init__(self, skills: list):
self.skills = skills
self.executor = SkillExecutor()
self.loader = SkillLoader()
self.skills_info = self.loader.load_skills()
def run(self, initial_input: dict) -> dict:
result = initial_input
for skill in self.skills:
result = self.executor.execute_skill(skill, result, self.skills_info)
if result is None:
break
return result
5.2 技能权限控制
在生产环境中,我们需要控制不同智能体对技能的访问权限:
python复制class SkillAccessController:
def __init__(self, role_skills_mapping: dict):
self.mapping = role_skills_mapping
def get_accessible_skills(self, role: str) -> list:
return self.mapping.get(role, [])
def can_access(self, role: str, skill: str) -> bool:
return skill in self.get_accessible_skills(role)
6. 实战示例:构建天气查询智能体
让我们用一个完整示例演示如何使用这个框架:
python复制# 初始化技能
loader = SkillLoader('skills')
skills = loader.load_skills()
# 设置执行器
executor = SkillExecutor()
# 创建天气查询工具
weather_tool = SkillTool(
name='weather-query',
description=skills['weather-query']['description'],
skill_executor=executor,
skills_info=skills
)
# 初始化Agent
agent = initialize_agent(
[weather_tool],
OpenAI(temperature=0),
agent=[Agent](https://taotoken.net?utm_source=ai)Type.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# 执行查询
response = agent.run("上海现在的天气怎么样?")
print(response)
7. 性能优化技巧
在实际使用中,我们发现几个性能瓶颈和优化点:
- 技能缓存:频繁加载技能描述文件会影响性能,可以添加缓存机制:
python复制from functools import lru_cache
class CachedSkillLoader(SkillLoader):
@lru_cache(maxsize=32)
def load_skills(self):
return super().load_skills()
- 并行执行:对于可以并行执行的技能,可以使用多线程:
python复制from concurrent.futures import ThreadPoolExecutor
class ParallelSkillExecutor(SkillExecutor):
def execute_multiple(self, skill_tasks: list) -> dict:
with ThreadPoolExecutor() as executor:
futures = {
executor.submit(
self.execute_skill,
task['skill'],
task['args'],
task['skills']
): task['skill']
for task in skill_tasks
}
results = {}
for future in futures:
results[futures[future]] = future.result()
return results
- 技能预热:提前加载常用技能,减少首次执行延迟:
python复制def preload_common_skills(loader: SkillLoader):
common_skills = ['weather-query', 'translation', 'calculator']
loader.load_skills()
print(f"已预热 {len(common_skills)} 个常用技能")
8. 错误处理与调试
在技能开发过程中,良好的错误处理机制至关重要:
8.1 技能验证工具
python复制import jsonschema
from typing import Tuple
class SkillValidator:
SCHEMA = {
"type": "object",
"properties": {
"name": {"type": "string"},
"description": {"type": "string"},
"parameters": {"type": "object"},
"output": {"type": "object"}
},
"required": ["name", "description"]
}
@classmethod
def validate_skill(cls, skill_meta: dict) -> Tuple[bool, str]:
try:
jsonschema.validate(instance=skill_meta, schema=cls.SCHEMA)
return True, "验证通过"
except jsonschema.ValidationError as e:
return False, f"验证失败: {e.message}"
8.2 技能执行日志
python复制import logging
from datetime import datetime
class SkillLogger:
def __init__(self):
logging.basicConfig(
filename='skills.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def log_execution(self, skill: str, args: dict, success: bool):
status = "成功" if success else "失败"
logging.info(
f"执行技能 {skill} {status} - 参数: {args}"
)
def log_error(self, skill: str, error: Exception):
logging.error(
f"技能 {skill} 执行错误: {str(error)}",
exc_info=True
)
9. 测试策略
为确保技能质量,需要建立完善的测试体系:
9.1 单元测试示例
python复制import unittest
from unittest.mock import patch
class TestSkillSystem(unittest.TestCase):
def setUp(self):
self.loader = SkillLoader('tests/test_skills')
def test_skill_loading(self):
skills = self.loader.load_skills()
self.assertIn('test-skill', skills)
self.assertEqual(skills['test-skill']['name'], 'test-skill')
@patch('subprocess.run')
def test_skill_execution(self, mock_run):
mock_run.return_value.stdout = '{"result": "ok"}'
executor = SkillExecutor()
result = executor.execute_skill(
'test-skill',
{'param': 'value'},
{'test-skill': {'path': 'tests/test_skills/test-skill'}}
)
self.assertEqual(result, {'result': 'ok'})
9.2 集成测试方案
python复制class IntegrationTest:
def test_end_to_end(self):
# 初始化所有组件
loader = SkillLoader()
executor = SkillExecutor()
validator = SkillValidator()
# 加载并验证技能
skills = loader.load_skills()
for name, skill in skills.items():
valid, msg = validator.validate_skill(skill)
self.assertTrue(valid, msg)
# 执行测试用例
test_cases = [
('weather-query', {'city': '北京'}),
('translation', {'text': 'hello', 'target': 'zh'})
]
for skill, args in test_cases:
result = executor.execute_skill(skill, args, skills)
self.assertIsNotNone(result, f"{skill} 执行失败")
10. 部署与维护
10.1 技能热更新
实现无需重启服务的技能更新:
python复制import watchdog.events
import watchdog.observers
import time
class SkillFileHandler(watchdog.events.FileSystemEventHandler):
def __init__(self, loader: SkillLoader):
self.loader = loader
def on_modified(self, event):
if event.src_path.endswith('SKILL.md'):
print(f"检测到技能变更: {event.src_path}")
self.loader.load_skills()
def start_skill_watcher(loader: SkillLoader):
observer = watchdog.observers.Observer()
handler = SkillFileHandler(loader)
observer.schedule(handler, path='skills', recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
10.2 技能版本控制
建议将技能目录纳入Git管理,方便版本控制和回滚:
bash复制skills/
├── .gitignore
├── weather/
│ ├── SKILL.md
│ └── scripts/
└── translation/
├── SKILL.md
└── scripts/
11. 安全注意事项
在实现技能系统时,安全是重中之重:
- 脚本执行沙箱:所有技能脚本应在受限环境中运行
- 参数校验:严格校验输入参数,防止注入攻击
- 权限隔离:不同技能应有不同的文件系统访问权限
- 资源限制:限制脚本的执行时间和内存使用
python复制import resource
def set_resource_limits():
# 限制CPU时间(秒)
resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
# 限制内存(MB)
resource.setrlimit(resource.RLIMIT_AS, (256 * 1024 * 1024, 256 * 1024 * 1024))
12. 扩展思路
这个基础框架还可以进一步扩展:
- 远程技能仓库:从远程服务器动态加载技能
- 技能市场:实现技能的分享和下载机制
- 技能依赖管理:处理技能间的依赖关系
- 技能性能监控:收集技能执行指标,用于优化
python复制class RemoteSkillLoader:
def __init__(self, repo_url: str):
self.repo_url = repo_url
def load_remote_skill(self, skill_name: str):
"""从远程仓库加载特定技能"""
# 实现HTTP请求下载技能包
pass
def sync_all_skills(self):
"""同步所有远程技能"""
pass
13. 替代方案比较
与现有解决方案相比,我们的实现有以下优势:
| 特性 | 本实现 | DeepAgent | LangChain原生 |
|---|---|---|---|
| 轻量级 | ✓ | ✗ | ✓ |
| 无需额外依赖 | ✓ | ✗ | ✓ |
| 完全可控 | ✓ | ✗ | ✓ |
| 易于定制 | ✓ | 部分 | ✗ |
| 性能开销小 | ✓ | ✗ | ✓ |
| 学习曲线平缓 | ✓ | ✗ | ✓ |
14. 常见问题解决
在实际使用中,可能会遇到以下问题:
-
技能加载失败
- 检查SKILL.md格式是否正确
- 确认文件路径权限
- 验证YAML语法
-
脚本执行无输出
- 检查脚本执行权限
- 确认Python环境正确
- 添加脚本日志输出
-
性能瓶颈
- 启用技能缓存
- 优化脚本性能
- 考虑并行执行
-
权限问题
- 检查文件系统权限
- 验证技能访问控制列表
- 确保沙箱配置正确
15. 总结与展望
通过这个项目,我们实现了一个轻量级但功能完备的AgentSkills系统,成功解决了LangChain原生不支持技能管理的问题。这个方案具有以下特点:
- 模块化设计,易于扩展
- 与LangChain无缝集成
- 灵活的技能组合方式
- 完善的安全控制机制
未来可以考虑添加更多高级特性,如技能版本管理、自动回滚机制、技能性能分析等。这个框架已经在我们多个生产项目中稳定运行,大大提升了智能体的灵活性和可维护性。
