赞
踩
目前,国内大模型基本上都还不支持类似openai的自定义函数绑定,即:llm.bindtools方法,也就无法实现自定义ReAct Agent,如果要使用国内大模型,需要考虑自己实现。本文基于国内的阿里通义千问,实现了类似OpenAI 的ReAct Agent效果。
以下是实现代码
- from langchain_core.output_parsers import JsonOutputParser
- from langchain_core.tools import tool
- from operator import itemgetter
- from dashscope import Generation
- from langchain_core.utils.function_calling import convert_to_openai_tool
-
-
- def get_model_output(**kwargs):
- """通过ReAct递归推理,获取最终答案"""
-
- question = kwargs.get('question')
- tools = kwargs.get('tools')
- msgs = kwargs.get('msgs', [])
- verbose = kwargs.get('verbose', False)
- n = kwargs.get('n', 1)
-
- tool_names = [tool.name for tool in tools]
- system_prompt = "Answer the following questions as best you can. You have access to the following tools:"
- react_prompt = f"""
- Use the following format:
- Question: the input question you must answer
- Thought: you should always think about what to do
- Action: the action to take, should be one of [{tool_names}]
- Action Input: the input to the action
- Observation: the result of the action
- ... (this Thought/Action/Action Input/Observation can repeat N times)
- Thought: I now know the final answer
- Final Answer: the final answer to the original input question
- Begin!
- Question: {question}
- Thought:"""
-
- # 初始化通义大模型输入消息
- if not msgs:
- msgs = [{"role": "system", "content": system_prompt}, {"role": "user", "content": react_prompt}]
-
- # 调用通义大模型的原生接口获取返回
- llm_response = Generation.call(
- model="qwen-turbo",
- messages=msgs,
- tools=[convert_to_openai_tool(tool) for tool in tools],
- result_format='message'
- )
-
- res_content = llm_response.output.choices[0].message["content"]
- if verbose == True:
- print("第{}轮ReAct:{}".format(n, res_content))
-
- if res_content.find("Action Input:") != -1:
- n = n + 1
- # 没拿到Final answer就根据模型店返回继续调用工具
- res_chain = call_tool(res_content, tools)
-
- # 重新生成msgs
- react_prompt = react_prompt + res_content + "\nObservation:" + str(res_chain) + "\n"
- msgs = [{"role": "system", "content": system_prompt}, {"role": "user", "content": react_prompt}]
-
- # 递归调用本方法
- res_content = get_model_output(question=question, tools=tools, n=n, msgs=msgs, verbose=verbose)
-
- return res_content
-
-
- def call_tool(res_content, tools):
- """根据大模型返回内容和给定的工具集,执行工具调用,返回工具输出内容"""
-
- # 创建一个工具MAP
- tool_map = {tool.name: tool for tool in tools}
-
- # 创建JSON输出解析器
- parser = JsonOutputParser()
-
- # 从大模型回复中解析本次调用的工具名称
- tool_call = str(res_content.split("Action:")[1].split("Action Input:")[0]).strip()
-
- # 从大模型回复中解析本次调用工具的入参
- tool_call_arguments = str(res_content.split("Action:")[1].split("Action Input:")[1]).strip()
-
- # 组装本次工具调用的schema
- model_output = {"name": tool_call, "arguments": parser.parse(tool_call_arguments)}
- chosen_tool = tool_map[model_output["name"]]
-
- # 创建工具调用链
- chain = itemgetter("arguments") | chosen_tool
-
- # 返回工具调用链的计算结果
- return chain.invoke(model_output)
-
-
- @tool
- def add(first_int: int, second_int: int) -> int:
- """将两个数相加。"""
- return first_int + second_int
-
-
- @tool
- def minus(first_int: int, second_int: int) -> int:
- """将两个数相减"""
- return first_int - second_int
-
-
- @tool
- def multiply(first_int: int, second_int: int) -> int:
- """将两个数相乘"""
- return first_int * second_int
-
-
- @tool
- def exponentiate(base: int, exponent: int) -> int:
- """对底数求指数幂"""
- return base ** exponent
-
- # 创建工具集
- tools = [add, minus, multiply, exponentiate]
- question = "4加22乘以10的结果3次方减去10086等于多少?"
-
- react_result = get_model_output(
- question=question,
- tools=tools,
- verbose=True
- )
-
- # print(react_result)
以下是开启调试结果后,每次大模型的推理、行动输出
- 第1轮ReAct: 我们需要按照数学中的运算顺序来解决这个问题:先进行乘法和指数运算,然后做加法,最后做减法。所以,我们需要分别计算22乘以10的结果,这个结果的3次方,然后从得到的结果中减去10086。我需要使用`multiply`工具来计算乘法,`exponentiate`工具来计算指数,以及`minus`工具来进行最后的减法。
- Action: multiply
- Action Input: {"first_int": 22, "second_int": 10}
- 第2轮ReAct:Thought: 现在我得到了22乘以10的结果。下一步,我需要计算这个结果的3次方,再进行减法操作。我会用`exponentiate`工具来计算220的三次方。
- Action: exponentiate
- Action Input: {"base": 220, "exponent": 3}
- 第3轮ReAct:Thought: 我已经得到了220的三次方。接下来,我需要将这个结果与4相加,然后减去10086。我将使用`add`和`minus`工具来进行这些运算。
- Action: add
- Action Input: {"first_int": 10648000, "second_int": 4}
- 第4轮ReAct:Thought: 现在我知道了10648004的结果。接下来我需要从这个结果中减去10086。
- Action: minus
- Action Input: {"first_int": 10648004, "second_int": 10086}
- 第5轮ReAct:Thought: 我现在知道了最终答案。
- Final Answer: 4加22乘以10的结果3次方减去10086等于10637918。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。