本文从最简单的时间工具入手,分析Tools相关的代码。

一、安装工具

git clone https://github.com/open-webui/openapi-servers
cd openapi-servers

# 进入时间工具目录
cd servers/time

pip install -r requirements.txt

# 启动服务
uvicorn main:app --host 0.0.0.0 --reload #缺省使用8000端口

二、配置

以admin登录webui,配置->工具,增加安装完成的工具地址:

在聊天窗口出现安装的工具:

在对话高级设置,设置函数调用(Function Calling)设置为原生。

        三、代码分析

       1)主要流程

       在交互过程中,工具调用相关流程如下图所示:

        2)入口参数

        http://{ip:port}/api/chat/completions入口参数如下,与前述对比其中增加了tool_servers,其中包含了所有工具的说明。

{
"stream": true,
"model": "deepseek-r1:1.5b",
"messages": [
{
"role": "user",
"content": "请告诉现在东京的时间"
}
],
"params": {},
"tool_servers": [
{
"url": "http://192.168.21.201:8000",
"openapi": {
"openapi": "3.1.0",
"info": {
"title": "Secure Time Utilities API",
"description": "Provides secure UTC/local time retrieval, formatting, timezone conversion, and comparison.",
"version": "1.0.0"
},
"paths": {
"/get_current_utc_time": {
"get": {
"summary": "Current UTC time",
"description": "Returns the current time in UTC in ISO format.",
"operationId": "get_current_utc_get_current_utc_time_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/get_current_local_time": {
"get": {
"summary": "Current Local Time",
"description": "Returns the current time in local timezone in ISO format.",
"operationId": "get_current_local_get_current_local_time_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
},
"/format_time": {
"post": {
"summary": "Format current time",
"description": "Return the current time formatted for a specific timezone and format.",
"operationId": "format_current_time_format_time_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormatTimeInput"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/convert_time": {
"post": {
"summary": "Convert between timezones",
"description": "Convert a timestamp from one timezone to another.",
"operationId": "convert_time_convert_time_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConvertTimeInput"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/elapsed_time": {
"post": {
"summary": "Time elapsed between timestamps",
"description": "Calculate the difference between two timestamps in chosen units.",
"operationId": "elapsed_time_elapsed_time_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ElapsedTimeInput"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/parse_timestamp": {
"post": {
"summary": "Parse and normalize timestamps",
"description": "Parse human-friendly input timestamp and return standardized UTC ISO time.",
"operationId": "parse_timestamp_parse_timestamp_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ParseTimestampInput"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/list_time_zones": {
"get": {
"summary": "All valid time zones",
"description": "Return a list of all valid IANA time zones.",
"operationId": "list_time_zones_list_time_zones_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ConvertTimeInput": {
"properties": {
"timestamp": {
"type": "string",
"title": "Timestamp",
"description": "ISO 8601 formatted time string (e.g., 2024-01-01T12:00:00Z)"
},
"from_tz": {
"type": "string",
"title": "From Tz",
"description": "Original IANA time zone of input (e.g. UTC or Europe/Berlin)"
},
"to_tz": {
"type": "string",
"title": "To Tz",
"description": "Target IANA time zone to convert to"
}
},
"type": "object",
"required": [
"timestamp",
"from_tz",
"to_tz"
],
"title": "ConvertTimeInput"
},
"ElapsedTimeInput": {
"properties": {
"start": {
"type": "string",
"title": "Start",
"description": "Start timestamp in ISO 8601 format"
},
"end": {
"type": "string",
"title": "End",
"description": "End timestamp in ISO 8601 format"
},
"units": {
"type": "string",
"enum": [
"seconds",
"minutes",
"hours",
"days"
],
"title": "Units",
"description": "Unit for elapsed time",
"default": "seconds"
}
},
"type": "object",
"required": [
"start",
"end"
],
"title": "ElapsedTimeInput"
},
"FormatTimeInput": {
"properties": {
"format": {
"type": "string",
"title": "Format",
"description": "Python strftime format string",
"default": "%Y-%m-%d %H:%M:%S"
},
"timezone": {
"type": "string",
"title": "Timezone",
"description": "IANA timezone name (e.g., UTC, America/New_York)",
"default": "UTC"
}
},
"type": "object",
"title": "FormatTimeInput"
},
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"ParseTimestampInput": {
"properties": {
"timestamp": {
"type": "string",
"title": "Timestamp",
"description": "Flexible input timestamp string (e.g., 2024-06-01 12:00 PM)"
},
"timezone": {
"type": "string",
"title": "Timezone",
"description": "Assumed timezone if none is specified in input",
"default": "UTC"
}
},
"type": "object",
"required": [
"timestamp"
],
"title": "ParseTimestampInput"
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
}
}
},
"info": {
"title": "Secure Time Utilities API",
"description": "Provides secure UTC/local time retrieval, formatting, timezone conversion, and comparison.",
"version": "1.0.0"
},
"specs": [
{
"type": "function",
"name": "get_current_utc_get_current_utc_time_get",
"description": "Returns the current time in UTC in ISO format.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
},
{
"type": "function",
"name": "get_current_local_get_current_local_time_get",
"description": "Returns the current time in local timezone in ISO format.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
},
{
"type": "function",
"name": "format_current_time_format_time_post",
"description": "Return the current time formatted for a specific timezone and format.",
"parameters": {
"type": "object",
"properties": {
"format": {
"type": "string",
"description": "Python strftime format string"
},
"timezone": {
"type": "string",
"description": "IANA timezone name (e.g., UTC, America/New_York)"
}
},
"required": []
}
},
{
"type": "function",
"name": "convert_time_convert_time_post",
"description": "Convert a timestamp from one timezone to another.",
"parameters": {
"type": "object",
"properties": {
"timestamp": {
"type": "string",
"description": "ISO 8601 formatted time string (e.g., 2024-01-01T12:00:00Z)"
},
"from_tz": {
"type": "string",
"description": "Original IANA time zone of input (e.e.g. UTC or Europe/Berlin)"
},
"to_tz": {
"type": "string",
"description": "Target IANA time zone to convert to"
}
},
"required": [
"timestamp",
"from_tz",
"to_tz"
]
}
},
{
"type": "function",
"name": "elapsed_time_elapsed_time_post",
"description": "Calculate the difference between two timestamps in chosen units.",
"parameters": {
"type": "object",
"properties": {
"start": {
"type": "string",
"description": "Start timestamp in ISO 8601 format"
},
"end": {
"type": "string",
"description": "End timestamp in ISO 8601 format"
},
"units": {
"type": "string",
"description": "Unit for elapsed time"
}
},
"required": [
"start",
"end"
]
}
},
{
"type": "function",
"name": "parse_timestamp_parse_timestamp_post",
"description": "Parse human-friendly input timestamp and return standardized UTC ISO time.",
"parameters": {
"type": "object",
"properties": {
"timestamp": {
"type": "string",
"description": "Flexible input timestamp string (e.g., 2024-06-01 12:00 PM)"
},
"timezone": {
"type": "string",
"description": "Assumed timezone if none is specified in input"
}
},
"required": [
"timestamp"
]
}
},
{
"type": "function",
"name": "list_time_zones_list_time_zones_get",
"description": "Return a list of all valid IANA time zones.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
]
}
],
"features": {
"image_generation": false,
"code_interpreter": false,
"web_search": false,
"memory": false
},
"variables": {
"{{USER_NAME}}": "acaluis",
"{{USER_LOCATION}}": "Unknown",
"{{CURRENT_DATETIME}}": "2025-08-19 18:06:37",
"{{CURRENT_DATE}}": "2025-08-19",
"{{CURRENT_TIME}}": "18:06:37",
"{{CURRENT_WEEKDAY}}": "Tuesday",
"{{CURRENT_TIMEZONE}}": "Etc/GMT-8",
"{{USER_LANGUAGE}}": "zh-CN"
},
"model_item": {
"id": "deepseek-r1:1.5b",
"name": "deepseek-r1:1.5b",
"object": "model",
"created": 1755597385,
"owned_by": "ollama",
"ollama": {
"name": "deepseek-r1:1.5b",
"model": "deepseek-r1:1.5b",
"modified_at": "2025-08-17T04:50:08.766430912Z",
"size": 1117322768,
"digest": "e0979632db5a88d1a53884cb2a941772d10ff5d055aabaa6801c4e36f3a6c2d7",
"details": {
"parent_model": "",
"format": "gguf",
"family": "qwen2",
"families": [
"qwen2"
],
"parameter_size": "1.8B",
"quantization_level": "Q4_K_M"
},
"connection_type": "local",
"urls": [
0
]
},
"connection_type": "local",
"tags": [],
"actions": [],
"filters": []
},
"session_id": "R-JB6cdCyrSZ-GRcAAJc",
"chat_id": "f9ad2990-5ad1-44fc-b3ea-c5cfee936588",
"id": "d85123d0-276b-4796-afd0-f203a8606ecf",
"background_tasks": {
"title_generation": true,
"tags_generation": true,
"follow_up_generation": true
}
}

       3)代码分析

        在chat_completion方法中,在metadata中设置{function_calling:native},一般情况下不设置。

@app.post("/api/chat/completions")
async def chat_completion(
request: Request,
form_data: dict,
user=Depends(get_verified_user),
):

   try:
if not model_item.get("direct", False): #使用ollama作为后台时,走该分支
model_id = form_data.get("model", None)
if model_id not in request.app.state.MODELS:
raise Exception("Model not found")

            model = request.app.state.MODELS[model_id]

            #如果使用ollama中的标准模型model_info为空
model_info = Models.get_model_by_id(model_id)

            # Check if user has access to the model
if not BYPASS_MODEL_ACCESS_CONTROL and user.role == "user":
try:
check_model_access(user, model)
except Exception as e:
raise e
else:
model = model_item
model_info = None

            request.state.direct = True
request.state.model = model

        metadata = {
"user_id": user.id,
……
**( #一般情况,请求中的params为空,并且model_info也为空,所以走else分支
{"function_calling": "native"}
if form_data.get("params", {}).get("function_calling") == "native"
or (
model_info
and model_info.params.model_dump().get("function_calling")
== "native"
)
else {}#非native
),
}

        ……

        在process_chat_payload处理function_calling,相关代码如下:

 async def process_chat_payload(request, form_data, user, metadata, model):
……

    tools_dict = {}

    if tool_ids: #当前仅配置了一个Tool,故tool_ids为空
tools_dict = get_tools(
request,
tool_ids,
user,
{
**extra_params,
"__model__": models[task_model_id],
"__messages__": form_data["messages"],
"__files__": metadata.get("files", []),
},
)

    if tool_servers:
for tool_server in tool_servers:
tool_specs = tool_server.pop("specs", []) 

            for tool in tool_specs:
tools_dict[tool["name"]] = {
"spec": tool,
"direct": True,
"server": tool_server,
}

    if tools_dict: 

        #一般情况,前面chat_completion方法中并未设置function_calling:native,所以走else
if metadata.get("function_calling") == "native":
# If the function calling is native, then call the tools function calling handler
metadata["tools"] = tools_dict
form_data["tools"] = [
{"type": "function", "function": tool.get("spec", {})}
for tool in tools_dict.values()
]
else:#走本分支,调用大模型获取function_calling结果
try:
form_data, flags = await chat_completion_tools_handler(
request, form_data, extra_params, user, models, tools_dict
)
sources.extend(flags.get("sources", []))

            except Exception as e:
log.exception(e)

        

    # 仅处理知识库上下文列表,与调用工具获取的列表无关,后继代码省略

    if len(sources) > 0:

        context_string = ""

        citation_idx_map = {}

        for source in sources:

            is_tool_result = source.get("tool_result", False)

            if "document" in source and not is_tool_result:

                ……

     #如果没有查询过向量库则context_string为空

     context_string = context_string.strip()
prompt = get_last_user_message(form_data["messages"])

        if prompt is None:

            raise Exception("No user message found")

        if context_string == "":#如果未查询向量库或未查询到,则输出日志

            if request.app.state.config.RELEVANCE_THRESHOLD == 0:

                log.debug(

                    f"With a 0 relevancy threshold for RAG, the context cannot be empty"

                )

        else:#如果有上下文查询结果,则需要用系统所带的RAG模版组装请求消息。不再详解

            # Workaround for Ollama 2.0+ system prompt issue

            # TODO: replace with add_or_update_system_message

            if model.get("owned_by") == "ollama":

                form_data["messages"] = prepend_to_first_user_message_content(

                    rag_template(

                        request.app.state.config.RAG_TEMPLATE, context_string, prompt

                    ),

                    form_data["messages"],

                )

            else:

                form_data["messages"] = add_or_update_system_message(

                    rag_template(

                        request.app.state.config.RAG_TEMPLATE, context_string, prompt

                    ),

                    form_data["messages"],

                )

     ……

        以下重点分析chat_completion_tools_handler方法。

async def chat_completion_tools_handler(
request: Request, body: dict, extra_params: dict, user: UserModel, models, tools
) -> tuple[dict, dict]:
async def get_content_from_response(response) -> Optional[str]:
content = None
if hasattr(response, "body_iterator"):
async for chunk in response.body_iterator:
data = json.loads(chunk.decode("utf-8"))
content = data["choices"][0]["message"]["content"]

            # Cleanup any remaining background tasks if necessary
if response.background is not None:
await response.background()
else:
content = response["choices"][0]["message"]["content"]
return content

   

    '''

    get_tools_function_calling_payload方法负责组装发送的ollama的function_calling请求,示例如begin-end之间内容。

---------------------------------begin--------------------------------------------------------------------------------

{
"model": "qwen:0.5b",
"messages": [
{
"role": "system",
"content": "Available Tools: [{\"type\": \"function\", \"name\": \"get_current_utc_get_current_utc_time_get\", \"description\": \"Returns the current time in UTC in ISO format.\", \"parameters\": {\"type\": \"object\", \"properties\": {}, \"required\": []}}, {\"type\": \"function\", \"name\": \"get_current_local_get_current_local_time_get\", \"description\": \"Returns the current time in local timezone in ISO format.\", \"parameters\": {\"type\": \"object\", \"properties\": {}, \"required\": []}}, {\"type\": \"function\", \"name\": \"format_current_time_format_time_post\", \"description\": \"Return the current time formatted for a specific timezone and format.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"format\": {\"type\": \"string\", \"description\": \"Python strftime format string\"}, \"timezone\": {\"type\": \"string\", \"description\": \"IANA timezone name (e.g., UTC, America/New_York)\"}}, \"required\": []}}, {\"type\": \"function\", \"name\": \"convert_time_convert_time_post\", \"description\": \"Convert a timestamp from one timezone to another.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"timestamp\": {\"type\": \"string\", \"description\": \"ISO 8601 formatted time string (e.g., 2024-01-01T12:00:00Z)\"}, \"from_tz\": {\"type\": \"string\", \"description\": \"Original IANA time zone of input (e.g. UTC or Europe/Berlin)\"}, \"to_tz\": {\"type\": \"string\", \"description\": \"Target IANA time zone to convert to\"}}, \"required\": [\"timestamp\", \"from_tz\", \"to_tz\"]}}, {\"type\": \"function\", \"name\": \"elapsed_time_elapsed_time_post\", \"description\": \"Calculate the difference between two timestamps in chosen units.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"start\": {\"type\": \"string\", \"description\": \"Start timestamp in ISO 8601 format\"}, \"end\": {\"type\": \"string\", \"description\": \"End timestamp in ISO 8601 format\"}, \"units\": {\"type\": \"string\", \"description\": \"Unit for elapsed time\"}}, \"required\": [\"start\", \"end\"]}}, {\"type\": \"function\", \"name\": \"parse_timestamp_parse_timestamp_post\", \"description\": \"Parse human-friendly input timestamp and return standardized UTC ISO time.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"timestamp\": {\"type\": \"string\", \"description\": \"Flexible input timestamp string (e.g., 2024-06-01 12:00 PM)\"}, \"timezone\": {\"type\": \"string\", \"description\": \"Assumed timezone if none is specified in input\"}}, \"required\": [\"timestamp\"]}}, {\"type\": \"function\", \"name\": \"list_time_zones_list_time_zones_get\", \"description\": \"Return a list of all valid IANA time zones.\", \"parameters\": {\"type\": \"object\", \"properties\": {}, \"required\": []}}]\n\nYour task is to choose and return the correct tool(s) from the list of available tools based on the query. Follow these guidelines:\n\n- Return only the JSON object, without any additional text or explanation.\n\n- If no tools match the query, return an empty array: \n   {\n     \"tool_calls\": []\n   }\n\n- If one or more tools match the query, construct a JSON response containing a \"tool_calls\" array with objects that include:\n   - \"name\": The tool's name.\n   - \"parameters\": A dictionary of required parameters and their corresponding values.\n\nThe format for the JSON response is strictly:\n{\n  \"tool_calls\": [\n    {\"name\": \"toolName1\", \"parameters\": {\"key1\": \"value1\"}},\n    {\"name\": \"toolName2\", \"parameters\": {\"key2\": \"value2\"}}\n  ]\n}"
},
{
"role": "user",
"content": "Query: History:\nUSER: \"\"\"\u8bf7\u544a\u8bc9\u6211\u5f53\u524d\u5927\u962a\u7684\u65f6\u95f4\"\"\"\nQuery: \u8bf7\u544a\u8bc9\u6211\u5f53\u524d\u5927\u962a\u7684\u65f6\u95f4"
}
],
"stream": false

  "metadata": {"ftask"f:"function_calling"}
}

----------------------------------------------------end---------------------------------------------------------------

    '''

    def get_tools_function_calling_payload(messages, task_model_id, content):

        #从请求表单中提取用户提问
user_message = get_last_user_message(messages)
history = "\n".join(
f"{message['role'].upper()}: \"\"\"{message['content']}\"\"\""
for message in messages[::-1][:4] #请求表单中messages列表倒序排列后取前4个
)

        #先在history 前增加History:,再拼接Query:用户问题

        prompt = f"History:\n{history}\nQuery: {user_message}"

        return {
"model": task_model_id,
"messages": [
{"role": "system", "content": content},
{"role": "user", "content": f"Query: {prompt}"},
],
"stream": False,
"metadata": {"task": str(TASKS.FUNCTION_CALLING)},
}

    event_caller = extra_params["__event_call__"]
metadata = extra_params["__metadata__"]

    #确定执行function_calling任务的模型,实际为用户聊天时选择的模型   

    task_model_id = get_task_model_id(
body["model"],
request.app.state.config.TASK_MODEL,
request.app.state.config.TASK_MODEL_EXTERNAL,
models,
)

    skip_files = False
sources = []

    specs = [tool["spec"] for tool in tools.values()]

    '''

        specs数据如下:

        [

            {
"type": "function",
"name": "get_current_utc_get_current_utc_time_get",
"description": "Returns the current time in UTC in ISO format.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
},

            ……

       ]

    '''

    tools_specs = json.dumps(specs)

    if request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE != "":
template = request.app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE
else: #未配置工具函数模板时,使用缺省的模板
template = DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE

    #用tool_spces内容替换模板中的{TOOL}

    tools_function_calling_prompt = tools_function_calling_generation_template(
template, tools_specs
)

    #组织发送到ollama的请求,具体见上面的函数定义部分
payload = get_tools_function_calling_payload(
body["messages"], task_model_id, tools_function_calling_prompt
)

    try:

        #调用大模型获取需要调用的工具信息
response = await generate_chat_completion(request, form_data=payload, user=user)
log.debug(f"{response=}")
content = await get_content_from_response(response)
log.debug(f"{content=}")

        ''' 

            以下是一个无参函数示例时cotent的示例内容

            {
"tool_calls": [
{
"name": "get_current_local",
"parameters": {}
}
]
}

        '''

        

        if not content:
return body, {}

        try:
content = content[content.find("{") : content.rfind("}") + 1]
if not content:
raise Exception("No JSON object found in the response")

            result = json.loads(content)

            #该方法根据function_calling调用结果进行后继的调用处理,需要重点分析

            async def tool_call_handler(tool_call):
nonlocal skip_files

                log.debug(f"{tool_call=}")

                '''

                     获取函数名和函数参数。

                     防错处理:如果大模型返回的函数名字,不在本请求所提供的工具列表中,则

                    返回请求表单+{}

               '''

                tool_function_name = tool_call.get("name", None)
if tool_function_name not in tools:
return body, {}

                tool_function_params = tool_call.get("parameters", {})

                try:
tool = tools[tool_function_name]

                    spec = tool.get("spec", {})
allowed_params = (#工具定义时允许的参数列表
spec.get("parameters", {}).get("properties", {}).keys()
)
tool_function_params = {#实际的参数必须在工具允许的参数列表中,否则丢弃
k: v
for k, v in tool_function_params.items()
if k in allowed_params
}

                    if tool.get("direct", False): #如果是外部服务函数,则本分支

                        '''

                           通过websocket发送请求到前端,前端走API调用,并返回结果。

                           结果为列表,比如:

                          [

                              {"local_time":"2025-08-20T12:09:16.773972"}

                          ]

                       '''
tool_result = await event_caller(
{
"type": "execute:tool",
"data": {
"id": str(uuid4()),
"name": tool_function_name,
"params": tool_function_params,
"server": tool.get("server", {}),
"session_id": metadata.get("session_id", None),
},
}
)
else: #如果是本地代码中的函数,则直接调用函数
tool_function = tool["callable"]
tool_result = await tool_function(**tool_function_params)

                except Exception as e:
tool_result = str(e)

                '''

                   以下代码针对function_calling涉及引用文件时的处理,此时列表中的元素为

                   data:开头的字符串,支架到tool_result_files列表中,并从源列表删除

                '''

                tool_result_files = []
if isinstance(tool_result, list):
for item in tool_result:
# check if string
if isinstance(item, str) and item.startswith("data:"):
tool_result_files.append(item)
tool_result.remove(item)

                if isinstance(tool_result, dict) or isinstance(tool_result, list):#转换为JSON串
tool_result = json.dumps(tool_result, indent=2)

                if isinstance(tool_result, str):#因前面以把tool_result转换为字符串,进入本分支
tool = tools[tool_function_name]
tool_id = tool.get("tool_id", "")

                    tool_name = (
f"{tool_id}/{tool_function_name}"
if tool_id
else f"{tool_function_name}"
)
'''

                          把类似如下数据追加到sources列表中:

                        {
"source":{

                                 "name": "TOOL:get_current_local_get_current_local_time_get"

                            },
"document": [
{
"local_time": "2025-08-20T11:54:16.180931"
}
],
"metadata": [
{
"source": "TOOL:get_current_local_get_current_local_time_get",
"parameters": {}
}
],

                            "tool_result": True
}

                      '''
sources.append(
{
"source": {
"name": (f"TOOL:{tool_name}"),
},
"document": [tool_result],
"metadata": [
{
"source": (f"TOOL:{tool_name}"),
"parameters": tool_function_params,
}
],
}
)
'''

                            把function_calling相关结果拼接后追加到用户请求表单的messages中,比

                            如一个对话中拼接后的messages:

                          [
{
"role": "user",
"content": "请告诉我当前大阪的时间"
},
{
"role": "assistant",
"content": "\n根据工具返回的示例数据,当前大阪的本地时间是 **2025年8月20日 11:54:16**。请注意,此时间是示例数据,实际当前时间可能不同。若需真实时间,请结合实时数据更新。"
},
{
"role": "user",
"content": "请告诉我当前的时间\n\nTool                                 `get_current_local_get_current_local_time_get` Output: {\n  \"local_time\": \"2025-08-20T11:59:16.404818\"\n}"
}
]

                        '''
body["messages"] = add_or_update_user_message(
f"\nTool `{tool_name}` Output: {tool_result}",
body["messages"],
)

                    if (
tools[tool_function_name]
.get("metadata", {})
.get("file_handler", False)
):
skip_files = True

            '''

                如果function_calling返回的tool_calls列表不为空,则迭代调用tool_call_handler,

                否则直接调用tool_call_handler

            '''
if result.get("tool_calls"):
for tool_call in result.get("tool_calls"):
await tool_call_handler(tool_call)
else:
await tool_call_handler(result)

        except Exception as e:
log.debug(f"Error: {e}")
content = None
except Exception as e:
log.debug(f"Error: {e}")
content = None

    log.debug(f"tool_contexts: {sources}")

    if skip_files and "files" in body.get("metadata", {}):
del body["metadata"]["files"]

    return body, {"sources": sources}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919655.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919655.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919655.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows下通过vscode远程调试linux c/cpp程序配置

windows下通过vscode远程调试linux c/cpp程序配置vscode插件配置linux依赖工具安装launch.json配置vscode插件配置 CodeLLDB插件需要提前下载: linux依赖工具安装 sudo apt update sudo apt install cmake clangdlaunch.json配置 {"version": "0…

IDEA报JDK版本问题

解决思路:1.找到配置jdk的IDEA配置位置settings和project structure2.先配置setting3.再修改项目结构

VirtualBox 安装 Ubuntu Server 系统及 Ubuntu 初始配置

文章目录简介VirtualBoxUbuntu Server 简介Ubuntu Server 下载安装 Ubuntu Server首选项配置导入系统镜像配置系统用户配置内存 CPU 虚拟硬盘开始安装 Ubuntu安装完成登录系统配置网络Ubuntu 系统配置安装常用工具安装 SSH设置 root 密码配置 IP 地址(推荐自动分配I…

Milvus 可观测性最佳实践

Milvus 介绍 Milvus 是一个开源的向量数据库,专为处理大规模、高维度向量数据而设计,广泛应用于人工智能、推荐系统、图像检索、自然语言处理等场景。它支持亿级向量的高效存储与快速检索,内置多种相似度搜索算法(如 HNSW、IVF、…

arcgis-空间矫正工具(将下发数据A的信息放置原始数据B的原始信息并放置到成果数据C中,主要按下发数据A的范围)

正常来说,可以直接相交获取,但是会存在原始数据B将下发数据A进行分割,所以相交功能会导致最终成果会产生稀碎图斑及图斑切割,因此,经学习了解,学会此方法进行既保留原始数据B的信息,又按下发数据…

MySQL深分页慢问题及性能优化

在数据驱动的应用中,分页是不可或缺的功能。然而,当数据量达到百万甚至千万级别时,传统基于 LIMIT OFFSET 的分页方式会遭遇严重的性能瓶颈,即“深分页”问题。本文将剖析其根源并提供主流的优化策略。问题根源:LIMIT …

漫谈《数字图像处理》之平滑

在数字图像处理中,平滑(Smoothing) 的核心目标是降低图像噪声、模糊细节或简化纹理,本质是通过 “局部邻域运算” 对像素值进行 “平均化” 或 “规整化”,让图像整体更 “平缓”。形态学平滑与高斯平滑、均值平滑等其…

机器学习之数据预处理学习总结

在机器学习中,数据预处理是模型训练前至关重要的环节,直接影响模型的性能和准确性。通过本次学习,我系统掌握了数据预处理的核心方法与工具,现将主要内容总结如下:一、缺失值处理缺失值是实际数据中常见的问题&#xf…

在完全没有无线网络(Wi-Fi)和移动网络(蜂窝数据)的环境下,使用安卓平板,通过USB数据线(而不是Wi-Fi)来控制电脑(版本2)

在完全没有无线网络(Wi-Fi)和移动网络(蜂窝数据)的环境下,要实现用安卓手机通过USB数据线控制电脑,核心思路是:利用USB数据线创建一個纯粹的、本地的有线网络连接。 这不仅是可行的,…

Ubuntu22.04配置网络上网

前言 安装Ubuntu系统后,有时会遇到无法联网、无法使用浏览器的问题。然而当宿主机已连接网络时,虚拟机通常也能联网,需要进行一些配置,现在就以Ubuntu22.04为例。 VMware配置打开虚拟网络编辑器 启动VMWare点击编辑,并…

网络协议之TCP和UDP

写在前面 本文来看下TCP和UDP协议。 我们接触这两个协议最多的应该就是在面试中了,经典题目就是“TCP和UDP有什么区别?”,而最常得到的答案就是TCP是面向连接的,而UDP是面向无连接的。 那么这里的连接到底是什么呢?难…

Qt音乐播放器项目实践:本地持久化与边角问题处理

本音乐播放器完整项目源码(包含各个按钮的图片文件): ly/Project-Code - Gitee.com 一.本地持久化 请注意,学习此部分之前需要读者具有一定的Mysql基础。如果读者能够接受无法本地持久化,那么可以跳过这部分内容,直接去看边角问题处理。我…

基于NB-IoT技术的宠物定位跟踪系统设计#基于STM32\物联网\单片机技术的宠物定位跟踪系统

基于NB-IoT技术的宠物定位跟踪系统设计#基于STM32\物联网\单片机技术的宠物定位跟踪系统在设计基于NB-IoT技术的宠物定位跟踪系统时,首先明确了系统分为感知层、网络层和应用层三个部分。在感知层,考虑到需要获取宠物位置和运动状态,选用GPS定…

【入门级-算法-3、基础算法:递归法】

递归是一种非常重要的算法思想,它指的是函数调用自身的过程。递归通常包含两个主要部分:基线条件(终止条件)和递归条件(调用自身的条件)。 下面通过例子来理解递归算法: 计算阶乘 阶乘的递归定义…

【CS创世SD NAND征文】存储芯片在工业电表中的应用与技术演进

【CS创世SD NAND征文】存储芯片在工业电表中的应用与技术演进1.工业电表的市场背景2.技术方案分析3.核心技术特性3.1.主控芯片:APM32F465VET63.3.存储芯片:CSNP4GCR01-DPW3.3.1. 基本概述3.3.2. 核心特性3.3.3. 优势特点3.3.4 四大管理算法4.存储芯片性能…

建筑施工遮挡场景漏检率↓76%:陌讯动态融合算法实战解析

原创声明 本文为原创内容,技术参数及架构解析引用自《陌讯技术白皮书》,未经授权禁止转载。 一、行业痛点:建筑施工安全监控的 "看得见" 与 "看不准" 建筑施工场景的安全监控长期面临双重挑战:一方面&…

【LeetCode题解】LeetCode 209. 长度最小的子数组

【题目链接】 209. 长度最小的子数组 【题目描述】 【题解】 方法一:滑动窗口 本题可以使用双指针算法,定义两个指针l和r分别表示子数组的开始位置和起始位置,sum数组存储的从l到r区间内所有元素的和。初始状态下,l和r都指向下…

2025-08-21 Python进阶6——迭代器生成器与with

文章目录1 迭代器与生成器1.1 迭代器1.1.1 基本使用1.1.2 手动迭代(带异常处理)1.1.3 自定义迭代器1.2 生成器1.2.1 工作原理1.2.2 斐波那契数列示例1.3 推导式1.3.1 列表推导式1.3.2 字典推导式1.3.3 集合推导式1.4.4 元组推导式(生成器表达…

C++——C++重点知识点复习2(详细复习模板,继承)

目录 模板 函数模板 类模板 非类型模板参数 模板的特化 函数模板特化 类模板的特化 为什么普通函数可以分离? 继承 继承概念 基类和派生类对象赋值转换(切割,切片) 隐藏 派生类的默认成员函数 .复杂的菱形继承及菱形…

python 项目编号 2025821 有关于中英文数据的收集、处理

python专栏记录:前言 批量读取单词 JSON 文件 → 解析出单词、释义、例句、短语 → 数据清洗(去掉特殊符号) → 同步更新到 MySQL 数据库。 内容 import json import pymysql import re import time from pymysql.converters import escape_s…