工具调用的瓶颈在"参数"而不在"调用"

很多Agent接入工具后效果差,问题不在函数本身,而是LLM生成的参数不对:日期格式错了、枚举值不在范围内、必填字段缺失、单位没换算。Function Calling的参数抽取,本质是把"自然语言意图"转成"严格类型的JSON",需要Prompt约束、Schema定义、代码校验三层配合。

一、先定义清晰的工具Schema

工具描述越含糊,参数抽取越不准。用JSON Schema把每个字段的约束写死:

TOOLS = [{
    "type": "function",
    "function": {
        "name": "book_meeting",
        "description": "预定会议室,必须提供开始时间与时长",
        "parameters": {
            "type": "object",
            "properties": {
                "room_id": {
                    "type": "string",
                    "enum": ["A101", "A102", "B201"],  # 枚举约束
                    "description": "会议室编号,只能是枚举值之一"
                },
                "start_time": {
                    "type": "string",
                    "format": "date-time",  # ISO 8601格式约束
                    "description": "会议开始时间,ISO格式如2026-08-24T14:00:00"
                },
                "duration_minutes": {
                    "type": "integer",
                    "minimum": 15,
                    "maximum": 240
                }
            },
            "required": ["room_id", "start_time", "duration_minutes"]
        }
    }
}]

二、Prompt层:给LLM"翻译规则"

光有Schema不够,实测还要在System Prompt里补充隐含规则,比如时间表达换算:

当用户说"明天下午3点"时,start_time必须换算成具体的ISO 8601时间戳,
基准日期为今天。如果用户没指定会议室,不要猜测,把room_id留空并在
参数中附加missing_fields说明。

三、代码层:参数校验与自动修复

LLM输出再可靠也要兜底。用Pydantic校验+修复策略:

from pydantic import BaseModel, ValidationError
from datetime import datetime, timedelta

class BookMeetingParams(BaseModel):
    room_id: str
    start_time: datetime
    duration_minutes: int

def parse_and_fix(raw_args: dict) -> dict:
    # 策略1:直接校验
    try:
        return BookMeetingParams(**raw_args).model_dump()
    except ValidationError:
        pass
    # 策略2:常见问题自动修复
    fixed = dict(raw_args)
    if isinstance(fixed.get("start_time"), str):
        try:
            # "明天下午3点"等自然语言交给LLM二次修正
            fixed["start_time"] = normalize_time(fixed["start_time"])
        except Exception:
            return {"error": "时间解析失败,请明确具体时间"}
    if fixed.get("room_id") not in ("A101", "A102", "B201"):
        return {"error": f"会议室不存在: {fixed.get('room_id')}"}
    return fixed

四、参数抽取质量评估清单

检查项通过标准测试方法
枚举值合法100%落在枚举内构造50条边界case
时间格式全部为ISO 8601正则+datetime解析
必填字段无缺失Schema校验
隐含换算相对时间正确转绝对时间跨时区case
拒绝率信息不足时明确拒绝而非瞎猜缺省case

五、高频翻车场景与对策

  • **单位问题**:"半小时"→ LLM可能传0.5而不是30,Schema里用minimum/maximum卡死,Prompt里写明"时长单位是分钟"
  • 2. 日期歧义:"周五"到底指这周还是下周?Prompt里给基准日期,代码里做二次确认

    3. 幻觉参数:用户没提的参数,LLM会脑补。对策:Prompt强调"未提及的字段不要填",代码层校验未授权字段一律拒绝

    总结:参数抽取做得好不好,直接决定工具链路的稳定性。把Schema写严、把Prompt规则写清、把校验兜底写实,三步下来工具调用的成功率能稳定在95%以上。