Подключение к Saiga2 кастомной базы знаний

#1
by maxschmaltz - opened

Привет Илья,

недавно писал тебе по поводу использования Saiga на GPU, спасибо за комментарий, все получилось! Сейчас есть другой вопрос, уже связанный с Saiga2.

Я делаю кастомного чат-бота на материале русского языка, и не могу никак понять, как мне начать для этого использовать Saiga2 (с первой Saiga все получается). Задача заключается в следующем: у меня есть коллекция документов; документы надо спарсить, обработать, преобразовать в векторную базу данных и подключить к какой-либо генеративной LLM, чтобы с ее помощью на материале (только) этих документов генерить ответы на вопросы пользователя; огромным плюсом будет учет истории и printout токенов по мере их генерации. При этом работать все должно в закрытом контуре, поэтому модель должна быть установлена локально.
Гайдов по этой теме полно, подавляющее большинство из них показывает, как решить подобную задачу с помощью LangChain. С версией Saiga для llama-cpp все заработало без вопросов, а вот Saiga2 для llama-cpp у меня не грузится:

from langchain.llms import LlamaCpp
llm = LlamaCpp(model_path='./models/saiga2_7b_gguf/ggml-model-q8_0.gguf')

Выдает:

ValidationError: 1 validation error for LlamaCpp
__root__
  Could not load Llama model from path: ./models/saiga2_7b_gguf/ggml-model-q8_0.gguf. Received error  (type=value_error)

Использую LangChain (а не, например, написанный тобой скрипт) ровно потому, что нужны фичи, которые предоставляет LangChain: подключение кастомной базы знаний, история etc.

В связи с этим такой вопрос: ты мог бы посоветовать наиболее оптимальный способ для решения моей задачи? Есть ли альтернативы LangChain, с которыми я мог бы использовать Saiga2 в подобном сценарии? Или, если нет, как мне запустить Saiga2 с LangChain? Я еще параллельно буду пробовать твой адаптер saiga2_7b_lora, есть ли смысл попробовать использовать его с LangChain.HuggingFacePipeline?

Заранее спасибо!

Best,
Макс

GGUF - новый формат, для него нужны новые версии биндингов.

Про GGUF уже прочитал, понял :) Это уже, насколько я понял, с langchain.llms.CTransformers делается?

Нет, это всё та же llama.cpp

Да, на новой версии llama.cpp все получилось.

Но, кстати, сработало и с CTransformers:

config = {
    'temperature': 0,
    'context_length': 2000,
    'max_new_tokens': 2000,
    'stream': True,
    'batch_size': 512,
    'gpu_layers': 32
}

llm = CTransformers(
    model='./models/saiga2_7b_gguf/ggml-model-q8_0.gguf',
    config=config
)

Почему может быть такое, что Saiga2 генерит сначала на русском, потом на английском?

Я все делаю с LangChain, использую HuggingFaceEmbeddings с моделью all-mpnet-base-v2 (родные эмбеддинги пока использовать не позволяет GPU), историю переписки реализую с ConversationBufferWindowMemory и заворачиваю это все в ConversationalRetrievalChain. На первый вопрос ответ на русском, все хорошо, но вот на последующие отвечает на английском, причем ответ в тему (то есть не на рандом).

Я пока что пробую следующие способы (в порядке приоритетности):

  1. Использовать другие эмбеддинги: чисто для русского языка либо мультиязычные (хотя all-mpnet-base-v2 вроде справляется с русским).
  2. Промптинг: менять системные промпты самой модели, Chain'ов etc. Кст, промптинг по типу "отвечай только на русском" не дает результатов.
  3. Другие виды / сочетания Chain'ов (хотя не думаю, что поможет).

Если есть подобный опыт, мог бы ты, пожалуйста, поделиться, в каких еще направлениях стоит покопать и/или в каких не стоит?

Спасибо!

Best,
Макс

Так а формат промпта правильный? Как в скрипте?

изображение.png

А так звучит так, что Langchain промптит на английском, поэтому и ответы на английском

А так звучит так, что Langchain промптит на английском, поэтому и ответы на английском

Я об этом же и подумал, к этому и был мой второй пункт :) просто пока еще не было времени проверить. Тогда в первую очередь посмотрю в том направлении. Спасибо про напоминание про особый промпт для Saiga, проверю первым делом!

Best,
Макс

@maxschmaltz , привет!
Передо мной сейчас такая же задача: создать бота, который получал бы контекст из документов и отвечал строго по нему. Использую также LangChain, ConversationalRetrievalChain.
Пока что не получается добиться адекватных ответов, просьба "отвечай только по контексту" игнорируется. Думаю, проблема все же в промтах.
Не мог бы ты показать, как реализовал подключение модели, создание промтов, заворачивание в ConversationalRetrievalChain?

Вот моя текущая реализация:


system_template = """
Тебя зовут Сайга. Ты полезный, уважительный и честный ассистент. Для ответа на вопрос пользователя используй информацию из контекста.
Если ты не знаешь ответа, просто скажи, что не знаешь, не пытайся придумать ответ.
Контекст: {context}
Вопрос: {question}
Возвращай только полезный ответ и ничего больше.
Полезный ответ:
"""

llm = LlamaCpp(
    model_path=model_path,
    n_ctx= 2400,
    verbose=True,
    use_mlock=True,
    n_gpu_layers=12,
    n_threads=4,
    n_batch=512
)

memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)
combine_docs_custom_prompt = PromptTemplate.from_template(system_template)

conversation_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    combine_docs_chain_kwargs=dict(prompt=combine_docs_custom_prompt),
    memory=memory,
)

Привет @GolubSeri ,

Прости за поздний ответ. К сожалению, я не могу раскрыть конкретную реализацию, так как она находится в рамках не исследования либо open-source проекта, но продукта для заказчика. Тем не менее, буду рад помочь, дав пару направлений, в которых ты можешь попробовать двинуться.

  1. Во-первых, бота я делал примерно так же, как ты в своей реализации, так что направление верное. В основном я ссылался на этот гайд (про ConversationalRetrievalChain внизу). Следуя ему, я создал question_generator и combine_docs_chain и передавал их вместе с memory и retriever в ConversationalRetrievalChain . Для всех Chain'ов использовал Saiga2. Именно такая архитектура помогла улучшить результат. К каждому Chain'у делал кастомный промпт на русском.

Что-то похожее на это:

question_generator = LLMChain(
    llm=...,
    prompt=...
)
combine_docs_chain = load_qa_with_sources_chain(
    llm=...
)

chain = ConversationalRetrievalChain(
    memory=...,
    retriever=...,
    question_generator=question_generator,
    combine_docs_chain=combine_docs_chain
)
  1. Промптинг оказался очень чувствительным, так что пробуй много много разных вариантов. Доходило до того, что реально совершенно менялся результат при добавлении переноса строки, не говоря уже об одном слове. Да и кажется, что модель case-sensitive.
  2. При дизайне промптов я брал за основу дефолтные промпты от langchain, переводил сначала дословно на русский и уже потом допиливал. Например, системный промпт я настраивал около 3-4 часов, перепробовав огромное количество вариантов. В общем, по моему опыту тут чисто калибровка нужна, и промпт влияет куда сильнее, чем все остальное. Опять-таки, конкретного промпта указать не могу, но вот что интересно: добавление изначально рекомендуемого "Ты — Сайга, русскоязычный автоматический ассистент. Ты разговариваешь с людьми и помогаешь им." как будто сбивало модель и приводило к отсутствию адекватных ответов, когда как те же промпты без него работали куда лучше ( @IlyaGusev , есть идеи, почему так может быть?). Что тут хорошо, это то, что результаты воспроизводимые, так что, нащупав улучшение, сохраняй где-нибудь этот промпт как чекпоинт, сэкономишь время)

Best,
Maкс

Привет @maxschmaltz ,

Большое спасибо, это очень ценно!
Буду экспериментировать дальше :)

Привет @GolubSeri
Решаю похожую задачу.
Не мог бы ты поделиться своими наработками, пока не могу добиться нормальных ответов?

Привет @IlyaGusev
Разбираюсь с запуском Saiga2 на GPU, при чем нужно запустить с потоковой генерацией текста.
Подскажешь, пожалуйста, возможно ли это и как можно это осуществить?

Sign up or log in to comment