15  LangChain Chat Agent

章节 14 中,除了 Structured Chat Agent 外,我们所介绍的 Agent 都是非 Chat 模式的 Agent。这里的 Chat 模式类似 章节 10.2.2 中介绍的 LLM 的 Chat 模式,其最主要的特点就是:他们以聊天消息列表格式的提示词作为输入。

15.1 修改 Chat Agent 的提示词逻辑

因为文心大模型 Chat 模式的 message 消息类型和 OpenAI 的不同——缺少 SystemMessage 类型,因此,如果要让 Chat Agent 支持文心,需要按照 列表 14.23 的思路对其 Prompt 的生成方式进行修改。

@classmethod
def create_prompt_for_ernie(
    ......
) -> BasePromptTemplate:
    ......
    messages = [
        HumanMessagePromptTemplate.from_template(template),
        AIMessagePromptTemplate.from_template("YES, I Know."),
        *_memory_prompts,
        HumanMessagePromptTemplate.from_template(human_message_template),
    ]
    return ChatPromptTemplate(input_variables=input_variables, messages=messages)

15.2 ChatConversationAgent

参照 列表 14.9列表 14.15,我们可以构建一个 chat-conversational-react-description

列表 15.1: Chat Conversation Agent

#encoding: utf-8

"""
@discribe: example for chat conversation agent.
@author: wangwei1237@gmail.com
"""

from langchain.chat_models import ErnieBotChat
from langchain.chains import LLMMathChain
from langchain.agents import Tool
from langchain.memory import ConversationBufferMemory
from langchain.agents import initialize_agent

memory = ConversationBufferMemory(memory_key="chat_history")

llm = ErnieBotChat(model_name="ERNIE-Bot-4")

# initialize the math tool
llm_math = LLMMathChain(llm=llm)
math_tool = Tool(
    name='Calculator',
    func=llm_math.run,
    description='Useful for when you need to answer questions about math.'
)

# when giving tools to LLM, we must pass as list of tools
tools = [math_tool]

chat_conversation_agent = initialize_agent(
    agent="chat-conversational-react-description",
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=3,
    memory=memory
)

chat_conversation_agent("4.1*7.9=?")
chat_conversation_agent("2 * 2")

但是,执行 列表 15.1 时,却报错了:

Traceback (most recent call last):
  File "code/test_chat_coversation_agent.py", line 38, in <module>
    chat_conversation_agent("4.1*7.9=?")
  ...
1ValueError: variable chat_history should be a list of base messages, got
1
chat_history 变量必须是一个消息列表

15.3 MessagesPlaceholder

我们说过,Agent 本质上就是 LLM,既然 列表 15.1 执行有异常,那我们就看下他的提示词究竟是怎么实现的(具体实现位于 langchain/agents/conversation_chat/base.pycreate_prompt())。

messages = [
    SystemMessagePromptTemplate.from_template(system_message),
1    MessagesPlaceholder(variable_name="chat_history"),
    HumanMessagePromptTemplate.from_template(final_prompt),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
]
1
从提示词的构造方式上,chat_history 是通过 MessagesPlaceholder 构造的。而此处的 chat_history 又是通过 ConversationBufferMemory 获取的。
memory = ConversationBufferMemory(memory_key="chat_history")

ConversationBufferMemory 返回的内容逻辑如下所示:

@property
def buffer(self) -> Any:
    """String buffer of memory."""
1    return self.buffer_as_messages if self.return_messages else self.buffer_as_str
1
根据 return_messages 来返回不同格式的记忆。

而在 LangChain 中,return_messages 默认值为 False,因此,实际上 buffer() 返回的是字符串格式的内容。这就是导致执行异常的根本原因。

为了解决这个问题,我们需要在初始化 ConversationBufferMemory 时,配置 return_messages = True

列表 15.2: Chat Conversation Agent

#encoding: utf-8

"""
@discribe: example for chat conversation agent.
@author: wangwei1237@gmail.com
"""

from langchain.chat_models import ErnieBotChat
from langchain.chains import LLMMathChain
from langchain.agents import Tool
from langchain.memory import ConversationBufferMemory
from langchain.agents import initialize_agent

1memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

llm = ErnieBotChat(model_name="ERNIE-Bot-4")

# initialize the math tool
llm_math = LLMMathChain(llm=llm)
math_tool = Tool(
    name='Calculator',
    func=llm_math.run,
    description='Useful for when you need to answer questions about math.'
)

# when giving tools to LLM, we must pass as list of tools
tools = [math_tool]

chat_conversation_agent = initialize_agent(
    agent="chat-conversational-react-description",
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=3,
    memory=memory
)

chat_conversation_agent("4.1*7.9=?")
chat_conversation_agent("2 * 2")
1
通过设置 return_messagesTrue 以返回消息列表格式的记忆内容。
警告

例如本节中提到的 LangChain 相关基建对文心大模型支持不够友好的问题,最好的修复方案还是给 LangChain 提交 PR 来解决。我们给 LangChain 提交了 PR 12921,还在等待官方的审核。如果您有比较好的想法,可以直接给 LangChain 提交 PR