从零构建Agent框架:LLM与Tool服务的模块化实现指南
一、引言:Agent框架的服务层设计意义
在Agent框架的架构中,服务层(Service Layer)是连接智能体核心逻辑与外部能力的桥梁。它通过抽象化LLM(大语言模型)和Tool(工具)的调用接口,实现以下核心价值:
- 解耦性:将模型推理与工具执行分离,降低系统耦合度
- 可扩展性:支持动态添加新模型或工具而无需修改核心逻辑
- 复用性:统一的服务接口使不同Agent可共享相同能力
本篇将聚焦LLM Service和Tool Service的实现,通过Python代码展示如何构建这两个关键模块,并讨论设计模式的选择。
二、LLM Service实现:模型调用的抽象层
1. 基础接口设计
from abc import ABC, abstractmethodfrom typing import Dict, Any, Optionalclass LLMService(ABC):"""大语言模型服务抽象基类"""@abstractmethodasync def complete(self,prompt: str,system_prompt: Optional[str] = None,temperature: float = 0.7,max_tokens: int = 2000,**kwargs) -> Dict[str, Any]:"""完成文本生成"""pass@abstractmethoddef get_model_info(self) -> Dict[str, Any]:"""获取模型信息"""pass
2. 具体实现示例(OpenAI兼容版)
import aiohttpfrom .base import LLMServiceclass OpenAICompatibleLLM(LLMService):def __init__(self, api_key: str, base_url: str = "https://api.openai.com/v1"):self.api_key = api_keyself.base_url = base_urlself.model = "gpt-3.5-turbo" # 默认模型async def complete(self, prompt: str, **kwargs) -> Dict:url = f"{self.base_url}/chat/completions"headers = {"Authorization": f"Bearer {self.api_key}"}messages = [{"role": "user", "content": prompt}]if kwargs.get("system_prompt"):messages.insert(0, {"role": "system", "content": kwargs["system_prompt"]})payload = {"model": self.model,"messages": messages,"temperature": kwargs.get("temperature", 0.7),"max_tokens": kwargs.get("max_tokens", 2000)}async with aiohttp.ClientSession() as session:async with session.post(url, json=payload, headers=headers) as resp:return await resp.json()def get_model_info(self) -> Dict:return {"provider": "openai", "model": self.model}
3. 设计要点解析
- 异步支持:使用
async/await处理网络请求,避免阻塞事件循环 - 参数标准化:统一温度、最大token等参数的命名和默认值
- 消息格式化:自动处理系统提示与用户提示的拼接
- 错误处理:实际实现中应添加重试机制和异常捕获
三、Tool Service实现:工具调用的标准化方案
1. 工具注册与发现机制
from typing import Callable, Dict, List, Coroutine, Anyclass ToolRegistry:"""工具注册中心"""def __init__(self):self._tools: Dict[str, Dict] = {}def register(self,name: str,func: Callable[..., Coroutine[Any, Any, Any]],description: str,required_params: List[str] = None) -> None:"""注册工具"""self._tools[name] = {"func": func,"description": description,"required_params": required_params or []}def get_tool(self, name: str) -> Dict:"""获取工具信息"""return self._tools.get(name)async def execute(self, name: str, **kwargs) -> Any:"""执行工具"""tool = self._tools.get(name)if not tool:raise ValueError(f"Tool {name} not found")# 参数校验逻辑...return await tool["func"](**kwargs)
2. 具体工具实现示例(搜索引擎)
from .registry import ToolRegistryimport aiohttpasync def search_web(query: str, num_results: int = 5) -> Dict:"""模拟搜索引擎工具"""# 实际实现应调用真实搜索引擎APIreturn {"results": [{"title": f"Result {i}", "url": f"https://example.com/{i}", "snippet": "Sample snippet"}for i in range(num_results)]}# 注册工具registry = ToolRegistry()registry.register(name="web_search",func=search_web,description="Perform web search",required_params=["query"])
3. 工具调用链实现
class ToolChain:"""工具调用链管理器"""def __init__(self, registry: ToolRegistry):self.registry = registryself.chain = []def add_tool(self, tool_name: str, input_mapping: Dict[str, str]) -> None:"""添加工具到调用链"""self.chain.append({"tool": tool_name,"input_mapping": input_mapping # 输入参数映射})async def execute(self, initial_input: Dict) -> Any:"""执行工具链"""current_input = initial_inputfor step in self.chain:tool = self.registry.get_tool(step["tool"])if not tool:raise ValueError(f"Tool {step['tool']} not found")# 构建工具调用参数tool_args = {k: current_input.get(v)for k, v in step["input_mapping"].items()}# 执行工具并更新输入current_input = await self.registry.execute(step["tool"], **tool_args)return current_input
四、服务集成与最佳实践
1. 服务依赖注入模式
class AgentContext:"""Agent上下文,管理服务依赖"""def __init__(self):self.llm_service: Optional[LLMService] = Noneself.tool_registry: Optional[ToolRegistry] = Nonedef set_llm_service(self, service: LLMService) -> None:self.llm_service = servicedef set_tool_registry(self, registry: ToolRegistry) -> None:self.tool_registry = registry
2. 服务配置管理建议
- 环境变量配置:使用
.env文件管理API密钥等敏感信息 - 服务发现:支持从配置文件动态加载服务实现
- 熔断机制:为LLM服务添加请求限流和失败重试
- 缓存层:对频繁调用的工具结果进行缓存
3. 测试策略
import pytestfrom unittest.mock import AsyncMockfrom my_agent.services import OpenAICompatibleLLM@pytest.mark.asyncioasync def test_llm_completion():# 创建模拟响应mock_response = {"choices": [{"message": {"content": "Test response"}}]}# 创建带模拟客户端的LLM服务llm = OpenAICompatibleLLM("fake-key")llm.client = AsyncMock()llm.client.post.return_value.__aenter__.return_value.json = AsyncMock(return_value=mock_response)# 测试调用result = await llm.complete("Test prompt")assert result["choices"][0]["message"]["content"] == "Test response"
五、扩展性设计:插件架构
1. 插件接口定义
from typing import Protocolclass AgentPlugin(Protocol):"""Agent插件协议"""async def setup(self, context: AgentContext) -> None:"""插件初始化"""passasync def teardown(self) -> None:"""插件清理"""pass
2. 插件加载示例
import importlibfrom pathlib import Pathfrom typing import Listclass PluginManager:"""插件管理器"""def __init__(self, plugin_dirs: List[str]):self.plugin_dirs = plugin_dirsself.plugins: List[AgentPlugin] = []async def load_plugins(self, context: AgentContext) -> None:"""加载所有插件"""for dir_path in self.plugin_dirs:for entry in Path(dir_path).glob("*.py"):module_name = entry.stemspec = importlib.util.spec_from_file_location(module_name,str(entry))if spec is None:continuemodule = importlib.util.module_from_spec(spec)spec.loader.exec_module(module)if hasattr(module, "PLUGIN_CLASS"):plugin_class = getattr(module, "PLUGIN_CLASS")if isinstance(plugin_class, type) and issubclass(plugin_class, AgentPlugin):plugin = plugin_class()await plugin.setup(context)self.plugins.append(plugin)
六、总结与展望
本篇详细阐述了Agent框架中LLM Service和Tool Service的实现方案,核心要点包括:
- 通过抽象基类定义标准化接口
- 采用异步编程模式提升并发性能
- 实现工具注册与发现机制
- 设计可扩展的插件架构
未来方向可考虑:
- 添加服务监控与日志系统
- 实现多模型路由策略
- 开发可视化工具配置界面
- 增加服务版本管理功能
通过模块化的服务设计,开发者可以构建出既稳定又灵活的Agent系统,为后续添加规划、记忆等高级功能奠定坚实基础。