arcstep / langchain_zhipuai

为了兼容Langchain,根据zhipu官方HTTP的API重新实现的Python SDK
50 stars 7 forks source link

LangChain Python tool helps #2

Closed lwx0218 closed 7 months ago

lwx0218 commented 7 months ago

在使用langChain的python toolkit时出现下列两个问题

一、使用OpenAI Functions Agent无法像create_pandas_dataframe_agent直接兼容

from langchain import hub
from langchain.agents import AgentExecutor
from langchain_experimental.tools import PythonREPLTool
from langchain.agents import create_openai_functions_agent
from langchain_zhipu import ChatZhipuAI

tools = [PythonREPLTool()]
instructions = """You are an agent designed to write and execute python code to answer questions.
You have access to a python REPL, which you can use to execute python code.
If you get an error, debug your code and try again.
Only use the output of your code to answer the question. 
You might know the answer without running any code, but you should still run the code to get the answer.
If it does not seem like you can write code to answer the question, just return "I don't know" as the answer.
"""
base_prompt = hub.pull("langchain-ai/openai-functions-template")
prompt = base_prompt.partial(instructions=instructions)

llm_zhipuai = ChatZhipuAI(  
                model="glm-4",
                temperature=0.1)

agent = create_openai_functions_agent(llm_zhipuai, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

agent_executor.invoke({"input": "What is the 10th fibonacci number?"})

image

可否添加对此处的支持

二、如果使用ReAct Agent,会持续陷入invalid sytax

tools = [PythonREPLTool()]
instructions = """You are an agent designed to write and execute python code to answer questions.
You have access to a python REPL, which you can use to execute python code.
If you get an error, debug your code and try again.
Only use the output of your code to answer the question. 
You might know the answer without running any code, but you should still run the code to get the answer.
If it does not seem like you can write code to answer the question, just return "I don't know" as the answer.
"""
base_prompt = hub.pull("langchain-ai/react-agent-template")
prompt = base_prompt.partial(instructions=instructions)

llm_zhipuai = ChatZhipuAI( 
                model="glm-4",
                temperature=0.1)

agent = create_react_agent(llm_zhipuai, tools, prompt)

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, agent_executor_kwargs={"handle_parsing_errors": True})
agent_executor.invoke({"input": "What is the 10th fibonacci number?"})

image

arcstep commented 7 months ago

oepnai 支持三种回调:一是较早发布的 plugin模式;二是 funciion-calling,每次返回一个工具函数;三是后来发布的 tools-calling,每次返回多个工具函数。目前 openai 主张使用第三种,funciton-calling已经被 openai 标记为即将废弃,建议使用 tools-calling模式。

国内的智谱是直接支持第三种 tools-calling 模式的,所以在大模型返回时只有这种 Tools 的消息类型,而没有 Function 的消息类型,自然就不能使用你用到的 function-calling 模式的智能体。但你完全可以使用 tools-calling 智能体来实现你的场景。

from langchain import hub
from langchain_experimental.tools import PythonREPLTool
from langchain.agents import AgentExecutor, Tool, create_react_agent, create_openai_tools_agent, create_openai_functions_agent

from langchain_zhipu import ChatZhipuAI

tools = [PythonREPLTool()]

instructions = """
You are an agent designed to write and execute python code to answer questions.
You have access to a python REPL, which you can use to execute python code.
If you get an error, debug your code and try again.
Only use the output of your code to answer the question. 
You might know the answer without running any code, but you should still run the code to get the answer.
If it does not seem like you can write code to answer the question, just return "I don't know" as the answer.
"""

base_prompt = hub.pull("langchain-ai/openai-functions-template")
prompt = base_prompt.partial(instructions=instructions)
llm_zhipuai = ChatZhipuAI(model="glm-4", temperature=0.1)

agent = create_openai_tools_agent(llm_zhipuai, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

返回结果如下:

> Entering new AgentExecutor chain...

Invoking: `Python_REPL` with `def fibonacci(n):
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))`

55
The 10th Fibonacci number is 55.

> Finished chain.
{'input': 'What is the 10th fibonacci number?',
 'output': 'The 10th Fibonacci number is 55.'}

至于你提到的 ReAct 智能体的问题,涉及的问题较多,包括:

我的建议是,如果你需要使用国内大模型,就不要使用langchain默认的 ReAct 智能体了,还是要自己调优一个才行。

arcstep commented 7 months ago

我试着自定义一个 ReAct 智能体,虽然智谱AI没有Open AI那么聪明,但也还是能解决问题。

核心思路是在提示语中使用JSON表示,并使用create_structured_chat_agent来创建智能体。

代码如下:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

system = """
你是一个会调用工具的AI助手,懂得在必要时调用工具。
如果不需要调用任何工具,你也可以直接生成结果。

你可以访问这些工具:

{tools}

必须使用$JSON_BLOB的描述来指定选择哪个工具,并通过其中的键action和action_input来具体指定;
所选择的action必须是 {tool_names} 之一;
合法的"action"值只能是 "Final Answer" 或者其他具体的工具名称。

每个$JSON_BLOB仅指定一个action,如:

'''
{{
  "action": $TOOL_NAME,
  "action_input": $INPUT
}}
'''

按照以下格式打印你思考的每一步过程:

问题: 需要回答的问题
思考: 已经完成的思考结论和执行步骤
行动(也叫action):
'''
$JSON_BLOB
'''
观察: action执行的结果
... (重复 Thought/Action/Observation 这个过程 N 次)
思考: I know what to respond

行动:
'''
{{
  "action": "Final Answer",
  "action_input": "Final response to human"
}}
'''
Format is Action:```$JSON_BLOB```then Observation.

永远使用合法的JSON结构表示上述提到的行动(action)
永远使用中文思考和返回。

请开始!
"""

human = '''{input}

{agent_scratchpad}

(reminder to respond in a JSON blob no matter what)
'''

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        MessagesPlaceholder("chat_history", optional=True),
        ("human", human),
    ]
)

from langchain import hub
from langchain_experimental.tools import PythonREPLTool
from langchain.agents import AgentExecutor, create_structured_chat_agent

from langchain_zhipu import ChatZhipuAI

tools = [PythonREPLTool()]

llm_zhipuai = ChatZhipuAI(model="glm-4", temperature=0.1)
agent = create_structured_chat_agent(llm_zhipuai, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)

agent_executor.invoke({"input": "肥波那契数列中的第10个数字是多少?"})

输出结果如下:

> Entering new AgentExecutor chain... Could not parse LLM output: 问题: 肥波那契数列中的第10个数字是多少? 思考: 肥波那契数列实际上是斐波那契数列的误写,斐波那契数列可以通过编写一个简单的Python脚本来计算第10个数字。我将使用Python_REPL工具。

行动: ```python tool_call(action='Python_REPL', action_input='query') ```Invalid or incomplete response思考: 斐波那契数列可以通过递归或迭代的方式在Python中计算。由于这个问题需要使用工具来解决,我将使用Python_REPL工具来计算斐波那契数列的第10个数字。

行动: ```json { "action": "Python_REPL", "action_input": "def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(10))" } ```

观察: (执行上述Python代码后的结果)SyntaxError('invalid syntax', ('', 1, 19, 'def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(10))\n', 1, 21))思考: 观察到之前的代码因为格式问题导致了语法错误,我将重新编写一个正确的Python代码片段来计算斐波那契数列的第10个数字,并使用迭代方式来提高效率。

行动: ```json { "action": "Python_REPL", "actioninput": "a, b = 0, 1\nfor in range(10):\n a, b = b, a + b\nprint(a)" } ```

观察: (执行上述Python代码后的结果) Observation55 思考: 经过计算,斐波那契数列的第10个数字已经得出。

行动: ```json { "action": "Final Answer", "action_input": "斐波那契数列中的第10个数字是55。" } ```

> Finished chain. {'input': '肥波那契数列中的第10个数字是多少?', 'output': '斐波那契数列中的第10个数字是55。'}

lwx0218 commented 7 months ago

指导的太好了,非常感谢!