langchain-ai / langchain

🦜🔗 Build context-aware reasoning applications
https://python.langchain.com
MIT License
95.44k stars 15.49k forks source link

KeyError: '' : output_key not found [in _get_input_output return inputs[prompt_input_key], outputs[output_key]] #23255

Closed Tisha-linkenite closed 1 month ago

Tisha-linkenite commented 5 months ago

Checked other resources

Example Code

from dotenv import load_dotenv
import streamlit as st
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import PromptTemplate
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import ConversationalRetrievalChain, StuffDocumentsChain, LLMChain
from langchain.memory import ConversationBufferMemory
import os

load_dotenv()

def load_documents(global_pdf_path, external_pdf_path=None, input_url=None):

    """ This functionality of loading global PDF knowledge base is currently placed inside load_documents function
    which is not a feasible approach has to perform the global pdf load only once hence the below funcion need
    to be placed somewhere else"""

    # Load the global internal knowledge base PDF
    global_loader = PyPDFLoader(global_pdf_path)
    global_docs = global_loader.load()
    documents = global_docs

    if external_pdf_path:
        # Load the external input knowledge base PDF
        external_loader = PyPDFLoader(external_pdf_path)
        external_docs = external_loader.load()
        documents += external_docs

    if input_url:
        # Load URL content
        url_loader = WebBaseLoader(input_url)
        url_docs = url_loader.load()
        documents += url_docs

    # Split the documents into smaller chunks
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    split_docs = text_splitter.split_documents(documents)

    return split_docs

def create_vector_store(documents):
    embeddings = OpenAIEmbeddings(api_key=os.environ['OPENAI_API_KEY'])
    vector_store = FAISS.from_documents(documents, embeddings)
    return vector_store

def get_LLM_response(query, task, content_type):

    llm = ChatOpenAI(api_key=os.environ['OPENAI_API_KEY'])

    # Create a prompt template
    prompt = ChatPromptTemplate.from_template(f"""You are a Marketing Assistant
        <context>
        {{context}}
        </context>
        Question: {{input}}""")

    # Create document chain
    document_chain = StuffDocumentsChain(
        llm_chain=LLMChain(llm=llm, prompt=prompt),
        document_variable_name="context"
    )

    retriever = vector_store.as_retriever()

    question_generator_template = PromptTemplate(
         input_variables=[
        "chat_history",
        "input_key",
    ],
      template= (  
        """
        Combine the chat history and follow up question into a standalone question.
        Chat History: {chat_history}
        Follow up question: {question}
    """)
    )

    question_generator_chain = LLMChain(
        llm=llm,
        prompt=question_generator_template,
    )

    # Create retrieval chain
    retrieval_chain = ConversationalRetrievalChain(
        combine_docs_chain=document_chain,
        question_generator=question_generator_chain,
        retriever=retriever,
        memory=ConversationBufferMemory(memory_key="chat_history", input_key="")
    )

    # Get the response
    response = retrieval_chain.invoke({"question": query, "context": documents, "input": ""})

    return response["answer"]

# Code for Frontend begins here
st.set_page_config(page_title="Linkenite AI", page_icon='🤖', layout='centered', initial_sidebar_state='collapsed')
st.header("🤖Linkenite Marketing Assistant")

prompt = st.text_input("Enter the prompt")
task = st.selectbox("Please select the input you want to provide", ('PDF', 'URL'), key=1)
content_type = st.selectbox("Select the type of content you want to generate", ("Blog", "Technical Blog", "Whitepaper", "Case Studies", "LinkedIn Post", "Social Media Post"), key=2)

input_file = None
input_url = None

if task == 'PDF':
    input_file = st.file_uploader("Upload a PDF file", type="pdf")
    # Work on tracking the path of the uploaded pdf
elif task == 'URL':
    input_url = st.text_input("Enter the URL")

submit = st.button("Generate")

if submit and (input_file or input_url):
    global_pdf_path = "input_kb.pdf"
    external_pdf_path = None

    if input_file:
        # The input pdf file's path has to be used below inplace of "input_kb.pdf"
        with open("input_kb.pdf", "wb") as f:
            f.write(input_file.read())
        external_pdf_path = "input_kb.pdf"

    documents = load_documents(global_pdf_path, external_pdf_path, input_url)
    vector_store = create_vector_store(documents)

    context = " ".join([doc.page_content for doc in documents])
    response = get_LLM_response(prompt, context, vector_store)
    st.write(response)

def set_bg_from_url(url, opacity=1):

    # Set background image using HTML and CSS
    st.markdown(
        f"""
        <style>
            body {{
                background: url('{url}') no-repeat center center fixed;
                background-size: cover;
                opacity: {opacity};
            }}
        </style>
        """,
        unsafe_allow_html=True
    )

# Set background image from URL
set_bg_from_url("https://cdn.create.vista.com/api/media/medium/231856778/stock-photo-smartphone-laptop-black-background-marketing-lettering-icons?token=", opacity=0.775)

Error Message and Stack Trace (if applicable)

(venv) PS C:\Users\User\Desktop\Linkenite\MarketingAI MVP> streamlit run apporiginal.py

USER_AGENT environment variable not set, consider setting it to identify your requests. C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain_core_api\deprecation.py:139: LangChainDeprecationWarning: The class LLMChain was deprecated in LangChain 0.1.17 and will be removed in 0.3.0. Use RunnableSequence, e.g., prompt | llm instead. warn_deprecated( C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain_core_api\deprecation.py:139: LangChainDeprecationWarning: The class ConversationalRetrievalChain was deprecated in LangChain 0.1.17 and will be removed in 0.3.0. Use create_history_aware_retriever together with create_retrieval_chain (see example in docstring) instead. warn_deprecated( 2024-06-21 12:54:19.810 Uncaught app exception Traceback (most recent call last): File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\streamlit\runtime\scriptrunner\script_runner.py", line 589, in _run_script exec(code, module.dict) File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\apporiginal.py", line 147, in response = get_LLM_response(prompt, context, vector_store) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\apporiginal.py", line 109, in get_LLM_response response = retrieval_chain.invoke({"question": query, "context": documents, "input": ""}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain\chains\base.py", line 166, in invoke raise e File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain\chains\base.py", line 161, in invoke final_outputs: Dict[str, Any] = self.prep_outputs( ^^^^^^^^^^^^^^^^^^ File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain\chains\base.py", line 460, in prep_outputs self.memory.save_context(inputs, outputs) File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain\memory\chat_memory.py", line 55, in save_context input_str, output_str = self._get_input_output(inputs, outputs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "C:\Users\User\Desktop\Linkenite\MarketingAI MVP\venv\Lib\site-packages\langchain\memory\chat_memory.py", line 51, in _get_input_output

return inputs[prompt_input_key], outputs[output_key]
       ~~~~~~^^^^^^^^^^^^^^^^^^

KeyError: ''

Description

I am trying to invoke a retrieval chain with three parameters passed {"question": query, "context": documents, "input": ""} the result throws a KeyError related to [ output_key ].

When I passed output_key like this {"question": query, "context": documents, "input": ", "output_key": ""} it gives another error.

The error comes from line 51 of langchain/memory/chat_memory.py -> in _get_input_output return inputs[prompt_input_key], outputs[output_key]


KeyError: ''
  Stopping...

### System Info

"pip freeze | grep langchain"
platform (windows)
python version (3.12.2)

System Information
------------------
> OS:  Windows
> OS Version:  10.0.22631
> Python Version:  3.12.4 (tags/v3.12.4:8e8a4ba, Jun  6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)]

Package Information
-------------------
> langchain_core: 0.2.9
> langchain: 0.2.5
> langchain_community: 0.2.5
> langsmith: 0.1.77
> langchain_chroma: 0.1.1
> langchain_openai: 0.1.8
> langchain_text_splitters: 0.2.1

Packages not installed (Not Necessarily a Problem)
--------------------------------------------------
The following packages were not found:

> langgraph
> langserve
keenborder786 commented 5 months ago

You are not using the correct input_key that goes along with the memory_key. Please see below:


question_generator_template = PromptTemplate(
        input_variables=[ # your input variables are not correct.
    "chat_history",
    "question", 
],
    template= (  
    """
    Combine the chat history and follow up question into a standalone question.
    Chat History: {chat_history}
    Follow up question: {question}
""")
)

question_generator_chain = LLMChain(
    llm=llm,
    prompt=question_generator_template,
)

# Create retrieval chain
retrieval_chain = ConversationalRetrievalChain(
    combine_docs_chain=document_chain,
    question_generator=question_generator_chain,
    retriever=retriever,
    memory=ConversationBufferMemory(memory_key="chat_history", input_key="question") # should use question as input key
)