核心模块(Modules)
代理(Agents)
快速开始(QuickStart)

快速入门

要最好地理解代理框架,让我们构建一个代理,其中包含两个工具:一个用于在线查找信息,另一个用于查找我们加载到索引中的特定数据。

这将假定您已了解 LLMs 和 检索,因此如果您还没有探索这些部分,建议您这样做。

设置:LangSmith

根据定义,代理在返回给用户的输出之前会执行一系列自我确定的、依赖输入的步骤。这使得调试这些系统特别棘手,而可观察性尤为重要。LangSmith 在这种情况下特别有用。

建立使用 LangChain 时,所有步骤都将自动在 LangSmith 中跟踪。 要设置 LangSmith,我们只需要设置以下环境变量:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="<your-api-key>"

定义工具

我们首先需要创建我们想要使用的工具。我们将使用两个工具:Tavily (opens in a new tab)(用于在线搜索),然后是在我们创建的本地索引上的检索器

Tavily (opens in a new tab)

LangChain 中有一个内置工具,可方便地使用 Tavily 搜索引擎作为工具。 请注意,这需要一个 API 密钥 - 他们有一个免费的套餐,但如果您没有或不想创建一个,您可以忽略这一步。

创建您的 API 密钥后,您需要将其导出为:

export TAVILY_API_KEY="..."
from langchain_community.tools.tavily_search import TavilySearchResults
search = TavilySearchResults()
search.invoke("what is the weather in SF")

检索器

我们还将在我们自己的一些数据上创建一个检索器。有关此处每个步骤的更深入解释,请查看 本节。

from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
 
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
docs = loader.load()
documents = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
).split_documents(docs)
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
retriever = vector.as_retriever()
retriever.invoke("how to upload a dataset")[0]

现在我们已经填充了我们将要进行检索的索引,我们可以轻松地将其转换为一个工具(代理正确使用它所需的格式)

from langchain.tools.retriever import create_retriever_tool
retriever_tool = create_retriever_tool(
    retriever,
    "langsmith_search",
    "Search for information about LangSmith. For any questions about LangSmith, you must use this tool!",
)

工具

现在我们已经创建了这两个工具,我们可以创建一个我们将在下游使用的工具列表。

tools = [search, retriever_tool]

创建代理

现在我们已经定义了工具,我们可以创建代理。我们将使用一个 OpenAI Functions 代理 - 有关此类代理的更多信息,以及其他选项,请参阅 本指南。

首先,我们选择要引导代理的 LLM。

from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)

接下来,我们选择要使用的提示来引导代理。

如果您想查看此提示的内容并访问 LangSmith,请前往:

https://smith.langchain.com/hub/hwchase17/openai-functions-agent (opens in a new tab)

from langchain import hub
 
# 获取要使用的提示 - 您可以修改这个!
prompt = hub.pull("hwchase17/openai-functions-agent")
prompt.messages

现在,我们可以使用 LLM、提示和工具初始化代理。代理负责接受输入并决定采取什么行动。至关重要的是,代理不执行这些操作 - 这是由 AgentExecutor(下一步)执行的。有关如何考虑这些组件的更多信息,请参阅我们的 概念指南。

from langchain.agents import create_tool_calling_agent
 
agent = create_tool_calling_agent(llm, tools, prompt)

最后,我们将代理(大脑)与工具结合在 AgentExecutor 中(该 Executor 将重复调用代理并执行工具)。

from langchain.agents import AgentExecutor
 
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

运行代理

现在我们可以在几个查询上运行代理!请注意,目前这些都是 无状态 查询(它不会记住先前的交互)。

agent_executor.invoke({"input": "hi!"})
agent_executor.invoke({"input": "how can langsmith help with testing?"})
agent_executor.invoke({"input": "whats the weather in sf?"})

添加内存

正如之前提到的,这个代理是无状态的。这意味着它不会记住先前的交互。要给它添加记忆,我们需要传入先前的 chat_history。注意:它需要被称为 chat_history,因为我们正在使用的提示。如果我们使用不同的提示,我们可以更改变量名

# 在这里,我们传入一个空的消息列表给 chat_history,因为这是对话中的第一条消息
agent_executor.invoke({"input": "hi! my name is bob", "chat_history": []})
from langchain_core.messages import AIMessage, HumanMessage
agent_executor.invoke(
    {
        "chat_history": [
            HumanMessage(content="hi! my name is bob"),
            AIMessage(content="Hello Bob! How can I assist you today?"),
        ],
        "input": "what's my name?",
    }
)

如果我们想自动跟踪这些消息,我们可以将其包装在一个 RunnableWithMessageHistory 中。有关如何使用此功能的更多信息,请参阅 此指南。

from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
message_history = ChatMessageHistory()
agent_with_chat_history = RunnableWithMessageHistory(
    agent_executor,
    # 这是必需的,因为在大多数实际情况下,需要一个会话 id
    # 这里并没有真正使用,因为我们使用的是一个简单的内存中的 ChatMessageHistory
    lambda session_id: message_history,
    input_messages_key="input",
    history_messages_key="chat_history",
)
agent_with_chat_history.invoke(
    {"input": "hi! I'm bob"},
    # 这是必需的,因为在大多数实际情况下,需要一个会话 id
    # 这里并没有真正使用,因为我们使用的是一个简单的内存中的 ChatMessageHistory
    config={"configurable": {"session_id": "<foo>"}},
)
agent_with_chat_history.invoke(
    {"input": "what's my name?"},
    # 这是必需的,因为在大多数实际情况下,需要一个会话 id
    # 这里并没有真正使用,因为我们使用的是一个简单的内存中的 ChatMessageHistory
    config={"configurable": {"session_id": "<foo>"}},
)

结论

到这里就结束了!在这个快速入门中,我们介绍了如何创建一个简单的代理。代理是一个复杂的主题,有很多内容需要学习!请返回 主代理页面,查找更多关于概念指南、不同类型的代理、如何创建自定义工具等的资源!