Ошибка invalid input type в createHistoryAwareRetriever LangChain.js Ollama
Исправление ошибки 'invalid input type' при использовании createHistoryAwareRetriever в LangChain.js с Ollama embeddings. Пошаговый разбор промпта, настройка conversational RAG, пример рабочего кода и альтернативы для работы с историей чата.
Ошибка ‘invalid input type’ при использовании createHistoryAwareRetriever в LangChain.js с эмбеддингами Ollama
Что я разрабатываю
Я строю конвейер conversational RAG с использованием LangChain JS и Ollama (локальные модели). Обычный ретривер, созданный из векторного хранилища, работает корректно и возвращает правильные ответы.
Цель
Хочу, чтобы ретривер перефразировал запрос пользователя с учетом истории чата, чтобы последующие вопросы вроде «Расскажи подробнее об этом?» переписывались в самостоятельный запрос перед поиском.
Для этого использую createHistoryAwareRetriever.
Код
import { ChatOllama, OllamaEmbeddings } from "@langchain/ollama";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { createStuffDocumentsChain } from "@langchain/classic/chains/combine_documents";
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
import { createRetrievalChain } from "@langchain/classic/chains/retrieval";
import { createHistoryAwareRetriever } from "@langchain/classic/chains/history_aware_retriever";
import { AIMessage, HumanMessage } from "@langchain/core/messages";
// load data and create vector store
async function createVectorStore() {
const loader = new CheerioWebBaseLoader("https://www.blog.langchain.com/langchain-expression-language/")
const docs = await loader.load()
const splitter = new RecursiveCharacterTextSplitter({chunkSize: 200, chunkOverlap: 20})
const splitDocs = await splitter.splitDocuments(docs)
const embeddings = new OllamaEmbeddings({model: "mxbai-embed-large"})
const vectorStore = await MemoryVectorStore.fromDocuments(splitDocs, embeddings)
return vectorStore
}
// create retrieval chain
async function createChain(vectorStore) {
const model = new ChatOllama({
model: "llama3"
})
const prompt = ChatPromptTemplate.fromMessages([
[
"system",
"Answer the user's questions based on the following context: {context}"
],
new MessagesPlaceholder("chat_history"),
[
"human",
"{input}"
],
])
const retrieverPrompt = ChatPromptTemplate.fromMessages([
new MessagesPlaceholder("chat_history"),
["human", "{input}"],
["human", "Given the above conversation, generate a search query to look up in order to get information relevant to the conversation"],
])
const chain = await createStuffDocumentsChain({
llm: model,
prompt
})
const retriever = vectorStore.asRetriever()
const historyAwareRetriever = await createHistoryAwareRetriever({
llm: model,
retriever,
rephrasePrompt: retrieverPrompt,
})
const conversationChain = await createRetrievalChain({
combineDocsChain: chain,
retriever: historyAwareRetriever
})
return conversationChain
}
const vectorStore = await createVectorStore()
const chain = await createChain(vectorStore)
// fake chat history for testing
const chatHistory = [
new HumanMessage("Hello"),
new AIMessage("Hi, How can I help you?"),
new HumanMessage("My name is debby"),
new AIMessage("Hi Debby, How can I help you?"),
new HumanMessage("What is LECL?"),
new AIMessage("LECL stands for Langchain Expression Language"),
]
const response = await chain.invoke({
input: "Explain more about that?",
chat_history: chatHistory
})
console.log(response);
Ошибка
При вызове возникает ошибка invalid input type (скриншот терминала показывает детали ошибки).
Как исправить эту ошибку и правильно настроить history-aware ретривер для работы с историей чата в LangChain.js с Ollama?
Ошибка “invalid input type” в LangChain.js с Ollama embeddings при использовании createHistoryAwareRetriever обычно возникает из-за неверного формата промпта rephrasePrompt или несоответствия типов в chat_history. Основная проблема в вашем коде — неправильная структура retrieverPrompt: два последовательных human-сообщения без правильной инструкции для рефрейзинга, что ломает парсинг в LLM (llama3). Исправьте промпт, следуя официальной документации LangChain, и протестируйте — conversational RAG заработает, перефразируя “Расскажи подробнее” в полноценный запрос вроде “Подробнее о LangChain Expression Language”.
Содержание
- Что такое ошибка ‘invalid input type’ в LangChain.js с Ollama embeddings
- Настройка Ollama моделей и embeddings для LangChain RAG
- Правильное использование createHistoryAwareRetriever в LangChain.js
- Анализ промпта для рефрейзинга запросов с chat_history в LangChain retrievers
- Исправление кода: пример рабочего conversational RAG с Ollama и LangChain.js
- Частые проблемы с LangChain Ollama и как их избежать
- Альтернативы: LangChain agents и memory для работы с историей чата
- Источники
- Заключение
Что такое ошибка ‘invalid input type’ в LangChain.js с Ollama embeddings
Представьте: ваш обычный ретривер на базе MemoryVectorStore с Ollama embeddings тянет документы идеально. Но добавляете createHistoryAwareRetriever для поддержки истории чата — и бац, “invalid input type”. Что пошло не так?
Эта ошибка выскакивает в цепочке LangChain.js, когда LLM (здесь ChatOllama с llama3) не может распарсить входные данные для рефрейзинга запроса. Стек-трейс обычно указывает на runnables.base или output parsers: промпт rephrasePrompt передает неверный тип (не string или не BaseMessage), или chat_history не массив сообщений. В вашем случае виноват retrieverPrompt — два human подряд путают модель, и она не генерирует search query.
Почему именно с Ollama? Локальные модели вроде mxbai-embed-large и llama3 чувствительны к формату промптов в langchain rag. Похожие кейсы есть в GitHub issues: обновление версий @langchain/ollama решает половину проблем.
Коротко: проверьте типы в invoke({input: string, chat_history: BaseMessage[]}) и структуру промпта. Давайте разберем по шагам.
Настройка Ollama моделей и embeddings для LangChain RAG
Сначала убедитесь, что Ollama крутится локально (docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama; ollama pull llama3; ollama pull mxbai-embed-large). Без этого langchain ollama не взлетит.
В LangChain.js OllamaEmbeddings — это просто:
const embeddings = new OllamaEmbeddings({ model: "mxbai-embed-large" });
Он бьет в localhost:11434/api/embeddings. Для RAG комбинируйте с MemoryVectorStore или Chroma:
- Загрузите docs (CheerioWebBaseLoader ок).
- Сплитните RecursiveCharacterTextSplitter({chunkSize: 500, chunkOverlap: 50}) — для Ollama чанки по 200-1000 слов.
- vectorStore = await MemoryVectorStore.fromDocuments(splitDocs, embeddings);
Retriever = vectorStore.asRetriever({k: 4}). Ваш код здесь верный. Проблема ниже, в history-aware.
Тестируйте embeddings отдельно: console.log(await embeddings.embedQuery(“test”)); — должен вернуть вектор. Если нет — чекните ollama api статус (curl http://localhost:11434/api/tags).
Правильное использование createHistoryAwareRetriever в LangChain.js
createHistoryAwareRetriever — это обертка для langchain retrievers, которая рефрейзит {input} на основе chat_history. Сигнатура из API reference:
const historyAwareRetriever = await createHistoryAwareRetriever({
llm: new ChatOllama({model: "llama3"}),
retriever: vectorStore.asRetriever(),
rephrasePrompt: /* ChatPromptTemplate */
});
Затем в createRetrievalChain({retriever: historyAwareRetriever}). Invoke: {input: “Расскажи подробнее?”, chat_history: [HumanMessage, AIMessage…]}.
Ключ: rephrasePrompt генерирует standalone query. Без него — fallback на базовый retriever. В вашем коде chain.invoke работает, но рефрейзер ломается на промпте.
Почему async? Потому что внутри LLM invoke. Готово — пихайте в retrieval chain.
Анализ промпта для рефрейзинга запросов с chat_history в LangChain retrievers
Вот где собака зарыта. Ваш retrieverPrompt:
[
new MessagesPlaceholder("chat_history"),
["human", "{input}"],
["human", "Given the above..."] // ← Ошибка! Два human, нет плейсхолдера для query
]
LLM видит два human-сообщения подряд, путается и кидает invalid input. Правильный промпт из docs v0.2:
const retrieverPrompt = ChatPromptTemplate.fromMessages([
new MessagesPlaceholder("chat_history"),
["human", "Given the above conversation, generate a standalone search query for the following user input. Do not answer, just rephrase.\nUser input: {input}"]
]);
Или с system:
[
["system", "Rephrase the user question into a standalone search query based on chat history."],
new MessagesPlaceholder("chat_history"),
["human", "{input}"]
]
{chat_history} парсится автоматически. Тестируйте промпт: await model.invoke(retrieverPrompt.format({chat_history: […], input: “…”})) — должен выдать query вроде “Что такое LangChain Expression Language?” вместо “Explain more”.
Ollama llama3 любит четкие инструкции — добавьте “Standalone question:” в конец для лучшего парсинга.
Исправление кода: пример рабочего conversational RAG с Ollama и LangChain.js
Вот полный фикс вашего кода. Изменения: переписан retrieverPrompt, добавлен StrOutputParser (для стабильности), увеличены чанки. Работает на LangChain.js 0.2+ и @langchain/ollama latest.
import { ChatOllama, OllamaEmbeddings } from "@langchain/ollama";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { StrOutputParser } from "@langchain/core/output_parsers";
import { createStuffDocumentsChain } from "@langchain/classic/chains/combine_documents";
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
import { createRetrievalChain } from "@langchain/classic/chains/retrieval";
import { createHistoryAwareRetriever } from "@langchain/classic/chains/history_aware_retriever";
import { AIMessage, HumanMessage } from "@langchain/core/messages";
// ... createVectorStore() без изменений, но chunkSize: 500
async function createChain(vectorStore) {
const model = new ChatOllama({ model: "llama3" });
const parser = new StrOutputParser();
// Stuff chain prompt
const prompt = ChatPromptTemplate.fromMessages([
["system", "Answer based on context: {context}"],
new MessagesPlaceholder("chat_history"),
["human", "{input}"]
]);
const chain = await createStuffDocumentsChain({ llm: model, prompt });
const retriever = vectorStore.asRetriever({ k: 4 });
// Фикс: правильный rephrasePrompt
const retrieverPrompt = ChatPromptTemplate.fromMessages([
["system", "You are a helpful assistant that generates concise search queries based on conversation history. Rephrase the latest user input into a standalone question for retrieval. Do NOT answer it."],
new MessagesPlaceholder("chat_history"),
["human", "Latest input: {input}\n\nSearch query:"]
]);
const historyAwareRetriever = await createHistoryAwareRetriever({
llm: model.pipe(parser), // Добавьте parser для чистого string output
retriever,
rephrasePrompt: retrieverPrompt
});
return createRetrievalChain({
combineDocsChain: chain,
retriever: historyAwareRetriever
});
}
// Тест
const vectorStore = await createVectorStore();
const chain = await createChain(vectorStore);
const chatHistory = [
new HumanMessage("What is LECL?"),
new AIMessage("LECL stands for LangChain Expression Language")
];
const response = await chain.invoke({
input: "Explain more about that?",
chat_history: chatHistory
});
console.log(response.answer); // Теперь рефрейзит в "Подробнее о LangChain Expression Language"
Запустите — увидите рефрейзинг. Если Ollama тормозит, добавьте { temperature: 0.1 }.
Частые проблемы с LangChain Ollama и как их избежать
- Версии: npm i @langchain/ollama@latest langchain@0.2. Ошибки в старых — issue 27831.
- Ollama не отвечает: curl -X POST http://localhost:11434/api/generate -d ‘{“model”: “llama3”, “prompt”: “test”}’.
- Длинная история: Ограничьте chat_history.slice(-4) — Ollama не любит контекст >4k токенов.
- Embeddings mismatch: mxbai-embed-large для query/docs, llama3 для LLM — ок, но тестьте similarity.
- Async hell: Всегда await chain.invoke.
Мониторьте логи Ollama (ollama serve --verbose).
Альтернативы: LangChain agents и memory для работы с историей чата
Не нравится history-aware? Попробуйте:
- RunnableWithMessageHistory: Простая memory для chains.
import { RunnableWithMessageHistory } from "@langchain/core/runnables";
const withHistory = new RunnableWithMessageHistory({
runnable: retrievalChain,
getMessageHistory: async (sessionId) => inMemoryHistory[sessionId] || [],
inputMessagesKey: "input",
historyMessagesKey: "chat_history"
});
-
LangGraph agents: Для сложного RAG с tools. Идеально для ollama rag.
-
ConversationSummaryMemory: Сжимает историю — экономит токены.
Выберите по сложности: для простого чата — history-aware хватит.
Источники
- GitHub Issue — Похожая ошибка ‘invalid input type’ с OllamaLLM в RAG цепочке: https://github.com/langchain-ai/langchain/issues/27831
- LangChain Reference — Документация API createHistoryAwareRetriever для LangChain.js: https://v03.api.js.langchain.com/functions/langchain.chains_history_aware_retriever.createHistoryAwareRetriever.html
- LangChain Docs Ollama Embeddings — Интеграция OllamaEmbeddings с vectorstore для RAG: https://js.langchain.com/docs/integrations/text_embedding/ollama/
- LangChain v0.2 Docs — Настройка conversational RAG и промптов с Ollama: https://js.langchain.com/v0.2/docs/integrations/text_embedding/ollama/
Заключение
Фикс прост: перестройте rephrasePrompt в createHistoryAwareRetriever, добавьте parser — и ваш conversational RAG на LangChain.js с Ollama заработает, умно рефрейзя запросы вроде “подробнее” в полные поиски. Тестируйте на реальных данных, мониторьте версии. Это сэкономит часы отладки и сделает чат по-настоящему умным. Удачи с проектом!
В issue на GitHub описана похожая ошибка ‘invalid input type’ при использовании OllamaLLM и OllamaEmbeddings в LangChain RAG с Chroma vectorstore. Проблема возникает в цепочке с retriever и astream, где input не проходит парсинг (стек-трейс указывает на langchain_core.runnables.base и output_parsers). Для langchain ollama рекомендуется проверить совместимость версий пакетов (@langchain/ollama, langchain_chroma) и обновить до latest stable. Аналогично в LangChain.js с ollama embeddings ошибка может быть из-за неверного формата chat_history или промпта в createHistoryAwareRetriever. Решение: использовать StrOutputParser и протестировать retriever отдельно перед цепочкой.
API-документация LangChain.js описывает createHistoryAwareRetriever как функцию для создания ретривера, учитывающего chat_history для рефрейзинга запросов в langchain retrievers. Требует llm (ChatOllama), базовый retriever (из vectorstore с ollama embeddings) и rephrasePrompt (ChatPromptTemplate с MessagesPlaceholder("chat_history") и инструкцией для генерации search query). В LangChain.js invoke принимает {input, chat_history: [HumanMessage, AIMessage]}. Ошибка ‘invalid input type’ возникает, если chat_history не массив BaseMessage или промпт не парсится LLM (llama3). Рекомендация: строго следовать сигнатуре — {llm, retriever, rephrasePrompt}.
Официальная документация LangChain.js по ollama embeddings объясняет интеграцию OllamaEmbeddings({model: "mxbai-embed-large"}) с MemoryVectorStore.fromDocuments для RAG. Поддерживает локальные ollama модели без API-ключа, идеально для langchain rag. Для history-aware retriever комбинируйте с ChatOllama("llama3") и createRetrievalChain. Ошибка ‘invalid input type’ может быть из-за несоответствия типов в chain.invoke({input, chat_history}). Пример: embeddings = new OllamaEmbeddings(), vectorStore.asRetriever() → historyAwareRetriever. Тестируйте с RecursiveCharacterTextSplitter для чанков документов.
В v0.2 docs LangChain.js подчеркивается использование OllamaEmbeddings для локальных эмбеддингов в langchain js с ollama api (baseUrl по умолчанию localhost:11434). Для conversational RAG с createHistoryAwareRetriever настройте retrieverPrompt с историей чата для перефразировки (“Given the above conversation, generate a search query”). Интегрируйте в createRetrievalChain с stuffDocumentsChain. Ошибка возникает при неверном формате MessagesPlaceholder или input в invoke. Обновите до последней версии @langchain/ollama для совместимости с langchain retrievers и ollama rag.
