MossHubAPI 文档
开发者文档 工具调用

工具调用

下载代码

由模型提出函数调用,由你的应用校验并执行。

Python 3 · 标准库Chat Completions服务端示例

使用前确认

需要:上游支持 tools 的 Chat Completions 模型;本例不使用流式。网关不检查 tools,原样交给上游;挑选模型时可参考控制台的「工具调用」标记。先完成快速开始中的环境变量配置,并把 YOUR_MODEL_ID 换成这把密钥可用的模型 ID。

完整示例

可从页头“下载代码”保存为 .py 文件,在配置好环境的服务端运行。

import os, json, urllib.request, urllib.error

BASE = os.environ["MOSSHUB_API_BASE"].rstrip("/")
KEY = os.environ["MOSSHUB_API_KEY"]
MODEL = "YOUR_MODEL_ID"

def chat(messages, **options):
    body = {"model": MODEL, "messages": messages, "stream": False, **options}
    request = urllib.request.Request(
        BASE + "/v1/chat/completions",
        data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
        headers={"Authorization": "Bearer " + KEY,
                 "Content-Type": "application/json"}, method="POST")
    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            result = json.load(response)
    except urllib.error.HTTPError as error:
        raise RuntimeError(f"HTTP {error.code}: {error.read().decode('utf-8')}") from error
    choices = result.get("choices", [])
    if not choices or not isinstance(choices[0].get("message"), dict):
        raise RuntimeError("未返回有效消息,请检查错误信息与模型能力")
    if choices[0].get("finish_reason") == "length":
        raise RuntimeError("回答因输出上限而截断,请调整预算后重试")
    return choices[0]["message"]

tools = [{"type": "function", "function": {
    "name": "get_order_status", "description": "查询演示订单状态",
    "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
                   "required": ["order_id"], "additionalProperties": False},
}}]
messages = [{"role": "user", "content": "帮我查询订单 DEMO-1001 的状态。"}]
for _ in range(3):
    message = chat(messages, tools=tools)
    calls = message.get("tool_calls") or []
    if not calls:
        print(message.get("content") or "模型未提供文本回答")
        break
    messages.append({"role": "assistant", "content": message.get("content"), "tool_calls": calls})
    for call in calls:
        function = call.get("function", {})
        try:
            args = json.loads(function.get("arguments", "{}"))
        except (json.JSONDecodeError, TypeError):
            args = None
        if function.get("name") != "get_order_status":
            result = {"error": "未知工具"}
        elif (not isinstance(args, dict) or set(args) != {"order_id"}
              or not isinstance(args["order_id"], str)):
            result = {"error": "参数无效"}
        elif args["order_id"] != "DEMO-1001":
            result = {"error": "演示订单不存在"}
        else:
            result = {"order_id": "DEMO-1001", "status": "已发货", "demo": True}
        if not call.get("id"):
            raise RuntimeError("工具调用缺少 id,不能回传结果")
        messages.append({"role": "tool", "tool_call_id": call["id"],
                         "content": json.dumps(result, ensure_ascii=False)})
else:
    raise RuntimeError("达到工具调用次数上限,交由应用处理")

完整往返

  1. 在请求中声明函数名称和参数结构。
  2. 把带 tool_calls 的 assistant 消息完整加入历史。
  3. 校验工具白名单、参数和当前用户权限,再执行应用自己的代码。
  4. 将结果通过 tool_call_id 对应回传,让模型继续回答。

示例最多往返 3 次,使用固定演示订单,不调用真实订单服务。函数参数是模型产生的输入,不应直接拼接进 SQL、Shell 或文件路径。

流式边界

开启流式后,工具参数可能分成多段出现在 delta.tool_calls 中,需按 index 累计 function.arguments,结束后再解析 JSON。只拼接 delta.content 的文本解析器读不到工具调用。

继续阅读

文本对话参数 · 协议兼容 · 错误排查

实际可调用的模型、授权与价格以控制台为准。
页面字体:MiSans(小米,依《MiSans 字体知识产权许可协议》使用);Google Sans Flex(SIL Open Font License 1.1)。

本页目录