Java for You AI Python调用Gemini Structured Outputs实现工单路由门禁

Python调用Gemini Structured Outputs实现工单路由门禁

笔电上的代码

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gemini API 的 Structured Outputs 能按 JSON Schema 生成结果;本篇用 Python 把退款、账号和普通咨询分流,并在模型输出越界时拒绝自动流转。你会得到一条能复制、能超时、能降级的最小链路。

为什么不直接解析一段自然语言

结构化输出的作用是规定“输出长什么样”,不是保证事实正确。Schema 让字段和枚举更稳定;业务规则仍要由服务端负责。本文把 priority 限在 low、normal、high,把 queue 限在三个队列。模型若返回未知值,程序转到人工队列。当前官方文档把它用于抽取、分类和 Agent 工作流,并通过 response_format 的 application/json 与 schema 配置。

mermaid diagram

环境准备

使用 Python 3.10+。安装依赖:python -m pip install google-genai。把密钥放入环境变量:export GEMINI_API_KEY='你的密钥'。模型名示例为文档中的 gemini-3.8-flash;你的账号可用模型与配额仍需在控制台确认。保存为 ticket_router.py,运行 python ticket_router.py。示例未在本次任务中实际调用线上 API;本地仅完成语法检查,目标环境安装依赖后应再作一次无敏感数据的联调。

import json
import os
from google import genai

ALLOWED_QUEUES = {"refund", "account", "general"}
ALLOWED_PRIORITY = {"low", "normal", "high"}
SCHEMA = {"type": "object", "properties": {
    "queue": {"type": "string", "enum": sorted(ALLOWED_QUEUES)},
    "priority": {"type": "string", "enum": sorted(ALLOWED_PRIORITY)},
    "reason": {"type": "string"}},
    "required": ["queue", "priority", "reason"]}

def safe_route(raw: str) -> dict:
    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        return {"queue": "human_review", "reason": "JSON无法解析"}
    if data.get("queue") not in ALLOWED_QUEUES:
        return {"queue": "human_review", "reason": "未知队列"}
    if data.get("priority") not in ALLOWED_PRIORITY:
        return {"queue": "human_review", "reason": "未知优先级"}
    return data

def classify(ticket: str) -> dict:
    if not os.getenv("GEMINI_API_KEY"):
        return {"queue": "human_review", "reason": "缺少GEMINI_API_KEY"}
    client = genai.Client()
    try:
        result = client.interactions.create(
            model="gemini-3.8-flash", input=ticket,
            response_format={"type": "text", "mime_type": "application/json",
                             "schema": SCHEMA}, timeout=20)
        return safe_route(result.output_text)
    except Exception as exc:
        return {"queue": "human_review", "reason": f"调用失败: {type(exc).__name__}"}

if __name__ == "__main__":
    print(classify("订单重复扣款,请尽快退款"))
    assert safe_route('{"queue":"refund","priority":"high","reason":"重复扣款"}')["queue"] == "refund"

代码分两层:SCHEMA 提前缩小模型输出空间;safe_route 再做独立验证,不能因为 API 承诺 JSON 就省略它。timeout=20 是为了不让一个慢请求占住 Web 工作线程;生产环境还应设置 HTTP 客户端级超时、重试次数和熔断。genai.Client() 从环境读取密钥,不要把密钥写进仓库。

预期输出(有密钥且调用成功时)类似 {'queue': 'refund', 'priority': 'high', 'reason': '...'};没配密钥则是人工复核。最常见的坑有:一,Schema 只约束格式,不会自动核验订单真伪;二,枚举改了却没同步服务端白名单;三,超时后盲目重试,造成同一工单被重复创建;四,把模型理由直接展示给用户而泄露内部规则。

适合把“先分给谁处理”自动化,不适合直接批准退款或关闭投诉。工程化时,把原始文本、模型版本、schema 版本、路由结果和人工改判一起记录;每周抽样计算错分率。5分钟实践:新增 security 队列,并写一个断言确保模型返回 delete_database 时永远进入 human_review。

你的工单里,哪一个字段一旦分类错就不该自动流转?

关注「蜗牛聊AI」,一起看懂技术变化背后的真正机会。


本文首发于 java4u.cn,转载请注明出处。

本文由 java4u.cn 发布,可自由转载、引用,但需署名作者且注明文章出处(作者:白色蜗牛,出处:java4u.cn)。如转载至微信公众号,请在文末添加作者公众号二维码。 https://java4u.cn/ai/3103.html

作者: 蜗牛

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

联系我们

公众号:蜗牛互联网

在线咨询: QQ交谈

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部