Skip to content

工具调用

工具调用介绍

工具调用(Function/Tool Calling)让大模型按既定接口规范与外部系统交互:当模型判断需要调用某工具时,会严格按 JSON Schema 生成结构化参数,客户端执行工具并把结果返回给模型,完成复杂任务编排与系统集成。

功能特性

  • 结构化参数生成:基于 JSON Schema,生成可直接调用的函数参数。
  • 多工具并行/串行:根据模型判断可一次返回多个工具调用或分步调用。
  • 可控执行:支持“自动选择工具”“强制指定某工具”或关闭工具。
  • 通用协议:AIPing 支持 OpenAI 格式与 Anthropic 格式的工具定义与调用,支持接入 Claude Code、Codex、Cursor 等外部编程工具。

工具调用参数(OpenAI 格式)

请求参数说明

工具调用请求中的关键字段:

  • 端点:https://aiping.cn/api/v1
  • messages:对话消息数组。
  • tools:工具列表。每个工具为 {"type":"function","function":{name, description, parameters}}
  • tool_choice:
    • "auto":自动选择是否与哪个工具。
    • "required":强制模型必须调用至少一个工具。
    • "none":禁用工具。
    • {"type":"function","function":{"name":"xxx"}}:强制使用指定函数。

响应参数说明

核心响应参数说明:

  • choices[].message.content:模型自然语言回答。
  • choices[].message.tool_calls:工具调用数组。
  • choices[].finish_reason:结束原因。
  • id, created, usage:请求元数据与令牌统计。

工具调用参数(Anthropic 格式)

核心参数说明

  • 端点:https://aiping.cn/api/v1/anthropic

    注:AIPing 当前仅支持部分模型使用 Anthropic 格式端点,查询方式见《查询 Anthropic 端点可用模型》一节。推荐使用 "minimax-m2" 和 "glm-4.6",以下文档示例以 "minimax-m2" 为例。

  • messages:对话消息数组。
  • tools:工具列表,每个工具为 {name, description, input_schema}
  • input_schema 使用 JSON Schema。
  • 其他通用生成参数:model, max_tokens, temperature, system 等。

响应参数说明

  • content[]:响应内容块数组,块类型可能为:
    • {"type":"text","text":"..."}:自然语言文本。
    • {"type":"tool_use","id":"...","name":"...","input":{...}}:工具调用。
  • stop_reason:结束原因(如达到 tokens、需要工具结果继续等)。
  • id, usage:请求元数据与令牌统计。

查询 Anthropic 端点可用模型

AIPing 的 Anthropic 端点提供了兼容 Anthropic API 的模型查询端点,允许用户查看当前可用的 Anthropic 兼容模型列表。

请求示例

bash
curl -X GET "https://aiping.cn/api/v1/anthropic/v1/models" \
     -H "Authorization: Bearer YOUR_TOKEN" \
     -H "Content-Type: application/json"

响应格式

成功响应返回 JSON 格式数据:

json
{
  "data": [
    {
      "id": "DeepSeek-V3.1",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "DeepSeek-V3.1",
      "type": "model"
    },
    {
      "id": "DeepSeek-V3.2-Exp",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "DeepSeek-V3.2-Exp",
      "type": "model"
    },
    {
      "id": "GLM-4.5",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "GLM-4.5",
      "type": "model"
    },
    {
      "id": "GLM-4.5-Air",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "GLM-4.5-Air",
      "type": "model"
    },
    {
      "id": "GLM-4.6",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "GLM-4.6",
      "type": "model"
    },
    {
      "id": "Kimi-K2-Instruct",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "Kimi-K2-Instruct",
      "type": "model"
    },
    {
      "id": "Kimi-K2-Thinking",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "Kimi-K2-Thinking",
      "type": "model"
    },
    {
      "id": "MiniMax-M2",
      "created_at": "1970-01-01T00:00:00Z",
      "display_name": "MiniMax-M2",
      "type": "model"
    }
  ],
  "first_id": "DeepSeek-V3.1",
  "has_more": false,
  "last_id": "MiniMax-M2"
}

获取单个模型详情

除了查询模型列表,还可以获取特定模型的详细信息:

bash
GET /v1/anthropic/v1/models/{model_id}

如果模型不存在或不在允许列表中,将返回 404 错误。

在各类工具中使用 AIPing

下面介绍在各类工具中使用 AIPing ,见在各类场景中使用 AiPing

示例代码

OpenAI 格式工具调用

python
#!/usr/bin/env python3
import os
import sys
import json
from openai import OpenAI

# 定义工具
def search_books(search_terms):
    query = " ".join(search_terms).lower()
    catalog = [
        {"id": 4300, "title": "Ulysses", "authors": [{"name": "Joyce, James"}]},
        {"id": 2814, "title": "Dubliners", "authors": [{"name": "Joyce, James"}]},
        {"id": 4217, "title": "A Portrait of the Artist as a Young Man", "authors": [{"name": "Joyce, James"}]},
        {"id": 766, "title": "Chamber Music", "authors": [{"name": "Joyce, James"}]},
    ]
    if "joyce" in query or "乔伊斯" in query:
        return catalog
    return []

def main() -> int:
    base_url = os.getenv("BASE_URL", "https://aiping.cn/api/v1")
    api_key = os.getenv("API_KEY", "<YOUR_AIPING_KEY>")

    client = OpenAI(base_url=base_url, api_key=api_key)

    tools = [
        {
            "type": "function",
            "function": {
                "name": "search_books",
                "description": "根据关键词检索本地书目(静态样例)",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "search_terms": {
                            "type": "array",
                            "items": {"type": "string"},
                            "description": "检索关键词列表"
                        }
                    },
                    "required": ["search_terms"],
                    "additionalProperties": False,
                },
            },
        }
    ]

    messages = [
        {"role": "user", "content": "乔伊斯的书名有哪些?请列出标题。"}
    ]

    # 请求携带 tools
    first = client.chat.completions.create(
        model="MiniMax-M2",
        messages=messages,
        tools=tools,
        tool_choice={"type": "function", "function": {"name": "search_books"}},
        max_tokens=2048,
    )

    choice = first.choices[0]
    if not choice.message.tool_calls:
        print("[ERROR] model did not return tool_calls", file=sys.stderr)
        return 3

    assistant_tool_calls = [
        {
            "id": tc.id,
            "type": "function",
            "function": {
                "name": tc.function.name,
                "arguments": tc.function.arguments,
            },
        }
        for tc in (choice.message.tool_calls or [])
    ]
    messages.append({
        "role": "assistant",
        "content": None,
        "tool_calls": assistant_tool_calls,
    })

    # 执行工具并附加 tool 结果
    for tc in (choice.message.tool_calls or []):
        args = json.loads(tc.function.arguments or "{}")
        res = search_books(args.get("search_terms", []))
        messages.append({
            "role": "tool",
            "tool_call_id": tc.id,
            "content": json.dumps(res, ensure_ascii=False),
        })

    # 把工具结果交回模型
    second = client.chat.completions.create(
        model="MiniMax-M2",
        messages=messages,
        tools=tools,
        max_tokens=2048,
    )

    final_text = (second.choices[0].message.content or "").strip()
    print({"model": second.model, "final_text": final_text})
    return 0

if __name__ == "__main__":
    raise SystemExit(main())

Anthropic 格式工具调用

python
#!/usr/bin/env python3
import os
import sys
import json
import requests

# 定义工具
def search_books(search_terms):
    query = " ".join(search_terms).lower()
    catalog = [
        {"id": 4300, "title": "Ulysses", "authors": [{"name": "Joyce, James"}]},
        {"id": 2814, "title": "Dubliners", "authors": [{"name": "Joyce, James"}]},
        {"id": 4217, "title": "A Portrait of the Artist as a Young Man", "authors": [{"name": "Joyce, James"}]},
        {"id": 766, "title": "Chamber Music", "authors": [{"name": "Joyce, James"}]},
    ]
    if "joyce" in query or "乔伊斯" in query:
        return catalog
    return []

def main() -> int:
    base_url = os.getenv("BASE_URL", "https://aiping.cn/api/v1/anthropic")
    api_key = os.getenv("API_KEY", "<YOUR_AIPING_KEY>")

    url = f"{base_url}/v1/messages"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }

    tools = [
        {
            "name": "search_books",
            "description": "根据关键词检索本地书目(静态样例)",
            "input_schema": {
                "type": "object",
                "properties": {
                    "search_terms": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "检索关键词列表"
                    }
                },
                "required": ["search_terms"],
                "additionalProperties": False,
            },
        }
    ]

    messages = [
        {
            "role": "user",
            "content": [{
                "type": "text",
                "text": (
                    "请严格按照以下要求完成:\n"
                    "1) 必须调用工具 search_books,并使用参数 search_terms=['Joyce'] 或 ['乔伊斯'];\n"
                    "2) 获取结果后,仅输出书名列表(中文名可选)。\n"
                    "注意:不调用工具请不要直接回答。"
                )
            }]
        }
    ]

    r1 = requests.post(
        url,
        headers=headers,
        data=json.dumps({
            "model": "MiniMax-M2",
            "max_tokens": 2048,
            "tools": tools,
            "messages": messages,
        }),
        timeout=60,
    )
    r1.raise_for_status()
    data1 = r1.json()

    tool_use_block = None
    for block in data1.get("content", []) or []:
        if block.get("type") == "tool_use" and block.get("name") == "search_books":
            tool_use_block = block
            break

    if not tool_use_block:
        texts = []
        for b in data1.get("content", []) or []:
            if b.get("type") == "text" and "text" in b:
                texts.append(b["text"])
        final_text = "".join(texts).strip()
        print({"model": data1.get("model"), "final_text": final_text})
        return 0

    args = tool_use_block.get("input", {})
    result = search_books(args.get("search_terms", []))

    # 把上轮 assistant 的 tool_use 原样带回,再追加 user 的 tool_result
    messages2 = [
        messages[0],
        {"role": "assistant", "content": [tool_use_block]},
        {
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use_block["id"],
                "content": json.dumps(result, ensure_ascii=False),
            }],
        },
    ]

    r2 = requests.post(
        url,
        headers=headers,
        data=json.dumps({
            "model": "MiniMax-M2",
            "max_tokens": 2048,
            "tools": tools,
            "messages": messages2,
        }),
        timeout=60,
    )
    r2.raise_for_status()
    data2 = r2.json()

    texts = []
    for b in data2.get("content", []) or []:
        if b.get("type") == "text" and "text" in b:
            texts.append(b["text"])
    final_text = "".join(texts).strip()

    print({"model": data2.get("model"), "final_text": final_text})
    return 0

if __name__ == "__main__":
    raise SystemExit(main())