大模型Agent面试精选15题(第六辑)
本文是Agent面试题的第六辑,精选15道关于Agent工程实践的高频面试题,涵盖API设计、中间件、插件系统、版本管理、测试方法、监控系统、日志管理、调试技巧、CI/CD、DevOps、容器化部署、微服务架构等核心知识点,适合准备大模型应用岗位面试的同学。
字数约 8000,预计阅读 16 分钟
一、Agent API与架构设计篇(3题)
01|如何设计 Agent 的 API 接口?需要考虑哪些因素?
参考答案:
设计原则:
-
RESTful 设计
- 使用标准的 HTTP 方法(GET、POST、PUT、DELETE)
- 资源导向的 URL 设计
- 统一的响应格式
- 状态码规范使用
-
易用性
- 清晰的接口命名
- 完整的参数说明
- 详细的错误信息
- 丰富的文档和示例
-
扩展性
- 支持版本控制(如
/api/v1/agent) - 可选的参数设计
- 向后兼容
- 插件化架构
- 支持版本控制(如
-
安全性
- 身份认证(API Key、OAuth)
- 权限控制
- 请求限流
- 数据加密
关键因素:
-
接口设计
接口设计需要遵循RESTful规范,使用标准的HTTP方法和资源导向的URL。请求体应包含用户消息、会话ID、可选工具列表、流式输出标志和温度参数等。响应格式应统一,包含Agent回复、会话ID、工具调用记录和使用统计信息(Token消耗、成本等)。使用JSON格式进行数据交换,确保跨平台兼容性。
典型的接口设计示例:
- 请求:
POST /api/v1/agent/chat,包含消息、会话ID、工具列表等参数 - 响应:包含回复内容、工具调用记录、Token使用统计等
- 请求:
-
异步支持
Agent API需要支持异步处理机制,主要包括:
- 流式响应(Streaming):支持Server-Sent Events (SSE)或WebSocket,实现逐Token返回,提升用户体验
- 长任务异步处理:对于耗时操作,采用异步任务模式,返回任务ID,客户端可轮询查询状态
- Webhook回调机制:任务完成后通过Webhook主动通知客户端,减少轮询开销
- 任务状态查询:提供任务状态查询接口,支持查询进度、结果和错误信息
-
错误处理
建立完善的错误处理机制:
- 统一的错误码体系:定义标准错误码,便于客户端识别和处理
- 详细的错误信息:提供清晰的错误描述和错误原因
- 错误恢复建议:在错误响应中包含修复建议或重试策略
- 重试机制:支持自动重试和指数退避策略,提高系统容错性
-
性能优化
通过多种技术手段提升API性能:
- 请求缓存:对相同请求进行缓存,减少重复计算
- 批量处理:支持批量请求处理,提高吞吐量
- 连接池管理:复用HTTP连接,减少连接建立开销
- 超时控制:设置合理的请求超时时间,避免资源浪费
实现要点:
使用FastAPI等现代Web框架实现API接口,通过Pydantic进行请求参数验证,确保数据格式正确。接口实现应包含参数验证、Agent调用、结果封装和异常处理等步骤。对于参数验证失败的情况,返回400状态码;对于系统内部错误,返回500状态码并记录详细日志。使用异步函数处理请求,提高并发处理能力。
最佳实践:
- 使用 OpenAPI/Swagger 文档
- 实现请求限流和熔断
- 提供 SDK 和示例代码
- 监控 API 使用情况
- 定期进行性能测试
02|Agent 中间件如何设计?有哪些常见的中间件模式?
参考答案:
中间件的作用:
中间件是 Agent 系统中处理请求和响应的组件,可以在请求处理前后执行特定逻辑,实现横切关注点(Cross-cutting Concerns)。
设计原则:
-
链式处理
- 中间件按顺序执行
- 每个中间件可以修改请求/响应
- 支持提前终止链
-
可组合性
- 中间件独立实现
- 可以灵活组合
- 易于测试和维护
-
异步支持
- 支持异步处理
- 不阻塞主流程
- 提高性能
常见中间件模式:
-
认证中间件(Authentication)
认证中间件负责验证请求的身份信息,通常从请求头中提取API Key或Token,验证其有效性。如果认证失败,返回401未授权状态码,阻止请求继续处理。支持多种认证方式,如API Key、OAuth 2.0、JWT等。
-
日志中间件(Logging)
日志中间件记录每个请求的详细信息,包括请求路径、请求时间、处理时长、响应状态等。在请求处理前后记录时间戳,计算处理耗时,便于性能分析和问题排查。支持结构化日志输出,便于日志分析和监控。
-
限流中间件(Rate Limiting)
限流中间件防止系统过载,通过滑动窗口或令牌桶算法限制每个客户端在时间窗口内的请求次数。维护每个客户端的请求时间戳列表,清理过期记录,检查当前请求数是否超过限制。如果超过限制,返回429状态码(Too Many Requests)。
-
错误处理中间件(Error Handling)
错误处理中间件统一捕获和处理异常,将不同类型的异常转换为标准的HTTP错误响应。验证错误返回400,认证错误返回401,系统错误返回500并记录详细日志。确保错误信息对用户友好,同时保留详细的调试信息供开发人员排查。
-
缓存中间件(Caching)
缓存中间件通过缓存响应结果减少重复计算,提高系统性能。根据请求生成缓存键,检查缓存中是否存在有效数据(未过期),如果存在直接返回缓存结果,否则执行处理并将结果存入缓存。支持设置TTL(Time To Live)控制缓存有效期。
-
监控中间件(Monitoring)
监控中间件收集系统运行指标,包括请求延迟、请求数量、成功率、错误率等。在请求处理前后记录时间戳,计算延迟并上报到监控系统。区分成功和失败的请求,分别记录指标,便于系统健康度评估和告警。
中间件链实现:
中间件链采用责任链模式,按顺序执行各个中间件。每个中间件接收请求和下一个处理器的引用,可以修改请求或响应,也可以提前终止链的执行。通过递归或迭代方式实现链式调用,确保中间件按配置顺序执行。中间件的执行顺序很重要,通常认证和限流应在业务逻辑之前执行,监控和日志应在最后执行以确保记录完整信息。
最佳实践:
- 中间件职责单一
- 避免中间件之间的依赖
- 合理设置执行顺序
- 提供配置选项
- 记录中间件执行时间
03|如何设计 Agent 的插件系统?插件如何与 Agent 交互?
参考答案:
插件系统的作用:
插件系统允许第三方开发者扩展 Agent 的功能,实现工具、能力、行为的动态加载,提高系统的灵活性和可扩展性。
设计原则:
-
标准化接口
- 统一的插件接口规范
- 清晰的插件生命周期
- 明确的权限和资源访问规则
-
隔离性
- 插件独立运行
- 错误隔离
- 资源隔离
-
可发现性
- 插件注册机制
- 插件元数据管理
- 插件市场/仓库
插件接口设计:
插件系统需要定义标准化的接口规范,所有插件必须实现基础接口。接口应包含插件的基本信息(名称、版本、描述)、生命周期方法(初始化、执行、清理)和功能定义。对于工具类插件,还需要定义工具列表,描述每个工具的名称、描述和参数。使用抽象基类或接口定义,确保插件实现的一致性。
插件注册与管理:
插件管理器负责插件的注册、卸载、查询和生命周期管理。注册插件时需要检查插件名称是否已存在,避免冲突。同时维护插件的元数据信息,包括版本、描述和配置信息。插件初始化时加载配置,卸载时清理资源。提供插件查询接口,支持按名称获取插件或列出所有已注册的插件。
插件与 Agent 交互:
-
工具注册方式
当插件加载到Agent系统时,如果是工具类插件,Agent会提取插件提供的工具列表,并将这些工具注册到Agent的工具库中。每个工具记录其所属插件信息,当Agent需要调用工具时,通过工具名称找到对应的插件,调用插件的执行方法。这种方式实现了插件与Agent的解耦,Agent无需了解工具的具体实现细节。
-
事件驱动交互
插件可以注册事件处理器,监听Agent系统中的特定事件(如用户消息、工具调用、错误发生等)。当事件发生时,Agent触发相应的事件,插件的事件处理器被调用,可以执行自定义逻辑。这种机制允许插件在Agent执行流程的特定节点进行干预或扩展。
-
钩子(Hook)机制
钩子机制允许插件在Agent执行的关键节点插入自定义逻辑。常见的钩子包括:执行前钩子(可以修改请求参数)、执行后钩子(可以修改响应结果)、工具调用钩子(可以拦截或修改工具调用)。钩子机制提供了更细粒度的控制,使插件能够深度集成到Agent的执行流程中。
插件实现要点:
插件实现需要遵循接口规范,提供清晰的工具定义和参数说明。初始化时加载配置信息,执行时根据动作类型和参数执行相应功能,清理时释放资源。工具类插件需要返回符合规范的工具描述,包括工具名称、功能描述和参数定义,以便Agent正确识别和调用。
插件安全机制:
-
权限控制
- 定义插件权限级别
- 限制资源访问
- 操作审计
-
沙箱执行
- 隔离执行环境
- 资源限制
- 异常捕获
-
签名验证
- 插件签名验证
- 来源验证
- 版本检查
最佳实践:
- 提供插件开发 SDK
- 完善的插件文档
- 插件版本管理
- 插件市场/仓库
- 插件性能监控
二、Agent版本与迁移篇(3题)
04|Agent 系统如何实现版本兼容性?有哪些策略?
参考答案:
版本兼容性的重要性:
版本兼容性确保系统升级时不影响现有用户和功能,实现平滑过渡,减少迁移成本。
兼容性策略:
-
语义化版本(Semantic Versioning)
- 主版本号(Major):不兼容的 API 变更
- 次版本号(Minor):向后兼容的功能新增
- 修订号(Patch):向后兼容的问题修复
- 例如:
v1.2.3→v2.0.0表示不兼容更新
-
API 版本控制
版本控制可以通过多种方式实现:
- URL路径版本控制 :在URL中包含版本号,如
/api/v1/agent/chat和/api/v2/agent/chat,不同版本使用不同的路由 - 请求头版本控制 :通过HTTP请求头指定版本,如
X-API-Version: v2或Accept: application/vnd.agent.v2+json - 查询参数版本控制 :通过URL查询参数指定版本,如
/api/agent/chat?version=v2
推荐使用URL路径版本控制,因为它最直观且易于管理。
- URL路径版本控制 :在URL中包含版本号,如
-
向后兼容设计
在设计新版本API时,应尽量保持向后兼容。通过以下方式实现:
- 使用可选参数和默认值,新参数不影响旧版本调用
- 保留旧字段名,同时支持新字段名,内部进行映射
- 新功能通过可选参数启用,默认行为与旧版本一致
- 避免删除或修改必需参数,如需变更应通过适配器转换
-
适配器模式(Adapter Pattern)
使用适配器模式处理不同版本之间的差异。版本适配器负责将旧版本请求转换为新版本格式,或将新版本响应转换为旧版本格式。适配器需要处理字段名变更、数据结构变化、参数映射等问题。通过适配器,可以在内部统一使用最新版本的实现,同时对外提供多版本支持。
-
弃用策略(Deprecation)
当需要废弃某个功能时,应采用渐进式弃用策略:
-
在文档中标记为已弃用,说明替代方案和迁移时间表
-
在代码中发出警告,提醒开发者使用新方法
-
保持旧功能继续工作一段时间,给用户迁移时间
-
在内部调用新方法实现,确保功能一致性
return self.new_method(param)
def new_method(self, param):
"""新方法"""
新实现
pass
-
-
配置驱动兼容性
pythonclass CompatibilityConfig: """兼容性配置""" SUPPORTED_VERSIONS = ["v1", "v2", "v3"] DEFAULT_VERSION = "v2" # 版本特性映射 VERSION_FEATURES = { "v1": ["basic_chat", "simple_tools"], "v2": ["basic_chat", "simple_tools", "streaming", "advanced_tools"], "v3": ["basic_chat", "simple_tools", "streaming", "advanced_tools", "multimodal"] } @classmethod def is_feature_supported(cls, version: str, feature: str) -> bool: """检查版本是否支持某个特性""" return feature in cls.VERSION_FEATURES.get(version, [])
实现要点:
版本化的API实现需要维护版本处理器映射表,根据请求中的版本信息选择对应的处理器。使用版本适配器将不同版本的请求转换为统一格式,在内部使用最新版本的逻辑处理,然后将响应适配回请求的版本格式。版本确定遵循优先级:显式指定的版本 > 请求中的版本 > 默认版本。这种方式既保证了内部实现的一致性,又对外提供了多版本支持。
最佳实践:
- 明确版本策略和生命周期
- 提供版本迁移指南
- 维护版本兼容性测试
- 及时通知用户版本变更
- 保留旧版本足够长时间
05|如何将旧版 Agent 迁移到新版本?迁移方案有哪些?
参考答案:
迁移策略:
-
渐进式迁移(Gradual Migration)
- 逐步迁移用户和功能
- 降低风险
- 可以快速回滚
- 适合大规模系统
-
一次性迁移(Big Bang Migration)
- 一次性完成迁移
- 迁移速度快
- 风险较高
- 适合小规模系统
-
并行运行(Parallel Running)
- 新旧版本同时运行
- 对比验证
- 平滑切换
- 适合关键系统
迁移方案:
-
数据迁移方案
pythonclass DataMigration: """数据迁移工具""" def migrate_conversations(self, old_version: str, new_version: str): """迁移对话数据""" # 1. 导出旧数据 old_data = self.export_old_data(old_version) # 2. 转换数据格式 new_data = self.transform_data(old_data, old_version, new_version) # 3. 验证数据 if not self.validate_data(new_data): raise MigrationError("Data validation failed") # 4. 导入新数据 self.import_new_data(new_data, new_version) # 5. 验证迁移结果 self.verify_migration(old_data, new_data) def transform_data(self, old_data: List[Dict], old_v: str, new_v: str) -> List[Dict]: """转换数据格式""" transformer = DataTransformer(old_v, new_v) return [transformer.transform(item) for item in old_data] -
配置迁移方案
pythonclass ConfigMigration: """配置迁移工具""" def migrate_config(self, old_config: Dict, target_version: str) -> Dict: """迁移配置""" migration_map = { "v1_to_v2": self._v1_to_v2_config, "v2_to_v3": self._v2_to_v3_config } current_version = old_config.get("version", "v1") migration_key = f"{current_version}_to_{target_version}" if migration_key in migration_map: return migration_map[migration_key](old_config) else: raise ValueError(f"No migration path from {current_version} to {target_version}") def _v1_to_v2_config(self, v1_config: Dict) -> Dict: """v1 配置转换为 v2""" return { "version": "v2", "agent": { "model": v1_config.get("model_name"), # 字段重命名 "temperature": v1_config.get("temp", 0.7), "max_tokens": v1_config.get("max_length", 1000) }, "tools": v1_config.get("capabilities", []), # 字段重命名 "memory": { "type": "conversation", "max_history": v1_config.get("history_length", 10) } } -
代码迁移方案
pythonclass CodeMigration: """代码迁移工具""" def generate_migration_script(self, old_code: str, target_version: str) -> str: """生成迁移脚本""" # 分析代码依赖 dependencies = self.analyze_dependencies(old_code) # 生成迁移代码 migration_code = self.generate_code(dependencies, target_version) return migration_code def analyze_dependencies(self, code: str) -> Dict: """分析代码依赖""" # 解析导入 imports = self.extract_imports(code) # 识别 API 调用 api_calls = self.identify_api_calls(code) return { "imports": imports, "api_calls": api_calls } -
用户迁移方案
pythonclass UserMigration: """用户迁移工具""" def migrate_user(self, user_id: str, target_version: str): """迁移用户""" # 1. 备份用户数据 backup = self.backup_user_data(user_id) # 2. 迁移用户配置 self.migrate_user_config(user_id, target_version) # 3. 迁移用户数据 self.migrate_user_data(user_id, target_version) # 4. 通知用户 self.notify_user(user_id, target_version) def rollback_user(self, user_id: str): """回滚用户迁移""" backup = self.get_backup(user_id) if backup: self.restore_user_data(user_id, backup)
迁移流程:
迁移管理器负责协调整个迁移过程,包括数据迁移、配置迁移和用户迁移。迁移流程通常包括以下步骤:
-
预检查阶段:评估迁移可行性,检查系统状态,验证数据完整性,确保满足迁移前置条件。
-
备份阶段:在迁移前创建完整的数据备份,包括对话历史、配置信息、用户数据等,确保可以回滚。
-
执行迁移阶段:根据迁移计划逐步执行各项迁移任务:
- 数据迁移:转换对话历史、工具调用记录等数据结构
- 配置迁移:迁移系统配置、插件配置等
- 用户迁移:迁移用户数据、权限设置等
-
验证阶段:验证迁移后的数据完整性和系统功能,确保迁移成功。
-
清理阶段:清理临时文件、释放资源,完成迁移。
如果迁移过程中出现错误,应立即执行回滚操作,恢复系统到迁移前的状态。
迁移检查清单:
-
迁移前
- 评估迁移影响范围
- 制定迁移计划
- 准备回滚方案
- 备份所有数据
- 通知相关用户
-
迁移中
- 监控迁移进度
- 验证数据完整性
- 测试关键功能
- 记录迁移日志
-
迁移后
- 验证系统功能
- 对比新旧版本性能
- 收集用户反馈
- 更新文档
最佳实践:
- 制定详细的迁移计划
- 在测试环境充分验证
- 提供迁移工具和文档
- 支持回滚机制
- 监控迁移过程
- 及时处理迁移问题
06|Agent 系统如何支持多版本共存?有哪些实现方式?
参考答案:
多版本共存的意义:
支持多版本共存允许系统同时运行多个版本的 Agent,满足不同用户需求,实现平滑升级,降低迁移风险。
实现方式:
-
路由层版本分发
在路由层实现版本分发,根据请求中的版本信息将请求路由到对应版本的处理器。版本信息可以从URL路径(如
/api/v1/agent/chat)、请求头(如X-API-Version: v2)或查询参数(如?version=v2)中提取。每个版本有独立的处理器,维护版本处理器的映射表,根据提取的版本信息选择对应的处理器。如果请求未指定版本,使用默认版本。 -
命名空间隔离
通过命名空间实现不同版本的隔离,每个版本运行在独立的命名空间中,包括独立的Agent实例、配置和资源。命名空间管理器维护各版本的命名空间映射,确保不同版本之间不会相互干扰。
def get_agent(self, version: str) -> Agent: """获取指定版本的 Agent""" if version not in self.namespaces: raise ValueError(f"Version {version} not found") return self.namespaces[version].agent class Namespace: """命名空间""" def __init__(self, name: str, agent: Agent): self.name = name self.agent = agent self.config = {} self.data_store = {} -
容器化部署
yaml# docker-compose.yml version: '3.8' services: agent-v1: image: agent:v1.0.0 ports: - "8001:8000" environment: - VERSION=v1 agent-v2: image: agent:v2.0.0 ports: - "8002:8000" environment: - VERSION=v2 agent-v3: image: agent:v3.0.0 ports: - "8003:8000" environment: - VERSION=v3 gateway: image: nginx:latest ports: - "8000:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf -
API 网关配置
nginx# nginx.conf upstream agent_v1 { server agent-v1:8000; } upstream agent_v2 { server agent-v2:8000; } upstream agent_v3 { server agent-v3:8000; } server { listen 80; location /api/v1/ { proxy_pass http://agent_v1/; } location /api/v2/ { proxy_pass http://agent_v2/; } location /api/v3/ { proxy_pass http://agent_v3/; } } -
版本管理器
pythonclass VersionManager: """版本管理器""" def __init__(self): self.versions = {} self.default_version = "v2" self.version_configs = { "v1": {"enabled": True, "deprecated": True}, "v2": {"enabled": True, "deprecated": False}, "v3": {"enabled": True, "deprecated": False} } def register_version(self, version: str, agent: Agent, config: Dict = None): """注册版本""" self.versions[version] = { "agent": agent, "config": config or {}, "created_at": datetime.now() } def get_version(self, version: str = None) -> Agent: """获取版本实例""" version = version or self.default_version if version not in self.versions: raise ValueError(f"Version {version} not found") version_info = self.version_configs.get(version, {}) if not version_info.get("enabled", False): raise ValueError(f"Version {version} is disabled") return self.versions[version]["agent"] def list_versions(self) -> List[str]: """列出所有可用版本""" return [ v for v, config in self.version_configs.items() if config.get("enabled", False) ] def deprecate_version(self, version: str): """弃用版本""" if version in self.version_configs: self.version_configs[version]["deprecated"] = True -
数据隔离
pythonclass VersionedDataStore: """版本化数据存储""" def __init__(self): self.stores = { "v1": DataStoreV1(), "v2": DataStoreV2(), "v3": DataStoreV3() } def get_store(self, version: str) -> DataStore: """获取指定版本的数据存储""" if version not in self.stores: raise ValueError(f"Version {version} not found") return self.stores[version] def save_conversation(self, version: str, conversation_id: str, data: Dict): """保存对话数据""" store = self.get_store(version) store.save(conversation_id, data) def get_conversation(self, version: str, conversation_id: str) -> Dict: """获取对话数据""" store = self.get_store(version) return store.get(conversation_id)
版本选择策略:
版本选择器根据多个因素确定使用的版本,优先级从高到低:
- 用户明确指定的版本偏好
- 请求中指定的版本
- 用户历史使用的版本(基于用户ID查询)
- 系统默认版本
在选择版本前需要检查版本是否可用,确保系统支持该版本。
版本监控:
版本监控系统跟踪各版本的使用情况,记录版本、端点、时间戳、用户ID、响应时间等指标。这些数据用于分析版本使用趋势,识别需要维护的旧版本,评估版本迁移进度,为版本管理决策提供数据支持。
def get_version_stats(self, version: str) -> Dict:
"""获取版本统计"""
return {
"total_requests": self.get_total_requests(version),
"avg_response_time": self.get_avg_response_time(version),
"error_rate": self.get_error_rate(version),
"active_users": self.get_active_users(version)
}
**最佳实践:**
- 清晰的版本标识和路由规则
- 独立的资源隔离
- 版本使用情况监控
- 平滑的版本切换机制
- 完善的版本文档
---
## 三、Agent测试与调试篇(3题)
### 07|Agent 系统有哪些测试方法?如何设计测试用例?
**参考答案:**
**测试方法分类:**
1. **功能测试(Functional Testing)**
- 验证 Agent 的核心功能
- 测试工具调用
- 验证对话流程
- 检查错误处理
2. **性能测试(Performance Testing)**
- 响应时间测试
- 吞吐量测试
- 并发测试
- 资源使用测试
3. **可靠性测试(Reliability Testing)**
- 错误恢复测试
- 长时间运行测试
- 压力测试
- 稳定性测试
4. **安全测试(Security Testing)**
- 权限验证测试
- 输入验证测试
- 数据安全测试
- 攻击防护测试
5. **兼容性测试(Compatibility Testing)**
- 版本兼容性测试
- 平台兼容性测试
- 工具兼容性测试
**测试用例设计:**
1. **基于场景的测试用例**
```python
class ScenarioTestCase:
"""场景测试用例"""
test_scenarios = [
{
"name": "简单对话",
"input": "你好",
"expected_output": "你好!有什么可以帮助你的吗?",
"expected_tools": []
},
{
"name": "工具调用",
"input": "查询北京天气",
"expected_output": "北京今天晴天,25度",
"expected_tools": ["weather_query"]
},
{
"name": "多轮对话",
"steps": [
{"input": "帮我订机票", "expected_tools": ["flight_search"]},
{"input": "去北京的", "expected_tools": ["flight_search"]},
{"input": "明天", "expected_tools": ["flight_book"]}
]
}
]
-
边界值测试用例
pythonclass BoundaryTestCase: """边界值测试用例""" test_cases = [ { "name": "空输入", "input": "", "expected": "error" }, { "name": "超长输入", "input": "A" * 10000, "expected": "truncated_or_error" }, { "name": "特殊字符", "input": "<script>alert('xss')</script>", "expected": "sanitized" }, { "name": "最大工具数量", "tools": 100, "expected": "handled" } ] -
错误处理测试用例
pythonclass ErrorHandlingTestCase: """错误处理测试用例""" test_cases = [ { "name": "工具调用失败", "scenario": "调用不存在的工具", "expected": "graceful_error_message" }, { "name": "网络超时", "scenario": "外部 API 超时", "expected": "retry_or_fallback" }, { "name": "无效参数", "scenario": "传递错误参数给工具", "expected": "validation_error" }, { "name": "资源不足", "scenario": "内存或计算资源不足", "expected": "resource_error_handling" } ] -
性能测试用例
pythonclass PerformanceTestCase: """性能测试用例""" test_cases = [ { "name": "响应时间", "metric": "response_time", "threshold": 2.0, # 秒 "test": "single_request" }, { "name": "并发处理", "metric": "throughput", "threshold": 100, # 请求/秒 "test": "concurrent_requests" }, { "name": "内存使用", "metric": "memory_usage", "threshold": 512, # MB "test": "memory_profiling" } ]
测试框架实现:
测试框架提供统一的测试接口,支持功能测试、性能测试和可靠性测试。功能测试验证Agent的输出是否符合预期,性能测试测量响应时间是否满足阈值要求,可靠性测试通过多次执行统计成功率和错误情况。测试框架记录测试结果,包括测试名称、是否通过、实际输出、预期输出、执行时间等信息,便于分析和报告。
result = self.agent.process("测试消息")
if result:
success_count += 1
except Exception as e:
errors.append(str(e))
success_rate = success_count / iterations
return {
"iterations": iterations,
"success_count": success_count,
"success_rate": success_rate,
"errors": errors
}
def _validate_result(self, actual: Any, expected: Dict) -> bool:
"""验证结果"""
if "expected_output" in expected:
return actual == expected["expected_output"]
if "expected_tools" in expected:
return set(actual.tools) == set(expected["expected_tools"])
return True
**测试用例设计原则:**
1. **全面性**
- 覆盖主要功能
- 覆盖边界情况
- 覆盖错误场景
2. **可维护性**
- 清晰的测试结构
- 易于理解的测试用例
- 良好的测试文档
3. **可重复性**
- 测试结果可重复
- 不依赖外部状态
- 独立的测试用例
4. **自动化**
- 自动化执行
- 自动化验证
- 自动化报告
**最佳实践:**
- 使用测试金字塔(单元测试 > 集成测试 > 端到端测试)
- 编写清晰的测试用例名称
- 使用 Mock 和 Stub 隔离依赖
- 定期运行测试套件
- 维护测试覆盖率报告
---
### 08|如何调试 Agent 系统?有哪些调试技巧和工具?
**参考答案:**
**调试方法:**
1. **日志调试(Logging)**
使用日志系统记录Agent的执行过程,包括请求、响应、工具调用和错误信息。配置不同级别的日志(DEBUG、INFO、WARNING、ERROR),DEBUG级别记录详细的执行流程,INFO级别记录关键操作,ERROR级别记录异常信息。日志可以输出到文件和控制台,使用结构化格式便于后续分析。在关键执行点添加日志记录,如请求接收、规划生成、工具调用、响应返回等,帮助定位问题。
2. **断点调试(Breakpoint Debugging)**
在代码中设置断点,暂停程序执行,检查变量状态和执行流程。使用Python的pdb调试器或IDE的调试功能,在关键位置设置断点,如规划生成前、工具调用前、响应返回前等。可以检查变量值、调用栈、执行路径等,帮助理解程序执行逻辑和定位问题。
if "after_planning" in self.breakpoints:
import pdb; pdb.set_trace()
# 执行工具调用
for step in plan.steps:
if f"before_tool_{step.tool}" in self.breakpoints:
import pdb; pdb.set_trace()
result = self.agent.execute_tool(step)
if f"after_tool_{step.tool}" in self.breakpoints:
import pdb; pdb.set_trace()
-
追踪调试(Tracing)
pythonimport functools import time def trace_execution(func): """执行追踪装饰器""" @functools.wraps(func) def wrapper(*args, **kwargs): print(f"[TRACE] Entering {func.__name__}") print(f"[TRACE] Args: {args}, Kwargs: {kwargs}") start_time = time.time() try: result = func(*args, **kwargs) duration = time.time() - start_time print(f"[TRACE] Exiting {func.__name__}, Duration: {duration}s") print(f"[TRACE] Result: {result}") return result except Exception as e: duration = time.time() - start_time print(f"[TRACE] Error in {func.__name__}, Duration: {duration}s") print(f"[TRACE] Error: {e}") raise return wrapper class Agent: @trace_execution def process(self, request: Dict): # Agent 处理逻辑 pass -
状态检查(State Inspection)
pythonclass StateInspector: """状态检查器""" def inspect_agent_state(self, agent: Agent) -> Dict: """检查 Agent 状态""" return { "conversation_history": agent.conversation_history, "current_plan": agent.current_plan, "tool_registry": list(agent.tools.keys()), "memory_state": agent.memory.get_state(), "config": agent.config } def compare_states(self, state1: Dict, state2: Dict) -> Dict: """比较两个状态""" differences = {} for key in set(state1.keys()) | set(state2.keys()): if state1.get(key) != state2.get(key): differences[key] = { "before": state1.get(key), "after": state2.get(key) } return differences
调试工具:
-
Python 调试器(pdb)
pythonimport pdb class Agent: def process(self, request: Dict): # 设置断点 pdb.set_trace() # 执行逻辑 result = self._execute(request) return result -
交互式调试(IPython)
pythonfrom IPython import embed class Agent: def process(self, request: Dict): # 进入交互式调试 embed() result = self._execute(request) return result -
性能分析器(Profiler)
pythonimport cProfile import pstats class PerformanceProfiler: """性能分析器""" def profile_agent(self, agent: Agent, request: Dict): """分析 Agent 性能""" profiler = cProfile.Profile() profiler.enable() result = agent.process(request) profiler.disable() # 生成报告 stats = pstats.Stats(profiler) stats.sort_stats('cumulative') stats.print_stats(20) # 打印前20个最耗时的函数 return result -
可视化调试工具
pythonclass VisualizationDebugger: """可视化调试器""" def visualize_conversation_flow(self, conversation: List[Dict]): """可视化对话流程""" import graphviz dot = graphviz.Digraph() for i, turn in enumerate(conversation): dot.node(f"turn_{i}", f"Turn {i}: {turn['type']}") if i > 0: dot.edge(f"turn_{i-1}", f"turn_{i}") dot.render("conversation_flow", format="png") def visualize_tool_calls(self, tool_calls: List[Dict]): """可视化工具调用""" import matplotlib.pyplot as plt tools = [call["tool"] for call in tool_calls] counts = {} for tool in tools: counts[tool] = counts.get(tool, 0) + 1 plt.bar(counts.keys(), counts.values()) plt.title("Tool Call Distribution") plt.xlabel("Tool") plt.ylabel("Count") plt.savefig("tool_calls.png")
调试技巧:
-
分层调试
- 先调试底层组件
- 再调试上层逻辑
- 逐步定位问题
-
最小化复现
- 简化输入
- 隔离问题
- 创建最小测试用例
-
对比调试
- 对比正常和异常情况
- 对比不同版本
- 对比不同配置
-
增量调试
- 逐步添加功能
- 逐步验证
- 定位问题范围
最佳实践:
- 使用结构化日志
- 设置合理的日志级别
- 记录关键状态信息
- 使用专业的调试工具
- 建立调试流程和规范
09|Agent 系统的单元测试、集成测试和端到端测试如何实现?
参考答案:
测试金字塔:
/\
/ \ 端到端测试(少量)
/----\
/ \ 集成测试(适量)
/--------\
/ \ 单元测试(大量)
/------------\
1. 单元测试(Unit Testing)
单元测试针对单个组件或函数进行测试,使用 Mock 隔离依赖。
python
import unittest
from unittest.mock import Mock, patch, MagicMock
class TestAgentPlanning(unittest.TestCase):
"""Agent 规划模块单元测试"""
def setUp(self):
"""测试前准备"""
self.agent = Agent()
self.mock_llm = Mock()
self.agent.llm = self.mock_llm
def test_simple_planning(self):
"""测试简单规划"""
# Mock LLM 响应
self.mock_llm.generate.return_value = {
"plan": ["step1", "step2"],
"reasoning": "test reasoning"
}
result = self.agent.plan("测试任务")
self.assertIsNotNone(result)
self.assertEqual(len(result.steps), 2)
self.mock_llm.generate.assert_called_once()
def test_planning_with_tools(self):
"""测试带工具的规划"""
self.mock_llm.generate.return_value = {
"plan": [
{"action": "call_tool", "tool": "search", "params": {"query": "test"}},
{"action": "respond", "message": "结果"}
]
}
result = self.agent.plan("搜索测试")
self.assertEqual(result.steps[0].tool, "search")
self.assertEqual(result.steps[0].params["query"], "test")
@patch('agent.tools.WeatherTool')
def test_tool_execution(self, mock_weather_tool):
"""测试工具执行"""
mock_weather_tool.return_value.query.return_value = {"temp": "25°C"}
result = self.agent.execute_tool("weather", {"city": "北京"})
self.assertEqual(result["temp"], "25°C")
mock_weather_tool.return_value.query.assert_called_once_with(city="北京")
2. 集成测试(Integration Testing)
集成测试验证多个组件协同工作。
python
class TestAgentIntegration(unittest.TestCase):
"""Agent 集成测试"""
def setUp(self):
"""测试前准备"""
# 使用真实的组件,但可能使用测试数据库
self.agent = Agent(
llm=LLMClient(api_key="test_key"),
memory=MemoryStore(test_mode=True),
tools=ToolRegistry()
)
def test_planning_and_execution(self):
"""测试规划和执行集成"""
request = {
"message": "查询北京天气",
"conversation_id": "test_conv_1"
}
# 执行规划
plan = self.agent.plan(request)
self.assertIsNotNone(plan)
# 执行计划
result = self.agent.execute_plan(plan)
self.assertIsNotNone(result)
# 验证结果
self.assertIn("weather", result.lower() or "")
def test_memory_integration(self):
"""测试记忆集成"""
# 第一轮对话
response1 = self.agent.process({
"message": "我的名字是张三",
"conversation_id": "test_conv_2"
})
# 第二轮对话,应该记住名字
response2 = self.agent.process({
"message": "我的名字是什么?",
"conversation_id": "test_conv_2"
})
self.assertIn("张三", response2)
def test_tool_registry_integration(self):
"""测试工具注册集成"""
# 注册新工具
self.agent.register_tool(TestTool())
# 使用工具
result = self.agent.process({
"message": "使用测试工具",
"conversation_id": "test_conv_3"
})
self.assertIsNotNone(result)
3. 端到端测试(End-to-End Testing)
端到端测试验证完整用户流程,包括UI端到端测试和API端到端测试。
UI端到端测试使用Selenium等工具自动化浏览器操作,模拟用户行为,如打开应用、输入消息、点击发送、等待响应、验证结果等。测试覆盖完整的对话流程和工具调用流程,确保前端与后端的集成正常工作。
API端到端测试 直接调用API接口,验证接口功能,包括聊天接口、多轮对话、工具调用等。测试发送请求、验证响应状态码、检查响应内容是否符合预期。多轮对话测试验证会话状态的保持和上下文理解能力。
assert response1.status_code == 200
# 第二轮
response2 = requests.post(
f"{self.BASE_URL}/agent/chat",
json={
"message": "我的名字是什么?",
"conversation_id": conversation_id
}
)
assert response2.status_code == 200
data = response2.json()
assert "李四" in data["response"]
def test_tool_calling_flow(self):
"""测试工具调用流程"""
response = requests.post(
f"{self.BASE_URL}/agent/chat",
json={
"message": "查询上海天气",
"conversation_id": "test_e2e_3",
"tools": ["weather"]
}
)
assert response.status_code == 200
data = response.json()
assert "tool_calls" in data
assert len(data["tool_calls"]) > 0
**测试框架配置:**
```python
# pytest.ini
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--cov=agent
--cov-report=html
--cov-report=term
测试最佳实践:
-
单元测试
- 快速执行
- 高覆盖率
- 使用 Mock 隔离
- 测试边界情况
-
集成测试
- 测试组件交互
- 使用测试数据库
- 验证数据流
- 测试错误处理
-
端到端测试
- 测试关键用户流程
- 使用真实环境
- 自动化执行
- 定期回归测试
最佳实践:
- 遵循测试金字塔原则
- 保持测试独立和可重复
- 使用合适的测试工具
- 维护测试文档
- 持续集成和自动化测试
四、Agent监控与运维篇(3题)
10|如何设计 Agent 的监控系统?需要监控哪些指标?
参考答案:
监控系统架构:
┌─────────────┐
│ 数据采集 │
└──────┬──────┘
│
┌──────▼──────┐
│ 数据存储 │
└──────┬──────┘
│
┌──────▼──────┐
│ 数据分析 │
└──────┬──────┘
│
┌──────▼──────┐
│ 告警通知 │
└─────────────┘
关键监控指标:
-
性能指标(Performance Metrics)
pythonclass PerformanceMetrics: """性能指标""" metrics = { "response_time": { "description": "响应时间", "unit": "seconds", "threshold": 2.0, "alert_threshold": 5.0 }, "throughput": { "description": "吞吐量", "unit": "requests/second", "threshold": 100, "alert_threshold": 50 }, "latency_p50": { "description": "50分位延迟", "unit": "milliseconds" }, "latency_p95": { "description": "95分位延迟", "unit": "milliseconds" }, "latency_p99": { "description": "99分位延迟", "unit": "milliseconds" } } -
业务指标(Business Metrics)
业务指标反映系统的业务运行状况,包括总请求数、成功请求数、失败请求数、错误率(失败请求数/总请求数)、活跃用户数、对话数量等。这些指标帮助了解系统的业务表现和用户使用情况。
-
资源指标(Resource Metrics)
资源指标监控系统资源使用情况,包括CPU使用率、内存使用率、磁盘使用率、网络I/O等。每个指标设置阈值和告警阈值,当资源使用超过阈值时触发告警,帮助及时发现资源瓶颈。
-
Agent 特定指标(Agent-Specific Metrics)
Agent特定指标监控Agent特有的功能,包括工具调用次数、工具调用成功率、平均对话轮数、LLM API调用次数、LLM API成本、缓存命中率等。这些指标帮助了解Agent的性能和成本情况。
监控系统实现:
使用Prometheus等监控系统定义和采集指标。定义计数器(Counter)记录累计值,如请求总数、工具调用总数;定义仪表盘(Gauge)记录当前值,如活跃用户数、错误率;定义直方图(Histogram)记录分布,如请求延迟分布。在关键执行点记录指标,如请求处理时记录请求数和延迟,工具调用时记录调用次数和状态。
监控数据采集:
指标采集器定期采集系统资源指标,包括CPU、内存、磁盘、网络等。采集的指标存储在缓冲区,可以定期上报到监控系统。采集间隔可以根据需要配置,通常设置为60秒。
告警系统:
告警管理器维护告警规则列表,定期检查指标是否触发告警条件。告警规则定义指标名称、阈值、比较条件(大于、小于等)和严重程度。当指标值超过阈值时,创建告警记录,包含规则名称、指标值、阈值、当前值和时间戳。告警可以通过多种渠道发送,如邮件、Slack、钉钉等,确保相关人员及时收到通知。告警历史记录用于分析告警趋势和系统稳定性。
监控仪表板:
监控仪表板可视化展示系统运行状态,包括响应时间趋势、错误率、工具调用统计、资源使用情况等。通过图表展示指标变化趋势,帮助运维人员快速了解系统健康状况。仪表板可以实时更新,也可以查看历史数据,支持时间范围选择和多维度分析。
最佳实践:
- 分层监控(应用层、系统层、业务层)
- 实时监控和定期报告
- 设置合理的告警阈值
- 保留历史数据用于分析
- 可视化监控数据
11|Agent 系统的日志如何管理?有哪些日志策略?
参考答案:
日志管理的重要性:
日志是系统运行状态、错误信息、用户行为的重要记录,对于问题诊断、性能分析、安全审计至关重要。
日志级别:
日志系统定义了不同级别的日志,从低到高包括:
- DEBUG:调试信息,记录详细的执行流程,用于开发调试
- INFO:一般信息,记录正常的操作和关键事件
- WARNING:警告信息,记录潜在问题,不影响功能但需要关注
- ERROR:错误信息,记录功能异常和错误情况
- CRITICAL:严重错误,记录系统故障和严重问题
根据环境选择合适的日志级别,生产环境通常使用INFO或WARNING级别,开发环境可以使用DEBUG级别。
日志策略:
-
结构化日志(Structured Logging)
pythonimport json import logging from datetime import datetime class StructuredLogger: """结构化日志记录器""" def __init__(self, name: str): self.logger = logging.getLogger(name) self.logger.setLevel(logging.INFO) def log(self, level: str, message: str, **kwargs): """记录结构化日志""" log_entry = { "timestamp": datetime.utcnow().isoformat(), "level": level, "message": message, **kwargs } log_message = json.dumps(log_entry, ensure_ascii=False) if level == "DEBUG": self.logger.debug(log_message) elif level == "INFO": self.logger.info(log_message) elif level == "WARNING": self.logger.warning(log_message) elif level == "ERROR": self.logger.error(log_message) elif level == "CRITICAL": self.logger.critical(log_message) def log_request(self, request_id: str, endpoint: str, method: str, params: Dict): """记录请求日志""" self.log("INFO", "Request received", request_id=request_id, endpoint=endpoint, method=method, params=params) def log_response(self, request_id: str, status_code: int, duration: float, response_size: int): """记录响应日志""" self.log("INFO", "Request completed", request_id=request_id, status_code=status_code, duration=duration, response_size=response_size) -
日志轮转(Log Rotation)
pythonimport logging.handlers class RotatingFileHandler(logging.handlers.RotatingFileHandler): """日志轮转处理器""" def __init__(self, filename: str, max_bytes: int = 10*1024*1024, backup_count: int = 5): super().__init__( filename, maxBytes=max_bytes, backupCount=backup_count ) # 使用示例 logger = logging.getLogger("agent") handler = RotatingFileHandler( "agent.log", max_bytes=10*1024*1024, # 10MB backup_count=5 # 保留5个备份文件 ) logger.addHandler(handler) -
日志分级存储
采用分级存储策略,根据日志的时间将日志存储到不同层级的存储中:
- 热存储:存储最近24小时的日志,提供快速访问
- 温存储:存储最近30天的日志,访问速度中等
- 冷存储:存储历史日志,访问速度较慢但成本低
当日志超过时间阈值时,自动移动到下一级存储,实现成本优化。
-
日志聚合(Log Aggregation)
日志聚合器按时间窗口聚合日志,统计每个时间窗口内的总日志数、错误数、警告数、平均延迟等指标。聚合后的数据减少存储空间,提高查询效率,便于趋势分析。
-
日志过滤和脱敏
日志过滤器识别并脱敏敏感信息,如密码、API密钥、Token、密钥等。在记录日志前过滤敏感字段,将敏感值替换为占位符,保护用户隐私和系统安全。支持递归处理嵌套的字典结构。
日志管理架构:
日志管理系统负责统一配置和管理日志记录器、处理器、过滤器和格式化器。系统支持多种日志输出方式:
- 文件日志:使用轮转文件处理器,当日志文件达到指定大小时自动创建新文件,保留指定数量的备份文件
- 控制台日志:输出到标准输出,便于开发调试
- 远程日志:发送到集中式日志系统,如ELK Stack、Splunk、CloudWatch等,便于统一管理和分析
日志格式化支持JSON格式和文本格式,JSON格式便于程序解析,文本格式便于人工阅读。系统根据配置创建相应的处理器和格式化器,并应用到根日志记录器。
日志查询和分析:
日志分析器提供日志搜索和分析功能,支持按时间范围、日志级别、关键词、请求ID等条件搜索日志。可以分析错误模式,统计错误类型和频率,识别常见问题。生成日志报告,包括总日志数、错误数、警告数、错误率、常见错误等统计信息,帮助了解系统运行状况和问题趋势。
最佳实践:
- 使用结构化日志格式
- 设置合适的日志级别
- 实现日志轮转和归档
- 过滤敏感信息
- 集中化日志管理
- 建立日志分析流程
12|Agent 系统如何实现健康检查和自动恢复?
参考答案:
健康检查的重要性:
健康检查用于检测系统运行状态,及时发现故障,触发自动恢复机制,保证系统高可用性。
健康检查类型:
-
存活检查(Liveness Probe)
pythonclass LivenessProbe: """存活检查""" def check(self) -> Dict: """检查服务是否存活""" try: # 检查进程是否运行 process_status = self._check_process() # 检查端口是否监听 port_status = self._check_port() return { "status": "healthy" if (process_status and port_status) else "unhealthy", "process": process_status, "port": port_status, "timestamp": time.time() } except Exception as e: return { "status": "unhealthy", "error": str(e), "timestamp": time.time() } def _check_process(self) -> bool: """检查进程""" import psutil import os pid = os.getpid() try: process = psutil.Process(pid) return process.is_running() except: return False def _check_port(self) -> bool: """检查端口""" import socket try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) result = sock.connect_ex(('localhost', 8000)) sock.close() return result == 0 except: return False -
就绪检查(Readiness Probe)
pythonclass ReadinessProbe: """就绪检查""" def check(self) -> Dict: """检查服务是否就绪""" checks = { "database": self._check_database(), "cache": self._check_cache(), "llm_api": self._check_llm_api(), "tools": self._check_tools() } all_ready = all(checks.values()) return { "status": "ready" if all_ready else "not_ready", "checks": checks, "timestamp": time.time() } def _check_database(self) -> bool: """检查数据库连接""" try: # 执行简单查询 db.execute("SELECT 1") return True except: return False def _check_cache(self) -> bool: """检查缓存连接""" try: cache.ping() return True except: return False def _check_llm_api(self) -> bool: """检查 LLM API 连接""" try: response = llm_client.health_check() return response.status_code == 200 except: return False def _check_tools(self) -> bool: """检查工具可用性""" try: for tool in required_tools: if not tool.is_available(): return False return True except: return False -
启动检查(Startup Probe)
pythonclass StartupProbe: """启动检查""" def check(self) -> Dict: """检查服务是否启动完成""" # 检查初始化是否完成 if not self._is_initialized(): return { "status": "starting", "progress": self._get_init_progress() } # 检查关键组件是否加载 components = { "agent": self._check_agent_loaded(), "tools": self._check_tools_loaded(), "memory": self._check_memory_loaded() } all_loaded = all(components.values()) return { "status": "started" if all_loaded else "starting", "components": components, "timestamp": time.time() }
健康检查服务:
python
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse
app = FastAPI()
class HealthCheckService:
"""健康检查服务"""
def __init__(self):
self.liveness_probe = LivenessProbe()
self.readiness_probe = ReadinessProbe()
self.startup_probe = StartupProbe()
def get_health_status(self) -> Dict:
"""获取健康状态"""
return {
"liveness": self.liveness_probe.check(),
"readiness": self.readiness_probe.check(),
"startup": self.startup_probe.check()
}
health_service = HealthCheckService()
@app.get("/health")
async def health_check():
"""健康检查端点"""
status = health_service.get_health_status()
# 如果所有检查都通过,返回 200
if (status["liveness"]["status"] == "healthy" and
status["readiness"]["status"] == "ready"):
return JSONResponse(content=status, status_code=200)
else:
return JSONResponse(content=status, status_code=503)
自动恢复机制:
-
自动重启(Auto Restart)
pythonclass AutoRestartManager: """自动重启管理器""" def __init__(self, max_restarts: int = 3, restart_window: int = 300): self.max_restarts = max_restarts self.restart_window = restart_window # 秒 self.restart_history = [] def check_and_restart(self): """检查并重启""" health_status = health_service.get_health_status() if health_status["liveness"]["status"] == "unhealthy": if self._should_restart(): self._restart_service() def _should_restart(self) -> bool: """判断是否应该重启""" now = time.time() # 清理过期的重启记录 self.restart_history = [ t for t in self.restart_history if now - t < self.restart_window ] # 检查重启次数 return len(self.restart_history) < self.max_restarts def _restart_service(self): """重启服务""" self.restart_history.append(time.time()) # 记录重启事件 logger.warning("Service restart triggered") # 执行重启逻辑 # 例如:发送信号、调用重启脚本等 os.kill(os.getpid(), signal.SIGTERM) -
故障转移(Failover)
pythonclass FailoverManager: """故障转移管理器""" def __init__(self, primary: Agent, secondary: Agent): self.primary = primary self.secondary = secondary self.current = primary self.failover_threshold = 3 self.failure_count = 0 def check_and_failover(self): """检查并故障转移""" if not self._is_healthy(self.current): self.failure_count += 1 if self.failure_count >= self.failover_threshold: self._switch_to_backup() else: self.failure_count = 0 def _is_healthy(self, agent: Agent) -> bool: """检查 Agent 是否健康""" try: response = agent.health_check() return response["status"] == "healthy" except: return False def _switch_to_backup(self): """切换到备用服务""" logger.warning(f"Failing over from {self.current} to {self.secondary}") if self.current == self.primary: self.current = self.secondary else: self.current = self.primary self.failure_count = 0 -
降级处理(Degradation)
pythonclass DegradationManager: """降级管理器""" def __init__(self): self.degradation_levels = ["full", "limited", "minimal"] self.current_level = "full" def check_and_degrade(self): """检查并降级""" health_status = health_service.get_health_status() if health_status["readiness"]["status"] != "ready": # 检查哪些功能不可用 unavailable_features = self._get_unavailable_features(health_status) # 根据不可用功能调整降级级别 if "llm_api" in unavailable_features: self.current_level = "minimal" elif "tools" in unavailable_features: self.current_level = "limited" def _get_unavailable_features(self, health_status: Dict) -> List[str]: """获取不可用的功能""" unavailable = [] checks = health_status.get("readiness", {}).get("checks", {}) if not checks.get("llm_api", False): unavailable.append("llm_api") if not checks.get("tools", False): unavailable.append("tools") return unavailable def is_feature_available(self, feature: str) -> bool: """检查功能是否可用""" if self.current_level == "full": return True elif self.current_level == "limited": return feature != "advanced_tools" else: # minimal return feature == "basic_chat" -
自动恢复服务
pythonclass AutoRecoveryService: """自动恢复服务""" def __init__(self): self.restart_manager = AutoRestartManager() self.failover_manager = None # 如果有备用服务 self.degradation_manager = DegradationManager() self.recovery_strategies = [] def start_monitoring(self): """开始监控""" import threading def monitor_loop(): while True: try: self._monitor_and_recover() time.sleep(10) # 每10秒检查一次 except Exception as e: logger.error(f"Monitoring error: {e}") thread = threading.Thread(target=monitor_loop, daemon=True) thread.start() def _monitor_and_recover(self): """监控并恢复""" health_status = health_service.get_health_status() # 1. 尝试自动重启 self.restart_manager.check_and_restart() # 2. 如果有备用服务,尝试故障转移 if self.failover_manager: self.failover_manager.check_and_failover() # 3. 如果无法恢复,执行降级 if health_status["readiness"]["status"] != "ready": self.degradation_manager.check_and_degrade()最佳实践:
- 实现多层次的健康检查
- 设置合理的检查间隔和超时
- 实现渐进式恢复策略
- 记录恢复操作日志
- 通知相关人员恢复事件
- 定期测试恢复机制
五、Agent部署与DevOps篇(3题)
13|Agent 系统的 CI/CD 流程如何设计?有哪些关键步骤?
参考答案:
CI/CD 流程设计:
代码提交 → 自动构建 → 自动化测试 → 代码质量检查 → 构建镜像 →
部署到测试环境 → 集成测试 → 部署到预生产环境 → 生产部署
**关键步骤:**
1. **持续集成(CI)阶段**
```yaml
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install flake8 black mypy
- name: Lint
run: |
flake8 .
black --check .
mypy .
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run tests
run: |
pytest tests/ --cov=agent --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v2
with:
file: ./coverage.xml
build:
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: |
docker build -t agent:${{ github.sha }} .
- name: Push to registry
run: |
docker tag agent:${{ github.sha }} registry.example.com/agent:${{ github.sha }}
docker push registry.example.com/agent:${{ github.sha }}
-
持续部署(CD)阶段
yaml# .github/workflows/cd.yml name: CD Pipeline on: push: branches: [ main ] jobs: deploy-staging: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Deploy to staging run: | kubectl set image deployment/agent \ agent=registry.example.com/agent:${{ github.sha }} \ -n staging - name: Run smoke tests run: | ./scripts/smoke-tests.sh staging deploy-production: runs-on: ubuntu-latest needs: [deploy-staging] if: github.ref == 'refs/heads/main' environment: production steps: - uses: actions/checkout@v2 - name: Deploy to production run: | kubectl set image deployment/agent \ agent=registry.example.com/agent:${{ github.sha }} \ -n production - name: Run smoke tests run: | ./scripts/smoke-tests.sh production - name: Monitor deployment run: | ./scripts/monitor-deployment.sh
CI/CD 实现:
python
# ci_cd_pipeline.py
class CICDPipeline:
"""CI/CD 流水线"""
def __init__(self):
self.stages = []
def add_stage(self, stage: PipelineStage):
"""添加阶段"""
self.stages.append(stage)
def execute(self):
"""执行流水线"""
for stage in self.stages:
print(f"Executing stage: {stage.name}")
try:
result = stage.execute()
if not result.success:
print(f"Stage {stage.name} failed: {result.error}")
return PipelineResult(success=False, error=result.error)
except Exception as e:
print(f"Stage {stage.name} raised exception: {e}")
return PipelineResult(success=False, error=str(e))
return PipelineResult(success=True)
class PipelineStage:
"""流水线阶段"""
def __init__(self, name: str):
self.name = name
def execute(self) -> StageResult:
"""执行阶段"""
raise NotImplementedError
class LintStage(PipelineStage):
"""代码检查阶段"""
def execute(self) -> StageResult:
"""执行代码检查"""
import subprocess
try:
# 运行 flake8
result = subprocess.run(
["flake8", "."],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error=result.stderr)
# 运行 black 检查
result = subprocess.run(
["black", "--check", "."],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error="Code formatting issues")
return StageResult(success=True)
except Exception as e:
return StageResult(success=False, error=str(e))
class TestStage(PipelineStage):
"""测试阶段"""
def execute(self) -> StageResult:
"""执行测试"""
import subprocess
try:
result = subprocess.run(
["pytest", "tests/", "--cov=agent", "--cov-report=xml"],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error=result.stderr)
return StageResult(success=True)
except Exception as e:
return StageResult(success=False, error=str(e))
class BuildStage(PipelineStage):
"""构建阶段"""
def execute(self) -> StageResult:
"""执行构建"""
import subprocess
try:
# 构建 Docker 镜像
result = subprocess.run(
["docker", "build", "-t", "agent:latest", "."],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error=result.stderr)
return StageResult(success=True)
except Exception as e:
return StageResult(success=False, error=str(e))
class DeployStage(PipelineStage):
"""部署阶段"""
def __init__(self, name: str, environment: str):
super().__init__(name)
self.environment = environment
def execute(self) -> StageResult:
"""执行部署"""
import subprocess
try:
# 部署到 Kubernetes
result = subprocess.run(
["kubectl", "apply", "-f", f"k8s/{self.environment}.yaml"],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error=result.stderr)
# 等待部署完成
result = subprocess.run(
["kubectl", "rollout", "status", f"deployment/agent-{self.environment}"],
capture_output=True,
text=True
)
if result.returncode != 0:
return StageResult(success=False, error="Deployment failed")
return StageResult(success=True)
except Exception as e:
return StageResult(success=False, error=str(e))
部署策略:
-
蓝绿部署(Blue-Green Deployment)
pythonclass BlueGreenDeployment: """蓝绿部署""" def deploy(self, new_version: str): """执行蓝绿部署""" # 1. 部署新版本到绿色环境 self._deploy_to_green(new_version) # 2. 运行健康检查 if not self._health_check_green(): self._rollback_green() return False # 3. 切换流量到绿色环境 self._switch_traffic_to_green() # 4. 监控新版本 if not self._monitor_green(): self._switch_traffic_to_blue() return False # 5. 清理蓝色环境 self._cleanup_blue() return True -
金丝雀部署(Canary Deployment)
pythonclass CanaryDeployment: """金丝雀部署""" def deploy(self, new_version: str, percentage: int = 10): """执行金丝雀部署""" # 1. 部署新版本到金丝雀实例 self._deploy_canary(new_version) # 2. 将部分流量路由到金丝雀 self._route_traffic_to_canary(percentage) # 3. 监控金丝雀实例 if not self._monitor_canary(): self._rollback_canary() return False # 4. 逐步增加流量 for p in [25, 50, 75, 100]: self._route_traffic_to_canary(p) if not self._monitor_canary(): self._rollback_canary() return False time.sleep(300) # 等待5分钟 return True
最佳实践:
- 自动化所有可重复的步骤
- 实现快速反馈机制
- 使用版本控制和标签
- 实现回滚机制
- 监控部署过程
- 建立部署文档和流程
14|Agent 系统如何实现容器化部署?Docker 和 Kubernetes 如何应用?
参考答案:
Docker 容器化:
-
Dockerfile 编写
dockerfile# Dockerfile FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 安装系统依赖 RUN apt-get update && apt-get install -y \ gcc \ g++ \ && rm -rf /var/lib/apt/lists/* # 复制依赖文件 COPY requirements.txt . # 安装 Python 依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 设置环境变量 ENV PYTHONUNBUFFERED=1 ENV PORT=8000 # 暴露端口 EXPOSE 8000 # 健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 # 启动命令 CMD ["python", "main.py"] -
多阶段构建
dockerfile# 构建阶段 FROM python:3.9-slim as builder WORKDIR /app COPY requirements.txt . RUN pip install --user -r requirements.txt # 运行阶段 FROM python:3.9-slim WORKDIR /app # 从构建阶段复制依赖 COPY --from=builder /root/.local /root/.local # 复制应用代码 COPY . . # 确保使用本地安装的包 ENV PATH=/root/.local/bin:$PATH EXPOSE 8000 CMD ["python", "main.py"] -
Docker Compose 配置
yaml# docker-compose.yml version: '3.8' services: agent: build: . image: agent:latest ports: - "8000:8000" environment: - DATABASE_URL=postgresql://user:pass@db:5432/agent - REDIS_URL=redis://redis:6379 - LLM_API_KEY=${LLM_API_KEY} depends_on: - db - redis volumes: - ./logs:/app/logs restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s db: image: postgres:14 environment: - POSTGRES_DB=agent - POSTGRES_USER=user - POSTGRES_PASSWORD=pass volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7-alpine volumes: - redis_data:/data volumes: postgres_data: redis_data:
Kubernetes 部署:
-
Deployment 配置
yaml# k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: agent labels: app: agent spec: replicas: 3 selector: matchLabels: app: agent template: metadata: labels: app: agent spec: containers: - name: agent image: registry.example.com/agent:latest ports: - containerPort: 8000 env: - name: DATABASE_URL valueFrom: secretKeyRef: name: agent-secrets key: database-url - name: LLM_API_KEY valueFrom: secretKeyRef: name: agent-secrets key: llm-api-key resources: requests: memory: "512Mi" cpu: "500m" limits: memory: "1Gi" cpu: "1000m" livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health/ready port: 8000 initialDelaySeconds: 5 periodSeconds: 5 -
Service 配置
yaml# k8s/service.yaml apiVersion: v1 kind: Service metadata: name: agent-service spec: selector: app: agent ports: - protocol: TCP port: 80 targetPort: 8000 type: LoadBalancer -
ConfigMap 和 Secret
yaml# k8s/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: agent-config data: config.yaml: | agent: max_tokens: 2000 temperature: 0.7 logging: level: INFO format: json # k8s/secret.yaml apiVersion: v1 kind: Secret metadata: name: agent-secrets type: Opaque stringData: database-url: postgresql://user:pass@db:5432/agent llm-api-key: your-api-key-here -
HorizontalPodAutoscaler
yaml# k8s/hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: agent-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: agent minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 -
Ingress 配置
yaml# k8s/ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: agent-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - agent.example.com secretName: agent-tls rules: - host: agent.example.com http: paths: - path: / pathType: Prefix backend: service: name: agent-service port: number: 80
部署脚本:
python
# deploy.py
import subprocess
import sys
class KubernetesDeployer:
"""Kubernetes 部署器"""
def __init__(self, namespace: str = "default"):
self.namespace = namespace
def deploy(self, image_tag: str):
"""部署应用"""
# 1. 更新镜像标签
self._update_image_tag(image_tag)
# 2. 应用配置
self._apply_configs()
# 3. 等待部署完成
self._wait_for_deployment()
# 4. 验证部署
self._verify_deployment()
def _update_image_tag(self, tag: str):
"""更新镜像标签"""
subprocess.run([
"kubectl", "set", "image",
f"deployment/agent=registry.example.com/agent:{tag}",
f"-n={self.namespace}"
], check=True)
def _apply_configs(self):
"""应用配置"""
configs = [
"k8s/configmap.yaml",
"k8s/secret.yaml",
"k8s/deployment.yaml",
"k8s/service.yaml",
"k8s/ingress.yaml"
]
for config in configs:
subprocess.run([
"kubectl", "apply", "-f", config,
f"-n={self.namespace}"
], check=True)
def _wait_for_deployment(self):
"""等待部署完成"""
subprocess.run([
"kubectl", "rollout", "status",
"deployment/agent",
f"-n={self.namespace}",
"--timeout=5m"
], check=True)
def _verify_deployment(self):
"""验证部署"""
# 检查 Pod 状态
result = subprocess.run([
"kubectl", "get", "pods",
"-l", "app=agent",
f"-n={self.namespace}",
"-o", "jsonpath={.items[*].status.phase}"
], capture_output=True, text=True)
if "Running" not in result.stdout:
raise Exception("Deployment verification failed")
最佳实践:
- 使用多阶段构建优化镜像大小
- 配置健康检查和资源限制
- 使用 ConfigMap 和 Secret 管理配置
- 实现自动扩缩容
- 使用 Ingress 管理外部访问
- 实现滚动更新和回滚机制
15|Agent 系统的微服务架构如何设计?有哪些最佳实践?
参考答案:
微服务架构设计:
┌─────────────┐
│ API Gateway │
└──────┬──────┘
│
┌───┴───┬─────────┬─────────┐
│ │ │ │
┌──▼──┐ ┌─▼──┐ ┌───▼──┐ ┌───▼──┐
│Agent│ │Tool│ │Memory│ │ LLM │
│Core │ │Svc │ │ Svc │ │ Svc │
└──┬──┘ └─┬──┘ └───┬──┘ └───┬──┘
│ │ │ │
└──────┴─────────┴─────────┘
│
┌──────▼──────┐
│ Database │
│ & Cache │
└─────────────┘
服务拆分:
-
Agent Core Service(Agent 核心服务)
python# agent_core_service.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI(title="Agent Core Service") class AgentCoreService: """Agent 核心服务""" def __init__(self): self.tool_service_client = ToolServiceClient() self.memory_service_client = MemoryServiceClient() self.llm_service_client = LLMServiceClient() async def process_request(self, request: Dict) -> Dict: """处理请求""" # 1. 获取上下文 context = await self.memory_service_client.get_context( request["conversation_id"] ) # 2. 调用 LLM 生成计划 plan = await self.llm_service_client.generate_plan( request["message"], context ) # 3. 执行计划 results = [] for step in plan.steps: if step.type == "tool_call": result = await self.tool_service_client.call_tool( step.tool, step.params ) results.append(result) # 4. 生成响应 response = await self.llm_service_client.generate_response( request["message"], context, results ) # 5. 保存上下文 await self.memory_service_client.save_context( request["conversation_id"], request["message"], response ) return {"response": response} @app.post("/api/v1/process") async def process(request: Dict): service = AgentCoreService() return await service.process_request(request) -
Tool Service(工具服务)
python# tool_service.py from fastapi import FastAPI app = FastAPI(title="Tool Service") class ToolService: """工具服务""" def __init__(self): self.tools = {} self._register_tools() def _register_tools(self): """注册工具""" self.tools["weather"] = WeatherTool() self.tools["search"] = SearchTool() self.tools["calculator"] = CalculatorTool() async def call_tool(self, tool_name: str, params: Dict) -> Dict: """调用工具""" if tool_name not in self.tools: raise ValueError(f"Tool {tool_name} not found") tool = self.tools[tool_name] result = await tool.execute(params) return { "tool": tool_name, "result": result, "timestamp": time.time() } @app.post("/api/v1/tools/{tool_name}/call") async def call_tool(tool_name: str, params: Dict): service = ToolService() return await service.call_tool(tool_name, params) -
Memory Service(记忆服务)
python# memory_service.py from fastapi import FastAPI app = FastAPI(title="Memory Service") class MemoryService: """记忆服务""" def __init__(self): self.memory_store = MemoryStore() self.cache = Cache() async def get_context(self, conversation_id: str) -> Dict: """获取上下文""" # 检查缓存 cached = await self.cache.get(f"context:{conversation_id}") if cached: return cached # 从数据库获取 context = await self.memory_store.get_conversation(conversation_id) # 更新缓存 await self.cache.set(f"context:{conversation_id}", context, ttl=3600) return context async def save_context(self, conversation_id: str, user_message: str, agent_response: str): """保存上下文""" await self.memory_store.add_turn( conversation_id, user_message, agent_response ) # 清除缓存 await self.cache.delete(f"context:{conversation_id}") @app.get("/api/v1/memory/{conversation_id}/context") async def get_context(conversation_id: str): service = MemoryService() return await service.get_context(conversation_id) -
LLM Service(LLM 服务)
python# llm_service.py from fastapi import FastAPI app = FastAPI(title="LLM Service") class LLMService: """LLM 服务""" def __init__(self): self.llm_client = LLMClient() self.cache = Cache() async def generate_plan(self, message: str, context: Dict) -> Dict: """生成计划""" cache_key = f"plan:{hash(message)}:{hash(str(context))}" # 检查缓存 cached = await self.cache.get(cache_key) if cached: return cached # 调用 LLM plan = await self.llm_client.generate_plan(message, context) # 更新缓存 await self.cache.set(cache_key, plan, ttl=300) return plan async def generate_response(self, message: str, context: Dict, tool_results: List[Dict]) -> str: """生成响应""" response = await self.llm_client.generate_response( message, context, tool_results ) return response @app.post("/api/v1/llm/plan") async def generate_plan(request: Dict): service = LLMService() return await service.generate_plan( request["message"], request["context"] )
服务间通信:
-
同步通信(REST/gRPC)
pythonclass ServiceClient: """服务客户端基类""" def __init__(self, base_url: str): self.base_url = base_url self.session = aiohttp.ClientSession() async def call(self, endpoint: str, method: str = "GET", data: Dict = None) -> Dict: """调用服务""" url = f"{self.base_url}{endpoint}" try: async with self.session.request( method, url, json=data ) as response: if response.status == 200: return await response.json() else: raise Exception(f"Service call failed: {response.status}") except Exception as e: # 实现重试逻辑 return await self._retry_call(endpoint, method, data) -
异步通信(消息队列)
pythonclass MessageQueue: """消息队列""" def __init__(self): self.rabbitmq = RabbitMQClient() async def publish(self, topic: str, message: Dict): """发布消息""" await self.rabbitmq.publish(topic, message) async def subscribe(self, topic: str, handler: Callable): """订阅消息""" await self.rabbitmq.subscribe(topic, handler)
API Gateway:
python
# api_gateway.py
from fastapi import FastAPI, Request
import httpx
app = FastAPI(title="API Gateway")
class APIGateway:
"""API 网关"""
def __init__(self):
self.services = {
"agent": "http://agent-core:8000",
"tools": "http://tool-service:8001",
"memory": "http://memory-service:8002",
"llm": "http://llm-service:8003"
}
async def route_request(self, path: str, method: str, data: Dict) -> Dict:
"""路由请求"""
# 路由规则
if path.startswith("/api/v1/agent"):
service_url = self.services["agent"]
elif path.startswith("/api/v1/tools"):
service_url = self.services["tools"]
elif path.startswith("/api/v1/memory"):
service_url = self.services["memory"]
elif path.startswith("/api/v1/llm"):
service_url = self.services["llm"]
else:
raise HTTPException(status_code=404, detail="Not found")
# 转发请求
async with httpx.AsyncClient() as client:
response = await client.request(
method,
f"{service_url}{path}",
json=data
)
return response.json()
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def gateway(request: Request, path: str):
gateway = APIGateway()
data = await request.json() if request.method in ["POST", "PUT"] else {}
return await gateway.route_request(f"/{path}", request.method, data)
服务发现和配置:
yaml
# docker-compose.yml
version: '3.8'
services:
api-gateway:
image: api-gateway:latest
ports:
- "8000:8000"
depends_on:
- agent-core
- tool-service
- memory-service
- llm-service
agent-core:
image: agent-core:latest
environment:
- TOOL_SERVICE_URL=http://tool-service:8001
- MEMORY_SERVICE_URL=http://memory-service:8002
- LLM_SERVICE_URL=http://llm-service:8003
tool-service:
image: tool-service:latest
ports:
- "8001:8000"
memory-service:
image: memory-service:latest
ports:
- "8002:8000"
depends_on:
- postgres
- redis
llm-service:
image: llm-service:latest
ports:
- "8003:8000"
最佳实践:
- 按业务领域拆分服务
- 服务间通过 API 通信
- 实现服务发现和负载均衡
- 使用 API Gateway 统一入口
- 实现分布式追踪和监控
- 设计容错和降级机制
- 使用配置中心管理配置
- 实现服务版本管理
总结
本文精选了15道关于Agent工程实践的高频面试题,涵盖了:
- API与架构设计:API设计、中间件、插件系统
- 版本与迁移:版本兼容性、迁移方案、多版本共存
- 测试与调试:测试方法、调试技巧、测试类型
- 监控与运维:监控系统、日志管理、健康检查
- 部署与DevOps:CI/CD流程、容器化部署、微服务架构
核心要点:
- API设计要考虑易用性、扩展性和安全性
- 版本管理要保证兼容性和平滑迁移
- 测试要覆盖各个层次和场景
- 监控和日志是生产环境的关键
- DevOps实践提高开发和部署效率
面试建议:
- 理解工程实践的重要性
- 掌握API设计和架构模式
- 熟悉测试和调试方法
- 了解监控和运维实践
- 具备实际项目经验
希望这些题目能帮助您更好地准备大模型应用岗位的面试!