工具函数的描述质量,直接决定了Gemini能否准确理解并正确调用你提供的接口。模糊的字段说明,很容易导致参数缺失甚至类型错误,严重影响调用成功率。
第一点,为每个参数明确指定type、description以及是否required。以天气查询为例,city参数必须列入"required": ["city"]数组中,否则模型很可能跳过该参数,生成一个不可用的请求。
第二点,描述参数用途时,应避免使用“其他”“相关”等模糊词汇。例如,使用“城市名称,如‘深圳’‘杭州’”比“目标地点”更易于模型准确识别。
第三点,枚举值(enum)必须穷举所有可能值,且大小写敏感。例如,定义"unit": {"type":"string","enum":["celsius","fahrenheit"]}时,用户输入“摄氏度”模型不会自动映射为celsius。**因此,必须在description中明确写出每个可选值对应的自然语言表达。**
处理模型返回的工具调用响应
从Gemini 3.5开始,结构化输出已较为稳定,但仍有小概率返回混合文本与JSON的脏数据。
一种做法是:使用正则表达式提取第一个完整的JSON块,匹配\{[^{}]*\},再递归补全嵌套的大括号,最后通过json.loads()解析。这样可以去除“正在为您调用天气工具…”等前置说明文字。
另一种做法是:启用Gemini的response_mime_type="application/json",强制输出纯JSON。但此选项仅适用于单工具调用场景,多工具并行时会被忽略。
注意,切勿直接依赖response.text解析——模型可能在JSON外层包裹Markdown代码块,直接解析会引发json.decoder.JSONDecodeError。
构建安全可控的工具执行层
所有工具调用必须通过路由层统一管控,切忌在业务逻辑中硬编码执行分支。
① 注册工具时,需校验name的唯一性。重复注册会覆盖前一个,导致线上调用混乱。
② 执行前,进行白名单校验:if tool_name not in ALLOWED_TOOLS: → 记录告警并返回空结果。Gemini本身不会主动拒绝未声明的工具名,需要服务端来兜底。
③ 参数注入后,立即进行类型强转。例如将字符串"123"转换为int,避免下游数据库抛出psycopg2.DataError。
④ 高危操作(如delete_user、send_email)必须添加RBAC权限检查。从request.auth.user.roles中提取角色,若不在["admin", "ops"]中,则中断执行。
优化并行调用与结果组装逻辑
当用户一句话触发多个工具时(例如“查昨日销量TOP3 + 发邮件给张三”),Gemini 3.5会并行返回两个调用指令,但执行顺序需要由开发者编排。
方法1:按工具间的依赖关系进行拓扑排序。如果send_email的body参数依赖get_top_sales的结果,则后者必须优先执行。
方法2:对无依赖关系的工具,启用线程池并发执行。使用concurrent.futures.ThreadPoolExecutor控制最大并发数为3,避免单次请求压垮下游API。
此步骤操作较为直接,直接将文件拖入即可。但需注意:并发执行时,每个工具的timeout必须独立设置,不能共用全局超时,否则一个慢接口会拖垮整组调用。
调试与日志追踪关键点
生产环境中,必须记录四类原始数据:用户输入、模型原始响应、解析后的工具调用指令、工具执行结果。
在日志中,使用trace_id将整条链路串联起来,否则出现问题后,无法定位是模型理解错误、Schema定义缺陷,还是工具执行异常。
特别提醒:Gemini返回的args字段可能含有多余的空格或换行符,例如"city": " 北京\n"。直接传给HTTP客户端会触发400错误。**务必在执行前,使用.strip()清洗所有字符串参数。**
