Day12:深入探究工具调用结果解析与反馈:完善大模型应用闭环

摘要:本文着重探讨如何在大语言模型应用中,对工具调用的返回结果进行有效解析,并将其转化为模型可理解的格式,从而实现自然语言回答的生成,构建完整的 “工具调用→结果解析→回答生成” 闭环。以通义千问大模型为依托,详细阐述核心任务与补充任务的实现过程,助力读者掌握这一关键技术。

一、引言

在大语言模型借助工具解决问题的过程中,仅仅完成工具调用是不够的。如何精准解析工具返回的结果,并让模型依据这些结果生成符合用户期望的自然语言回答,是构建高效、智能应用的关键环节。今天,我们就以通义千问大模型为例,深入学习如何实现这一完整的闭环流程。

二、核心任务:实现 “工具调用→结果解析→回答生成” 的闭环

(一)工具调用结果解析基础

  1. 理解工具返回格式:不同工具返回的结果格式各异,比如天气查询工具可能返回 JSON 格式的数据,包含各种天气信息;计算器工具返回简单的数值;搜索工具可能返回包含多条信息的列表。我们需要了解每个工具返回结果的结构,以便进行针对性解析。

  2. 解析方法选择:对于简单的返回值,如计算器的结果,直接使用即可。对于复杂格式,如 JSON,我们可以使用 Python 的 json 库来提取所需信息;对于列表,可能需要根据列表元素的特点进行遍历和筛选。

(二)将结果整理为模型可理解的格式

  1. 信息提取与整合:从工具返回的结果中提取关键信息。例如,天气查询结果中,我们可能关心天气状况、温度等信息。将这些信息整合为一个简洁的格式,便于模型理解。

  2. 格式转换:有时工具返回的格式不能直接被模型处理,需要进行转换。比如将日期格式调整为模型熟悉的格式,或者将特定领域的术语转换为通用语言。

(三)让模型根据结果生成自然语言回答

  1. 构建输入提示:将整理好的结果融入到给模型的输入提示中。例如,对于天气查询结果,构建提示 “根据以下天气信息生成回答:天气状况为晴天,温度 25 摄氏度”。

  2. 调用模型生成回答:使用通义千问的 API,将构建好的提示发送给模型,获取模型生成的自然语言回答。

(四)代码实现

import requests
import json
from pydantic import BaseModel, field_validator


# 天气查询工具
class WeatherQueryParams(BaseModel):
    city: str
    api_key: str

    @field_validator('city')
    def city_not_empty(cls, v):
        if not v.strip():
            raise ValueError('城市名称不能为空')
        return v

    @field_validator('api_key')
    def api_key_not_empty(cls, v):
        if not v.strip():
            raise ValueError('api_key不能为空')
        return v


def query_weather(params: WeatherQueryParams):
    base_url = "http://api.weatherapi.com/v1/current.json"
    params_dict = {
        "key": params.api_key,
        "q": params.city
    }
    try:
        response = requests.get(base_url, params=params_dict)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        print(f"查询天气失败: {e}")
        return None


# 计算器工具
class CalculatorParams(BaseModel):
    num1: float
    num2: float
    operation: str

    @field_validator('operation')
    def valid_operation(cls, v):
        valid_ops = ['+', '-', '*', '/']
        if v not in valid_ops:
            raise ValueError('不支持的运算操作')
        return v


def calculate(params: CalculatorParams):
    if params.operation == '+':
        return params.num1 + params.num2
    elif params.operation == '-':
        return params.num1 - params.num2
    elif params.operation == '*':
        return params.num1 * params.num2
    elif params.operation == '/':
        if params.num2 == 0:
            print("除数不能为零")
            return None
        return params.num1 / params.num2


# 模拟通义千问API调用(实际需替换为真实API调用)
def call_qwen_api(api_key, prompt):
    url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}"
    }
    data = {
        "model": "qwen-plus",
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "stream": False
    }
    try:
        response = requests.post(url, headers=headers, json=data)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        print(f"调用通义千问API失败: {e}")
        return None


# 解析天气工具结果
def parse_weather_result(result):
    if result:
        condition = result["current"]["condition"]["text"]
        temp_c = result["current"]["temp_c"]
        return f"天气状况为{condition},温度为{temp_c}摄氏度"
    return ""


# 解析计算器工具结果
def parse_calculator_result(result):
    if result is not None:
        return f"计算结果为{result}"
    return ""


# 实现“调用→解析→回答”闭环
def closed_loop_flow(user_input, api_key):
    # 假设这里先判断用户输入选择工具,简单示例,实际需更复杂推理
    if "天气" in user_input:
        # 工具调用
        weather_params = WeatherQueryParams(city="北京", api_key=api_key)
        weather_result = query_weather(weather_params)
        # 结果解析
        parsed_weather = parse_weather_result(weather_result)
        # 回答生成
        prompt = f"根据以下天气信息生成回答:{parsed_weather}"
        response = call_qwen_api(api_key, prompt)
        if response:
            return response["choices"][0]["message"]["content"]
    elif "计算" in user_input:
        # 工具调用
        calculator_params = CalculatorParams(num1=3, num2=5, operation='+')
        calculator_result = calculate(calculator_params)
        # 结果解析
        parsed_calculator = parse_calculator_result(calculator_result)
        # 回答生成
        prompt = f"根据以下计算信息生成回答:{parsed_calculator}"
        response = call_qwen_api(api_key, prompt)
        if response:
            return response["choices"][0]["message"]["content"]
    return "无法处理该问题"


# 用户输入测试
if __name__ == "__main__":
    api_key = "api_key"
    user_question1 = "北京今天天气如何"
    user_question2 = "计算3加5"

    result1 = closed_loop_flow(user_question1, api_key)
    print(result1)

    result2 = closed_loop_flow(user_question2, api_key)
    print(result2)

代码说明

  1. 工具函数定义:包含天气查询(query_weather)和计算器(calculate)工具函数,以及相应的参数校验。

  2. 通义千问 API 调用函数call_qwen_api 用于调用通义千问 API,实际使用需替换真实 API 密钥。

  3. 结果解析函数parse_weather_result 用于解析天气工具返回的 JSON 结果,提取关键信息;parse_calculator_result 处理计算器工具的简单返回值。

  4. 闭环流程函数closed_loop_flow 根据用户输入选择工具,进行工具调用、结果解析,并构建提示调用通义千问生成回答。

三、补充任务:测试不同工具的结果解析

(一)测试计划

  1. 针对天气工具,测试不同城市的天气查询结果解析,包括晴天、雨天、多云等不同天气状况。

  2. 对于计算器工具,测试不同运算操作(加、减、乘、除)以及特殊情况(如除数为零)的结果解析。

  3. 考虑添加搜索工具时,测试搜索结果为列表等复杂格式的解析。

(二)处理复杂结果

  1. JSON 格式结果:如天气工具返回的 JSON,通过指定键值准确提取所需信息,如天气状况、温度等。

  2. 列表格式结果:假设搜索工具返回包含多个搜索结果的列表,可以根据需求选择第一个结果,或者对所有结果进行摘要处理。例如,提取每个搜索结果的标题和简要描述,组合成一个更易读的格式供模型理解。

(三)确保模型能正确理解并生成回答

  1. 仔细检查解析后的结果格式是否符合模型输入要求,避免出现格式错误导致模型误解。

  2. 通过多次测试不同输入,观察模型生成的回答是否合理。如果回答不合理,调整解析方法或输入提示,确保模型能够准确理解解析后的结果并生成恰当的回答。

四、总结

通过今天的学习,我们成功实现了 “工具调用→结果解析→回答生成” 的闭环,并且对不同工具的结果解析进行了测试和优化,以确保模型能正确处理复杂结果并生成合适的回答。

在实际应用中,不同工具的结果格式可能更加复杂多样,需要根据具体情况灵活调整解析方法。记得将工具结果解析代码和完整的闭环代码整理保存,方便后续参考和扩展。如果在学习过程中遇到问题,比如模型生成的回答不符合预期,可以检查工具调用是否成功、结果解析是否准确以及输入提示是否合理。

希望大家通过掌握这些知识和技能,在基于大语言模型的应用开发中能够构建更加完善、智能的系统。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐