การปรับแต่ง LLM

ในด้านโดเมนของโมเดล AI ปัจจุบัน มีหลากหลายของโมเดล และการผสานทางทางการเป็นทางการของ LangChain ไม่ครอบคลุมโมเดลทั้งหมด บางครั้งคุณอาจต้องการปรับแต่งโมเดลและผสานทางทางทางการของคุณเข้ากับกรอบงาน LangChain

บทนี้จะแนะนำวิธีการสร้างคลุม LLM ที่ปรับแต่ง ทำให้คุณสามารถใช้โมเดลของคุณเองหรือโมเดลที่ไม่ได้รับการสนับสนุนจาก LangChain ได้อย่างสะดวก

ใน LangChain หากคุณต้องการใช้ LLM ของคุณเองหรือคลุมที่แตกต่างจากคลุมที่ได้รับการสนับสนุนจาก LangChain คุณสามารถสร้างคลุม LLM ที่ปรับแต่ง คลุม 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 kwargs are not permitted.")
        return prompt[: self.n]

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        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
Params: {'n': 10}

การปรับแต่งโมเดลแชท

ที่นี่เราจะอธิบายวิธีการปรับแต่งโมเดลแชทของ LangChain

ข้อมูลเข้าและข้อมูลออกของข้อความ

ในโมเดลแชท ข้อความคือศูนย์ในข้อมูลเข้าและข้อมูลออก ข้อความคือเนื้อหาที่ผู้ใช้ป้อนเข้าและการตอบสนองที่สร้างขึ้นโดยโมเดล

ข้อความ

โมเดลแชทรับข้อความเป็นข้อมูลเข้าและจากนั้นสร้างข้อความหรือมากกว่าหนึ่งข้อความเป็นข้อมูลออก ใน LangChain มีหลายประเภทข้อความที่มีอยู่แบบซึ่งรวมไปถึง

  • SystemMessage: ใช้เริ่มต้นพฤติกรรม AI โดยทั่วไปจะเป็นข้อความแรกในชุดข้อความที่ป้อนเข้า
  • HumanMessage: แสดงสิ่งตอบสนองของผู้ใช้กับโมเดลแชท
  • AIMessage: แทนข้อความจากโมเดลแชท ซึ่งอาจเป็นข้อความหรือคำขอการเรียกใช้เครื่องมือ
  • FunctionMessage / ToolMessage: ใช้ส่งผลลัพธ์ของการเรียกใช้เครื่องมือกลับไปยังโมเดล

การใช้ประเภทข้อความเหล่านี้สามารถขยายและปรับแต่งตามความต้องการเฉพาะ เช่นการปรับตัวตามพารามิเตอร์ function และ tool ของ OpenAI

from langchain_core.messages import (
    AIMessage,
    BaseMessage,
    FunctionMessage,
    HumanMessage,
    SystemMessage,
)

Fluent Variants

ข้อความแชททั้งหมดมีตัวแปรทางชีวิตที่เรียกว่า Chunk ในชื่อของพวกเขา

from langchain_core.messages import (
    AIMessageChunk,
    FunctionMessageChunk,
    HumanMessageChunk,
    SystemMessageChunk,
    ToolMessageChunk,
)

Chunk เหล่านี้ใช้เมื่อสตรีมมิ่งโมเดลแชทและแต่ละตัวกำหนดแอททริบิวต์สะสม

ตัวอย่าง

AIMessageChunk(content="Hello") + AIMessageChunk(content=" world!")

คืนค่า

AIMessageChunk(content='Hello world!')

โมเดลแชทง่าย

การสืบทอดจาก 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):
    """Implement a custom chat model that returns the first `n` characters of the last message."""


    n: int
    """Custom model parameter"""

    def _generate(
        self,
        messages: List[BaseMessage],
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> ChatResult:
        """ที่นี่ ตรรกะการเรียกโมเดลถูกปรับใช้ โดยภาคลอจิกการเรียก API ของโมเดลภายนอกโดยปกติ และจากนั้นห่อผลลัพธ์ที่คืนโดย 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)