langchain-ai / langchainjs

🦜🔗 Build context-aware reasoning applications 🦜🔗
https://js.langchain.com/docs/
MIT License
12.28k stars 2.07k forks source link

DOC: <Issue related to /v0.2/docs/tutorials/qa_chat_history> #6016

Open tim-field opened 2 months ago

tim-field commented 2 months ago

Checklist

Issue with current documentation:

The example doesn't work. I assume it needs to check for arrray length on chat history? Without it you don't have context for the first question. I'm too new to this all to understand exactly why it doesn't work, but it doesn't!

Idea or request for content:

No response

dosubot[bot] commented 2 months ago

Hey @tim-field! I'm here to help you out with any bugs, questions, or contributions you have. Let's tackle this together!

To resolve the issue with the documentation example in /v0.2/docs/tutorials/qa_chat_history, you need to ensure that the collections and docs arrays have the same length or handle the case where collections has a length of 1 and docs is not defined. The provided code already includes this check in the constructor of the FirestoreChatMessageHistory class:

constructor({
    collectionName,
    collections,
    docs,
    sessionId,
    userId,
    appIdx = 0,
    config,
  }: FirestoreDBChatMessageHistory) {
    super();
    if (collectionName && collections) {
      throw new Error(
        "Can not pass in collectionName and collections. Please use collections only."
      );
    }
    if (!collectionName && !collections) {
      throw new Error(
        "Must pass in a list of collections. Fields `collectionName` and `collections` are both undefined."
      );
    }
    if (collections || docs) {
      if (
        !(
          collections?.length === docs?.length ||
          (collections?.length === 1 && !docs)
        )
      ) {
        throw new Error(
          "Collections and docs options must have the same length, or collections must have a length of 1 if docs is not defined."
        );
      }
    }

    this.collections = collections || ([collectionName] as string[]);
    this.docs = docs || ([sessionId] as string[]);
    this.sessionId = sessionId;
    this.userId = userId;
    this.document = null;
    this.appIdx = appIdx;
    if (config) this.config = config;

    try {
      this.ensureFirestore();
    } catch (error) {
      throw new Error(`Unknown response type`);
    }
  }

Additionally, in the ConversationalRetrievalQAChain class, there is a method getChatHistoryString that converts the chat history input into a formatted string. This method includes a check for the length of the chat history:

static getChatHistoryString(
    chatHistory: string | BaseMessage[] | string[][]
  ) {
    let historyMessages: BaseMessage[];
    if (Array.isArray(chatHistory)) {
      if (
        Array.isArray(chatHistory[0]) &&
        typeof chatHistory[0][0] === "string"
      ) {
        console.warn(
          "Passing chat history as an array of strings is deprecated.\nPlease see https://js.langchain.com/docs/modules/chains/popular/chat_vector_db#externally-managed-memory for more information."
        );
        historyMessages = chatHistory.flat().map((stringMessage, i) => {
          if (i % 2 === 0) {
            return new HumanMessage(stringMessage);
          } else {
            return new AIMessage(stringMessage);
          }
        });
      } else {
        historyMessages = chatHistory as BaseMessage[];
      }
      return historyMessages
        .map((chatMessage) => {
          if (chatMessage._getType() === "human") {
            return `Human: ${chatMessage.content}`;
          } else if (chatMessage._getType() === "ai") {
            return `Assistant: ${chatMessage.content}`;
          } else {
            return `${chatMessage.content}`;
          }
        })
        .join("\n");
    }
    return chatHistory;
  }

This method ensures that the chat history is properly formatted and handles different input types, including arrays of strings and arrays of BaseMessage instances. This should help in resolving the issue with the example in the documentation [1][2].

To continue talking to Dosu, mention @dosu.