当前位置:   article > 正文

基于阿里通义千问实现ReAct_通义千问 react

通义千问 react
问题背景

目前,国内大模型基本上都还不支持类似openai的自定义函数绑定,即:llm.bindtools方法,也就无法实现自定义ReAct Agent,如果要使用国内大模型,需要考虑自己实现。本文基于国内的阿里通义千问,实现了类似OpenAI 的ReAct Agent效果。

实现思路
  1. 使用通义千问的原生接口调用方法,以千问大模型支持的方式来调用工具
  2. 使用langchain的react agent提示词模板,传给通义大模型,实现大模型的ReAct推理方式
  3. 解析通义大模型的返回
  4. 根据大模型返回内容,判断是否已经拿到了最终推理结果,如果没有,就继续递归调用,如果有,返回最终推理结果。
实现代码

以下是实现代码

  1. from langchain_core.output_parsers import JsonOutputParser
  2. from langchain_core.tools import tool
  3. from operator import itemgetter
  4. from dashscope import Generation
  5. from langchain_core.utils.function_calling import convert_to_openai_tool
  6. def get_model_output(**kwargs):
  7. """通过ReAct递归推理,获取最终答案"""
  8. question = kwargs.get('question')
  9. tools = kwargs.get('tools')
  10. msgs = kwargs.get('msgs', [])
  11. verbose = kwargs.get('verbose', False)
  12. n = kwargs.get('n', 1)
  13. tool_names = [tool.name for tool in tools]
  14. system_prompt = "Answer the following questions as best you can. You have access to the following tools:"
  15. react_prompt = f"""
  16. Use the following format:
  17. Question: the input question you must answer
  18. Thought: you should always think about what to do
  19. Action: the action to take, should be one of [{tool_names}]
  20. Action Input: the input to the action
  21. Observation: the result of the action
  22. ... (this Thought/Action/Action Input/Observation can repeat N times)
  23. Thought: I now know the final answer
  24. Final Answer: the final answer to the original input question
  25. Begin!
  26. Question: {question}
  27. Thought:"""
  28. # 初始化通义大模型输入消息
  29. if not msgs:
  30. msgs = [{"role": "system", "content": system_prompt}, {"role": "user", "content": react_prompt}]
  31. # 调用通义大模型的原生接口获取返回
  32. llm_response = Generation.call(
  33. model="qwen-turbo",
  34. messages=msgs,
  35. tools=[convert_to_openai_tool(tool) for tool in tools],
  36. result_format='message'
  37. )
  38. res_content = llm_response.output.choices[0].message["content"]
  39. if verbose == True:
  40. print("第{}轮ReAct:{}".format(n, res_content))
  41. if res_content.find("Action Input:") != -1:
  42. n = n + 1
  43. # 没拿到Final answer就根据模型店返回继续调用工具
  44. res_chain = call_tool(res_content, tools)
  45. # 重新生成msgs
  46. react_prompt = react_prompt + res_content + "\nObservation:" + str(res_chain) + "\n"
  47. msgs = [{"role": "system", "content": system_prompt}, {"role": "user", "content": react_prompt}]
  48. # 递归调用本方法
  49. res_content = get_model_output(question=question, tools=tools, n=n, msgs=msgs, verbose=verbose)
  50. return res_content
  51. def call_tool(res_content, tools):
  52. """根据大模型返回内容和给定的工具集,执行工具调用,返回工具输出内容"""
  53. # 创建一个工具MAP
  54. tool_map = {tool.name: tool for tool in tools}
  55. # 创建JSON输出解析器
  56. parser = JsonOutputParser()
  57. # 从大模型回复中解析本次调用的工具名称
  58. tool_call = str(res_content.split("Action:")[1].split("Action Input:")[0]).strip()
  59. # 从大模型回复中解析本次调用工具的入参
  60. tool_call_arguments = str(res_content.split("Action:")[1].split("Action Input:")[1]).strip()
  61. # 组装本次工具调用的schema
  62. model_output = {"name": tool_call, "arguments": parser.parse(tool_call_arguments)}
  63. chosen_tool = tool_map[model_output["name"]]
  64. # 创建工具调用链
  65. chain = itemgetter("arguments") | chosen_tool
  66. # 返回工具调用链的计算结果
  67. return chain.invoke(model_output)
  68. @tool
  69. def add(first_int: int, second_int: int) -> int:
  70. """将两个数相加。"""
  71. return first_int + second_int
  72. @tool
  73. def minus(first_int: int, second_int: int) -> int:
  74. """将两个数相减"""
  75. return first_int - second_int
  76. @tool
  77. def multiply(first_int: int, second_int: int) -> int:
  78. """将两个数相乘"""
  79. return first_int * second_int
  80. @tool
  81. def exponentiate(base: int, exponent: int) -> int:
  82. """对底数求指数幂"""
  83. return base ** exponent
  84. # 创建工具集
  85. tools = [add, minus, multiply, exponentiate]
  86. question = "4加22乘以10的结果3次方减去10086等于多少?"
  87. react_result = get_model_output(
  88. question=question,
  89. tools=tools,
  90. verbose=True
  91. )
  92. # print(react_result)

以下是开启调试结果后,每次大模型的推理、行动输出

  1. 1轮ReAct: 我们需要按照数学中的运算顺序来解决这个问题:先进行乘法和指数运算,然后做加法,最后做减法。所以,我们需要分别计算22乘以10的结果,这个结果的3次方,然后从得到的结果中减去10086。我需要使用`multiply`工具来计算乘法,`exponentiate`工具来计算指数,以及`minus`工具来进行最后的减法。
  2. Action: multiply
  3. Action Input: {"first_int": 22, "second_int": 10}
  4. 2轮ReAct:Thought: 现在我得到了22乘以10的结果。下一步,我需要计算这个结果的3次方,再进行减法操作。我会用`exponentiate`工具来计算220的三次方。
  5. Action: exponentiate
  6. Action Input: {"base": 220, "exponent": 3}
  7. 3轮ReAct:Thought: 我已经得到了220的三次方。接下来,我需要将这个结果与4相加,然后减去10086。我将使用`add`和`minus`工具来进行这些运算。
  8. Action: add
  9. Action Input: {"first_int": 10648000, "second_int": 4}
  10. 4轮ReAct:Thought: 现在我知道了10648004的结果。接下来我需要从这个结果中减去10086
  11. Action: minus
  12. Action Input: {"first_int": 10648004, "second_int": 10086}
  13. 5轮ReAct:Thought: 我现在知道了最终答案。
  14. Final Answer: 422乘以10的结果3次方减去10086等于10637918
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/875186
推荐阅读
相关标签
  

闽ICP备14008679号