AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


langchain和qwen实现tool工具代理的几种方式
发布日期:2024-05-15 04:15:44 浏览次数: 4520 来源:河指令


大模型在面对实行性、私域知识型问题或数学计算等问题时可能效果不佳,如查询天气,连续搜索引擎查询等。最常使用的解决方式就是直接调用外部工具来提升模型的输出效果。


大纲:

qwen请求的介绍

使用工具的流程

一、通过官方例子实现

二、通过langchain实现


有些模型是不支持调用工具的,下面我们看下qwen调用工具的参数要求,其实就是在参数中声明roletool

qwen请求的介绍

  • messages:用户与模型的对话历史。array中的每个元素形式为{"role":角色, "content": 内容},角色当前可选值:systemuserassistanttool

    • system:表示系统级消息,用于指导模型按照预设的规范、角色或情境进行回应。是否使用system角色是可选的,如果使用则必须位于messages的最开始部分。

    • userassistant:表示用户和模型的消息。它们应交替出现在对话中,模拟实际对话流程。

    • tool:表示工具的消息。在使用function call功能时,如果要传入工具的结果,需将元素的形式设为{"content":"工具返回的结果", "name":"工具的函数名", "role":"tool"}。其中name是工具函数的名称,需要和上轮response中的tool_callsi['name']参数保持一致;content是工具函数的输出。


tool参数用于指定可供模型调用的工具库,一次function call流程模型会从中选择其中一个工具。tools中每一个tool的结构如下:

  • type,类型为string,表示tools的类型,当前仅支持function。

  • function,类型为object,键值包括name,description和parameters:

    • name:类型为string,表示工具函数的名称,必须是字母、数字,可以包含下划线和短划线,最大长度为64。

    • description:类型为string,表示工具函数的描述,供模型选择何时以及如何调用工具函数。

    • parameters:类型为object,表示工具的参数描述,需要是一个合法的JSON Schema。如果parameters参数为空,表示function没有入参。

使用tools时需要同时指定result_format为message。在function call流程中,无论是发起function call的轮次,还是向模型提交工具函数的执行结果,均需设置tools参数。当前支持的模型包括qwen-turbo、qwen-plus、qwen-max和qwen-max-longcontext。

说明

tools暂时无法和incremental_output参数同时使用。


使用工具的流程

大概使用的工具的流程是,首先我们向大模型提出问题,在提问之前我们要把使用的工具配置和用户提的问题一起发送给大模型,工具的配置一般都会有工具的名称和参数,还有对工具的描述,这几个参数是很重要的。大模型拿到数据后,会根据用户提的问题判断应该调用哪个工具,之后会把调用的工具的信息返回给我们的程序,程序再根据工具名称判断调用哪个工具,拿到结果之后再二次发送给模型进行加工。

注:该图来源于千问模型官网


背景也交代完了,下面我们就直接开始教程吧。


一、通过官方例子实现

from dashscope import Generation
from datetime import datetime
import random

# 定义工具列表,模型在选择使用哪个工具时会参考工具的name和description
tools = [
   # 工具1 获取当前时刻的时间
 {
       "type": "function",
       "function": {
           "name": "get_current_time",
           "description": "当你想知道现在的时间时非常有用。",
           "parameters": {}  # 因为获取当前时间无需输入参数,因此parameters为空字典
     }
 },  
   # 工具2 获取指定城市的天气
 {
       "type": "function",
       "function": {
           "name": "get_current_weather",
           "description": "当你想查询指定城市的天气时非常有用。",
           "parameters": {  # 查询天气时需要提供位置,因此参数设置为location
                       "type": "object",
               "properties": {
                   "location": {
                       "type": "string",
                       "description": "城市或县区,比如北京市、杭州市、余杭区等。"
                 }
             }
         },
           "required": [
               "location"
         ]
     }
 }
]

# 模拟天气查询工具。返回结果示例:“北京今天是晴天。”
def get_current_weather(location):
   return f"{location}今天是晴天。 "

# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
   # 获取当前日期和时间
   current_datetime = datetime.now()
   # 格式化当前日期和时间
   formatted_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
   # 返回格式化后的当前时间
   return f"当前时间:{formatted_time}。"

# 封装模型响应函数
def get_response(messages):
   response = Generation.call(
       model='qwen-turbo',
       messages=messages,
       tools=tools,
       api_key="申请的qwen-api-key",
       seed=random.randint(1, 10000),  # 设置随机数种子seed,如果没有设置,则随机数种子默认为1234
       result_format='message'  # 将输出设置为message形式
 )
   return response

def call_with_messages():
   messages = [
         {
               "content": input('请输入问题:'),  # 提问示例:"现在几点了?" "一个小时后几点" "北京天气如何?"
               "role": "user"
         }
 ]
   
   # 模型的第一轮调用
   assistant_output = get_response(messages).output.choices[0].message
   print("返回的消息:")
   print(assistant_output)
   messages.append(assistant_output)
   if 'tool_calls' not in assistant_output:  # 如果模型判断无需调用工具,则将assistant的回复直接打印出来,无需进行模型的第二轮调用
       print(assistant_output.content)
       return
   # 如果模型选择的工具是get_current_weather
   elif assistant_output.tool_calls[0]['function']['name'] == 'get_current_weather':
       tool_info = {"name": "get_current_weather", "role":"tool"}
       location = assistant_output.tool_calls[0]['function']['arguments']
       print(f"调用天气的参数:{location}")
       tool_info['content'] = get_current_weather(location)
   # 如果模型选择的工具是get_current_time
   elif assistant_output.tool_calls[0]['function']['name'] == 'get_current_time':
       tool_info = {"name": "get_current_time", "role":"tool"}
       tool_info['content'] = get_current_time()
   messages.append(tool_info)

   print(messages)

   # 模型的第二轮调用,对工具的输出进行总结
   response = get_response(messages)
   print(f"模型回复:{response.output.choices[0].message['content']}")

   
if __name__ == '__main__':
   call_with_messages()
   


二、通过langchain实现

langchain中最常使用的是通过bind_tools方法(注:以下代码不能直接运行)

llm = ChatOpenAI(model="gpt-3.5-turbo-0125")
tools = [multiply, exponentiate, add]
llm_with_tools = llm.bind_tools(tools)

目前langchainqwen模型没有提供该bind_tools,所以我们不能通过该方式直接调用。不过,好消息的是,已经看到有人提交了合并请求,在后续版本中应该就可以用该方法直接调用工具了。


ChatTongyi中的bind(tools=tools)方式,具体代码如下

from langchain_core.prompts import (
   ChatPromptTemplate,
   HumanMessagePromptTemplate
)
from langchain_core.messages import (
   HumanMessage,
   FunctionMessage
)
# from langchain_community.llms import Tongyi
from langchain_community.chat_models.tongyi import ChatTongyi
import os

qwen_api_key = "申请的qwen-api-key"
os.environ["DASHSCOPE_API_KEY"] = qwen_api_key

定义工具参数和方法

tools = [
   # 工具1 获取当前时刻的时间
 {
       "type": "function",
       "function": {
           "name": "get_current_time",
           "description": "当你想知道现在的时间时非常有用。",
           "parameters": {}  # 因为获取当前时间无需输入参数,因此parameters为空字典
     }
 },  
   # 工具2 获取指定城市的天气
 {
       "type": "function",
       "function": {
           "name": "get_current_weather",
           "description": "当你想查询指定城市的天气时非常有用。",
           "parameters": {  # 查询天气时需要提供位置,因此参数设置为location
                       "type": "object",
               "properties": {
                   "location": {
                       "type": "string",
                       "description": "城市或县区,比如北京市、杭州市、余杭区等。"
                 }
             }
         },
           "required": [
               "location"
         ]
     }
 }
]

# 模拟天气查询工具。返回结果示例:“北京今天是晴天。”
def get_current_weather(location):
   return f"{location}今天是晴天。 "

# 查询当前时间的工具。返回结果示例:“当前时间:2024-04-15 17:15:18。“
def get_current_time():
   formatted_time = "2024年4月25日22:10:32"
   # 返回格式化后的当前时间
   return f"当前时间:{formatted_time}。"

开始调用

chat = ChatTongyi(model="qwen-plus")

prompt_tmpl = "使用给定函数回答下列问题 {input}"
prompt_msgs = [
   HumanMessagePromptTemplate.from_template(prompt_tmpl),
]
prompt = ChatPromptTemplate(messages=prompt_msgs)

# 绑定我们定义的工具配置
chain = prompt | chat.bind(tools=tools)

message = HumanMessage(content="上海的天气?")
response = chain.batch([{"input": message}])
response

我们看看返回的参数,已经有调用天气的函数了。tool_callsget_current_weather

[AIMessage(content='', additional_kwargs={'tool_calls': [{'function': {'name': 'get_current_weather', 'arguments': '{"properties": {"location": {"description": "上海市", "type": "string"}}}'}, 'id': '', 'type': 'function'}]}, response_metadata={'model_name': 'qwen-plus', 'finish_reason': 'tool_calls', 'request_id': 'e65c3092-78c6-90ef-89f0-d2b4dcf0472f', 'token_usage': {'input_tokens': 233, 'output_tokens': 31, 'total_tokens': 264}}, id='run-5d225659-082b-4e45-9ffa-18dc61eb268a-0', tool_calls=[{'name': 'get_current_weather', 'args': {'properties': {'location': {'description': '上海市', 'type': 'string'}}}, 'id': ''}])]

后续可以参考官方的例子,拿到方法名称,直接调用对应的方法就好了。


53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询