Настройка LLM (языковая модель)
В текущей области моделей искусственного интеллекта существует огромное разнообразие моделей, и официальная интеграция LangChain не покрывает все модели. Иногда вам может потребоваться настроить модель и интегрировать ее в рамки LangChain.
Эта глава познакомит вас с созданием собственной оболочки LLM, что позволит вам легко использовать собственную модель или модели, не поддерживаемые LangChain.
В LangChain, если вам нужно использовать свою собственную LLM или другую оболочку, не поддерживаемую LangChain, вы можете создать собственную оболочку LLM. Для этого достаточно реализовать два обязательных метода:
- Метод
_call
, который принимает входную строку, некоторые необязательные стоп-слова и возвращает строку, выполняя вызов модели в методе_call
. - Атрибут
_llm_type
, возвращающий строку, представляющую название модели, используемой исключительно для ведения журнала.
Помимо обязательных методов собственная LLM также может реализовать необязательный метод:
- Атрибут
_identifying_params
, используемый для помощи при печати класса. Он должен возвращать словарь.
Реализация простой собственной LLM
Давайте реализуем очень простую собственную LLM, которая возвращает только первые n символов ввода.
from typing import Any, List, Mapping, Optional
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
class CustomLLM(LLM):
n: int
@property
def _llm_type(self) -> str:
return "custom"
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> str:
if stop is not None:
raise ValueError("stop аргументы не допускаются.")
return prompt[: self.n]
@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Получить идентифицирующие параметры."""
return {"n": self.n}
Теперь мы можем использовать эту собственную LLM так же, как любую другую LLM.
Использование собственной LLM
Мы можем создать экземпляр и использовать объект собственной LLM, продемонстрировав, как вызвать собственную LLM и настроить вывод в консоль.
llm = CustomLLM(n=10)
llm.invoke("This is a foobar thing")
'This is a '
Мы также можем вывести LLM и посмотреть его настраиваемый вывод в консоли.
print(llm)
CustomLLM
Параметры: {'n': 10}
Настройка модели чата
Здесь мы расскажем, как настраивать чат-модель LangChain.
Ввод и вывод сообщений
В чат-модели сообщения являются основой ввода и вывода. Сообщение - это содержимое, введенное пользователем, и ответ, сгенерированный моделью.
Сообщения
Чат-модель принимает сообщения в качестве ввода, а затем генерирует одно или несколько сообщений в качестве вывода. В LangChain существует несколько встроенных типов сообщений, включая:
-
SystemMessage
: Используется для инициализации поведения ИИ, обычно в качестве первого сообщения в серии входящих сообщений. -
HumanMessage
: Представляет взаимодействие пользователя с чат-моделью. -
AIMessage
: Представляет сообщения от чат-модели, которые могут быть текстовыми или запросами на вызов инструмента. -
FunctionMessage
/ToolMessage
: Используются для передачи результата вызова инструмента обратно в модель.
Использование этих типов сообщений может быть расширено и настроено в соответствии с конкретными требованиями, такими как настройка на основе параметров function
и tool
OpenAI.
from langchain_core.messages import (
AIMessage,
BaseMessage,
FunctionMessage,
HumanMessage,
SystemMessage,
)
Плавные варианты
У всех сообщений чата есть плавный вариант с Chunk
в названии.
from langchain_core.messages import (
AIMessageChunk,
FunctionMessageChunk,
HumanMessageChunk,
SystemMessageChunk,
ToolMessageChunk,
)
Эти Chunk
используются при потоковой передаче чат-модели, и каждый из них определяет накапливаемый атрибут!
Пример
AIMessageChunk(content="Привет") + AIMessageChunk(content=" мир!")
Возвращает
AIMessageChunk(content='Привет, мир!')
Простая модель чата
Наследование от SimpleChatModel
позволяет быстро реализовать простую модель чата.
Хотя она может не включать все необходимые функции для модели чата, она обеспечивает быструю реализацию. Если требуется больше функций, то можно перейти к BaseChatModel
, описанной ниже.
Наследование от SimpleChatModel
требует реализации следующего интерфейса:
- метод
_call
- реализация внешних вызовов API модели.
Дополнительно можно указать:
- атрибут
_identifying_params
- используется для записи параметризованной информации о модели.
Опционально:
- метод
_stream
- используется для реализации потокового вывода.
Базовая модель чата
Наследование от BaseChatModel
требует реализации метода _generate
и атрибута _llm_type
. Опционально можно реализовать _stream
, _agenerate
, _astream
и _identifying_params
.
Пример пользовательской модели чата
В этом разделе мы продемонстрируем реализацию кода пользовательской модели чата под названием CustomChatModelAdvanced
, включая генерацию результатов чата, потоковый вывод и реализацию асинхронного потока.
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional
from langchain_core.callbacks import (
AsyncCallbackManagerForLLMRun,
CallbackManagerForLLMRun,
)
from langchain_core.language_models import BaseChatModel, SimpleChatModel
from langchain_core.messages import AIMessageChunk, BaseMessage, HumanMessage
from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult
from langchain_core.runnables import run_in_executor
class CustomChatModelAdvanced(BaseChatModel):
"""Реализация пользовательской модели чата, которая возвращает первые `n` символов последнего сообщения."""
n: int
"""Параметр пользовательской модели"""
def _generate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> ChatResult:
"""Здесь реализована логика вызова модели, обычно путем вызова API сторонней модели, а затем инкапсуляции результатов в формате, который может распознать langchain.
Объяснение ключевого параметра:
messages: Список подсказок, состоящих из сообщений
"""
last_message = messages[-1]
tokens = last_message.content[: self.n]
message = AIMessage(content=tokens)
generation = ChatGeneration(message=message)
return ChatResult(generations=[generation])
def _stream(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> Iterator[ChatGenerationChunk]:
"""Реализация потокового вывода модели, аналогично методу `_generate`, но с обработкой потокового вывода."""
last_message = messages[-1]
tokens = last_message.content[: self.n]
for token in tokens:
chunk = ChatGenerationChunk(message=AIMessageChunk(content=token))
if run_manager:
run_manager.on_llm_new_token(token, chunk=chunk)
yield chunk
async def _astream(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> AsyncIterator[ChatGenerationChunk]:
"""Асинхронная версия реализации метода `stream`"""
result = await run_in_executor(
None,
self._stream,
messages,
stop=stop,
run_manager=run_manager.get_sync() if run_manager else None,
**kwargs,
)
for chunk in result:
yield chunk
@property
def _llm_type(self) -> str:
"""Возвращает тег пользовательской модели"""
return "echoing-chat-model-advanced"
@property
def _identifying_params(self) -> Dict[str, Any]:
"""Возвращает пользовательскую отладочную информацию"""
return {"n": self.n}
Тестирование пользовательской модели чата
Давайте протестируем модель чата, включая использование методов invoke
, batch
, stream
и асинхронную реализацию потока.
model = CustomChatModelAdvanced(n=3)
model.invoke([HumanMessage(content="hello!")])
model.invoke("hello")
model.batch(["hello", "goodbye"])
for chunk in model.stream("cat"):
print(chunk.content, end="|")
async for chunk in model.astream("cat"):
print(chunk.content, end="|")
async for event in model.astream_events("cat", version="v1"):
print(event)