langchain LCEL内存示例返回KeyError,

lx0bsm1f  于 2个月前  发布在  其他
关注(0)|答案(9)|浏览(32)

系统信息

langchain==0.0.319, mac, python 3.10

谁可以帮忙?

@hwchase17@agola11
我正在尝试使用这个来自:https://python.langchain.com/docs/expression_language/cookbook/memory

model = ChatOpenAI()
  prompt = ChatPromptTemplate.from_messages([
      ("system", "You are a helpful chatbot"),
      MessagesPlaceholder(variable_name="history"),
      ("human", "{input}")
  ])

  memory = ConversationBufferMemory(return_messages=True)

  memory.load_memory_variables({})

  chain = RunnablePassthrough.assign(
      memory=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
  ) | prompt | model

  inputs = {"input": "hi im bob"}
  response = chain.invoke(inputs)

的示例,并得到:

File "/Users/name/.pyenv/versions/3.10.10/lib/python3.10/site-packages/langchain/schema/prompt_template.py", line 60, in <dictcomp>
    **{key: inner_input[key] for key in self.input_variables}
KeyError: 'history'

信息

  • 官方示例笔记本/脚本
  • 我自己的修改过的脚本

相关组件

  • LLMs/聊天模型
  • 嵌入模型
  • 提示/提示模板/提示选择器
  • 输出解析器
  • 文档加载器
  • 向量存储/检索器
  • 内存
  • 代理/代理执行器
  • 工具/工具包
  • 回调/跟踪
  • 异步

复现方法

请运行上面的代码。

预期行为

使其表现得像文档中描述的那样。

kiayqfof

kiayqfof1#

也让我感到意外 - 谢谢!

vbkedwbf

vbkedwbf2#

请分享一下如何在LCEL中最好地保存和加载输入输出?
还是我们必须手动在外部进行操作?
文档不清楚如何进行简单的字符串输入输出之外的操作。
谢谢!

i2loujxw

i2loujxw3#

@RaedShabbir 也许我可以分享我已经找到的内容,希望它能有所帮助!
我最终想要使用一个 Agent with LCEL ,但也想要一个 Conversation Summary Buffer 。我最初遵循了 Agents -> How to -> Custom Agent -> Adding memory 部分,但没有办法实现缓冲功能,所以我尝试进行即兴创作。
话虽如此,我现在所做的并不会调用 predict_new_summary ,而是直接使用 load_memory_variables 加载所有聊天记录。理想情况下,我会创建一个自定义函数,该函数可以决定是否应该进行总结,甚至可能返回最后 k 条消息,但始终对之前的所有内容进行总结?
我认为这个文档的这个部分隐式地实现了这一点。也许在那里为LCEL创建另一个部分会更好。

代码示例(不包括导入)

  • 创建提示
MEMORY_KEY = "chat_history"

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are Larry. A helpful AI assistant capable of performing a variety of tasks on the data available to you through the custom tools you have been provided with.",
        ),
        MessagesPlaceholder(variable_name=MEMORY_KEY),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)
  • 绑定一些自定义工具
tools = [
    Tool1(),
    Tool2(),
]

llm = ChatOpenAI(model=config.model)
formatted_functions = [format_tool_to_openai_function(t) for t in tools]
llm_with_tools = llm.bind(functions=formatted_functions)

for f in formatted_functions:
    print(f"function: {f}")
  • 创建内存
history = ChatMessageHistory()
history.add_user_message("Hi, my name is Jeff.")
history.add_ai_message("Hello Jeff! How can I assist you today?")

memory = ConversationSummaryBufferMemory(
    llm=ChatOpenAI(model="gpt-3.5-turbo"),
    return_messages=True,
    memory_key=MEMORY_KEY,
    chat_memory=history
)

print(memory.load_memory_variables({}))
memory.predict_new_summary(existing_summary="", messages=history.messages)

{'chat_history': [HumanMessage(content='Hi, my name is Jeff.'), AIMessage(content='Hello Jeff! How can I assist you today?')]}
'人类自我介绍为杰夫。AI向杰夫问好并询问今天如何帮助他。'

  • 创建代理
agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_function_messages(
            x["intermediate_steps"]
        ),
    }
    | RunnablePassthrough.assign(
        # chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter(MEMORY_KEY)
        **{MEMORY_KEY: RunnableLambda(memory.load_memory_variables) | itemgetter(MEMORY_KEY)}
    )
    | prompt
    | llm_with_tools
    | OpenAIFunctionsAgentOutputParser()
)

agent_executor = AgentExecutor(agent=agent, tools=tools)  # type: ignore
  • 使用代理
response = agent_executor.invoke({"input": "Hi, my name is Jeff."})

{'input': 'Hi, my name is Jeff.', 'output': "你好,杰夫!看来我们已经互相问候过了。有什么具体的事情你想了解或者做吗?我在这里帮助你!"}

sbtkgmzw

sbtkgmzw4#

在尝试将对话缓冲区内存(PostgresChatMessageHistory)实现到我的LCEL代理中时,我需要添加另一个RunnableLambda来保存内存上下文吗?

crcmnpdw

crcmnpdw5#

@usersina
我正在尝试将对话缓冲区内存(PostgresChatMessageHistory)实现到我的LCEL代理中。我需要添加另一个RunnableLambda来保存内存上下文吗?

from langchain.memory import ConversationSummaryMemory
from langchain_core.runnables import RunnableLambda,RunnablePassthrough

memory = ConversationSummaryMemory(
    llm=llm, return_messages=True, output_key="answer", input_key="question"
    )

def save_mem(x):
    print(x["answer"])
    print(x["question"])
    memory.save_context({"question": x["question"]}, {"answer": x["answer"]})
    return x

def load_mem(x):
    return memory.load_memory_variables({})

from langchain import PromptTemplate
from langchain.prompts.chat import  ChatPromptTemplate,HumanMessagePromptTemplate,SystemMessagePromptTemplate
from langchain.schema import  SystemMessage

chat_prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate.from_template("Tu es un assistant qui répond à l'utilisateur, voici l'historique de conversation: {chat_history}"),
        HumanMessagePromptTemplate.from_template(" {question}") 
     ])

from langchain_core.output_parsers import StrOutputParser

output_parser = StrOutputParser()

chain = {"chat_history": RunnableLambda(memory.load_memory_variables), "question": RunnablePassthrough()}  | chat_prompt | llm | output_parser 
save_chain =  {"question": RunnablePassthrough(), "answer": RunnablePassthrough()| chain} | RunnableLambda(save_mem)

当你想使用记忆机制时,你会使用save_chain
请注意,在我的基本示例中,内存没有被提示使用,但应该

vqlkdk9b

vqlkdk9b6#

你好,
你遇到的 KeyError for 'history' 可能是由于链中的提示模板中使用的键与ConversationBufferMemory示例中的memory_key参数不匹配。在你的情况中,memory_key被设置为"history"。这个键应该与链中提示模板中使用的键相匹配。
要解决这个问题,请确保链中提示模板中使用的键也是"history"。如果不是,你可以将提示模板中的键更改为与ConversationBufferMemory示例中的memory_key相匹配,或者反之亦然。
以下是如何设置链的提示模板的示例:

chain = LLMChain(
    memory=memory,
    prompt_template={
        'history': '{history}',
        ...
    },
    ...
)

在这个例子中,提示模板中的键'history'与ConversationBufferMemory示例中的memory_key相匹配。如果提示模板中的键是其他内容,如'conversation',当链尝试访问内存中的'history'时,会出现KeyError。
LangChain中的ConversationBufferMemory类的load_memory_variables方法负责返回历史缓冲区。它接受一个输入字典作为参数,并返回一个字典,其中键是内存键(在这种情况下是"history"),值是缓冲区。缓冲区可以是对话历史的字符串表示形式,也可以是消息列表,具体取决于return_messages的值。
这是该方法:

def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
    """Return history buffer."""
    return {self.memory_key: self.buffer}

当你想要加载存储在内存中的历史对话时,这个方法很有用。
希望这对你有所帮助!如果你有任何其他问题,请告诉我。

参考资料

此响应旨在帮助你节省时间并提供有用的信息。它并不是精确的解决方案,而是你自己研究的起点。
请帮助我变得更有用!如果这有帮助,请留下👍;如果无关紧要,请留下👎。
如果你想继续对话,请以@dosu-bot开头回复。

ssm49v7z

ssm49v7z7#

我不敢相信我花了两个小时在这上面。拼写错误是:

chain = RunnablePassthrough.assign(
      memory=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
      ^^^ this should be history
  ) | prompt | model
q9yhzks0

q9yhzks08#

我欠你两小时@sradu

e4yzc0pl

e4yzc0pl9#

文档(https://python.langchain.com/docs/expression_language/cookbook/memory)应该进行更正:
FROM:
chain = RunnablePassthrough.assign(
memory=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
) | prompt | model
TO
chain = RunnablePassthrough.assign(
history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
) | prompt | model

相关问题