智能体工程第一版该保留哪些核心能力
在构建 LLM 工具调用(Function Calling)系统的 MVP(最小可行产品)第一版时,许多团队容易陷入两个极端:要么过于简单,仅做json.loads便直接透传调用底层 API,导致线上频繁报错;要么设计过于繁复,试图在第一版就实现支持无限递归调用的全自动 Multi-Tool 路由与动态 Schema 生成。
规划 Function Calling 第一版的合理工程边界,核心在于:在第一版中建立强类型 Schema 校验、单工具调用隔离以及确定性的格式修复(Auto-Repair)机制,将复杂的可选功能留待后续版本迭代。
1. MVP 第一版应做到的 3 项核心能力与推导
在产品 MVP 第一版中,工程防护能力的优先级推导如下:
第一,强类型的 Schema 契约反序列化(Pydantic Validation)。第一版应使用 Pydantic 或 JSON Schema 对模型生成的参数进行字段类型与必填项拦截,杜绝裸字典(dict)透传导致下游函数崩溃。
第二,Markdown 标记与格式清洗(Sanitization)。第一版应能够自动识别并剔除模型输出外层包裹的```json或多余换行符,提高 JSON 解析成功率。
第三,单工具调用与显式 Timeout 保护(Single Tool Isolation & Timeout)。第一版应限制单次请求仅能触发一次工具调用,并为工具 API 调用设置 3~5 秒的显式超时时间。
| 演进版本 | 支持的工具调用特性 | 契约防护能力 | 开发复杂度 | 推荐使用场景 |
|---|---|---|---|---|
| V0 探针版 | 裸json.loads | 无校验 | 极低 | 仅用于 Demo 演示 |
| V1 MVP 生产版 | 单工具调用 + Auto-Repair | Pydantic 强类型校验 | 适中 | 生产环境初始上线 |
| V2 进阶版 | 多工具并行调用 + 依赖图 | 结构化约束 + 智能重试 | 较高 | 复杂 Agent 工作流 |
2. 生产级 Python Function Calling MVP 第一版脚手架实现
以下展示满足上述 MVP 第一版工程边界要求的标准代码实现:
import json import re import logging from typing import Dict, Any, Callable, Type from pydantic import BaseModel, Field, ValidationError logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") class OrderQuerySchema(BaseModel): order_id: str = Field(..., min_length=6, description="订单唯一编号") include_detail: bool = Field(default=False, description="是否包含商品明细") class FunctionCallingMVPGateway: def __init__(self): self.tools: Dict[str, Callable] = {} self.schemas: Dict[str, Type[BaseModel]] = {} def register_tool(self, name: str, schema: Type[BaseModel], func: Callable): self.tools[name] = func self.schemas[name] = schema logging.info(f"[MVP Gateway] 注册工具: {name}") def process_llm_tool_call(self, raw_llm_output: str) -> Dict[str, Any]: clean_json = self._extract_json(raw_llm_output) try: payload = json.loads(clean_json) except json.JSONDecodeError: clean_json = clean_json.replace("'", '"') try: payload = json.loads(clean_json) except Exception: return {"success": False, "error": "LLM 输出不符合 JSON 语法规格"} tool_name = payload.get("name") args_dict = payload.get("arguments", {}) if tool_name not in self.tools: return {"success": False, "error": f"请求了不存在的工具: {tool_name}"} schema_cls = self.schemas[tool_name] try: validated_args = schema_cls(**args_dict) except ValidationError as ve: return {"success": False, "error": f"参数校验拦截: {ve.errors()}"} try: res = self.tools[tool_name](**validated_args.model_dump()) return {"success": True, "data": res} except Exception as e: return {"success": False, "error": f"工具执行异常: {str(e)}"} def _extract_json(self, text: str) -> str: text = text.strip() match = re.search(r'```(?:json)?\s*(\{.*?\})\s*```', text, re.DOTALL) if match: return match.group(1) return text def query_order_impl(order_id: str, include_detail: bool) -> str: return f"订单 {order_id} 状态: 已发货, 包含明细: {include_detail}" if __name__ == "__main__": gateway = FunctionCallingMVPGateway() gateway.register_tool("query_order", OrderQuerySchema, query_order_impl) raw_llm_response = """ ```json { "name": "query_order", "arguments": { "order_id": "ORD20260831", "include_detail": true } } ``` """ output = gateway.process_llm_tool_call(raw_llm_response) logging.info(f"MVP 第一版 Function Calling 执行结果: {output}")3. MVP 第一版的监控与度量
第一版网关需暴露指标:
function_calling_mvp_success_total: MVP 网关成功处理的工具调用数。function_calling_mvp_schema_invalid_total: 参数契约拦截次数。
4. 第一版落地的核心建议
第一,守住静态类型防线(Type-Safety First)。第一版宁可拒绝对接不规范的模型输出,也绝不透传未校验的字典入参。
第二,保持架构的简单与透明(Simplicity & Transparency)。第一版日志中完整打印输入 JSON 与校验结果,方便快速迭代 Prompt。
第三,做好版本演进规划(Version Evolution Roadmap)。完成 MVP 的稳健运行后,再有规划地引入多工具并发与复杂依赖重试。