Langchain ReAct

lightsong發表於2024-11-10

official

https://python.langchain.com/v0.1/docs/modules/agents/agent_types/react/

https://python.langchain.com/v0.2/api_reference/langchain/agents/langchain.agents.react.agent.create_react_agent.html

from langchain import hub
from langchain_community.llms import OpenAI
from langchain.agents import AgentExecutor, create_react_agent

prompt = hub.pull("hwchase17/react")
model = OpenAI()
tools = ...

agent = create_react_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)

agent_executor.invoke({"input": "hi"})

# Use with chat history
from langchain_core.messages import AIMessage, HumanMessage
agent_executor.invoke(
    {
        "input": "what's my name?",
        # Notice that chat_history is a string
        # since this prompt is aimed at LLMs, not chat models
        "chat_history": "Human: My name is Bob\nAI: Hello Bob!",
    }
)

from langchain_core.prompts import PromptTemplate

template = '''Answer the following questions as best you can. You have access to the following tools:

{tools}

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: {input}
Thought:{agent_scratchpad}'''

prompt = PromptTemplate.from_template(template)

demo

https://zhuanlan.zhihu.com/p/685013312

# You need to set the environmental variable OPENAI_API_KEY
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langchain import hub


# Custom tool for the Agent 
@tool
def get_employee_id(name):
  """
  To get employee id, it takes employee name as arguments
  name(str): Name of the employee
  """
  fake_employees = {
    "Alice": "E001",
    "Bob": "E002",
    "Charlie": "E003",
    "Diana": "E004",
    "Evan": "E005",
    "Fiona": "E006",
    "George": "E007",
    "Hannah": "E008",
    "Ian": "E009",
    "Jasmine": "E010"}
  
  return fake_employees.get(name,"Employee not found")

# Custom tool for the Agent 
@tool
def get_employee_salary(employee_id):
  """
  To get the salary of an employee, it takes employee_id as input and return salary
  """
  employee_salaries = {
    "E001": 56000,
    "E002": 47000,
    "E003": 52000,
    "E004": 61000,
    "E005": 45000,
    "E006": 58000,
    "E007": 49000,
    "E008": 53000,
    "E009": 50000,
    "E010": 55000
    }
  return employee_salaries.get(employee_id,"Employee not found")

# Saved React Prompt in langchain hub, we could manually type the prompt as well.
prompt = hub.pull("hwchase17/react")
model = ChatOpenAI(model='gpt-4-0125-preview')

tools = [get_employee_salary, get_employee_id]
agent = create_react_agent(model,tools, prompt)
agent_executor = AgentExecutor(agent=agent,tools=tools,verbose=True)
agent_executor.invoke({"input":"What is the Salary of Evan?"})

https://www.cnblogs.com/mangod/p/18230328

from langchain import hub
from langchain.agents import create_structured_chat_agent, AgentExecutor
from langchain.memory import ConversationBufferMemory
from langchain.schema import HumanMessage
from langchain.tools import BaseTool
from langchain_openai import ChatOpenAI

# 模型
model = ChatOpenAI(model="gpt-3.5-turbo",
                   openai_api_key="sk-XXXXXXXXXX",
                   openai_api_base="https://api.aigc369.com/v1")
# 直接讓模型計算數字,模型會算錯
model.invoke([HumanMessage(content="你幫我算下,3.941592623412424+4.3434532535353的結果")])


# 下面開始使用ReAct機制,定義工具,讓LLM使用工具做專業的事情。

# 定義工具,要繼承自LangChain的BaseTool
class SumNumberTool(BaseTool):
    name = "數字相加計算工具"
    description = "當你被要求計算2個數字相加時,使用此工具"

    def _run(self, a, b):
        return a.value + b.value
        
# 工具合集
tools = [SumNumberTool()]
# 提示詞,直接從langchain hub上下載,因為寫這個ReAct機制的prompt比較複雜,直接用現成的。
prompt = hub.pull("hwchase17/structured-chat-agent")
# 定義AI Agent
agent = create_structured_chat_agent(
    llm=model,
    tools=tools,
    prompt=prompt
)
# 使用Memory記錄上下文
memory = ConversationBufferMemory(
    memory_key='chat_history',
    return_messages=True
)
# 定義AgentExecutor,必須使用AgentExecutor,才能執行代理定義的工具
agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent, tools=tools, memory=memory, verbose=True, handle_parsing_errors=True
)
# 測試使用到工具的場景
agent_executor.invoke({"input": "你幫我算下3.941592623412424+4.3434532535353的結果"})

# 測試不使用工具的場景
agent_executor.invoke({"input": "請你充當稿件稽核師,幫我看看'''號裡的內容有沒有錯別字,如果有的話幫我糾正下。'''今天班級裡的學生和老實要去哪裡玩'''"})        

autoCOT 理解

https://zhuanlan.zhihu.com/p/659102403

langchain react理解

https://github.com/Papakobina/Langchain-React-Agent/blob/main/react-langchain/main.py

https://zhuanlan.zhihu.com/p/686796330

from typing import Union, List
from dotenv import load_dotenv
from langchain.agents import tool
from langchain.agents.format_scratchpad import format_log_to_str
from langchain.agents.output_parsers import ReActSingleInputOutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.schema import AgentAction, AgentFinish
from langchain.tools import Tool
from langchain.tools.render import render_text_description


load_dotenv()


@tool
def get_text_length(text: str) -> int:
    """Returns the length of a text by characters"""
    print(f"get_text_length enter with {text=}")
    text = text.strip("'\n").strip(
        '"'
    )  # stripping away non-alphabetic characters just in case

    return len(text)


def find_tool_by_name(tools: List[Tool], tool_name: str) -> Tool:
    for tool in tools:
        if tool.name == tool_name:
            return tool
    raise ValueError(f"Tool wtih name {tool_name} not found")


if __name__ == "__main__":
    print("Hello ReAct LangChain!")
    tools = [get_text_length]

    template = """
    Answer the following questions as best you can. You have access to the following tools:

    {tools}
    
    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: {input}
    Thought: {agent_scratchpad}
    """

    prompt = PromptTemplate.from_template(template=template).partial(
        tools=render_text_description(tools),
        tool_names=", ".join([t.name for t in tools]),
    )

    llm = ChatOpenAI(
        temperature=0,
        model_kwargs={"stop": ["\nObservation", "Observation"]},
    )
    intermediate_steps = []
    agent = (
        {
            "input": lambda x: x["input"],
            "agent_scratchpad": lambda x: format_log_to_str(x["agent_scratchpad"]),
        }
        | prompt
        | llm
        | ReActSingleInputOutputParser()
    )

    agent_step: Union[AgentAction, AgentFinish] = agent.invoke(
        {
            "input": "What is the length of the word: DOG",
            "agent_scratchpad": intermediate_steps,
        }
    )
    print(agent_step)
    if isinstance(agent_step, AgentAction):
        tool_name = agent_step.tool
        tool_to_use = find_tool_by_name(tools, tool_name)
        tool_input = agent_step.tool_input
        observation = tool_to_use.func(str(tool_input))
        print(f"{observation=}")
        intermediate_steps.append((agent_step, str(observation)))

    agent_step: Union[AgentAction, AgentFinish] = agent.invoke(
        {
            "input": "What is the length of the word: DOG",
            "agent_scratchpad": intermediate_steps,
        }
    )
    print(agent_step)
    if isinstance(agent_step, AgentFinish):
        print("### AgentFinish ###")
        print(agent_step.return_values)

相關文章