ที่หลักของ, หลังเชน เป็นเฟรมเวิร์กนวัตกรรมที่ออกแบบมาเพื่อการสร้างแอปพลิเคชันที่ใช้ประโยชน์จากความสามารถของโมเดลภาษา เป็นชุดเครื่องมือที่ออกแบบมาสำหรับนักพัฒนาเพื่อสร้างแอปพลิเคชันที่รับรู้บริบทและสามารถให้เหตุผลที่ซับซ้อนได้
ซึ่งหมายความว่าแอปพลิเคชัน LangChain สามารถเข้าใจบริบทได้ เช่น คำแนะนำที่รวดเร็วหรือการตอบสนองตามเนื้อหา และใช้โมเดลภาษาสำหรับงานการให้เหตุผลที่ซับซ้อน เช่น การตัดสินใจว่าจะตอบสนองอย่างไรหรือต้องดำเนินการอย่างไร LangChain แสดงให้เห็นถึงแนวทางที่เป็นหนึ่งเดียวในการพัฒนาแอปพลิเคชันอัจฉริยะ ทำให้การเดินทางจากแนวคิดไปสู่การดำเนินการง่ายขึ้นด้วยส่วนประกอบที่หลากหลาย
ทำความเข้าใจกับ LangChain
LangChain เป็นมากกว่าแค่กรอบงาน มันเป็นระบบนิเวศที่ครบถ้วนสมบูรณ์ซึ่งประกอบไปด้วยส่วนสำคัญหลายส่วน
- ประการแรก มี LangChain Libraries ให้เลือกใช้งานทั้งแบบ Python และ JavaScript ไลบรารีเหล่านี้เป็นแกนหลักของ LangChain ที่นำเสนออินเทอร์เฟซและการบูรณาการสำหรับส่วนประกอบต่างๆ โดยจัดเตรียมรันไทม์พื้นฐานสำหรับการรวมส่วนประกอบเหล่านี้เข้ากับเชนและเอเจนต์ที่เชื่อมโยงกัน พร้อมด้วยการใช้งานที่พร้อมใช้งานทันที
- ต่อไป เรามีเทมเพลต LangChain เหล่านี้เป็นชุดของสถาปัตยกรรมอ้างอิงที่ปรับใช้ได้ซึ่งปรับแต่งมาสำหรับงานที่หลากหลาย ไม่ว่าคุณกำลังสร้างแชทบอทหรือเครื่องมือวิเคราะห์ที่ซับซ้อน เทมเพลตเหล่านี้ก็เป็นจุดเริ่มต้นที่ชัดเจน
- LangServe ก้าวเข้ามาเป็นไลบรารีอเนกประสงค์สำหรับการปรับใช้โซ่ LangChain เป็น REST API เครื่องมือนี้จำเป็นสำหรับการเปลี่ยนโปรเจ็กต์ LangChain ของคุณให้เป็นบริการเว็บที่เข้าถึงได้และปรับขนาดได้
- สุดท้ายนี้ LangSmith ทำหน้าที่เป็นแพลตฟอร์มสำหรับนักพัฒนา ได้รับการออกแบบมาเพื่อแก้ไขจุดบกพร่อง ทดสอบ ประเมิน และติดตามเชนที่สร้างขึ้นบนเฟรมเวิร์ก LLM ใดๆ การผสานรวมอย่างราบรื่นกับ LangChain ทำให้เป็นเครื่องมือที่ขาดไม่ได้สำหรับนักพัฒนาที่ต้องการปรับแต่งและทำให้แอปพลิเคชันของตนสมบูรณ์แบบ
ส่วนประกอบเหล่านี้ร่วมกันช่วยให้คุณพัฒนา ผลิต และปรับใช้แอปพลิเคชันได้อย่างง่ายดาย ด้วย LangChain คุณจะเริ่มต้นด้วยการเขียนแอปพลิเคชันของคุณโดยใช้ไลบรารี โดยอ้างอิงเทมเพลตเพื่อเป็นแนวทาง จากนั้น LangSmith จะช่วยคุณในการตรวจสอบ ทดสอบ และติดตามห่วงโซ่ของคุณ เพื่อให้มั่นใจว่าแอปพลิเคชันของคุณได้รับการปรับปรุงอย่างต่อเนื่องและพร้อมสำหรับการใช้งาน สุดท้ายนี้ ด้วย LangServe คุณสามารถเปลี่ยนเชนใดๆ ให้เป็น API ได้อย่างง่ายดาย ทำให้การปรับใช้เป็นเรื่องง่าย
ในส่วนถัดไป เราจะเจาะลึกลงไปถึงวิธีการตั้งค่า LangChain และเริ่มต้นการเดินทางของคุณในการสร้างแอปพลิเคชันอัจฉริยะที่ขับเคลื่อนด้วยโมเดลภาษา
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
การติดตั้งและการตั้งค่า
คุณพร้อมที่จะดำดิ่งสู่โลกของ LangChain แล้วหรือยัง? การตั้งค่านั้นตรงไปตรงมา และคู่มือนี้จะแนะนำคุณตลอดกระบวนการทีละขั้นตอน
ขั้นตอนแรกในการเดินทาง LangChain ของคุณคือการติดตั้ง คุณสามารถทำได้ง่ายๆ โดยใช้ pip หรือ conda รันคำสั่งต่อไปนี้ในเทอร์มินัลของคุณ:
pip install langchain
สำหรับผู้ที่ชื่นชอบฟีเจอร์ใหม่ล่าสุดและสบายใจกับการผจญภัยอีกเล็กน้อย คุณสามารถติดตั้ง LangChain ได้โดยตรงจากแหล่งที่มา โคลนพื้นที่เก็บข้อมูลและไปที่ langchain/libs/langchain
ไดเรกทอรี จากนั้นให้รัน:
pip install -e .
สำหรับคุณลักษณะทดลอง ให้พิจารณาติดตั้ง langchain-experimental
. เป็นแพ็คเกจที่มีโค้ดล้ำสมัยและมีไว้สำหรับการวิจัยและการทดลอง ติดตั้งโดยใช้:
pip install langchain-experimental
LangChain CLI เป็นเครื่องมือที่มีประโยชน์สำหรับการทำงานกับเทมเพลต LangChain และโปรเจ็กต์ LangServe หากต้องการติดตั้ง LangChain CLI ให้ใช้:
pip install langchain-cli
LangServe เป็นสิ่งจำเป็นสำหรับการปรับใช้โซ่ LangChain ของคุณเป็น REST API มันถูกติดตั้งควบคู่ไปกับ LangChain CLI
LangChain มักต้องการการผสานรวมกับผู้ให้บริการโมเดล พื้นที่เก็บข้อมูล API ฯลฯ สำหรับตัวอย่างนี้ เราจะใช้ Model API ของ OpenAI ติดตั้งแพ็คเกจ OpenAI Python โดยใช้:
pip install openai
หากต้องการเข้าถึง API ให้ตั้งค่าคีย์ OpenAI API ของคุณเป็นตัวแปรสภาพแวดล้อม:
export OPENAI_API_KEY="your_api_key"
หรือส่งรหัสโดยตรงในสภาพแวดล้อมหลามของคุณ:
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain ช่วยให้สามารถสร้างแอปพลิเคชันโมเดลภาษาผ่านโมดูลได้ โมดูลเหล่านี้สามารถแยกเดี่ยวหรือประกอบขึ้นสำหรับกรณีการใช้งานที่ซับซ้อน โมดูลเหล่านี้คือ -
- รุ่น I/O: อำนวยความสะดวกในการโต้ตอบกับโมเดลภาษาต่างๆ จัดการอินพุตและเอาท์พุตได้อย่างมีประสิทธิภาพ
- การแก้ไข: ช่วยให้สามารถเข้าถึงและโต้ตอบกับข้อมูลเฉพาะแอปพลิเคชัน ซึ่งมีความสำคัญอย่างยิ่งต่อการใช้ข้อมูลแบบไดนามิก
- ตัวแทน: ส่งเสริมให้แอปพลิเคชันเลือกเครื่องมือที่เหมาะสมตามคำสั่งระดับสูง ช่วยเพิ่มความสามารถในการตัดสินใจ
- โซ่: เสนอองค์ประกอบที่กำหนดไว้ล่วงหน้าและนำกลับมาใช้ใหม่ได้ ซึ่งทำหน้าที่เป็นองค์ประกอบหลักสำหรับการพัฒนาแอปพลิเคชัน
- หน่วยความจำ: รักษาสถานะของแอปพลิเคชันในการดำเนินการหลายลูกโซ่ ซึ่งจำเป็นสำหรับการโต้ตอบแบบคำนึงถึงบริบท
แต่ละโมดูลกำหนดเป้าหมายความต้องการการพัฒนาที่เฉพาะเจาะจง ทำให้ LangChain เป็นชุดเครื่องมือที่ครอบคลุมสำหรับการสร้างแอปพลิเคชันโมเดลภาษาขั้นสูง
นอกจากส่วนประกอบข้างต้นแล้วเรายังมี ภาษานิพจน์ LangChain (LCEL)ซึ่งเป็นวิธีการประกาศในการรวบรวมโมดูลเข้าด้วยกันได้อย่างง่ายดาย และช่วยให้สามารถเชื่อมโยงส่วนประกอบต่างๆ โดยใช้อินเทอร์เฟซ Runnable สากล
LCE มีลักษณะเช่นนี้ –
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
หลังจากที่เราได้กล่าวถึงพื้นฐานแล้ว เราจะดำเนินการต่อในเรื่อง:
- เจาะลึกลงไปในรายละเอียดแต่ละโมดูลของ Langchain
- เรียนรู้วิธีใช้ภาษานิพจน์ LangChain
- สำรวจกรณีการใช้งานทั่วไปและนำไปปฏิบัติ
- ปรับใช้แอปพลิเคชันแบบ end-to-end ด้วย LangServe
- ตรวจสอบ LangSmith สำหรับการดีบัก การทดสอบ และการตรวจสอบ
มาเริ่มกันเลย!
โมดูล XNUMX : รุ่น I/O
ใน LangChain องค์ประกอบหลักของแอปพลิเคชันใดๆ ก็ตามจะเกี่ยวข้องกับโมเดลภาษา โมดูลนี้มีองค์ประกอบที่จำเป็นในการเชื่อมต่อกับโมเดลภาษาใดๆ ได้อย่างมีประสิทธิภาพ ช่วยให้มั่นใจได้ถึงการบูรณาการและการสื่อสารที่ราบรื่น
ส่วนประกอบสำคัญของโมเดล I/O
- LLM และโมเดลการแชท (ใช้แทนกันได้):
- LLM:
- คำนิยาม: โมเดลการเติมข้อความให้สมบูรณ์
- Input / Output: นำสตริงข้อความเป็นอินพุตและส่งกลับสตริงข้อความเป็นเอาต์พุต
- โมเดลการแชท
- LLM:
- คำนิยาม: โมเดลที่ใช้โมเดลภาษาเป็นฐานแต่แตกต่างกันในรูปแบบอินพุตและเอาต์พุต
- Input / Output: ยอมรับรายการข้อความแชทเป็นอินพุตและส่งกลับข้อความแชท
- แจ้ง: สร้างเทมเพลต เลือกแบบไดนามิก และจัดการอินพุตโมเดล ช่วยให้สามารถสร้างพรอมต์ที่ยืดหยุ่นและเฉพาะบริบทเพื่อเป็นแนวทางในการตอบสนองของโมเดลภาษา
- ตัวแยกวิเคราะห์เอาต์พุต: แยกและจัดรูปแบบข้อมูลจากเอาต์พุตของโมเดล มีประโยชน์สำหรับการแปลงเอาต์พุตดิบของโมเดลภาษาเป็นข้อมูลที่มีโครงสร้างหรือรูปแบบเฉพาะที่แอปพลิเคชันต้องการ
ปริญญามหาบัณฑิต
การบูรณาการของ LangChain กับ Large Language Models (LLM) เช่น OpenAI, Cohere และ Hugging Face ถือเป็นลักษณะพื้นฐานของฟังก์ชันการทำงาน LangChain เองไม่ได้โฮสต์ LLM แต่มีอินเทอร์เฟซที่เหมือนกันเพื่อโต้ตอบกับ LLM ต่างๆ
ส่วนนี้ให้ภาพรวมของการใช้ wrapper OpenAI LLM ใน LangChain ซึ่งใช้ได้กับ LLM ประเภทอื่นๆ เช่นกัน เราได้ติดตั้งสิ่งนี้ไว้แล้วในส่วน "การเริ่มต้น" ให้เราเริ่มต้น LLM
from langchain.llms import OpenAI
llm = OpenAI()
- LLMs ดำเนินการ อินเทอร์เฟซที่รันได้ซึ่งเป็นองค์ประกอบพื้นฐานของ ภาษานิพจน์ LangChain (LCEL). ซึ่งหมายความว่าพวกเขาสนับสนุน
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
โทร - LLM ยอมรับ เงื่อนไข เป็นอินพุตหรืออ็อบเจ็กต์ที่สามารถบังคับให้สตริงพร้อมท์ได้รวมไปถึง
List[BaseMessage]
และPromptValue
. (เพิ่มเติมเกี่ยวกับสิ่งเหล่านี้ในภายหลัง)
ให้เราดูตัวอย่างบางส่วน
response = llm.invoke("List the seven wonders of the world.")
print(response)
คุณสามารถเรียกวิธีการสตรีมเพื่อสตรีมการตอบกลับข้อความได้
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
โมเดลการแชท
การบูรณาการของ LangChain กับโมเดลการแชท ซึ่งเป็นรูปแบบเฉพาะของโมเดลภาษา เป็นสิ่งจำเป็นสำหรับการสร้างแอปพลิเคชันแชทเชิงโต้ตอบ แม้ว่าจะใช้โมเดลภาษาภายใน โมเดลการแชทจะมีอินเทอร์เฟซที่แตกต่างกันซึ่งมีศูนย์กลางอยู่ที่ข้อความแชทเป็นอินพุตและเอาต์พุต ส่วนนี้ให้ภาพรวมโดยละเอียดเกี่ยวกับการใช้โมเดลการแชทของ OpenAI ใน LangChain
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
โมเดลการแชทใน LangChain ทำงานร่วมกับข้อความประเภทต่างๆ เช่น AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
และ ChatMessage
(พร้อมพารามิเตอร์บทบาทที่กำหนดเอง) โดยทั่วไป, HumanMessage
, AIMessage
และ SystemMessage
มีการใช้บ่อยที่สุด
โมเดลการแชทยอมรับเป็นหลัก List[BaseMessage]
เป็นอินพุต สตริงสามารถแปลงเป็น HumanMessage
และ PromptValue
ยังได้รับการสนับสนุน
from langchain.schema.messages import HumanMessage, SystemMessage
messages = [ SystemMessage(content="You are Micheal Jordan."), HumanMessage(content="Which shoe manufacturer are you associated with?"),
]
response = chat.invoke(messages)
print(response.content)
แจ้ง
ข้อความแจ้งถือเป็นสิ่งสำคัญในการกำหนดโมเดลภาษาเพื่อสร้างผลลัพธ์ที่เกี่ยวข้องและสอดคล้องกัน อาจมีตั้งแต่คำแนะนำง่ายๆ ไปจนถึงตัวอย่างสั้นๆ ที่ซับซ้อน ใน LangChain การจัดการ prompt อาจเป็นกระบวนการที่มีประสิทธิภาพมาก เนื่องจากมีคลาสและฟังก์ชันเฉพาะมากมาย
ของแลงเชน PromptTemplate
class เป็นเครื่องมืออเนกประสงค์สำหรับการสร้างพรอมต์สตริง มันใช้ของ Python str.format
ไวยากรณ์ที่ช่วยให้สามารถสร้างพรอมต์ไดนามิก คุณสามารถกำหนดเทมเพลตด้วยตัวยึดตำแหน่งและกรอกค่าเฉพาะตามต้องการ
from langchain.prompts import PromptTemplate # Simple prompt with placeholders
prompt_template = PromptTemplate.from_template( "Tell me a {adjective} joke about {content}."
) # Filling placeholders to create a prompt
filled_prompt = prompt_template.format(adjective="funny", content="robots")
print(filled_prompt)
สำหรับโมเดลการแชท ข้อความแจ้งจะมีโครงสร้างมากขึ้น โดยเกี่ยวข้องกับข้อความที่มีบทบาทเฉพาะ ข้อเสนอของ LangChain ChatPromptTemplate
เพื่อจุดประสงค์นี้.
from langchain.prompts import ChatPromptTemplate # Defining a chat prompt with various roles
chat_template = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful AI bot. Your name is {name}."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!"), ("human", "{user_input}"), ]
) # Formatting the chat prompt
formatted_messages = chat_template.format_messages(name="Bob", user_input="What is your name?")
for message in formatted_messages: print(message)
วิธีการนี้ช่วยให้สามารถสร้างแชทบอทเชิงโต้ตอบและมีส่วนร่วมพร้อมการตอบสนองแบบไดนามิก
ทั้งสอง PromptTemplate
และ ChatPromptTemplate
ผสานรวมเข้ากับ LangChain Expression Language (LCEL) ได้อย่างราบรื่น ทำให้สามารถเป็นส่วนหนึ่งของเวิร์กโฟลว์ที่ใหญ่และซับซ้อนได้ เราจะหารือเพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง
เทมเพลตพรอมต์แบบกำหนดเองบางครั้งจำเป็นสำหรับงานที่ต้องการการจัดรูปแบบเฉพาะหรือคำแนะนำเฉพาะ การสร้างเทมเพลตพรอมต์แบบกำหนดเองเกี่ยวข้องกับการกำหนดตัวแปรอินพุตและวิธีการจัดรูปแบบแบบกำหนดเอง ความยืดหยุ่นนี้ทำให้ LangChain สามารถตอบสนองความต้องการเฉพาะแอปพลิเคชันได้หลากหลาย อ่านเพิ่มเติมได้ที่นี่
LangChain ยังรองรับการแจ้งแบบไม่กี่ช็อต ทำให้โมเดลสามารถเรียนรู้จากตัวอย่างได้ คุณลักษณะนี้มีความสำคัญสำหรับงานที่ต้องใช้ความเข้าใจตามบริบทหรือรูปแบบเฉพาะ เทมเพลตพรอมต์ไม่กี่ช็อตสามารถสร้างขึ้นจากชุดตัวอย่างหรือโดยใช้ออบเจ็กต์ตัวเลือกตัวอย่าง อ่านเพิ่มเติมได้ที่นี่
ตัวแยกวิเคราะห์เอาต์พุต
ตัวแยกวิเคราะห์เอาต์พุตมีบทบาทสำคัญใน Langchain ทำให้ผู้ใช้สามารถจัดโครงสร้างการตอบสนองที่สร้างโดยโมเดลภาษา ในส่วนนี้ เราจะสำรวจแนวคิดของเอาท์พุตพาร์เซอร์ และจัดเตรียมตัวอย่างโค้ดโดยใช้ PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser และ XMLOutputParser ของ Langchain
PydanticOutputParser
Langchain จัดเตรียม PydanticOutputParser สำหรับการแยกวิเคราะห์การตอบสนองในโครงสร้างข้อมูล Pydantic ด้านล่างนี้เป็นตัวอย่างวิธีใช้งานทีละขั้นตอน:
from typing import List
from langchain.llms import OpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain.pydantic_v1 import BaseModel, Field, validator # Initialize the language model
model = OpenAI(model_name="text-davinci-003", temperature=0.0) # Define your desired data structure using Pydantic
class Joke(BaseModel): setup: str = Field(description="question to set up a joke") punchline: str = Field(description="answer to resolve the joke") @validator("setup") def question_ends_with_question_mark(cls, field): if field[-1] != "?": raise ValueError("Badly formed question!") return field # Set up a PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Joke) # Create a prompt with format instructions
prompt = PromptTemplate( template="Answer the user query.n{format_instructions}n{query}n", input_variables=["query"], partial_variables={"format_instructions": parser.get_format_instructions()},
) # Define a query to prompt the language model
query = "Tell me a joke." # Combine prompt, model, and parser to get structured output
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": query}) # Parse the output using the parser
parsed_result = parser.invoke(output) # The result is a structured object
print(parsed_result)
การส่งออกจะได้รับ:
SimpleJsonOutputParser
SimpleJsonOutputParser ของ Langchain จะใช้เมื่อคุณต้องการแยกวิเคราะห์เอาต์พุตที่คล้ายกับ JSON นี่คือตัวอย่าง:
from langchain.output_parsers.json import SimpleJsonOutputParser # Create a JSON prompt
json_prompt = PromptTemplate.from_template( "Return a JSON object with `birthdate` and `birthplace` key that answers the following question: {question}"
) # Initialize the JSON parser
json_parser = SimpleJsonOutputParser() # Create a chain with the prompt, model, and parser
json_chain = json_prompt | model | json_parser # Stream through the results
result_list = list(json_chain.stream({"question": "When and where was Elon Musk born?"})) # The result is a list of JSON-like dictionaries
print(result_list)
CommaSeparatedListOutputParser
CommaSeparatedListOutputParser มีประโยชน์เมื่อคุณต้องการแยกรายการที่คั่นด้วยเครื่องหมายจุลภาคจากการตอบกลับของโมเดล นี่คือตัวอย่าง:
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI # Initialize the parser
output_parser = CommaSeparatedListOutputParser() # Create format instructions
format_instructions = output_parser.get_format_instructions() # Create a prompt to request a list
prompt = PromptTemplate( template="List five {subject}.n{format_instructions}", input_variables=["subject"], partial_variables={"format_instructions": format_instructions}
) # Define a query to prompt the model
query = "English Premier League Teams" # Generate the output
output = model(prompt.format(subject=query)) # Parse the output using the parser
parsed_result = output_parser.parse(output) # The result is a list of items
print(parsed_result)
DatetimeOutputParser
DatetimeOutputParser ของ Langchain ได้รับการออกแบบมาเพื่อแยกวิเคราะห์ข้อมูลวันที่และเวลา นี่คือวิธีการใช้งาน:
from langchain.prompts import PromptTemplate
from langchain.output_parsers import DatetimeOutputParser
from langchain.chains import LLMChain
from langchain.llms import OpenAI # Initialize the DatetimeOutputParser
output_parser = DatetimeOutputParser() # Create a prompt with format instructions
template = """
Answer the user's question:
{question}
{format_instructions} """ prompt = PromptTemplate.from_template( template, partial_variables={"format_instructions": output_parser.get_format_instructions()},
) # Create a chain with the prompt and language model
chain = LLMChain(prompt=prompt, llm=OpenAI()) # Define a query to prompt the model
query = "when did Neil Armstrong land on the moon in terms of GMT?" # Run the chain
output = chain.run(query) # Parse the output using the datetime parser
parsed_result = output_parser.parse(output) # The result is a datetime object
print(parsed_result)
ตัวอย่างเหล่านี้แสดงให้เห็นว่าเอาท์พุตพาร์เซอร์ของ Langchain สามารถใช้จัดโครงสร้างการตอบสนองของโมเดลประเภทต่างๆ ได้อย่างไร ทำให้เหมาะสมกับแอปพลิเคชันและรูปแบบที่แตกต่างกัน ตัวแยกวิเคราะห์เอาต์พุตเป็นเครื่องมือที่มีค่าสำหรับการปรับปรุงการใช้งานและการตีความของเอาต์พุตโมเดลภาษาใน Langchain
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
โมดูล II: การดึงข้อมูล
การดึงข้อมูลใน LangChain มีบทบาทสำคัญในแอปพลิเคชันที่ต้องการข้อมูลเฉพาะของผู้ใช้ ซึ่งไม่รวมอยู่ในชุดการฝึกอบรมของโมเดล กระบวนการนี้เรียกว่าการดึงข้อมูล Augmented Generation (RAG) เกี่ยวข้องกับการดึงข้อมูลภายนอกและรวมเข้ากับกระบวนการสร้างของแบบจำลองภาษา LangChain มอบชุดเครื่องมือและฟังก์ชันการทำงานที่ครอบคลุมเพื่ออำนวยความสะดวกในกระบวนการนี้ เพื่อรองรับการใช้งานทั้งแบบเรียบง่ายและซับซ้อน
LangChain บรรลุผลสำเร็จในการดึงข้อมูลผ่านชุดส่วนประกอบต่างๆ ซึ่งเราจะพูดคุยกันทีละรายการ
รถตักเอกสาร
ตัวโหลดเอกสารใน LangChain ช่วยให้สามารถดึงข้อมูลจากแหล่งต่างๆ ได้ ด้วยตัวโหลดมากกว่า 100 ตัว รองรับประเภทเอกสาร แอพ และแหล่งที่มาที่หลากหลาย (บัคเก็ต s3 ส่วนตัว เว็บไซต์สาธารณะ ฐานข้อมูล)
คุณสามารถเลือกตัวโหลดเอกสารได้ตามความต้องการของคุณ โปรดคลิกที่นี่เพื่ออ่านรายละเอียดเพิ่มเติม.
ตัวโหลดทั้งหมดนี้นำเข้าข้อมูลเข้าไป เอกสาร ชั้นเรียน เราจะเรียนรู้วิธีใช้ข้อมูลที่นำเข้าลงในคลาสเอกสารในภายหลัง
ตัวโหลดไฟล์ข้อความ: โหลดง่ายๆ .txt
ลงในเอกสาร
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
ตัวโหลด CSV: โหลดไฟล์ CSV ลงในเอกสาร
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
เราสามารถเลือกปรับแต่งการแยกวิเคราะห์ได้โดยระบุชื่อฟิลด์ –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
ตัวโหลด PDF: PDF Loaders ใน LangChain นำเสนอวิธีการที่หลากหลายในการแยกวิเคราะห์และแยกเนื้อหาออกจากไฟล์ PDF ตัวโหลดแต่ละตัวรองรับความต้องการที่แตกต่างกันและใช้ไลบรารีพื้นฐานที่แตกต่างกัน ด้านล่างนี้เป็นตัวอย่างโดยละเอียดสำหรับตัวโหลดแต่ละตัว
PyPDFLoader ใช้สำหรับการแยกวิเคราะห์ PDF ขั้นพื้นฐาน
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader เหมาะอย่างยิ่งสำหรับการแยกเนื้อหาและไดอะแกรมทางคณิตศาสตร์
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader ทำงานรวดเร็วและรวมถึงการแยกข้อมูลเมตาโดยละเอียด
from langchain.document_loaders import PyMuPDFLoader loader = PyMuPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load() # Optionally pass additional arguments for PyMuPDF's get_text() call
data = loader.load(option="text")
PDFMiner Loader ใช้สำหรับการควบคุมการแยกข้อความที่ละเอียดยิ่งขึ้น
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTextractPDFParser ใช้ AWS Textract สำหรับ OCR และคุณสมบัติการแยกวิเคราะห์ PDF ขั้นสูงอื่นๆ
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader สร้าง HTML จาก PDF สำหรับการแยกวิเคราะห์ความหมาย
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader ให้ข้อมูลเมตาโดยละเอียดและรองรับหนึ่งเอกสารต่อหน้า
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
รถตักรวม: LangChain นำเสนอตัวโหลดแบบกำหนดเองที่หลากหลายเพื่อโหลดข้อมูลจากแอปของคุณโดยตรง (เช่น Slack, Sigma, Notion, Confluence, Google Drive และอื่นๆ อีกมากมาย) และฐานข้อมูล และใช้ในแอปพลิเคชัน LLM
รายการทั้งหมดคือ โปรดคลิกที่นี่เพื่ออ่านรายละเอียดเพิ่มเติม.
ด้านล่างนี้เป็นตัวอย่างบางส่วนที่แสดงให้เห็นสิ่งนี้ –
ตัวอย่างที่ XNUMX – Slack
Slack ซึ่งเป็นแพลตฟอร์มการส่งข้อความโต้ตอบแบบทันทีที่ใช้กันอย่างแพร่หลาย สามารถรวมเข้ากับเวิร์กโฟลว์และแอปพลิเคชัน LLM ได้
- ไปที่หน้าการจัดการพื้นที่ทำงาน Slack ของคุณ
- นำทางไปยัง
{your_slack_domain}.slack.com/services/export
. - เลือกช่วงวันที่ที่ต้องการและเริ่มการส่งออก
- Slack จะแจ้งเตือนทางอีเมลและ DM เมื่อการส่งออกพร้อม
- การส่งออกส่งผลให้ก
.zip
ไฟล์ที่อยู่ในโฟลเดอร์ดาวน์โหลดของคุณหรือเส้นทางการดาวน์โหลดที่คุณกำหนด - กำหนดเส้นทางของการดาวน์โหลด
.zip
ไฟล์ไปที่LOCAL_ZIPFILE
. - ใช้
SlackDirectoryLoader
จากlangchain.document_loaders
บรรจุภัณฑ์
from langchain.document_loaders import SlackDirectoryLoader SLACK_WORKSPACE_URL = "https://xxx.slack.com" # Replace with your Slack URL
LOCAL_ZIPFILE = "" # Path to the Slack zip file loader = SlackDirectoryLoader(LOCAL_ZIPFILE, SLACK_WORKSPACE_URL)
docs = loader.load()
print(docs)
ตัวอย่างที่ XNUMX – รูปที่
Figma ซึ่งเป็นเครื่องมือยอดนิยมสำหรับการออกแบบอินเทอร์เฟซ นำเสนอ REST API สำหรับการรวมข้อมูล
- รับคีย์ไฟล์ Figma จากรูปแบบ URL:
https://www.figma.com/file/{filekey}/sampleFilename
. - พบรหัสโหนดในพารามิเตอร์ URL
?node-id={node_id}
. - สร้างโทเค็นการเข้าถึงตามคำแนะนำที่ ศูนย์ช่วยเหลือฟิกม่า.
- พื้นที่
FigmaFileLoader
ชั้นเรียนจากlangchain.document_loaders.figma
ใช้ในการโหลดข้อมูล Figma - โมดูล LangChain ต่างๆ เช่น
CharacterTextSplitter
,ChatOpenAI
ฯลฯ ใช้สำหรับการประมวลผล
import os
from langchain.document_loaders.figma import FigmaFileLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.chat_models import ChatOpenAI
from langchain.indexes import VectorstoreIndexCreator
from langchain.chains import ConversationChain, LLMChain
from langchain.memory import ConversationBufferWindowMemory
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate figma_loader = FigmaFileLoader( os.environ.get("ACCESS_TOKEN"), os.environ.get("NODE_IDS"), os.environ.get("FILE_KEY"),
) index = VectorstoreIndexCreator().from_loaders([figma_loader])
figma_doc_retriever = index.vectorstore.as_retriever()
- พื้นที่
generate_code
ฟังก์ชั่นใช้ข้อมูล Figma เพื่อสร้างโค้ด HTML/CSS - ใช้การสนทนาแบบเทมเพลตกับโมเดลที่ใช้ GPT
def generate_code(human_input): # Template for system and human prompts system_prompt_template = "Your coding instructions..." human_prompt_template = "Code the {text}. Ensure it's mobile responsive" # Creating prompt templates system_message_prompt = SystemMessagePromptTemplate.from_template(system_prompt_template) human_message_prompt = HumanMessagePromptTemplate.from_template(human_prompt_template) # Setting up the AI model gpt_4 = ChatOpenAI(temperature=0.02, model_name="gpt-4") # Retrieving relevant documents relevant_nodes = figma_doc_retriever.get_relevant_documents(human_input) # Generating and formatting the prompt conversation = [system_message_prompt, human_message_prompt] chat_prompt = ChatPromptTemplate.from_messages(conversation) response = gpt_4(chat_prompt.format_prompt(context=relevant_nodes, text=human_input).to_messages()) return response # Example usage
response = generate_code("page top header")
print(response.content)
- พื้นที่
generate_code
เมื่อดำเนินการแล้ว ฟังก์ชันจะส่งคืนโค้ด HTML/CSS ตามอินพุตการออกแบบ Figma
ตอนนี้ให้เราใช้ความรู้ของเราเพื่อสร้างชุดเอกสารสองสามชุด
ก่อนอื่นเราจะโหลด PDF ซึ่งเป็นรายงานความยั่งยืนประจำปีของ BCG
เราใช้ PyPDFLoader สำหรับสิ่งนี้
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
เราจะนำเข้าข้อมูลจาก Airtable ทันที เรามี Airtable ที่มีข้อมูลเกี่ยวกับ OCR และโมเดลการแยกข้อมูลต่างๆ -
ให้เราใช้ AirtableLoader สำหรับสิ่งนี้ ซึ่งพบได้ในรายการตัวโหลดแบบรวม
from langchain.document_loaders import AirtableLoader api_key = "XXXXX"
base_id = "XXXXX"
table_id = "XXXXX" loader = AirtableLoader(api_key, table_id, base_id)
airtabledocs = loader.load()
ให้เราดำเนินการต่อและเรียนรู้วิธีใช้คลาสเอกสารเหล่านี้
เอกสารหม้อแปลง
ตัวแปลงเอกสารใน LangChain เป็นเครื่องมือสำคัญที่ออกแบบมาเพื่อจัดการเอกสาร ซึ่งเราสร้างขึ้นในส่วนย่อยก่อนหน้านี้
ใช้สำหรับงานต่างๆ เช่น การแยกเอกสารขนาดยาวออกเป็นส่วนเล็กๆ การรวม และการกรอง ซึ่งมีความสำคัญอย่างยิ่งในการปรับเอกสารให้เข้ากับหน้าต่างบริบทของโมเดล หรือตอบสนองความต้องการของแอปพลิเคชันเฉพาะ
เครื่องมือหนึ่งดังกล่าวคือ RecursiveCharacterTextSplitter ซึ่งเป็นตัวแยกข้อความอเนกประสงค์ที่ใช้รายการอักขระสำหรับการแยก อนุญาตให้ใช้พารามิเตอร์ต่างๆ เช่น ขนาดชิ้น การทับซ้อนกัน และดัชนีเริ่มต้น นี่คือตัวอย่างวิธีการใช้ใน Python:
from langchain.text_splitter import RecursiveCharacterTextSplitter state_of_the_union = "Your long text here..." text_splitter = RecursiveCharacterTextSplitter( chunk_size=100, chunk_overlap=20, length_function=len, add_start_index=True,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])
เครื่องมืออีกอย่างหนึ่งคือ CharacterTextSplitter ซึ่งแบ่งข้อความตามอักขระที่ระบุ และมีตัวควบคุมสำหรับขนาดก้อนและการทับซ้อนกัน:
from langchain.text_splitter import CharacterTextSplitter text_splitter = CharacterTextSplitter( separator="nn", chunk_size=1000, chunk_overlap=200, length_function=len, is_separator_regex=False,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
HTMLHeaderTextSplitter ได้รับการออกแบบมาเพื่อแยกเนื้อหา HTML ตามแท็กส่วนหัว โดยคงโครงสร้างความหมายไว้:
from langchain.text_splitter import HTMLHeaderTextSplitter html_string = "Your HTML content here..."
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")] html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text(html_string)
print(html_header_splits[0])
การจัดการที่ซับซ้อนยิ่งขึ้นสามารถทำได้โดยการรวม HTMLHeaderTextSplitter เข้ากับตัวแยกอื่น เช่น Pipelined Splitter:
from langchain.text_splitter import HTMLHeaderTextSplitter, RecursiveCharacterTextSplitter url = "https://example.com"
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")]
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text_from_url(url) chunk_size = 500
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size)
splits = text_splitter.split_documents(html_header_splits)
print(splits[0])
LangChain ยังมีตัวแยกเฉพาะสำหรับภาษาการเขียนโปรแกรมที่แตกต่างกัน เช่น Python Code Splitter และ JavaScript Code Splitter:
from langchain.text_splitter import RecursiveCharacterTextSplitter, Language python_code = """
def hello_world(): print("Hello, World!")
hello_world() """ python_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=50
)
python_docs = python_splitter.create_documents([python_code])
print(python_docs[0]) js_code = """
function helloWorld() { console.log("Hello, World!");
}
helloWorld(); """ js_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.JS, chunk_size=60
)
js_docs = js_splitter.create_documents([js_code])
print(js_docs[0])
สำหรับการแยกข้อความตามจำนวนโทเค็น ซึ่งมีประโยชน์สำหรับโมเดลภาษาที่มีการจำกัดโทเค็น จะใช้ TokenTextSplitter:
from langchain.text_splitter import TokenTextSplitter text_splitter = TokenTextSplitter(chunk_size=10)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
สุดท้ายนี้ LongContextReorder จะจัดลำดับเอกสารใหม่เพื่อป้องกันประสิทธิภาพลดลงในโมเดลเนื่องจากบริบทที่ยาว:
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
เครื่องมือเหล่านี้สาธิตวิธีการต่างๆ ในการแปลงเอกสารใน LangChain ตั้งแต่การแยกข้อความแบบธรรมดาไปจนถึงการเรียงลำดับใหม่ที่ซับซ้อนและการแยกเฉพาะภาษา สำหรับกรณีการใช้งานเชิงลึกและเฉพาะเจาะจงมากขึ้น ควรศึกษาเอกสารประกอบและส่วนบูรณาการของ LangChain
ในตัวอย่างของเรา ตัวโหลดได้สร้างเอกสารแบบก้อนให้เราแล้ว และส่วนนี้ได้รับการจัดการแล้ว
โมเดลการฝังข้อความ
โมเดลการฝังข้อความใน LangChain มอบอินเทอร์เฟซมาตรฐานสำหรับผู้ให้บริการโมเดลการฝังต่างๆ เช่น OpenAI, Cohere และ Hugging Face โมเดลเหล่านี้แปลงข้อความเป็นการแสดงเวกเตอร์ ช่วยให้ดำเนินการต่างๆ เช่น การค้นหาความหมายผ่านความคล้ายคลึงกันของข้อความในพื้นที่เวกเตอร์
หากต้องการเริ่มต้นใช้งานโมเดลการฝังข้อความ โดยทั่วไปคุณจะต้องติดตั้งแพ็กเกจเฉพาะและตั้งค่าคีย์ API เราได้ทำสิ่งนี้แล้วสำหรับ OpenAI
ใน LangChain นั้น embed_documents
วิธีการใช้ในการฝังข้อความหลายรายการ โดยจัดให้มีรายการการแสดงเวกเตอร์ ตัวอย่างเช่น:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a list of texts
embeddings = embeddings_model.embed_documents( ["Hi there!", "Oh, hello!", "What's your name?", "My friends call me World", "Hello World!"]
)
print("Number of documents embedded:", len(embeddings))
print("Dimension of each embedding:", len(embeddings[0]))
สำหรับการฝังข้อความเดียว เช่น คำค้นหา embed_query
ใช้วิธีการ สิ่งนี้มีประโยชน์สำหรับการเปรียบเทียบแบบสอบถามกับชุดของการฝังเอกสาร ตัวอย่างเช่น:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a single query
embedded_query = embeddings_model.embed_query("What was the name mentioned in the conversation?")
print("First five dimensions of the embedded query:", embedded_query[:5])
การทำความเข้าใจการฝังเหล่านี้เป็นสิ่งสำคัญ ข้อความแต่ละชิ้นจะถูกแปลงเป็นเวกเตอร์ ซึ่งขนาดจะขึ้นอยู่กับรุ่นที่ใช้ ตัวอย่างเช่น โมเดล OpenAI โดยทั่วไปจะสร้างเวกเตอร์ขนาด 1536 มิติ การฝังเหล่านี้จะใช้เพื่อดึงข้อมูลที่เกี่ยวข้อง
ฟังก์ชันการฝังของ LangChain ไม่ได้จำกัดอยู่เพียง OpenAI แต่ได้รับการออกแบบมาเพื่อทำงานร่วมกับผู้ให้บริการที่หลากหลาย การตั้งค่าและการใช้งานอาจแตกต่างกันเล็กน้อยขึ้นอยู่กับผู้ให้บริการ แต่แนวคิดหลักของการฝังข้อความลงในพื้นที่เวกเตอร์ยังคงเหมือนเดิม สำหรับการใช้งานโดยละเอียด รวมถึงการกำหนดค่าขั้นสูงและการผสานรวมกับผู้ให้บริการโมเดลการฝังต่างๆ เอกสารประกอบของ LangChain ในส่วนการรวมระบบถือเป็นทรัพยากรที่มีค่า
ร้านเวกเตอร์
ร้านค้าเวกเตอร์ใน LangChain รองรับการจัดเก็บและการค้นหาการฝังข้อความอย่างมีประสิทธิภาพ LangChain ทำงานร่วมกับร้านค้าเวกเตอร์มากกว่า 50 แห่ง มอบอินเทอร์เฟซที่ได้มาตรฐานเพื่อความสะดวกในการใช้งาน
ตัวอย่าง: การจัดเก็บและการค้นหาการฝัง
หลังจากฝังข้อความแล้ว เราก็สามารถจัดเก็บไว้ในเวคเตอร์สโตร์ได้ Chroma
และทำการค้นหาความคล้ายคลึงกัน:
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
ให้เราใช้ FAISS vector store เพื่อสร้างดัชนีสำหรับเอกสารของเรา
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
รีทรีฟเวอร์
ตัวดึงข้อมูลใน LangChain เป็นอินเทอร์เฟซที่ส่งคืนเอกสารเพื่อตอบสนองต่อแบบสอบถามที่ไม่มีโครงสร้าง มีลักษณะทั่วไปมากกว่าร้านค้าเวกเตอร์ โดยเน้นไปที่การดึงข้อมูลมากกว่าการจัดเก็บ แม้ว่าร้านเวกเตอร์จะสามารถใช้เป็นกระดูกสันหลังของรีทรีฟเวอร์ได้ แต่ก็มีรีทรีฟเวอร์ประเภทอื่นๆ เช่นกัน
หากต้องการตั้งค่า Chroma รีทรีฟเวอร์ คุณต้องติดตั้งโดยใช้ก่อน pip install chromadb
. จากนั้น คุณโหลด แยก ฝัง และเรียกค้นเอกสารโดยใช้ชุดคำสั่ง Python นี่คือตัวอย่างโค้ดสำหรับการตั้งค่า Chroma รีทรีฟเวอร์:
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma full_text = open("state_of_the_union.txt", "r").read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
texts = text_splitter.split_text(full_text) embeddings = OpenAIEmbeddings()
db = Chroma.from_texts(texts, embeddings)
retriever = db.as_retriever() retrieved_docs = retriever.invoke("What did the president say about Ketanji Brown Jackson?")
print(retrieved_docs[0].page_content)
MultiQueryRetriever ปรับพร้อมท์โดยอัตโนมัติโดยการสร้างหลายแบบสอบถามสำหรับแบบสอบถามที่ผู้ใช้ป้อนและรวมผลลัพธ์ นี่คือตัวอย่างการใช้งานที่เรียบง่าย:
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever question = "What are the approaches to Task Decomposition?"
llm = ChatOpenAI(temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm( retriever=db.as_retriever(), llm=llm
) unique_docs = retriever_from_llm.get_relevant_documents(query=question)
print("Number of unique documents:", len(unique_docs))
การบีบอัดตามบริบทใน LangChain บีบอัดเอกสารที่ดึงมาโดยใช้บริบทของการสืบค้น เพื่อให้มั่นใจว่าจะส่งกลับเฉพาะข้อมูลที่เกี่ยวข้องเท่านั้น ซึ่งเกี่ยวข้องกับการลดเนื้อหาและการกรองเอกสารที่เกี่ยวข้องน้อยกว่าออกไป ตัวอย่างโค้ดต่อไปนี้แสดงวิธีการใช้ Contextual Compression Retriever:
from langchain.llms import OpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever) compressed_docs = compression_retriever.get_relevant_documents("What did the president say about Ketanji Jackson Brown")
print(compressed_docs[0].page_content)
EnsembleRetriever รวมอัลกอริธึมการดึงข้อมูลที่แตกต่างกันเพื่อให้ได้ประสิทธิภาพที่ดีขึ้น ตัวอย่างการรวม BM25 และ FAISS Retrievers จะแสดงในโค้ดต่อไปนี้:
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain.vectorstores import FAISS bm25_retriever = BM25Retriever.from_texts(doc_list).set_k(2)
faiss_vectorstore = FAISS.from_texts(doc_list, OpenAIEmbeddings())
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2}) ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
) docs = ensemble_retriever.get_relevant_documents("apples")
print(docs[0].page_content)
MultiVector Retriever ใน LangChain ช่วยให้สามารถสืบค้นเอกสารที่มีเวกเตอร์หลายตัวต่อเอกสาร ซึ่งมีประโยชน์สำหรับการจับลักษณะความหมายที่แตกต่างกันภายในเอกสาร วิธีสร้างเวกเตอร์หลายตัว ได้แก่ การแยกออกเป็นชิ้นเล็กๆ การสรุป หรือการสร้างคำถามเชิงสมมุติ สำหรับการแบ่งเอกสารออกเป็นส่วนเล็กๆ คุณสามารถใช้โค้ด Python ต่อไปนี้:
python
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.storage import InMemoryStore
from langchain.document_loaders from TextLoader
import uuid loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()]
text_splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
docs = text_splitter.split_documents(docs) vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
id_key = "doc_id"
retriever = MultiVectorRetriever(vectorstore=vectorstore, docstore=store, id_key=id_key) doc_ids = [str(uuid.uuid4()) for _ in docs]
child_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
sub_docs = [sub_doc for doc in docs for sub_doc in child_text_splitter.split_documents([doc])]
for sub_doc in sub_docs: sub_doc.metadata[id_key] = doc_ids[sub_docs.index(sub_doc)] retriever.vectorstore.add_documents(sub_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
การสร้างบทสรุปเพื่อการเรียกค้นที่ดีขึ้นเนื่องจากการนำเสนอเนื้อหาที่เน้นมากขึ้นเป็นอีกวิธีหนึ่ง นี่คือตัวอย่างการสร้างสรุป:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.document import Document chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Summarize the following document:nn{doc}") | ChatOpenAI(max_retries=0) | StrOutputParser()
summaries = chain.batch(docs, {"max_concurrency": 5}) summary_docs = [Document(page_content=s, metadata={id_key: doc_ids[i]}) for i, s in enumerate(summaries)]
retriever.vectorstore.add_documents(summary_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
การสร้างคำถามสมมุติที่เกี่ยวข้องกับแต่ละเอกสารโดยใช้ LLM เป็นอีกวิธีหนึ่ง ซึ่งสามารถทำได้ด้วยรหัสต่อไปนี้:
functions = [{"name": "hypothetical_questions", "parameters": {"questions": {"type": "array", "items": {"type": "string"}}}}]
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Generate 3 hypothetical questions:nn{doc}") | ChatOpenAI(max_retries=0).bind(functions=functions, function_call={"name": "hypothetical_questions"}) | JsonKeyOutputFunctionsParser(key_name="questions")
hypothetical_questions = chain.batch(docs, {"max_concurrency": 5}) question_docs = [Document(page_content=q, metadata={id_key: doc_ids[i]}) for i, questions in enumerate(hypothetical_questions) for q in questions]
retriever.vectorstore.add_documents(question_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Parent Document Retriever เป็นอีกหนึ่งรีทรีฟเวอร์ที่สร้างความสมดุลระหว่างความแม่นยำในการฝังและการเก็บรักษาบริบทโดยการจัดเก็บชิ้นส่วนขนาดเล็กและเรียกค้นเอกสารพาเรนต์ที่มีขนาดใหญ่กว่า การนำไปปฏิบัติมีดังนี้:
from langchain.retrievers import ParentDocumentRetriever loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()] child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
retriever = ParentDocumentRetriever(vectorstore=vectorstore, docstore=store, child_splitter=child_splitter) retriever.add_documents(docs, ids=None) retrieved_docs = retriever.get_relevant_documents("query")
ตัวดึงข้อมูลการสืบค้นด้วยตนเองจะสร้างการสืบค้นที่มีโครงสร้างจากอินพุตภาษาธรรมชาติและนำไปใช้กับ VectorStore ที่เป็นรากฐาน การใช้งานจะแสดงอยู่ในรหัสต่อไปนี้:
from langchain.chat_models from ChatOpenAI
from langchain.chains.query_constructor.base from AttributeInfo
from langchain.retrievers.self_query.base from SelfQueryRetriever metadata_field_info = [AttributeInfo(name="genre", description="...", type="string"), ...]
document_content_description = "Brief summary of a movie"
llm = ChatOpenAI(temperature=0) retriever = SelfQueryRetriever.from_llm(llm, vectorstore, document_content_description, metadata_field_info) retrieved_docs = retriever.invoke("query")
WebResearchRetriever ดำเนินการวิจัยเว็บตามคำค้นหาที่กำหนด –
from langchain.retrievers.web_research import WebResearchRetriever # Initialize components
llm = ChatOpenAI(temperature=0)
search = GoogleSearchAPIWrapper()
vectorstore = Chroma(embedding_function=OpenAIEmbeddings()) # Instantiate WebResearchRetriever
web_research_retriever = WebResearchRetriever.from_llm(vectorstore=vectorstore, llm=llm, search=search) # Retrieve documents
docs = web_research_retriever.get_relevant_documents("query")
สำหรับตัวอย่างของเรา เรายังสามารถใช้รีทรีฟเวอร์มาตรฐานที่ใช้งานอยู่แล้วโดยเป็นส่วนหนึ่งของอ็อบเจ็กต์เวกเตอร์สโตร์ของเราดังต่อไปนี้ –
ตอนนี้เราสามารถสอบถามผู้ดึงข้อมูลได้แล้ว ผลลัพธ์ของการสืบค้นของเราจะเป็นออบเจ็กต์เอกสารที่เกี่ยวข้องกับการสืบค้น สิ่งเหล่านี้จะถูกนำไปใช้เพื่อสร้างคำตอบที่เกี่ยวข้องในท้ายที่สุด
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
โมดูลที่ XNUMX : ตัวแทน
LangChain นำเสนอแนวคิดอันทรงพลังที่เรียกว่า "ตัวแทน" ซึ่งนำแนวคิดเรื่อง chain ไปสู่อีกระดับหนึ่ง เจ้าหน้าที่ใช้ประโยชน์จากโมเดลภาษาเพื่อกำหนดลำดับการดำเนินการแบบไดนามิก ทำให้มีความหลากหลายและปรับเปลี่ยนได้อย่างไม่น่าเชื่อ ต่างจากเครือข่ายแบบเดิมที่การดำเนินการต่างๆ จะถูกฮาร์ดโค้ดในโค้ด เจ้าหน้าที่ใช้แบบจำลองภาษาเป็นเครื่องมือในการให้เหตุผลเพื่อตัดสินใจว่าจะดำเนินการใดและเรียงลำดับอย่างไร
ตัวแทน เป็นองค์ประกอบหลักที่รับผิดชอบในการตัดสินใจ โดยจะควบคุมพลังของแบบจำลองภาษาและการแจ้งเตือนเพื่อกำหนดขั้นตอนถัดไปเพื่อให้บรรลุวัตถุประสงค์เฉพาะ ข้อมูลนำเข้าไปยังตัวแทนโดยทั่วไปจะรวมถึง:
- เครื่องมือ: คำอธิบายของเครื่องมือที่มีอยู่ (เพิ่มเติมในภายหลัง)
- อินพุตของผู้ใช้: วัตถุประสงค์ระดับสูงหรือแบบสอบถามจากผู้ใช้
- ขั้นตอนกลาง: ประวัติของคู่ (การกระทำ เอาท์พุตเครื่องมือ) ที่ดำเนินการเพื่อเข้าถึงอินพุตของผู้ใช้ปัจจุบัน
ผลลัพธ์ของเอเจนต์อาจเป็นผลลัพธ์ถัดไป การกระทำ เพื่อดำเนินการ (การกระทำของตัวแทน) หรือรอบชิงชนะเลิศ คำตอบ เพื่อส่งให้กับผู้ใช้ (ตัวแทนเสร็จสิ้น) การกระทำ ระบุ a เครื่องมือ และ อินพุต สำหรับเครื่องมือนั้น
เครื่องมือ
เครื่องมือคืออินเทอร์เฟซที่ตัวแทนสามารถใช้เพื่อโต้ตอบกับโลกได้ ช่วยให้ตัวแทนสามารถทำงานต่างๆ ได้ เช่น การค้นหาเว็บ การรันคำสั่งเชลล์ หรือการเข้าถึง API ภายนอก ใน LangChain เครื่องมือเป็นสิ่งจำเป็นสำหรับการขยายขีดความสามารถของตัวแทนและช่วยให้พวกเขาสามารถบรรลุงานที่หลากหลายได้
หากต้องการใช้เครื่องมือใน LangChain คุณสามารถโหลดเครื่องมือเหล่านั้นได้โดยใช้ตัวอย่างต่อไปนี้:
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
เครื่องมือบางอย่างอาจต้องใช้ Base Language Model (LLM) เพื่อเริ่มต้น ในกรณีเช่นนี้ คุณสามารถผ่าน LLM ได้เช่นกัน:
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
การตั้งค่านี้ช่วยให้คุณเข้าถึงเครื่องมือที่หลากหลายและรวมเข้ากับขั้นตอนการทำงานของตัวแทนของคุณได้ รายการเครื่องมือทั้งหมดพร้อมเอกสารการใช้งานคือ โปรดคลิกที่นี่เพื่ออ่านรายละเอียดเพิ่มเติม.
ให้เราดูตัวอย่างบางส่วนของเครื่องมือ
DuckDuckGo
เครื่องมือ DuckDuckGo ช่วยให้คุณทำการค้นหาเว็บโดยใช้เครื่องมือค้นหา นี่คือวิธีการใช้งาน:
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
ข้อมูลสำหรับ SEO
ชุดเครื่องมือ DataForSeo ช่วยให้คุณได้รับผลลัพธ์ของเครื่องมือค้นหาโดยใช้ DataForSeo API หากต้องการใช้ชุดเครื่องมือนี้ คุณจะต้องตั้งค่าข้อมูลรับรอง API ของคุณ ต่อไปนี้เป็นวิธีกำหนดค่าข้อมูลประจำตัว:
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
เมื่อตั้งค่าข้อมูลประจำตัวของคุณแล้ว คุณสามารถสร้าง DataForSeoAPIWrapper
เครื่องมือในการเข้าถึง API:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
พื้นที่ DataForSeoAPIWrapper
เครื่องมือดึงผลลัพธ์ของเครื่องมือค้นหาจากแหล่งต่างๆ
คุณสามารถปรับแต่งประเภทผลลัพธ์และช่องที่ส่งคืนในการตอบกลับ JSON ได้ ตัวอย่างเช่น คุณสามารถระบุประเภทผลลัพธ์ ฟิลด์ และตั้งค่าจำนวนสูงสุดสำหรับจำนวนผลลัพธ์อันดับต้นๆ ที่จะแสดง:
json_wrapper = DataForSeoAPIWrapper( json_result_types=["organic", "knowledge_graph", "answer_box"], json_result_fields=["type", "title", "description", "text"], top_count=3,
) json_result = json_wrapper.results("Bill Gates")
ตัวอย่างนี้ปรับแต่งการตอบสนอง JSON โดยระบุประเภทผลลัพธ์ ช่อง และการจำกัดจำนวนผลลัพธ์
คุณยังสามารถระบุสถานที่และภาษาสำหรับผลการค้นหาของคุณโดยส่งพารามิเตอร์เพิ่มเติมไปยัง API Wrapper:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en"},
) customized_result = customized_wrapper.results("coffee near me")
ด้วยการระบุพารามิเตอร์สถานที่และภาษา คุณสามารถปรับแต่งผลการค้นหาให้เหมาะกับภูมิภาคและภาษาที่ต้องการได้
คุณมีความยืดหยุ่นในการเลือกเครื่องมือค้นหาที่คุณต้องการใช้ เพียงระบุเครื่องมือค้นหาที่ต้องการ:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en", "se_name": "bing"},
) customized_result = customized_wrapper.results("coffee near me")
ในตัวอย่างนี้ การค้นหาได้รับการปรับแต่งเพื่อใช้ Bing เป็นเครื่องมือค้นหา
นอกจากนี้ API wrapper ยังช่วยให้คุณระบุประเภทการค้นหาที่คุณต้องการดำเนินการได้ ตัวอย่างเช่น คุณสามารถค้นหาแผนที่ได้:
maps_search = DataForSeoAPIWrapper( top_count=10, json_result_fields=["title", "value", "address", "rating", "type"], params={ "location_coordinate": "52.512,13.36,12z", "language_code": "en", "se_type": "maps", },
) maps_search_result = maps_search.results("coffee near me")
นี่เป็นการปรับแต่งการค้นหาเพื่อดึงข้อมูลที่เกี่ยวข้องกับแผนที่
เชลล์ (ทุบตี)
ชุดเครื่องมือเชลล์ช่วยให้เอเจนต์สามารถเข้าถึงสภาพแวดล้อมของเชลล์ได้ ทำให้สามารถรันคำสั่งเชลล์ได้ คุณลักษณะนี้มีประสิทธิภาพมาก แต่ควรใช้ด้วยความระมัดระวัง โดยเฉพาะในสภาพแวดล้อมแบบแซนด์บ็อกซ์ ต่อไปนี้คือวิธีที่คุณสามารถใช้เครื่องมือเชลล์:
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
ในตัวอย่างนี้ เครื่องมือ Shell รันคำสั่งเชลล์สองคำสั่ง: สะท้อน “Hello World!” และแสดงเวลาปัจจุบัน
คุณสามารถมอบเครื่องมือเชลล์ให้กับตัวแทนเพื่อดำเนินงานที่ซับซ้อนมากขึ้นได้ นี่คือตัวอย่างเอเจนต์ดึงลิงก์จากหน้าเว็บโดยใช้เครื่องมือ Shell:
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0.1) shell_tool.description = shell_tool.description + f"args {shell_tool.args}".replace( "{", "{{"
).replace("}", "}}")
self_ask_with_search = initialize_agent( [shell_tool], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
self_ask_with_search.run( "Download the langchain.com webpage and grep for all urls. Return only a sorted list of them. Be sure to use double quotes."
)
ในสถานการณ์สมมตินี้ เอเจนต์ใช้เครื่องมือเชลล์เพื่อดำเนินการตามลำดับคำสั่งเพื่อดึงข้อมูล กรอง และเรียงลำดับ URL จากเว็บเพจ
ตัวอย่างที่ให้มาแสดงให้เห็นถึงเครื่องมือบางอย่างที่มีอยู่ใน LangChain เครื่องมือเหล่านี้จะขยายขีดความสามารถของตัวแทนในที่สุด (สำรวจในส่วนย่อยถัดไป) และเสริมศักยภาพให้พวกเขาทำงานต่างๆ ได้อย่างมีประสิทธิภาพ คุณสามารถเลือกเครื่องมือและชุดเครื่องมือที่เหมาะกับความต้องการของโปรเจ็กต์ของคุณได้ดีที่สุด และรวมเข้ากับขั้นตอนการทำงานของตัวแทนของคุณได้ ทั้งนี้ขึ้นอยู่กับความต้องการของคุณ
กลับมาที่ตัวแทน
มาดูตัวแทนกันดีกว่า
AgentExecutor คือสภาพแวดล้อมรันไทม์สำหรับเอเจนต์ มีหน้าที่รับผิดชอบในการเรียกตัวแทน ดำเนินการตามที่เลือก ส่งเอาต์พุตการดำเนินการกลับไปยังตัวแทน และทำซ้ำขั้นตอนจนกว่าตัวแทนจะเสร็จสิ้น ในรหัสเทียม AgentExecutor อาจมีลักษณะดังนี้:
next_action = agent.get_action(...)
while next_action != AgentFinish: observation = run(next_action) next_action = agent.get_action(..., next_action, observation)
return next_action
AgentExecutor จัดการกับความซับซ้อนต่างๆ เช่น การจัดการกับกรณีที่เอเจนต์เลือกเครื่องมือที่ไม่มีอยู่ การจัดการข้อผิดพลาดของเครื่องมือ การจัดการเอาต์พุตที่เอเจนต์สร้างขึ้น และจัดทำการบันทึกและความสามารถในการสังเกตในทุกระดับ
แม้ว่าคลาส AgentExecutor จะเป็นรันไทม์ของเอเจนต์หลักใน LangChain แต่ก็มีรันไทม์ทดลองอื่นๆ ที่รองรับเพิ่มเติม รวมถึง:
- วางแผนและดำเนินการตัวแทน
- เบบี้เอจี
- ออโต้จีพีที
เพื่อให้เข้าใจเฟรมเวิร์กตัวแทนได้ดีขึ้น เรามาสร้างเอเจนต์พื้นฐานตั้งแต่เริ่มต้น จากนั้นไปสำรวจเอเจนต์ที่สร้างไว้ล่วงหน้ากันดีกว่า
ก่อนที่เราจะเจาะลึกในการสร้างตัวแทน จำเป็นต้องทบทวนคำศัพท์และสคีมาที่สำคัญบางประการอีกครั้ง:
- การดำเนินการของตัวแทน: นี่คือคลาสข้อมูลที่แสดงถึงการดำเนินการที่ตัวแทนควรทำ ประกอบด้วย
tool
คุณสมบัติ (ชื่อของเครื่องมือที่จะเรียกใช้) และtool_input
คุณสมบัติ (อินพุตสำหรับเครื่องมือนั้น) - ตัวแทนเสร็จสิ้น: คลาสข้อมูลนี้บ่งชี้ว่าเอเจนต์เสร็จสิ้นภารกิจแล้ว และควรตอบกลับไปยังผู้ใช้ โดยทั่วไปจะมีพจนานุกรมของค่าที่ส่งคืน ซึ่งมักจะมีคีย์ "เอาต์พุต" ที่มีข้อความตอบกลับ
- ขั้นตอนกลาง: สิ่งเหล่านี้คือบันทึกการดำเนินการของตัวแทนก่อนหน้านี้และเอาต์พุตที่เกี่ยวข้อง สิ่งเหล่านี้มีความสำคัญอย่างยิ่งในการส่งผ่านบริบทไปสู่การทำซ้ำในอนาคตของเอเจนต์
ในตัวอย่างของเรา เราจะใช้การเรียกฟังก์ชัน OpenAI เพื่อสร้างตัวแทนของเรา วิธีการนี้เชื่อถือได้สำหรับการสร้างตัวแทน เราจะเริ่มต้นด้วยการสร้างเครื่องมือง่ายๆ ที่ใช้คำนวณความยาวของคำ เครื่องมือนี้มีประโยชน์เนื่องจากบางครั้งโมเดลภาษาอาจทำให้เกิดข้อผิดพลาดเนื่องจากโทเค็นเมื่อนับความยาวของคำ
ขั้นแรก มาโหลดโมเดลภาษาที่เราจะใช้ในการควบคุมตัวแทน:
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
มาทดสอบโมเดลด้วยการคำนวณความยาวของคำกัน:
llm.invoke("how many letters in the word educa?")
คำตอบควรระบุจำนวนตัวอักษรในคำว่า “educa”
ต่อไป เราจะกำหนดฟังก์ชัน Python อย่างง่ายเพื่อคำนวณความยาวของคำ:
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
เราได้สร้างเครื่องมือชื่อ get_word_length
ที่รับคำเป็นอินพุตและส่งกลับความยาว
ตอนนี้ เรามาสร้างพร้อมท์สำหรับตัวแทนกันดีกว่า พร้อมต์จะแนะนำเอเจนต์เกี่ยวกับวิธีการให้เหตุผลและจัดรูปแบบเอาต์พุต ในกรณีของเรา เรากำลังใช้การเรียกใช้ฟังก์ชัน OpenAI ซึ่งต้องการคำแนะนำเพียงเล็กน้อย เราจะกำหนดพรอมต์พร้อมตัวยึดตำแหน่งสำหรับการป้อนข้อมูลของผู้ใช้และตัวแทน scratchpad:
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
ตอนนี้ตัวแทนรู้ได้อย่างไรว่าสามารถใช้เครื่องมือใดได้บ้าง เรากำลังใช้ฟังก์ชัน OpenAI ที่เรียกโมเดลภาษา ซึ่งจำเป็นต้องส่งฟังก์ชันแยกกัน เพื่อมอบเครื่องมือของเราให้กับตัวแทน เราจะจัดรูปแบบเป็นการเรียกใช้ฟังก์ชัน OpenAI:
from langchain.tools.render import format_tool_to_openai_function llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])
ตอนนี้ เราสามารถสร้างเอเจนต์ได้โดยกำหนดการแมปอินพุตและเชื่อมต่อส่วนประกอบต่างๆ:
นี่คือภาษา LCEL เราจะหารือเรื่องนี้โดยละเอียดในภายหลัง
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai _function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
เราได้สร้างตัวแทนของเรา ซึ่งเข้าใจอินพุตของผู้ใช้ ใช้เครื่องมือที่มีอยู่ และรูปแบบเอาต์พุต ตอนนี้เรามาโต้ตอบกับมันกันดีกว่า:
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
เอเจนต์ควรตอบกลับด้วย AgentAction ซึ่งระบุการดำเนินการถัดไปที่จะดำเนินการ
เราได้สร้างตัวแทนแล้ว แต่ตอนนี้เราต้องเขียนรันไทม์สำหรับตัวแทนนั้น รันไทม์ที่ง่ายที่สุดคือรันไทม์ที่เรียกใช้ตัวแทนอย่างต่อเนื่อง ดำเนินการ และทำซ้ำจนกว่าตัวแทนจะเสร็จสิ้น นี่คือตัวอย่าง:
from langchain.schema.agent import AgentFinish user_input = "how many letters in the word educa?"
intermediate_steps = [] while True: output = agent.invoke( { "input": user_input, "intermediate_steps": intermediate_steps, } ) if isinstance(output, AgentFinish): final_result = output.return_values["output"] break else: print(f"TOOL NAME: {output.tool}") print(f"TOOL INPUT: {output.tool_input}") tool = {"get_word_length": get_word_length}[output.tool] observation = tool.run(output.tool_input) intermediate_steps.append((output, observation)) print(final_result)
ในลูปนี้ เราจะเรียกตัวแทนซ้ำๆ ดำเนินการ และอัปเดตขั้นตอนกลางจนกว่าตัวแทนจะเสร็จสิ้น เรายังจัดการการโต้ตอบของเครื่องมือภายในลูปด้วย
เพื่อทำให้กระบวนการนี้ง่ายขึ้น LangChain จึงจัดให้มีคลาส AgentExecutor ซึ่งสรุปการดำเนินการของตัวแทนและเสนอการจัดการข้อผิดพลาด การหยุดก่อนกำหนด การติดตาม และการปรับปรุงอื่น ๆ ลองใช้ AgentExecutor เพื่อโต้ตอบกับตัวแทน:
from langchain.agents import AgentExecutor agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) agent_executor.invoke({"input": "how many letters in the word educa?"})
AgentExecutor ช่วยลดความซับซ้อนของกระบวนการดำเนินการและให้วิธีที่สะดวกในการโต้ตอบกับตัวแทน
หน่วยความจำจะกล่าวถึงรายละเอียดในภายหลัง
ตัวแทนที่เราสร้างขึ้นจนถึงขณะนี้ไม่มีสถานะ ซึ่งหมายความว่าจะจำการโต้ตอบก่อนหน้านี้ไม่ได้ หากต้องการเปิดใช้งานคำถามและการสนทนาติดตามผล เราจำเป็นต้องเพิ่มหน่วยความจำให้กับตัวแทน สิ่งนี้เกี่ยวข้องกับสองขั้นตอน:
- เพิ่มตัวแปรหน่วยความจำในพรอมต์เพื่อจัดเก็บประวัติการแชท
- ติดตามประวัติการแชทระหว่างการโต้ตอบ
เริ่มต้นด้วยการเพิ่มตัวยึดหน่วยความจำในพรอมต์:
from langchain.prompts import MessagesPlaceholder MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), MessagesPlaceholder(variable_name=MEMORY_KEY), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
ตอนนี้ สร้างรายการเพื่อติดตามประวัติการแชท:
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
ในขั้นตอนการสร้างตัวแทน เราจะรวมหน่วยความจำด้วย:
agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), "chat_history": lambda x: x["chat_history"], } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
ตอนนี้ เมื่อเรียกใช้ตัวแทน อย่าลืมอัปเดตประวัติการแชท:
input1 = "how many letters in the word educa?"
result = agent_executor.invoke({"input": input1, "chat_history": chat_history})
chat_history.extend([ HumanMessage(content=input1), AIMessage(content=result["output"]),
])
agent_executor.invoke({"input": "is that a real word?", "chat_history": chat_history})
ซึ่งช่วยให้ตัวแทนสามารถรักษาประวัติการสนทนาและตอบคำถามติดตามผลตามการโต้ตอบครั้งก่อนได้
ยินดีด้วย! คุณสร้างและดำเนินการตัวแทนแบบ end-to-end ตัวแรกใน LangChain สำเร็จแล้ว หากต้องการเจาะลึกถึงความสามารถของ LangChain คุณสามารถสำรวจ:
- รองรับตัวแทนประเภทต่างๆ
- ตัวแทนที่สร้างไว้ล่วงหน้า
- วิธีทำงานกับเครื่องมือและการผสานรวมเครื่องมือ
ประเภทตัวแทน
LangChain นำเสนอตัวแทนหลายประเภท แต่ละประเภทเหมาะสำหรับกรณีการใช้งานเฉพาะ นี่คือตัวแทนบางส่วนที่มีอยู่:
- การตอบสนองแบบซีโร่ช็อต: เอเจนต์นี้ใช้เฟรมเวิร์ก ReAct เพื่อเลือกเครื่องมือตามคำอธิบายเท่านั้น ต้องมีคำอธิบายสำหรับแต่ละเครื่องมือและมีความหลากหลายสูง
- ปฏิกิริยาอินพุตที่มีโครงสร้าง: เอเจนต์นี้จัดการเครื่องมือแบบมัลติอินพุตและเหมาะสำหรับงานที่ซับซ้อน เช่น การนำทางเว็บเบราว์เซอร์ มันใช้สกีมาอาร์กิวเมนต์ของเครื่องมือสำหรับการป้อนข้อมูลที่มีโครงสร้าง
- ฟังก์ชั่น OpenAI: ออกแบบมาโดยเฉพาะสำหรับรุ่นที่ปรับแต่งเพื่อการเรียกใช้ฟังก์ชัน เอเจนต์นี้เข้ากันได้กับรุ่นต่างๆ เช่น gpt-3.5-turbo-0613 และ gpt-4-0613 เราใช้สิ่งนี้เพื่อสร้างตัวแทนแรกของเราด้านบน
- การสนทนา: ออกแบบมาสำหรับการตั้งค่าการสนทนา เอเจนต์นี้ใช้ ReAct สำหรับการเลือกเครื่องมือ และใช้หน่วยความจำเพื่อจดจำการโต้ตอบก่อนหน้า
- ถามตัวเองด้วยการค้นหา: เจ้าหน้าที่นี้ใช้เครื่องมือเดียวคือ "คำตอบระดับกลาง" ซึ่งจะค้นหาคำตอบที่เป็นข้อเท็จจริงสำหรับคำถามต่างๆ เทียบเท่ากับการถามตัวเองแบบเดิมด้วยกระดาษค้นหา
- ที่เก็บเอกสาร ReAct: เอเจนต์นี้โต้ตอบกับที่เก็บเอกสารโดยใช้เฟรมเวิร์ก ReAct ต้องใช้เครื่องมือ "ค้นหา" และ "ค้นหา" และคล้ายกับตัวอย่าง Wikipedia ของรายงาน ReAct ต้นฉบับ
สำรวจตัวแทนประเภทเหล่านี้เพื่อค้นหาตัวแทนที่ตรงกับความต้องการของคุณใน LangChain เอเจนต์เหล่านี้ช่วยให้คุณสามารถผูกชุดเครื่องมือภายในเพื่อจัดการกับการดำเนินการและสร้างการตอบสนอง เรียนรู้เพิ่มเติมเกี่ยวกับ วิธีสร้างตัวแทนของคุณเองด้วยเครื่องมือที่นี่.
ตัวแทนที่สร้างไว้ล่วงหน้า
มาสำรวจตัวแทนของเราต่อไป โดยมุ่งเน้นไปที่ตัวแทนที่สร้างไว้ล่วงหน้าที่มีอยู่ใน LangChain
Gmail
LangChain นำเสนอชุดเครื่องมือ Gmail ที่ให้คุณเชื่อมต่ออีเมล LangChain ของคุณกับ Gmail API ในการเริ่มต้น คุณจะต้องตั้งค่าข้อมูลรับรองตามที่อธิบายไว้ในเอกสารประกอบของ Gmail API เมื่อคุณได้ดาวน์โหลดไฟล์ credentials.json
คุณสามารถดำเนินการต่อโดยใช้ Gmail API ได้ นอกจากนี้ คุณจะต้องติดตั้งไลบรารีที่จำเป็นบางส่วนโดยใช้คำสั่งต่อไปนี้:
pip install --upgrade google-api-python-client > /dev/null
pip install --upgrade google-auth-oauthlib > /dev/null
pip install --upgrade google-auth-httplib2 > /dev/null
pip install beautifulsoup4 > /dev/null # Optional for parsing HTML messages
คุณสามารถสร้างชุดเครื่องมือ Gmail ได้ดังนี้:
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
คุณยังสามารถปรับแต่งการรับรองความถูกต้องได้ตามความต้องการของคุณ เบื้องหลัง ทรัพยากร Googleapi ถูกสร้างขึ้นโดยใช้วิธีการต่อไปนี้:
from langchain.tools.gmail.utils import build_resource_service, get_gmail_credentials credentials = get_gmail_credentials( token_file="token.json", scopes=["https://mail.google.com/"], client_secrets_file="credentials.json",
)
api_resource = build_resource_service(credentials=credentials)
toolkit = GmailToolkit(api_resource=api_resource)
ชุดเครื่องมือนี้มีเครื่องมือต่างๆ ที่สามารถนำไปใช้ภายในตัวแทนได้ รวมไปถึง:
GmailCreateDraft
: สร้างอีเมลฉบับร่างพร้อมช่องข้อความที่ระบุGmailSendMessage
: ส่งข้อความอีเมล์GmailSearch
: ค้นหาข้อความอีเมลหรือกระทู้GmailGetMessage
: ดึงอีเมลด้วยรหัสข้อความGmailGetThread
: ค้นหาข้อความอีเมล
หากต้องการใช้เครื่องมือเหล่านี้ภายในเอเจนต์ คุณสามารถเตรียมใช้งานเอเจนต์ได้ดังต่อไปนี้:
from langchain.llms import OpenAI
from langchain.agents import initialize_agent, AgentType llm = OpenAI(temperature=0)
agent = initialize_agent( tools=toolkit.get_tools(), llm=llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
)
ต่อไปนี้คือตัวอย่างบางส่วนของวิธีการใช้เครื่องมือเหล่านี้:
- สร้างร่าง Gmail เพื่อแก้ไข:
agent.run( "Create a gmail draft for me to edit of a letter from the perspective of a sentient parrot " "who is looking to collaborate on some research with her estranged friend, a cat. " "Under no circumstances may you send the message, however."
)
- ค้นหาอีเมลล่าสุดในฉบับร่างของคุณ:
agent.run("Could you search in my drafts for the latest email?")
ตัวอย่างเหล่านี้แสดงให้เห็นถึงความสามารถของชุดเครื่องมือ Gmail ของ LangChain ภายในตัวแทน ซึ่งช่วยให้คุณสามารถโต้ตอบกับ Gmail โดยทางโปรแกรมได้
ตัวแทนฐานข้อมูล SQL
ส่วนนี้จะแสดงภาพรวมของตัวแทนที่ออกแบบมาเพื่อโต้ตอบกับฐานข้อมูล SQL โดยเฉพาะฐานข้อมูล Chinook เอเจนต์นี้สามารถตอบคำถามทั่วไปเกี่ยวกับฐานข้อมูลและกู้คืนจากข้อผิดพลาดได้ โปรดทราบว่ายังอยู่ในระหว่างการพัฒนา และคำตอบบางข้ออาจไม่ถูกต้อง โปรดใช้ความระมัดระวังเมื่อรันบนข้อมูลที่ละเอียดอ่อน เนื่องจากอาจดำเนินการคำสั่ง DML บนฐานข้อมูลของคุณ
หากต้องการใช้เอเจนต์นี้ คุณสามารถเริ่มต้นได้ดังนี้:
from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
from langchain.llms.openai import OpenAI
from langchain.agents import AgentExecutor
from langchain.agents.agent_types import AgentType
from langchain.chat_models import ChatOpenAI db = SQLDatabase.from_uri("sqlite:///../../../../../notebooks/Chinook.db")
toolkit = SQLDatabaseToolkit(db=db, llm=OpenAI(temperature=0)) agent_executor = create_sql_agent( llm=OpenAI(temperature=0), toolkit=toolkit, verbose=True, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
)
เอเจนต์นี้สามารถเริ่มต้นได้โดยใช้ ZERO_SHOT_REACT_DESCRIPTION
ประเภทตัวแทน ออกแบบมาเพื่อตอบคำถามและให้คำอธิบาย หรือคุณสามารถเตรียมใช้งานเอเจนต์ได้โดยใช้ OPENAI_FUNCTIONS
ประเภทตัวแทนที่มีโมเดล GPT-3.5-turbo ของ OpenAI ซึ่งเราใช้ในไคลเอนต์ก่อนหน้านี้
ข้อจำกัดความรับผิดชอบ
- สายการสืบค้นอาจสร้างการแทรก/อัปเดต/ลบการสืบค้น โปรดใช้ความระมัดระวังและใช้พรอมต์ที่กำหนดเองหรือสร้างผู้ใช้ SQL โดยไม่มีสิทธิ์ในการเขียนหากจำเป็น
- โปรดทราบว่าการเรียกใช้คิวรีบางอย่าง เช่น "เรียกใช้คิวรีที่ใหญ่ที่สุดที่เป็นไปได้" อาจทำให้ฐานข้อมูล SQL ของคุณทำงานหนักเกินไป โดยเฉพาะอย่างยิ่งหากมีหลายล้านแถว
- ฐานข้อมูลเชิงคลังข้อมูลมักจะสนับสนุนโควต้าระดับผู้ใช้เพื่อจำกัดการใช้ทรัพยากร
คุณสามารถขอให้ตัวแทนอธิบายตาราง เช่น ตาราง "เพลย์ลิสต์แทร็ก" นี่คือตัวอย่างวิธีการ:
agent_executor.run("Describe the playlisttrack table")
ตัวแทนจะให้ข้อมูลเกี่ยวกับสคีมาของตารางและแถวตัวอย่าง
หากคุณถามโดยไม่ได้ตั้งใจเกี่ยวกับตารางที่ไม่มีอยู่ ตัวแทนสามารถกู้คืนและให้ข้อมูลเกี่ยวกับตารางที่ใกล้เคียงที่สุดได้ ตัวอย่างเช่น:
agent_executor.run("Describe the playlistsong table")
ตัวแทนจะค้นหาตารางที่ตรงกันที่ใกล้ที่สุดและให้ข้อมูลเกี่ยวกับตารางดังกล่าว
คุณยังสามารถขอให้ตัวแทนดำเนินการสืบค้นในฐานข้อมูลได้ ตัวอย่างเช่น:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
ตัวแทนจะดำเนินการสอบถามและให้ผลลัพธ์ เช่น ประเทศที่มียอดขายรวมสูงสุด
หากต้องการทราบจำนวนแทร็กทั้งหมดในแต่ละเพลย์ลิสต์ คุณสามารถใช้คำค้นหาต่อไปนี้:
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
ตัวแทนจะส่งคืนชื่อเพลย์ลิสต์พร้อมกับจำนวนแทร็กทั้งหมดที่เกี่ยวข้อง
ในกรณีที่ตัวแทนพบข้อผิดพลาด ก็สามารถกู้คืนและให้การตอบสนองที่แม่นยำได้ ตัวอย่างเช่น:
agent_executor.run("Who are the top 3 best selling artists?")
แม้จะพบข้อผิดพลาดเบื้องต้นตัวแทนก็จะปรับเปลี่ยนและให้คำตอบที่ถูกต้องซึ่งในกรณีนี้คือศิลปินที่ขายดีที่สุด 3 อันดับแรก
ตัวแทน DataFrame ของ Pandas
ส่วนนี้จะแนะนำตัวแทนที่ออกแบบมาเพื่อโต้ตอบกับ Pandas DataFrames เพื่อวัตถุประสงค์ในการตอบคำถาม โปรดทราบว่าตัวแทนนี้ใช้ตัวแทน Python ภายใต้ประทุนเพื่อรันโค้ด Python ที่สร้างโดยโมเดลภาษา (LLM) ใช้ความระมัดระวังเมื่อใช้ตัวแทนนี้เพื่อป้องกันอันตรายที่อาจเกิดขึ้นจากโค้ด Python ที่เป็นอันตรายที่สร้างโดย LLM
คุณสามารถเริ่มต้นเอเจนต์ Pandas DataFrame ได้ดังต่อไปนี้:
from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
from langchain.chat_models import ChatOpenAI
from langchain.agents.agent_types import AgentType from langchain.llms import OpenAI
import pandas as pd df = pd.read_csv("titanic.csv") # Using ZERO_SHOT_REACT_DESCRIPTION agent type
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True) # Alternatively, using OPENAI_FUNCTIONS agent type
# agent = create_pandas_dataframe_agent(
# ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613"),
# df,
# verbose=True,
# agent_type=AgentType.OPENAI_FUNCTIONS,
# )
คุณสามารถขอให้ตัวแทนนับจำนวนแถวใน DataFrame ได้:
agent.run("how many rows are there?")
ตัวแทนจะดำเนินการโค้ด df.shape[0]
แล้วให้คำตอบ เช่น “ใน dataframe มี 891 แถว”
คุณยังสามารถขอให้ตัวแทนกรองแถวตามเกณฑ์เฉพาะได้ เช่น ค้นหาจำนวนคนที่มีพี่น้องมากกว่า 3 คน:
agent.run("how many people have more than 3 siblings")
ตัวแทนจะดำเนินการโค้ด df[df['SibSp'] > 3].shape[0]
แล้วให้คำตอบ เช่น “30 คน มีพี่น้องมากกว่า 3 คน”
หากคุณต้องการคำนวณรากที่สองของอายุเฉลี่ย คุณสามารถถามตัวแทนได้ว่า:
agent.run("whats the square root of the average age?")
ตัวแทนจะคำนวณอายุเฉลี่ยที่ใช้ df['Age'].mean()
แล้วคำนวณหารากที่สองโดยใช้ math.sqrt()
. โดยจะให้คำตอบ เช่น “รากที่สองของอายุเฉลี่ยคือ 5.449689683556195”
มาสร้างสำเนาของ DataFrame กัน และค่าอายุที่ขาดหายไปจะถูกเติมด้วยอายุเฉลี่ย:
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
จากนั้น คุณสามารถเริ่มต้นเอเจนต์ด้วยทั้ง DataFrames และถามคำถาม:
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
เจ้าหน้าที่จะเปรียบเทียบคอลัมน์อายุใน DataFrames ทั้งสองและให้คำตอบ เช่น “177 แถวในคอลัมน์อายุแตกต่างกัน”
จิรา ทูลคิท
ส่วนนี้จะอธิบายวิธีใช้ชุดเครื่องมือ Jira ซึ่งช่วยให้ตัวแทนโต้ตอบกับอินสแตนซ์ Jira ได้ คุณสามารถดำเนินการต่างๆ ได้ เช่น การค้นหาปัญหาและสร้างปัญหาโดยใช้ชุดเครื่องมือนี้ มันใช้ไลบรารี atlassian-python-api หากต้องการใช้ชุดเครื่องมือนี้ คุณต้องตั้งค่าตัวแปรสภาพแวดล้อมสำหรับอินสแตนซ์ Jira ของคุณ รวมถึง JIRA_API_TOKEN, JIRA_USERNAME และ JIRA_INSTANCE_URL นอกจากนี้ คุณอาจต้องตั้งค่าคีย์ OpenAI API ของคุณเป็นตัวแปรสภาพแวดล้อม
ในการเริ่มต้น ให้ติดตั้งไลบรารี atlassian-python-api และตั้งค่าตัวแปรสภาพแวดล้อมที่จำเป็น:
%pip install atlassian-python-api import os
from langchain.agents import AgentType
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits.jira.toolkit import JiraToolkit
from langchain.llms import OpenAI
from langchain.utilities.jira import JiraAPIWrapper os.environ["JIRA_API_TOKEN"] = "abc"
os.environ["JIRA_USERNAME"] = "123"
os.environ["JIRA_INSTANCE_URL"] = "https://jira.atlassian.com"
os.environ["OPENAI_API_KEY"] = "xyz" llm = OpenAI(temperature=0)
jira = JiraAPIWrapper()
toolkit = JiraToolkit.from_jira_api_wrapper(jira)
agent = initialize_agent( toolkit.get_tools(), llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
คุณสามารถสั่งให้ตัวแทนสร้างปัญหาใหม่ในโครงการเฉพาะพร้อมข้อมูลสรุปและคำอธิบาย:
agent.run("make a new issue in project PW to remind me to make more fried rice")
ตัวแทนจะดำเนินการที่จำเป็นเพื่อสร้างปัญหาและให้คำตอบ เช่น “มีการสร้างปัญหาใหม่ในโครงการ PW พร้อมบทสรุป 'ทำข้าวผัดเพิ่ม' และคำอธิบาย 'เตือนให้ทำข้าวผัดมากขึ้น'”
สิ่งนี้ทำให้คุณสามารถโต้ตอบกับอินสแตนซ์ Jira ของคุณโดยใช้คำแนะนำภาษาธรรมชาติและชุดเครื่องมือ Jira
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
โมดูลที่ XNUMX : โซ่
LangChain เป็นเครื่องมือที่ออกแบบมาเพื่อใช้ Large Language Models (LLM) ในแอปพลิเคชันที่ซับซ้อน โดยจัดเตรียมกรอบงานสำหรับการสร้างกลุ่มส่วนประกอบต่างๆ รวมถึง LLM และส่วนประกอบประเภทอื่นๆ สองกรอบหลัก
- ภาษานิพจน์ LangChain (LCEL)
- อินเทอร์เฟซลูกโซ่แบบเดิม
LangChain Expression Language (LCEL) เป็นไวยากรณ์ที่ช่วยให้สามารถจัดองค์ประกอบของ chain ได้อย่างง่ายดาย รองรับฟีเจอร์ขั้นสูง เช่น การสตรีม การโทรแบบอะซิงโครนัส การแบ่งกลุ่ม การทำงานแบบขนาน การลองใหม่ ทางเลือกสำรอง และการติดตาม ตัวอย่างเช่น คุณสามารถเขียนพรอมต์ โมเดล และตัวแยกวิเคราะห์เอาต์พุตใน LCEL ดังที่แสดงในโค้ดต่อไปนี้:
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
prompt = ChatPromptTemplate.from_messages([ ("system", "You're a very knowledgeable historian who provides accurate and eloquent answers to historical questions."), ("human", "{question}")
])
runnable = prompt | model | StrOutputParser() for chunk in runnable.stream({"question": "What are the seven wonders of the world"}): print(chunk, end="", flush=True)
อีกทางหนึ่ง LLMChain เป็นตัวเลือกที่คล้ายกับ LCEL สำหรับการเขียนส่วนประกอบ ตัวอย่าง LLMChain มีดังต่อไปนี้:
from langchain.chains import LLMChain chain = LLMChain(llm=model, prompt=prompt, output_parser=StrOutputParser())
chain.run(question="What are the seven wonders of the world")
Chains ใน LangChain ยังสามารถ stateful ได้ด้วยการรวม Object Memory เข้าด้วยกัน ซึ่งช่วยให้ข้อมูลคงอยู่ระหว่างการโทร ดังที่แสดงในตัวอย่างนี้:
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory conversation = ConversationChain(llm=chat, memory=ConversationBufferMemory())
conversation.run("Answer briefly. What are the first 3 colors of a rainbow?")
conversation.run("And the next 4?")
LangChain ยังรองรับการผสานรวมกับ API การเรียกฟังก์ชันของ OpenAI ซึ่งมีประโยชน์สำหรับการรับเอาต์พุตที่มีโครงสร้างและดำเนินการฟังก์ชันภายในเชน สำหรับการรับเอาต์พุตที่มีโครงสร้าง คุณสามารถระบุได้โดยใช้คลาส Pydantic หรือ JsonSchema ดังภาพประกอบด้านล่าง:
from langchain.pydantic_v1 import BaseModel, Field
from langchain.chains.openai_functions import create_structured_output_runnable
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") fav_food: Optional[str] = Field(None, description="The person's favorite food") llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = ChatPromptTemplate.from_messages([ # Prompt messages here
]) runnable = create_structured_output_runnable(Person, llm, prompt)
runnable.invoke({"input": "Sally is 13"})
สำหรับเอาต์พุตที่มีโครงสร้าง ยังมีแนวทางดั้งเดิมที่ใช้ LLMChain อีกด้วย:
from langchain.chains.openai_functions import create_structured_output_chain class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") chain = create_structured_output_chain(Person, llm, prompt, verbose=True)
chain.run("Sally is 13")
LangChain ใช้ประโยชน์จากฟังก์ชัน OpenAI เพื่อสร้างเครือข่ายเฉพาะต่างๆ เพื่อวัตถุประสงค์ที่แตกต่างกัน ซึ่งรวมถึงเชนสำหรับการดึงข้อมูล การแท็ก OpenAPI และ QA พร้อมการอ้างอิง
ในบริบทของการดึงข้อมูล กระบวนการจะคล้ายกับห่วงโซ่เอาท์พุตที่มีโครงสร้าง แต่มุ่งเน้นไปที่การดึงข้อมูลหรือเอนทิตี สำหรับการแท็ก แนวคิดคือการติดป้ายกำกับเอกสารด้วยคลาสต่างๆ เช่น ความรู้สึก ภาษา สไตล์ หัวข้อที่ครอบคลุม หรือแนวโน้มทางการเมือง
ตัวอย่างวิธีการทำงานของการแท็กใน LangChain สามารถสาธิตได้ด้วยโค้ด Python กระบวนการเริ่มต้นด้วยการติดตั้งแพ็คเกจที่จำเป็นและการตั้งค่าสภาพแวดล้อม:
pip install langchain openai
# Set env var OPENAI_API_KEY or load from a .env file:
# import dotenv
# dotenv.load_dotenv() from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import create_tagging_chain, create_tagging_chain_pydantic
มีการกำหนดสคีมาสำหรับการแท็ก โดยระบุคุณสมบัติและประเภทที่คาดหวัง:
schema = { "properties": { "sentiment": {"type": "string"}, "aggressiveness": {"type": "integer"}, "language": {"type": "string"}, }
} llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_tagging_chain(schema, llm)
ตัวอย่างของการรันห่วงโซ่การแท็กด้วยอินพุตที่แตกต่างกันแสดงความสามารถของโมเดลในการตีความความรู้สึก ภาษา และความก้าวร้าว:
inp = "Estoy increiblemente contento de haberte conocido! Creo que seremos muy buenos amigos!"
chain.run(inp)
# {'sentiment': 'positive', 'language': 'Spanish'} inp = "Estoy muy enojado con vos! Te voy a dar tu merecido!"
chain.run(inp)
# {'sentiment': 'enojado', 'aggressiveness': 1, 'language': 'es'}
เพื่อการควบคุมที่ละเอียดยิ่งขึ้น คุณสามารถกำหนดสคีมาให้เฉพาะเจาะจงยิ่งขึ้น รวมถึงค่าที่เป็นไปได้ คำอธิบาย และคุณสมบัติที่จำเป็น ตัวอย่างของการควบคุมที่ได้รับการปรับปรุงนี้แสดงอยู่ด้านล่าง:
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Pydantic schema ยังสามารถใช้เพื่อกำหนดเกณฑ์การแท็กได้ โดยให้วิธี Pythonic เพื่อระบุคุณสมบัติและประเภทที่ต้องการ:
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
นอกจากนี้ ตัวแปลงเอกสารแท็กเกอร์ข้อมูลเมตาของ LangChain ยังสามารถใช้เพื่อดึงข้อมูลเมตาจากเอกสาร LangChain ซึ่งมีฟังก์ชันการทำงานคล้ายกับห่วงโซ่การแท็ก แต่นำไปใช้กับเอกสาร LangChain
การอ้างอิงแหล่งที่มาในการดึงข้อมูลเป็นอีกคุณสมบัติหนึ่งของ LangChain โดยใช้ฟังก์ชัน OpenAI เพื่อแยกการอ้างอิงจากข้อความ สิ่งนี้แสดงให้เห็นในรหัสต่อไปนี้:
from langchain.chains import create_citation_fuzzy_match_chain
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_citation_fuzzy_match_chain(llm)
# Further code for running the chain and displaying results
ใน LangChain การผูกมัดในแอปพลิเคชัน Large Language Model (LLM) โดยทั่วไปจะเกี่ยวข้องกับการรวมเทมเพลตพร้อมท์เข้ากับ LLM และตัวแยกวิเคราะห์เอาต์พุต (เป็นทางเลือก) วิธีที่แนะนำในการทำเช่นนี้คือผ่าน LangChain Expression Language (LCEL) แม้ว่าวิธี LLMChain แบบเดิมก็ได้รับการสนับสนุนเช่นกัน
การใช้ LCEL นั้น BasePromptTemplate, BaseLanguageModel และ BaseOutputParser ล้วนใช้อินเทอร์เฟซ Runnable และสามารถไพพ์เข้าด้วยกันได้อย่างง่ายดาย นี่คือตัวอย่างที่แสดงให้เห็นสิ่งนี้:
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser prompt = PromptTemplate.from_template( "What is a good name for a company that makes {product}?"
)
runnable = prompt | ChatOpenAI() | StrOutputParser()
runnable.invoke({"product": "colorful socks"})
# Output: 'VibrantSocks'
การกำหนดเส้นทางใน LangChain ช่วยให้สามารถสร้างเครือข่ายที่ไม่สามารถกำหนดได้ โดยที่เอาต์พุตของขั้นตอนก่อนหน้าจะกำหนดขั้นตอนถัดไป สิ่งนี้ช่วยในการจัดโครงสร้างและรักษาความสม่ำเสมอในการโต้ตอบกับ LLM ตัวอย่างเช่น หากคุณมีเทมเพลตสองแบบที่ปรับให้เหมาะกับคำถามประเภทต่างๆ คุณสามารถเลือกเทมเพลตตามการป้อนข้อมูลของผู้ใช้
ต่อไปนี้คือวิธีที่คุณสามารถทำได้โดยใช้ LCEL กับ RunnableBranch ซึ่งเริ่มต้นด้วยรายการคู่ (เงื่อนไข, runnable) และ runnable เริ่มต้น:
from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableBranch
# Code for defining physics_prompt and math_prompt general_prompt = PromptTemplate.from_template( "You are a helpful assistant. Answer the question as accurately as you can.nn{input}"
)
prompt_branch = RunnableBranch( (lambda x: x["topic"] == "math", math_prompt), (lambda x: x["topic"] == "physics", physics_prompt), general_prompt,
) # More code for setting up the classifier and final chain
จากนั้นห่วงโซ่สุดท้ายจะถูกสร้างขึ้นโดยใช้ส่วนประกอบต่างๆ เช่น ตัวแยกประเภทหัวข้อ สาขาพร้อมต์ และตัวแยกวิเคราะห์เอาต์พุต เพื่อกำหนดโฟลว์ตามหัวข้อของอินพุต:
from operator import itemgetter
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough final_chain = ( RunnablePassthrough.assign(topic=itemgetter("input") | classifier_chain) | prompt_branch | ChatOpenAI() | StrOutputParser()
) final_chain.invoke( { "input": "What is the first prime number greater than 40 such that one plus the prime number is divisible by 3?" }
)
# Output: Detailed answer to the math question
วิธีการนี้เป็นตัวอย่างความยืดหยุ่นและประสิทธิภาพของ LangChain ในการจัดการคิวรี่ที่ซับซ้อนและกำหนดเส้นทางอย่างเหมาะสมตามอินพุต
ในขอบเขตของโมเดลภาษา แนวทางปฏิบัติทั่วไปคือการติดตามการโทรครั้งแรกด้วยชุดการโทรที่ตามมา โดยใช้เอาต์พุตของการเรียกหนึ่งครั้งเป็นอินพุตสำหรับการโทรครั้งถัดไป วิธีการตามลำดับนี้มีประโยชน์อย่างยิ่งเมื่อคุณต้องการต่อยอดข้อมูลที่สร้างขึ้นในการโต้ตอบครั้งก่อน แม้ว่า LangChain Expression Language (LCEL) เป็นวิธีที่แนะนำสำหรับการสร้างลำดับเหล่านี้ แต่วิธี SequentialChain ยังคงได้รับการบันทึกไว้สำหรับความเข้ากันได้แบบย้อนหลัง
เพื่อแสดงให้เห็นสิ่งนี้ ลองพิจารณาสถานการณ์ที่เราสร้างเรื่องย่อของบทละครขึ้นมาก่อน จากนั้นจึงทบทวนตามเรื่องย่อนั้น การใช้ Python langchain.prompts
เราสร้างสองอัน PromptTemplate
อินสแตนซ์: อันหนึ่งสำหรับเรื่องย่อและอีกอันสำหรับการทบทวน นี่คือโค้ดสำหรับตั้งค่าเทมเพลตเหล่านี้:
from langchain.prompts import PromptTemplate synopsis_prompt = PromptTemplate.from_template( "You are a playwright. Given the title of play, it is your job to write a synopsis for that title.nnTitle: {title}nPlaywright: This is a synopsis for the above play:"
) review_prompt = PromptTemplate.from_template( "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
)
ในแนวทาง LCE เราเชื่อมโยงพร้อมท์เหล่านี้ด้วย ChatOpenAI
และ StrOutputParser
เพื่อสร้างลำดับที่สร้างเรื่องย่อก่อนแล้วจึงทบทวน ข้อมูลโค้ดมีดังนี้:
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser llm = ChatOpenAI()
chain = ( {"synopsis": synopsis_prompt | llm | StrOutputParser()} | review_prompt | llm | StrOutputParser()
)
chain.invoke({"title": "Tragedy at sunset on the beach"})
หากเราต้องการทั้งเรื่องย่อและบทวิจารณ์เราก็สามารถใช้ได้ RunnablePassthrough
เพื่อสร้างเชนแยกกันสำหรับแต่ละอันแล้วรวมเข้าด้วยกัน:
from langchain.schema.runnable import RunnablePassthrough synopsis_chain = synopsis_prompt | llm | StrOutputParser()
review_chain = review_prompt | llm | StrOutputParser()
chain = {"synopsis": synopsis_chain} | RunnablePassthrough.assign(review=review_chain)
chain.invoke({"title": "Tragedy at sunset on the beach"})
สำหรับสถานการณ์ที่เกี่ยวข้องกับลำดับที่ซับซ้อนมากขึ้น SequentialChain
วิธีการเข้ามามีบทบาท ซึ่งช่วยให้สามารถอินพุตและเอาต์พุตได้หลายรายการ พิจารณากรณีที่เราต้องการเรื่องย่อตามชื่อละครและยุคสมัย ต่อไปนี้คือวิธีที่เราอาจตั้งค่าได้:
from langchain.llms import OpenAI
from langchain.chains import LLMChain, SequentialChain
from langchain.prompts import PromptTemplate llm = OpenAI(temperature=0.7) synopsis_template = "You are a playwright. Given the title of play and the era it is set in, it is your job to write a synopsis for that title.nnTitle: {title}nEra: {era}nPlaywright: This is a synopsis for the above play:"
synopsis_prompt_template = PromptTemplate(input_variables=["title", "era"], template=synopsis_template)
synopsis_chain = LLMChain(llm=llm, prompt=synopsis_prompt_template, output_key="synopsis") review_template = "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
prompt_template = PromptTemplate(input_variables=["synopsis"], template=review_template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review") overall_chain = SequentialChain( chains=[synopsis_chain, review_chain], input_variables=["era", "title"], output_variables=["synopsis", "review"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
ในสถานการณ์ที่คุณต้องการรักษาบริบทตลอดห่วงโซ่หรือส่วนหลังของห่วงโซ่ SimpleMemory
สามารถใช้ได้. สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการจัดการความสัมพันธ์อินพุต/เอาท์พุตที่ซับซ้อน ตัวอย่างเช่น ในสถานการณ์ที่เราต้องการสร้างโพสต์บนโซเชียลมีเดียตามชื่อละคร ยุคสมัย เรื่องย่อ และบทวิจารณ์ SimpleMemory
สามารถช่วยจัดการตัวแปรเหล่านี้ได้:
from langchain.memory import SimpleMemory
from langchain.chains import SequentialChain template = "You are a social media manager for a theater company. Given the title of play, the era it is set in, the date, time and location, the synopsis of the play, and the review of the play, it is your job to write a social media post for that play.nnHere is some context about the time and location of the play:nDate and Time: {time}nLocation: {location}nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:n{review}nnSocial Media Post:"
prompt_template = PromptTemplate(input_variables=["synopsis", "review", "time", "location"], template=template)
social_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="social_post_text") overall_chain = SequentialChain( memory=SimpleMemory(memories={"time": "December 25th, 8pm PST", "location": "Theater in the Park"}), chains=[synopsis_chain, review_chain, social_chain], input_variables=["era", "title"], output_variables=["social_post_text"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
นอกจากสายโซ่ตามลำดับแล้ว ยังมีสายโซ่เฉพาะสำหรับการทำงานกับเอกสารอีกด้วย แต่ละกลุ่มมีจุดประสงค์ที่แตกต่างกัน ตั้งแต่การรวมเอกสารไปจนถึงการปรับแต่งคำตอบตามการวิเคราะห์เอกสารซ้ำๆ ไปจนถึงการทำแผนที่และลดเนื้อหาเอกสารเพื่อการสรุปหรือการจัดอันดับใหม่ตามการตอบกลับที่ได้คะแนน โซ่เหล่านี้สามารถสร้างขึ้นใหม่ได้ด้วย LCEL เพื่อความยืดหยุ่นและการปรับแต่งเพิ่มเติม
-
StuffDocumentsChain
รวมรายการเอกสารเป็นพรอมต์เดียวที่ส่งไปยัง LLM -
RefineDocumentsChain
อัปเดตคำตอบซ้ำๆ สำหรับแต่ละเอกสาร เหมาะสำหรับงานที่เอกสารเกินความจุบริบทของโมเดล -
MapReduceDocumentsChain
ใช้ห่วงโซ่กับเอกสารแต่ละฉบับแยกกัน จากนั้นจึงรวมผลลัพธ์เข้าด้วยกัน -
MapRerankDocumentsChain
ให้คะแนนคำตอบตามเอกสารแต่ละรายการและเลือกคำตอบที่ได้คะแนนสูงสุด
นี่คือตัวอย่างวิธีที่คุณอาจตั้งค่า MapReduceDocumentsChain
ใช้ LCEL:
from functools import partial
from langchain.chains.combine_documents import collapse_docs, split_list_of_docs
from langchain.schema import Document, StrOutputParser
from langchain.schema.prompt_template import format_document
from langchain.schema.runnable import RunnableParallel, RunnablePassthrough llm = ChatAnthropic()
document_prompt = PromptTemplate.from_template("{page_content}")
partial_format_document = partial(format_document, prompt=document_prompt) map_chain = ( {"context": partial_format_document} | PromptTemplate.from_template("Summarize this content:nn{context}") | llm | StrOutputParser()
) map_as_doc_chain = ( RunnableParallel({"doc": RunnablePassthrough(), "content": map_chain}) | (lambda x: Document(page_content=x["content"], metadata=x["doc"].metadata))
).with_config(run_name="Summarize (return doc)") def format_docs(docs): return "nn".join(partial_format_document(doc) for doc in docs) collapse_chain = ( {"context": format_docs} | PromptTemplate.from_template("Collapse this content:nn{context}") | llm | StrOutputParser()
) reduce_chain = ( {"context": format_docs} | PromptTemplate.from_template("Combine these summaries:nn{context}") | llm | StrOutputParser()
).with_config(run_name="Reduce") map_reduce = (map_as_doc_chain.map() | collapse | reduce_chain).with_config(run_name="Map reduce")
การกำหนดค่านี้ช่วยให้สามารถวิเคราะห์เนื้อหาเอกสารได้อย่างละเอียดและครอบคลุม โดยใช้ประโยชน์จากจุดแข็งของ LCE และโมเดลภาษาที่สำคัญ
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
โมดูล V : หน่วยความจำ
ใน LangChain หน่วยความจำเป็นส่วนพื้นฐานของอินเทอร์เฟซการสนทนา ซึ่งช่วยให้ระบบสามารถอ้างอิงการโต้ตอบในอดีตได้ ซึ่งสามารถทำได้โดยการจัดเก็บและสืบค้นข้อมูล โดยมีการดำเนินการหลักสองประการ: การอ่านและการเขียน ระบบหน่วยความจำโต้ตอบกับลูกโซ่สองครั้งในระหว่างการรัน เพิ่มอินพุตของผู้ใช้และจัดเก็บอินพุตและเอาต์พุตเพื่อใช้อ้างอิงในอนาคต
การสร้างหน่วยความจำเข้าสู่ระบบ
- การจัดเก็บข้อความแชท: โมดูลหน่วยความจำ LangChain ผสานรวมวิธีการต่างๆ ในการจัดเก็บข้อความแชท ตั้งแต่รายการในหน่วยความจำไปจนถึงฐานข้อมูล เพื่อให้แน่ใจว่าการโต้ตอบการแชททั้งหมดจะถูกบันทึกไว้เพื่อใช้อ้างอิงในอนาคต
- การสืบค้นข้อความแชท: นอกเหนือจากการจัดเก็บข้อความแชทแล้ว LangChain ยังใช้โครงสร้างข้อมูลและอัลกอริธึมเพื่อสร้างมุมมองที่เป็นประโยชน์ของข้อความเหล่านี้ ระบบหน่วยความจำแบบธรรมดาอาจส่งคืนข้อความล่าสุด ในขณะที่ระบบขั้นสูงสามารถสรุปการโต้ตอบในอดีตหรือมุ่งเน้นไปที่เอนทิตีที่กล่าวถึงในการโต้ตอบปัจจุบัน
เพื่อสาธิตการใช้หน่วยความจำใน LangChain ให้พิจารณา ConversationBufferMemory
class ซึ่งเป็นรูปแบบหน่วยความจำอย่างง่ายที่เก็บข้อความแชทไว้ในบัฟเฟอร์ นี่คือตัวอย่าง:
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("Hello!")
memory.chat_memory.add_ai_message("How can I assist you?")
เมื่อรวมหน่วยความจำเข้ากับห่วงโซ่ จำเป็นอย่างยิ่งที่จะต้องเข้าใจตัวแปรที่ส่งคืนจากหน่วยความจำและวิธีการนำไปใช้ในห่วงโซ่ ตัวอย่างเช่น load_memory_variables
วิธีการช่วยจัดแนวตัวแปรที่อ่านจากหน่วยความจำให้สอดคล้องกับความคาดหวังของห่วงโซ่
ตัวอย่างแบบครบวงจรด้วย LangChain
พิจารณาใช้ ConversationBufferMemory
ใน LLMChain
. ห่วงโซ่ที่ผสมผสานกับเทมเพลตข้อความแจ้งที่เหมาะสมและหน่วยความจำ มอบประสบการณ์การสนทนาที่ราบรื่น นี่เป็นตัวอย่างง่ายๆ:
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory llm = OpenAI(temperature=0)
template = "Your conversation template here..."
prompt = PromptTemplate.from_template(template)
memory = ConversationBufferMemory(memory_key="chat_history")
conversation = LLMChain(llm=llm, prompt=prompt, memory=memory) response = conversation({"question": "What's the weather like?"})
ตัวอย่างนี้แสดงให้เห็นว่าระบบหน่วยความจำของ LangChain ทำงานร่วมกับเครือข่ายต่างๆ ได้อย่างไร เพื่อมอบประสบการณ์การสนทนาที่สอดคล้องและคำนึงถึงบริบท
ประเภทหน่วยความจำใน Langchain
Langchain นำเสนอหน่วยความจำหลายประเภทที่สามารถใช้เพื่อปรับปรุงการโต้ตอบกับโมเดล AI หน่วยความจำแต่ละประเภทมีพารามิเตอร์และประเภทการส่งคืนของตัวเอง ทำให้เหมาะสำหรับสถานการณ์ที่แตกต่างกัน มาสำรวจหน่วยความจำบางประเภทที่มีอยู่ใน Langchain พร้อมกับตัวอย่างโค้ดกันดีกว่า
1. หน่วยความจำบัฟเฟอร์การสนทนา
หน่วยความจำประเภทนี้ทำให้คุณสามารถจัดเก็บและดึงข้อความจากการสนทนาได้ คุณสามารถแยกประวัติเป็นสตริงหรือรายการข้อความได้
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) # Extract history as a string
{'history': 'Human: hinAI: whats up'} # Extract history as a list of messages
{'history': [HumanMessage(content='hi', additional_kwargs={}), AIMessage(content='whats up', additional_kwargs={})]}
คุณยังสามารถใช้ Conversation Buffer Memory ต่อเนื่องกันเพื่อการโต้ตอบแบบแชทได้
2. หน่วยความจำหน้าต่างบัฟเฟอร์การสนทนา
หน่วยความจำประเภทนี้จะเก็บรายการการโต้ตอบล่าสุดและใช้การโต้ตอบ K สุดท้าย เพื่อป้องกันไม่ให้บัฟเฟอร์ใหญ่เกินไป
from langchain.memory import ConversationBufferWindowMemory memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
เช่นเดียวกับหน่วยความจำบัฟเฟอร์การสนทนา คุณยังสามารถใช้หน่วยความจำประเภทนี้ในห่วงโซ่สำหรับการโต้ตอบแบบแชทได้
3. หน่วยความจำเอนทิตีการสนทนา
หน่วยความจำประเภทนี้จะจดจำข้อเท็จจริงเกี่ยวกับเอนทิตีเฉพาะในการสนทนา และดึงข้อมูลโดยใช้ LLM
from langchain.memory import ConversationEntityMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationEntityMemory(llm=llm)
_input = {"input": "Deven & Sam are working on a hackathon project"}
memory.load_memory_variables(_input)
memory.save_context( _input, {"output": " That sounds like a great project! What kind of project are they working on?"}
)
memory.load_memory_variables({"input": 'who is Sam'}) {'history': 'Human: Deven & Sam are working on a hackathon projectnAI: That sounds like a great project! What kind of project are they working on?', 'entities': {'Sam': 'Sam is working on a hackathon project with Deven.'}}
4. หน่วยความจำกราฟความรู้การสนทนา
หน่วยความจำประเภทนี้ใช้กราฟความรู้เพื่อสร้างหน่วยความจำขึ้นมาใหม่ คุณสามารถแยกเอนทิตีและความรู้สามเท่าในปัจจุบันออกจากข้อความได้
from langchain.memory import ConversationKGMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationKGMemory(llm=llm)
memory.save_context({"input": "say hi to sam"}, {"output": "who is sam"})
memory.save_context({"input": "sam is a friend"}, {"output": "okay"})
memory.load_memory_variables({"input": "who is sam"}) {'history': 'On Sam: Sam is friend.'}
คุณยังสามารถใช้หน่วยความจำประเภทนี้แบบต่อเนื่องเพื่อดึงความรู้ตามการสนทนาได้
5. หน่วยความจำสรุปการสนทนา
หน่วยความจำประเภทนี้จะสร้างบทสรุปของการสนทนาในช่วงเวลาหนึ่ง ซึ่งมีประโยชน์สำหรับการย่อข้อมูลจากการสนทนาที่ยาวขึ้น
from langchain.memory import ConversationSummaryMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationSummaryMemory(llm=llm)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) {'history': 'nThe human greets the AI, to which the AI responds.'}
6. หน่วยความจำบัฟเฟอร์สรุปการสนทนา
หน่วยความจำประเภทนี้จะรวมสรุปการสนทนาและบัฟเฟอร์เข้าด้วยกัน โดยรักษาสมดุลระหว่างการโต้ตอบล่าสุดและการสรุป ใช้ความยาวโทเค็นเพื่อกำหนดว่าเมื่อใดควรล้างการโต้ตอบ
from langchain.memory import ConversationSummaryBufferMemory
from langchain.llms import OpenAI llm = OpenAI()
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'System: nThe human says "hi", and the AI responds with "whats up".nHuman: not much younAI: not much'}
คุณสามารถใช้ประเภทหน่วยความจำเหล่านี้เพื่อปรับปรุงการโต้ตอบของคุณกับโมเดล AI ใน Langchain หน่วยความจำแต่ละประเภทมีจุดประสงค์เฉพาะและสามารถเลือกได้ตามความต้องการของคุณ
7. หน่วยความจำบัฟเฟอร์โทเค็นการสนทนา
ConversationTokenBufferMemory เป็นหน่วยความจำอีกประเภทหนึ่งที่เก็บบัฟเฟอร์ของการโต้ตอบล่าสุดไว้ในหน่วยความจำ ต่างจากประเภทหน่วยความจำก่อนหน้านี้ที่เน้นไปที่จำนวนการโต้ตอบ หน่วยความจำประเภทนี้ใช้ความยาวโทเค็นเพื่อกำหนดเวลาที่จะล้างการโต้ตอบ
การใช้หน่วยความจำกับ LLM:
from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI llm = OpenAI() memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"}) memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
ในตัวอย่างนี้ หน่วยความจำถูกตั้งค่าให้จำกัดการโต้ตอบตามความยาวของโทเค็นมากกว่าจำนวนการโต้ตอบ
คุณยังสามารถรับประวัติเป็นรายการข้อความเมื่อใช้หน่วยความจำประเภทนี้
memory = ConversationTokenBufferMemory( llm=llm, max_token_limit=10, return_messages=True
)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
ใช้ในห่วงโซ่:
คุณสามารถใช้ ConversationTokenBufferMemory ในห่วงโซ่เพื่อปรับปรุงการโต้ตอบกับโมเดล AI
from langchain.chains import ConversationChain conversation_with_summary = ConversationChain( llm=llm, # We set a very low max_token_limit for the purposes of testing. memory=ConversationTokenBufferMemory(llm=OpenAI(), max_token_limit=60), verbose=True,
)
conversation_with_summary.predict(input="Hi, what's up?")
ในตัวอย่างนี้ ConversationTokenBufferMemory ใช้ใน ConversationChain เพื่อจัดการการสนทนาและจำกัดการโต้ตอบตามความยาวของโทเค็น
8. VectorStoreRetrieverMemory
VectorStoreRetrieverMemory จัดเก็บความทรงจำไว้ใน Vector Store และค้นหาเอกสารที่ “โดดเด่น” ที่สุดในระดับ Top-K ทุกครั้งที่มีการเรียกใช้ หน่วยความจำประเภทนี้ไม่ได้ติดตามลำดับของการโต้ตอบอย่างชัดเจน แต่ใช้การดึงข้อมูลเวกเตอร์เพื่อดึงความทรงจำที่เกี่ยวข้อง
from datetime import datetime
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.memory import VectorStoreRetrieverMemory
from langchain.chains import ConversationChain
from langchain.prompts import PromptTemplate # Initialize your vector store (specifics depend on the chosen vector store)
import faiss
from langchain.docstore import InMemoryDocstore
from langchain.vectorstores import FAISS embedding_size = 1536 # Dimensions of the OpenAIEmbeddings
index = faiss.IndexFlatL2(embedding_size)
embedding_fn = OpenAIEmbeddings().embed_query
vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {}) # Create your VectorStoreRetrieverMemory
retriever = vectorstore.as_retriever(search_kwargs=dict(k=1))
memory = VectorStoreRetrieverMemory(retriever=retriever) # Save context and relevant information to the memory
memory.save_context({"input": "My favorite food is pizza"}, {"output": "that's good to know"})
memory.save_context({"input": "My favorite sport is soccer"}, {"output": "..."})
memory.save_context({"input": "I don't like the Celtics"}, {"output": "ok"}) # Retrieve relevant information from memory based on a query
print(memory.load_memory_variables({"prompt": "what sport should i watch?"})["history"])
ในตัวอย่างนี้ VectorStoreRetrieverMemory ใช้เพื่อจัดเก็บและดึงข้อมูลที่เกี่ยวข้องจากการสนทนาโดยยึดตามการดึงข้อมูลเวกเตอร์
คุณยังสามารถใช้ VectorStoreRetrieverMemory ในห่วงโซ่สำหรับการเรียกค้นความรู้ตามการสนทนา ดังที่แสดงในตัวอย่างก่อนหน้านี้
หน่วยความจำประเภทต่างๆ เหล่านี้ใน Langchain มอบวิธีต่างๆ ในการจัดการและดึงข้อมูลจากการสนทนา เพิ่มความสามารถของโมเดล AI ในการทำความเข้าใจและตอบสนองต่อคำถามและบริบทของผู้ใช้ คุณสามารถเลือกหน่วยความจำแต่ละประเภทได้ตามความต้องการเฉพาะของแอปพลิเคชันของคุณ
ตอนนี้เราจะเรียนรู้วิธีการใช้หน่วยความจำกับ LLMChain หน่วยความจำใน LLMChain ช่วยให้โมเดลจดจำการโต้ตอบและบริบทก่อนหน้านี้ เพื่อให้การตอบสนองที่สอดคล้องกันและคำนึงถึงบริบทมากขึ้น
หากต้องการตั้งค่าหน่วยความจำใน LLMChain คุณต้องสร้างคลาสหน่วยความจำ เช่น ConversationBufferMemory ต่อไปนี้เป็นวิธีการตั้งค่า:
from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.memory import ConversationBufferMemory
from langchain.prompts import PromptTemplate template = """You are a chatbot having a conversation with a human. {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history") llm = OpenAI()
llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) llm_chain.predict(human_input="Hi there my friend")
ในตัวอย่างนี้ ConversationBufferMemory ใช้เพื่อจัดเก็บประวัติการสนทนา ที่ memory_key
พารามิเตอร์ระบุคีย์ที่ใช้จัดเก็บประวัติการสนทนา
หากคุณใช้โมเดลการแชทแทนโมเดลแบบสมบูรณ์ คุณสามารถจัดโครงสร้างการแจ้งเตือนของคุณให้แตกต่างออกไปเพื่อใช้หน่วยความจำได้ดียิ่งขึ้น นี่คือตัวอย่างวิธีตั้งค่า LLMChain ตามโมเดลแชทพร้อมหน่วยความจำ:
from langchain.chat_models import ChatOpenAI
from langchain.schema import SystemMessage
from langchain.prompts import ( ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder,
) # Create a ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages( [ SystemMessage( content="You are a chatbot having a conversation with a human." ), # The persistent system prompt MessagesPlaceholder( variable_name="chat_history" ), # Where the memory will be stored. HumanMessagePromptTemplate.from_template( "{human_input}" ), # Where the human input will be injected ]
) memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) llm = ChatOpenAI() chat_llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) chat_llm_chain.predict(human_input="Hi there my friend")
ในตัวอย่างนี้ ChatPromptTemplate ใช้เพื่อจัดโครงสร้างพรอมต์ และ ConversationBufferMemory ใช้เพื่อจัดเก็บและดึงข้อมูลประวัติการสนทนา วิธีการนี้มีประโยชน์อย่างยิ่งสำหรับการสนทนาในรูปแบบแชทที่บริบทและประวัติศาสตร์มีบทบาทสำคัญ
สามารถเพิ่มหน่วยความจำลงในห่วงโซ่ที่มีอินพุตหลายรายการได้ เช่น ห่วงโซ่คำถาม/คำตอบ ต่อไปนี้คือตัวอย่างวิธีการตั้งค่าหน่วยความจำในห่วงโซ่คำถาม/คำตอบ:
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores.elastic_vector_search import ElasticVectorSearch
from langchain.vectorstores import Chroma
from langchain.docstore.document import Document
from langchain.chains.question_answering import load_qa_chain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.memory import ConversationBufferMemory # Split a long document into smaller chunks
with open("../../state_of_the_union.txt") as f: state_of_the_union = f.read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union) # Create an ElasticVectorSearch instance to index and search the document chunks
embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_texts( texts, embeddings, metadatas=[{"source": i} for i in range(len(texts))]
) # Perform a question about the document
query = "What did the president say about Justice Breyer"
docs = docsearch.similarity_search(query) # Set up a prompt for the question-answering chain with memory
template = """You are a chatbot having a conversation with a human. Given the following extracted parts of a long document and a question, create a final answer. {context} {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input", "context"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input")
chain = load_qa_chain( OpenAI(temperature=0), chain_type="stuff", memory=memory, prompt=prompt
) # Ask the question and retrieve the answer
query = "What did the president say about Justice Breyer"
result = chain({"input_documents": docs, "human_input": query}, return_only_outputs=True) print(result)
print(chain.memory.buffer)
ในตัวอย่างนี้ คำถามจะถูกตอบโดยใช้เอกสารที่แบ่งออกเป็นส่วนเล็กๆ ConversationBufferMemory ใช้เพื่อจัดเก็บและดึงข้อมูลประวัติการสนทนา ช่วยให้โมเดลสามารถให้คำตอบตามบริบทได้
การเพิ่มหน่วยความจำให้กับเอเจนต์ทำให้สามารถจดจำและใช้การโต้ตอบก่อนหน้าเพื่อตอบคำถามและให้การตอบกลับโดยคำนึงถึงบริบท ต่อไปนี้คือวิธีการตั้งค่าหน่วยความจำในตัวแทน:
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor
from langchain.memory import ConversationBufferMemory
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.utilities import GoogleSearchAPIWrapper # Create a tool for searching
search = GoogleSearchAPIWrapper()
tools = [ Tool( name="Search", func=search.run, description="useful for when you need to answer questions about current events", )
] # Create a prompt with memory
prefix = """Have a conversation with a human, answering the following questions as best you can. You have access to the following tools:"""
suffix = """Begin!" {chat_history}
Question: {input}
{agent_scratchpad}""" prompt = ZeroShotAgent.create_prompt( tools, prefix=prefix, suffix=suffix, input_variables=["input", "chat_history", "agent_scratchpad"],
)
memory = ConversationBufferMemory(memory_key="chat_history") # Create an LLMChain with memory
llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)
agent_chain = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, verbose=True, memory=memory
) # Ask a question and retrieve the answer
response = agent_chain.run(input="How many people live in Canada?")
print(response) # Ask a follow-up question
response = agent_chain.run(input="What is their national anthem called?")
print(response)
ในตัวอย่างนี้ หน่วยความจำจะถูกเพิ่มให้กับตัวแทน ทำให้สามารถจดจำประวัติการสนทนาก่อนหน้าและให้คำตอบตามบริบท ช่วยให้ตัวแทนสามารถตอบคำถามติดตามผลได้อย่างถูกต้องตามข้อมูลที่จัดเก็บไว้ในหน่วยความจำ
ภาษานิพจน์ LangChain
ในโลกของการประมวลผลภาษาธรรมชาติและการเรียนรู้ของเครื่อง การสร้างห่วงโซ่การดำเนินงานที่ซับซ้อนอาจเป็นงานที่น่ากังวล โชคดีที่ LangChain Expression Language (LCEL) ได้เข้ามาช่วยเหลือ โดยมอบวิธีการที่ชัดเจนและมีประสิทธิภาพในการสร้างและปรับใช้ไปป์ไลน์การประมวลผลภาษาที่ซับซ้อน LCEL ได้รับการออกแบบมาเพื่อทำให้กระบวนการประกอบโซ่ง่ายขึ้น ทำให้สามารถเปลี่ยนจากการสร้างต้นแบบไปสู่การผลิตได้อย่างง่ายดาย ในบล็อกนี้ เราจะสำรวจว่า LCEL คืออะไร และเหตุใดคุณจึงอาจต้องการใช้ LCEL พร้อมด้วยตัวอย่างโค้ดที่ใช้งานได้จริงเพื่อแสดงความสามารถของ LCEL
LCE หรือ LangChain Expression Language เป็นเครื่องมืออันทรงพลังสำหรับการเขียนห่วงโซ่การประมวลผลภาษา สร้างขึ้นโดยมีจุดประสงค์เพื่อรองรับการเปลี่ยนจากการสร้างต้นแบบไปสู่การใช้งานจริงได้อย่างราบรื่น โดยไม่ต้องเปลี่ยนแปลงโค้ดอย่างกว้างขวาง ไม่ว่าคุณจะสร้างสายโซ่ "prompt + LLM" ง่ายๆ หรือไปป์ไลน์ที่ซับซ้อนที่มีหลายร้อยขั้นตอน LCE ก็ช่วยคุณได้
ต่อไปนี้เป็นเหตุผลบางประการที่ควรใช้ LCE ในโครงการประมวลผลภาษาของคุณ:
- การสตรีมโทเค็นอย่างรวดเร็ว: LCEL ส่งมอบโทเค็นจากโมเดลภาษาไปยังตัวแยกวิเคราะห์เอาต์พุตแบบเรียลไทม์ ปรับปรุงการตอบสนองและประสิทธิภาพ
- API อเนกประสงค์: LCEL รองรับ API ทั้งแบบซิงโครนัสและแบบอะซิงโครนัสสำหรับการสร้างต้นแบบและการใช้งานจริง จัดการคำขอหลายรายการได้อย่างมีประสิทธิภาพ
- การทำงานแบบขนานอัตโนมัติ: LCEL ปรับการดำเนินการแบบขนานให้เหมาะสมเมื่อเป็นไปได้ ลดเวลาแฝงในอินเทอร์เฟซการซิงค์และอะซิงก์
- การกำหนดค่าที่เชื่อถือได้: กำหนดค่าการลองใหม่และการสำรองเพื่อเพิ่มความน่าเชื่อถือของเชนในวงกว้าง พร้อมรองรับการสตรีมในการพัฒนา
- สตรีมผลลัพธ์ระดับกลาง: เข้าถึงผลลัพธ์ระดับกลางระหว่างการประมวลผลเพื่อการอัปเดตผู้ใช้หรือวัตถุประสงค์ในการแก้ไขข้อบกพร่อง
- การสร้างสคีมา: LCEL สร้างสคีมา Pydantic และ JSONSchema สำหรับการตรวจสอบอินพุตและเอาต์พุต
- การติดตามที่ครอบคลุม: LangSmith ติดตามทุกขั้นตอนในห่วงโซ่ที่ซับซ้อนโดยอัตโนมัติเพื่อให้สามารถสังเกตและแก้ไขข้อบกพร่องได้
- ปรับใช้ง่าย: ปรับใช้เชนที่สร้าง LCEL ได้อย่างง่ายดายโดยใช้ LangServe
ตอนนี้ เรามาเจาะลึกตัวอย่างโค้ดที่ใช้งานได้จริงซึ่งแสดงให้เห็นถึงพลังของ LCE กัน เราจะสำรวจงานทั่วไปและสถานการณ์ที่ LCE โดดเด่น
พรอมต์ + LLM
องค์ประกอบพื้นฐานที่สุดเกี่ยวข้องกับการรวมพรอมต์และโมเดลภาษาเพื่อสร้างลูกโซ่ที่รับอินพุตของผู้ใช้ เพิ่มลงในพรอมต์ ส่งต่อไปยังโมเดล และส่งกลับเอาต์พุตโมเดลดิบ นี่คือตัวอย่าง:
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI()
chain = prompt | model result = chain.invoke({"foo": "bears"})
print(result)
ในตัวอย่างนี้ ห่วงโซ่สร้างเรื่องตลกเกี่ยวกับหมี
คุณสามารถแนบลำดับการหยุดเข้ากับเชนของคุณเพื่อควบคุมวิธีการประมวลผลข้อความ ตัวอย่างเช่น:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
การกำหนดค่านี้จะหยุดการสร้างข้อความเมื่อพบอักขระขึ้นบรรทัดใหม่
LCE รองรับการแนบข้อมูลการเรียกใช้ฟังก์ชันเข้ากับเครือข่ายของคุณ นี่คือตัวอย่าง:
functions = [ { "name": "joke", "description": "A joke", "parameters": { "type": "object", "properties": { "setup": {"type": "string", "description": "The setup for the joke"}, "punchline": { "type": "string", "description": "The punchline for the joke", }, }, "required": ["setup", "punchline"], }, }
]
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
result = chain.invoke({"foo": "bears"}, config={})
print(result)
ตัวอย่างนี้แนบข้อมูลการเรียกใช้ฟังก์ชันเพื่อสร้างเรื่องตลก
พร้อมท์ + LLM + OutputParser
คุณสามารถเพิ่มตัวแยกวิเคราะห์เอาต์พุตเพื่อแปลงเอาต์พุตโมเดล Raw ให้เป็นรูปแบบที่ใช้งานได้มากขึ้น ต่อไปนี้คือวิธีที่คุณสามารถทำได้:
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
ขณะนี้เอาต์พุตอยู่ในรูปแบบสตริง ซึ่งสะดวกกว่าสำหรับงานดาวน์สตรีม
เมื่อระบุฟังก์ชันที่จะส่งคืน คุณสามารถแยกวิเคราะห์ได้โดยตรงโดยใช้ LCE ตัวอย่างเช่น:
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser chain = ( prompt | model.bind(function_call={"name": "joke"}, functions=functions) | JsonOutputFunctionsParser()
)
result = chain.invoke({"foo": "bears"})
print(result)
ตัวอย่างนี้แยกวิเคราะห์ผลลัพธ์ของฟังก์ชัน "ตลก" โดยตรง
นี่เป็นเพียงตัวอย่างเล็กๆ น้อยๆ ของวิธีที่ LCEL ลดความซับซ้อนของงานประมวลผลภาษาที่ซับซ้อน ไม่ว่าคุณจะสร้างแชทบอท สร้างเนื้อหา หรือดำเนินการแปลงข้อความที่ซับซ้อน LCE ก็สามารถปรับปรุงขั้นตอนการทำงานของคุณและทำให้โค้ดของคุณสามารถบำรุงรักษาได้มากขึ้น
RAG (รุ่นเสริมการดึงข้อมูล)
LCE สามารถใช้เพื่อสร้างห่วงโซ่การสร้างการดึงข้อมูลที่เพิ่มขึ้น ซึ่งรวมขั้นตอนการสร้างการดึงข้อมูลและภาษา นี่คือตัวอย่าง:
from operator import itemgetter from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.vectorstores import FAISS # Create a vector store and retriever
vectorstore = FAISS.from_texts( ["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever() # Define templates for prompts
template = """Answer the question based only on the following context:
{context} Question: {question} """
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() # Create a retrieval-augmented generation chain
chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | model | StrOutputParser()
) result = chain.invoke("where did harrison work?")
print(result)
ในตัวอย่างนี้ สายโซ่ดึงข้อมูลที่เกี่ยวข้องจากบริบทและสร้างการตอบคำถาม
ห่วงโซ่การดึงการสนทนา
คุณสามารถเพิ่มประวัติการสนทนาในกลุ่มของคุณได้อย่างง่ายดาย นี่คือตัวอย่างของห่วงโซ่การดึงข้อมูลการสนทนา:
from langchain.schema.runnable import RunnableMap
from langchain.schema import format_document from langchain.prompts.prompt import PromptTemplate # Define templates for prompts
_template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language. Chat History:
{chat_history}
Follow Up Input: {question}
Standalone question:"""
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template) template = """Answer the question based only on the following context:
{context} Question: {question} """
ANSWER_PROMPT = ChatPromptTemplate.from_template(template) # Define input map and context
_inputs = RunnableMap( standalone_question=RunnablePassthrough.assign( chat_history=lambda x: _format_chat_history(x["chat_history"]) ) | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
)
_context = { "context": itemgetter("standalone_question") | retriever | _combine_documents, "question": lambda x: x["standalone_question"],
}
conversational_qa_chain = _inputs | _context | ANSWER_PROMPT | ChatOpenAI() result = conversational_qa_chain.invoke( { "question": "where did harrison work?", "chat_history": [], }
)
print(result)
ในตัวอย่างนี้ ห่วงโซ่จะจัดการคำถามติดตามผลภายในบริบทการสนทนา
ด้วยหน่วยความจำและเอกสารต้นฉบับที่ส่งคืน
LCE ยังรองรับหน่วยความจำและการส่งคืนเอกสารต้นฉบับ ต่อไปนี้คือวิธีที่คุณสามารถใช้หน่วยความจำในห่วงโซ่:
from operator import itemgetter
from langchain.memory import ConversationBufferMemory # Create a memory instance
memory = ConversationBufferMemory( return_messages=True, output_key="answer", input_key="question"
) # Define steps for the chain
loaded_memory = RunnablePassthrough.assign( chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"),
) standalone_question = { "standalone_question": { "question": lambda x: x["question"], "chat_history": lambda x: _format_chat_history(x["chat_history"]), } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
} retrieved_documents = { "docs": itemgetter("standalone_question") | retriever, "question": lambda x: x["standalone_question"],
} final_inputs = { "context": lambda x: _combine_documents(x["docs"]), "question": itemgetter("question"),
} answer = { "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(), "docs": itemgetter("docs"),
} # Create the final chain by combining the steps
final_chain = loaded_memory | standalone_question | retrieved_documents | answer inputs = {"question": "where did harrison work?"}
result = final_chain.invoke(inputs)
print(result)
ในตัวอย่างนี้ หน่วยความจำใช้เพื่อจัดเก็บและเรียกข้อมูลประวัติการสนทนาและเอกสารต้นฉบับ
หลายโซ่
คุณสามารถรวมหลาย ๆ เชนเข้าด้วยกันได้โดยใช้ Runnables นี่คือตัวอย่าง:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser prompt1 = ChatPromptTemplate.from_template("what is the city {person} is from?")
prompt2 = ChatPromptTemplate.from_template( "what country is the city {city} in? respond in {language}"
) model = ChatOpenAI() chain1 = prompt1 | model | StrOutputParser() chain2 = ( {"city": chain1, "language": itemgetter("language")} | prompt2 | model | StrOutputParser()
) result = chain2.invoke({"person": "obama", "language": "spanish"})
print(result)
ในตัวอย่างนี้ สองเครือข่ายจะรวมกันเพื่อสร้างข้อมูลเกี่ยวกับเมืองและประเทศในภาษาที่ระบุ
การแตกแขนงและการควบรวมกิจการ
LCE ช่วยให้คุณสามารถแยกและรวมเชนโดยใช้ RunnableMaps ต่อไปนี้เป็นตัวอย่างของการแตกแขนงและการผสาน:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser planner = ( ChatPromptTemplate.from_template("Generate an argument about: {input}") | ChatOpenAI() | StrOutputParser() | {"base_response": RunnablePassthrough()}
) arguments_for = ( ChatPromptTemplate.from_template( "List the pros or positive aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
)
arguments_against = ( ChatPromptTemplate.from_template( "List the cons or negative aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
) final_responder = ( ChatPromptTemplate.from_messages( [ ("ai", "{original_response}"), ("human", "Pros:n{results_1}nnCons:n{results_2}"), ("system", "Generate a final response given the critique"), ] ) | ChatOpenAI() | StrOutputParser()
) chain = ( planner | { "results_1": arguments_for, "results_2": arguments_against, "original_response": itemgetter("base_response"), } | final_responder
) result = chain.invoke({"input": "scrum"})
print(result)
ในตัวอย่างนี้ การแยกสาขาและการรวมสายโซ่ถูกใช้เพื่อสร้างอาร์กิวเมนต์และประเมินข้อดีข้อเสียก่อนที่จะสร้างการตอบกลับขั้นสุดท้าย
การเขียนโค้ด Python ด้วย LCE
หนึ่งในแอปพลิเคชั่นที่ทรงพลังของ LangChain Expression Language (LCEL) คือการเขียนโค้ด Python เพื่อแก้ไขปัญหาของผู้ใช้ ด้านล่างนี้คือตัวอย่างวิธีใช้ LCEL เพื่อเขียนโค้ด Python:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain_experimental.utilities import PythonREPL template = """Write some python code to solve the user's problem. Return only python code in Markdown format, e.g.: ```python
....
```"""
prompt = ChatPromptTemplate.from_messages([("system", template), ("human", "{input}")]) model = ChatOpenAI() def _sanitize_output(text: str): _, after = text.split("```python") return after.split("```")[0] chain = prompt | model | StrOutputParser() | _sanitize_output | PythonREPL().run result = chain.invoke({"input": "what's 2 plus 2"})
print(result)
ในตัวอย่างนี้ ผู้ใช้จัดเตรียมอินพุต และ LCEL จะสร้างโค้ด Python เพื่อแก้ไขปัญหา จากนั้นโค้ดจะถูกดำเนินการโดยใช้ Python REPL และโค้ด Python ที่เป็นผลลัพธ์จะถูกส่งกลับในรูปแบบ Markdown
โปรดทราบว่าการใช้ Python REPL สามารถรันโค้ดได้ตามต้องการ ดังนั้นโปรดใช้ด้วยความระมัดระวัง
การเพิ่มหน่วยความจำให้กับเชน
หน่วยความจำถือเป็นสิ่งสำคัญในแอปพลิเคชัน AI เชิงสนทนาจำนวนมาก ต่อไปนี้เป็นวิธีเพิ่มหน่วยความจำให้กับห่วงโซ่ที่กำหนดเอง:
from operator import itemgetter
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder model = ChatOpenAI()
prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful chatbot"), MessagesPlaceholder(variable_name="history"), ("human", "{input}"), ]
) memory = ConversationBufferMemory(return_messages=True) # Initialize memory
memory.load_memory_variables({}) chain = ( RunnablePassthrough.assign( history=RunnableLambda(memory.load_memory_variables) | itemgetter("history") ) | prompt | model
) inputs = {"input": "hi, I'm Bob"}
response = chain.invoke(inputs)
response # Save the conversation in memory
memory.save_context(inputs, {"output": response.content}) # Load memory to see the conversation history
memory.load_memory_variables({})
ในตัวอย่างนี้ หน่วยความจำถูกใช้เพื่อจัดเก็บและเรียกค้นประวัติการสนทนา ช่วยให้แชทบอตสามารถรักษาบริบทและตอบสนองได้อย่างเหมาะสม
การใช้เครื่องมือภายนอกกับ Runnables
LCE ช่วยให้คุณสามารถรวมเครื่องมือภายนอกเข้ากับ Runnables ได้อย่างราบรื่น นี่คือตัวอย่างการใช้เครื่องมือค้นหา DuckDuckGo:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.tools import DuckDuckGoSearchRun search = DuckDuckGoSearchRun() template = """Turn the following user input into a search query for a search engine: {input}"""
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() chain = prompt | model | StrOutputParser() | search search_result = chain.invoke({"input": "I'd like to figure out what games are tonight"})
print(search_result)
ในตัวอย่างนี้ Lcel ผสานรวมเครื่องมือค้นหา DuckDuckGo เข้ากับห่วงโซ่ ทำให้สามารถสร้างคำค้นหาจากการป้อนข้อมูลของผู้ใช้และดึงผลการค้นหาได้
ความยืดหยุ่นของ LCE ทำให้ง่ายต่อการรวมเครื่องมือและบริการภายนอกต่างๆ เข้ากับขั้นตอนการประมวลผลภาษาของคุณ ช่วยเพิ่มขีดความสามารถและฟังก์ชันการทำงาน
การเพิ่มการกลั่นกรองให้กับแอปพลิเคชัน LLM
เพื่อให้แน่ใจว่าแอปพลิเคชัน LLM ของคุณปฏิบัติตามนโยบายเนื้อหาและมีการป้องกันการกลั่นกรอง คุณสามารถรวมการตรวจสอบการกลั่นกรองเข้ากับห่วงโซ่ของคุณได้ ต่อไปนี้เป็นวิธีเพิ่มการกลั่นกรองโดยใช้ LangChain:
from langchain.chains import OpenAIModerationChain
from langchain.llms import OpenAI
from langchain.prompts import ChatPromptTemplate moderate = OpenAIModerationChain() model = OpenAI()
prompt = ChatPromptTemplate.from_messages([("system", "repeat after me: {input}")]) chain = prompt | model # Original response without moderation
response_without_moderation = chain.invoke({"input": "you are stupid"})
print(response_without_moderation) moderated_chain = chain | moderate # Response after moderation
response_after_moderation = moderated_chain.invoke({"input": "you are stupid"})
print(response_after_moderation)
ในตัวอย่างนี้ OpenAIModerationChain
ใช้เพื่อเพิ่มการกลั่นกรองการตอบสนองที่สร้างโดย LLM สายการกลั่นกรองจะตรวจสอบการตอบสนองต่อเนื้อหาที่ละเมิดนโยบายเนื้อหาของ OpenAI หากพบการละเมิดใด ๆ จะทำเครื่องหมายการตอบสนองตามนั้น
การกำหนดเส้นทางโดยความคล้ายคลึงกันของความหมาย
LCEL ช่วยให้คุณสามารถใช้ลอจิกการกำหนดเส้นทางที่กำหนดเองโดยยึดตามความคล้ายคลึงทางความหมายของอินพุตของผู้ใช้ ต่อไปนี้เป็นตัวอย่างวิธีการกำหนดตรรกะลูกโซ่แบบไดนามิกตามอินพุตของผู้ใช้:
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableLambda, RunnablePassthrough
from langchain.utils.math import cosine_similarity physics_template = """You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know. Here is a question:
{query}""" math_template = """You are a very good mathematician. You are great at answering math questions. You are so good because you are able to break down hard problems into their component parts, answer the component parts, and then put them together to answer the broader question. Here is a question:
{query}""" embeddings = OpenAIEmbeddings()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates) def prompt_router(input): query_embedding = embeddings.embed_query(input["query"]) similarity = cosine_similarity([query_embedding], prompt_embeddings)[0] most_similar = prompt_templates[similarity.argmax()] print("Using MATH" if most_similar == math_template else "Using PHYSICS") return PromptTemplate.from_template(most_similar) chain = ( {"query": RunnablePassthrough()} | RunnableLambda(prompt_router) | ChatOpenAI() | StrOutputParser()
) print(chain.invoke({"query": "What's a black hole"}))
print(chain.invoke({"query": "What's a path integral"}))
ในตัวอย่างนี้ prompt_router
ฟังก์ชั่นคำนวณความคล้ายคลึงโคไซน์ระหว่างอินพุตของผู้ใช้และเทมเพลตพรอมต์ที่กำหนดไว้ล่วงหน้าสำหรับคำถามฟิสิกส์และคณิตศาสตร์ จากคะแนนความคล้ายคลึงกัน ห่วงโซ่จะเลือกเทมเพลตข้อความแจ้งที่เกี่ยวข้องมากที่สุดแบบไดนามิก เพื่อให้มั่นใจว่าแชทบอทจะตอบคำถามของผู้ใช้ได้อย่างเหมาะสม
การใช้ตัวแทนและรันเอเบิล
LangChain ช่วยให้คุณสร้างตัวแทนโดยรวม Runnables, prompts, model และ tools เข้าด้วยกัน นี่คือตัวอย่างของการสร้างตัวแทนและการใช้งาน:
from langchain.agents import XMLAgent, tool, AgentExecutor
from langchain.chat_models import ChatAnthropic model = ChatAnthropic(model="claude-2") @tool
def search(query: str) -> str: """Search things about current events.""" return "32 degrees" tool_list = [search] # Get prompt to use
prompt = XMLAgent.get_default_prompt() # Logic for going from intermediate steps to a string to pass into the model
def convert_intermediate_steps(intermediate_steps): log = "" for action, observation in intermediate_steps: log += ( f"<tool>{action.tool}</tool><tool_input>{action.tool_input}" f"</tool_input><observation>{observation}</observation>" ) return log # Logic for converting tools to a string to go in the prompt
def convert_tools(tools): return "n".join([f"{tool.name}: {tool.description}" for tool in tools]) agent = ( { "question": lambda x: x["question"], "intermediate_steps": lambda x: convert_intermediate_steps( x["intermediate_steps"] ), } | prompt.partial(tools=convert_tools(tool_list)) | model.bind(stop=["</tool_input>", "</final_answer>"]) | XMLAgent.get_default_output_parser()
) agent_executor = AgentExecutor(agent=agent, tools=tool_list, verbose=True) result = agent_executor.invoke({"question": "What's the weather in New York?"})
print(result)
ในตัวอย่างนี้ เอเจนต์จะถูกสร้างขึ้นโดยรวมโมเดล เครื่องมือ พรอมต์ และตรรกะที่กำหนดเองสำหรับขั้นตอนกลางและการแปลงเครื่องมือ จากนั้นตัวแทนจะถูกดำเนินการ โดยให้การตอบสนองต่อคำถามของผู้ใช้
การสืบค้นฐานข้อมูล SQL
คุณสามารถใช้ LangChain เพื่อสืบค้นฐานข้อมูล SQL และสร้างคำสั่ง SQL ตามคำถามของผู้ใช้ นี่คือตัวอย่าง:
from langchain.prompts import ChatPromptTemplate template = """Based on the table schema below, write a SQL query that would answer the user's question:
{schema} Question: {question}
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template) from langchain.utilities import SQLDatabase # Initialize the database (you'll need the Chinook sample DB for this example)
db = SQLDatabase.from_uri("sqlite:///./Chinook.db") def get_schema(_): return db.get_table_info() def run_query(query): return db.run(query) from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough model = ChatOpenAI() sql_response = ( RunnablePassthrough.assign(schema=get_schema) | prompt | model.bind(stop=["nSQLResult:"]) | StrOutputParser()
) result = sql_response.invoke({"question": "How many employees are there?"})
print(result) template = """Based on the table schema below, question, SQL query, and SQL response, write a natural language response:
{schema} Question: {question}
SQL Query: {query}
SQL Response: {response}"""
prompt_response = ChatPromptTemplate.from_template(template) full_chain = ( RunnablePassthrough.assign(query=sql_response) | RunnablePassthrough.assign( schema=get_schema, response=lambda x: db.run(x["query"]), ) | prompt_response | model
) response = full_chain.invoke({"question": "How many employees are there?"})
print(response)
ในตัวอย่างนี้ LangChain ใช้เพื่อสร้างแบบสอบถาม SQL ตามคำถามของผู้ใช้และดึงคำตอบจากฐานข้อมูล SQL พรอมต์และการตอบกลับได้รับการจัดรูปแบบเพื่อให้มีการโต้ตอบด้วยภาษาธรรมชาติกับฐานข้อมูล
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
แลงเซิร์ฟ และ แลงสมิธ
LangServe ช่วยให้นักพัฒนาปรับใช้รันเนอร์และเชนของ LangChain เป็น REST API ไลบรารีนี้รวมเข้ากับ FastAPI และใช้ pydantic สำหรับการตรวจสอบข้อมูล นอกจากนี้ยังมีไคลเอนต์ที่สามารถใช้เพื่อเรียกใช้ runnables ที่ปรับใช้บนเซิร์ฟเวอร์ และไคลเอนต์ JavaScript มีให้ใช้งานใน LangChainJS
คุณสมบัติ
- สคีมาอินพุตและเอาท์พุตจะถูกอนุมานจากออบเจ็กต์ LangChain ของคุณโดยอัตโนมัติ และบังคับใช้กับการเรียก API ทุกครั้ง พร้อมด้วยข้อความแสดงข้อผิดพลาดมากมาย
- หน้าเอกสาร API ที่มี JSONSchema และ Swagger พร้อมใช้งาน
- ตำแหน่งข้อมูล /involve, /batch และ /stream ที่มีประสิทธิภาพพร้อมรองรับคำขอจำนวนมากพร้อมกันบนเซิร์ฟเวอร์เดียว
- /stream_log endpoint สำหรับการสตรีมขั้นตอนกลางทั้งหมด (หรือบางส่วน) จากเชน/เอเจนต์ของคุณ
- หน้า Playground ที่ /playground พร้อมเอาต์พุตแบบสตรีมมิ่งและขั้นกลาง
- การติดตาม LangSmith ในตัว (เป็นทางเลือก) เพียงเพิ่มคีย์ API ของคุณ (ดูคำแนะนำ)
- ทั้งหมดนี้สร้างขึ้นด้วยไลบรารี Python แบบโอเพ่นซอร์สที่ผ่านการทดสอบการต่อสู้ เช่น FastAPI, Pydantic, uvloop และ asyncio
ข้อ จำกัด
- ยังไม่รองรับการเรียกกลับของไคลเอ็นต์สำหรับเหตุการณ์ที่เกิดขึ้นบนเซิร์ฟเวอร์
- เอกสาร OpenAPI จะไม่ถูกสร้างขึ้นเมื่อใช้ Pydantic V2 FastAPI ไม่รองรับการผสมเนมสเปซ pydantic v1 และ v2 ดูส่วนด้านล่างสำหรับรายละเอียดเพิ่มเติม
ใช้ LangChain CLI เพื่อบูตโปรเจ็กต์ LangServe อย่างรวดเร็ว หากต้องการใช้ langchain CLI ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง langchain-cli เวอร์ชันล่าสุดแล้ว คุณสามารถติดตั้งได้ด้วย pip install -U langchain-cli
langchain app new ../path/to/directory
เริ่มต้นอินสแตนซ์ LangServe ของคุณอย่างรวดเร็วด้วยเทมเพลต LangChain สำหรับตัวอย่างเพิ่มเติม โปรดดูที่ดัชนีเทมเพลตหรือไดเร็กทอรีตัวอย่าง
นี่คือเซิร์ฟเวอร์ที่ใช้โมเดลการแชท OpenAI โมเดลการแชท Anthropic และเครือข่ายที่ใช้โมเดล Anthropic เพื่อเล่าเรื่องตลกเกี่ยวกับหัวข้อต่างๆ
#!/usr/bin/env python
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langserve import add_routes app = FastAPI( title="LangChain Server", version="1.0", description="A simple api server using Langchain's Runnable interfaces",
) add_routes( app, ChatOpenAI(), path="/openai",
) add_routes( app, ChatAnthropic(), path="/anthropic",
) model = ChatAnthropic()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
add_routes( app, prompt | model, path="/chain",
) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="localhost", port=8000)
เมื่อคุณปรับใช้เซิร์ฟเวอร์ข้างต้นแล้ว คุณสามารถดูเอกสาร OpenAPI ที่สร้างขึ้นได้โดยใช้:
curl localhost:8000/docs
อย่าลืมเพิ่มส่วนต่อท้าย /docs
from langchain.schema import SystemMessage, HumanMessage
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap
from langserve import RemoteRunnable openai = RemoteRunnable("http://localhost:8000/openai/")
anthropic = RemoteRunnable("http://localhost:8000/anthropic/")
joke_chain = RemoteRunnable("http://localhost:8000/chain/") joke_chain.invoke({"topic": "parrots"}) # or async
await joke_chain.ainvoke({"topic": "parrots"}) prompt = [ SystemMessage(content='Act like either a cat or a parrot.'), HumanMessage(content='Hello!')
] # Supports astream
async for msg in anthropic.astream(prompt): print(msg, end="", flush=True) prompt = ChatPromptTemplate.from_messages( [("system", "Tell me a long story about {topic}")]
) # Can define custom chains
chain = prompt | RunnableMap({ "openai": openai, "anthropic": anthropic,
}) chain.batch([{ "topic": "parrots" }, { "topic": "cats" }])
ใน TypeScript (ต้องใช้ LangChain.js เวอร์ชัน 0.0.166 หรือใหม่กว่า):
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python โดยใช้คำขอ:
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
คุณยังสามารถใช้ curl:
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
รหัสต่อไปนี้:
...
add_routes( app, runnable, path="/my_runnable",
)
เพิ่มจุดสิ้นสุดเหล่านี้ไปยังเซิร์ฟเวอร์:
- POST /my_runnable/intake – เรียกใช้ runnable ในอินพุตเดียว
- POST /my_runnable/batch – เรียกใช้ runnable บนชุดอินพุต
- POST /my_runnable/stream – เรียกใช้อินพุตเดียวและสตรีมเอาต์พุต
- POST /my_runnable/stream_log – เรียกใช้อินพุตเดียวและสตรีมเอาต์พุต รวมถึงเอาต์พุตของขั้นตอนกลางในขณะที่ถูกสร้างขึ้น
- GET /my_runnable/input_schema – json schema สำหรับอินพุตไปยัง runnable
- GET /my_runnable/output_schema – json schema สำหรับเอาต์พุตของ runnable
- GET /my_runnable/config_schema – json schema สำหรับการกำหนดค่าของ runnable
คุณสามารถค้นหาหน้า Playground สำหรับรันของคุณได้ที่ /my_runnable/playground สิ่งนี้จะแสดง UI แบบง่ายในการกำหนดค่าและเรียกใช้สิ่งที่รันได้ของคุณด้วยเอาต์พุตสตรีมมิ่งและขั้นตอนระดับกลาง
สำหรับทั้งไคลเอนต์และเซิร์ฟเวอร์:
pip install "langserve[all]"
หรือ pip ติดตั้ง “langserve[client]” สำหรับโค้ดไคลเอ็นต์ และ pip ติดตั้ง “langserve[server]” สำหรับโค้ดเซิร์ฟเวอร์
หากคุณต้องการเพิ่มการรับรองความถูกต้องให้กับเซิร์ฟเวอร์ของคุณ โปรดอ้างอิงเอกสารการรักษาความปลอดภัยของ FastAPI และเอกสารมิดเดิลแวร์
คุณทำให้ GCP Cloud Run ใช้งานได้โดยใช้คำสั่งต่อไปนี้
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe ให้การสนับสนุน Pydantic 2 โดยมีข้อจำกัดบางประการ เอกสาร OpenAPI จะไม่ถูกสร้างขึ้นสำหรับการเรียกใช้/แบทช์/สตรีม/สตรีม_log เมื่อใช้ Pydantic V2 Fast API ไม่รองรับการผสมเนมสเปซ pydantic v1 และ v2 LangChain ใช้เนมสเปซ v1 ใน Pydantic v2 โปรดอ่านคำแนะนำต่อไปนี้เพื่อให้แน่ใจว่าสามารถใช้งานร่วมกับ LangChain ได้ ยกเว้นข้อจำกัดเหล่านี้ เราคาดว่าตำแหน่งข้อมูล API, Playground และฟีเจอร์อื่นๆ จะทำงานตามที่คาดไว้
แอปพลิเคชัน LLM มักจะจัดการกับไฟล์ มีสถาปัตยกรรมที่แตกต่างกันที่สามารถสร้างเพื่อใช้การประมวลผลไฟล์ ในระดับสูง:
- ไฟล์อาจถูกอัพโหลดไปยังเซิร์ฟเวอร์ผ่านทางจุดสิ้นสุดเฉพาะและประมวลผลโดยใช้จุดสิ้นสุดที่แยกต่างหาก
- ไฟล์อาจถูกอัปโหลดตามค่า (ไบต์ของไฟล์) หรือการอ้างอิง (เช่น s3 url ไปยังเนื้อหาไฟล์)
- จุดสิ้นสุดการประมวลผลอาจบล็อกหรือไม่บล็อก
- หากจำเป็นต้องมีการประมวลผลที่สำคัญ การประมวลผลอาจถูกออฟโหลดไปยังกลุ่มกระบวนการเฉพาะ
คุณควรพิจารณาว่าสถาปัตยกรรมใดที่เหมาะสมสำหรับแอปพลิเคชันของคุณ ในปัจจุบัน หากต้องการอัปโหลดไฟล์ตามค่าไปยัง runable ให้ใช้การเข้ารหัส base64 สำหรับไฟล์ (ยังไม่รองรับ multipart/form-data)
นี่คือ ตัวอย่าง ที่แสดงวิธีใช้การเข้ารหัส base64 เพื่อส่งไฟล์ไปยังรีโมตที่รันได้ โปรดจำไว้ว่า คุณสามารถอัปโหลดไฟล์โดยการอ้างอิง (เช่น s3 url) หรืออัปโหลดเป็นหลายส่วน/ฟอร์มข้อมูลไปยังจุดสิ้นสุดเฉพาะได้เสมอ
ประเภทอินพุตและเอาต์พุตถูกกำหนดไว้ใน runnable ทั้งหมด คุณสามารถเข้าถึงได้ผ่านคุณสมบัติ input_schema และ output_schema LangServe ใช้ประเภทเหล่านี้ในการตรวจสอบและจัดทำเอกสาร หากคุณต้องการแทนที่ประเภทอนุมานเริ่มต้น คุณสามารถใช้เมธอด with_types
นี่คือตัวอย่างของเล่นเพื่ออธิบายแนวคิด:
from typing import Any
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda app = FastAPI() def func(x: Any) -> int: """Mistyped function that should accept an int but accepts anything.""" return x + 1 runnable = RunnableLambda(func).with_types( input_schema=int,
) add_routes(app, runnable)
รับค่าจาก CustomUserType หากคุณต้องการให้ข้อมูลดีซีเรียลไลซ์เป็นรูปแบบ pydantic แทนที่จะเป็นการแสดง dict ที่เทียบเท่ากัน ในขณะนี้ ประเภทนี้ใช้งานได้เฉพาะฝั่งเซิร์ฟเวอร์และใช้เพื่อระบุลักษณะการถอดรหัสที่ต้องการ หากสืบทอดจากประเภทนี้ เซิร์ฟเวอร์จะเก็บประเภทที่ถอดรหัสไว้เป็นโมเดล pydantic แทนที่จะแปลงเป็น dict
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
from langserve import add_routes
from langserve.schema import CustomUserType app = FastAPI() class Foo(CustomUserType): bar: int def func(foo: Foo) -> int: """Sample function that expects a Foo type which is a pydantic model""" assert isinstance(foo, Foo) return foo.bar add_routes(app, RunnableLambda(func), path="/foo")
Playground ช่วยให้คุณสามารถกำหนดวิดเจ็ตแบบกำหนดเองสำหรับการเรียกใช้จากแบ็กเอนด์ได้ มีการระบุวิดเจ็ตที่ระดับฟิลด์และจัดส่งเป็นส่วนหนึ่งของสคีมา JSON ของประเภทอินพุต วิดเจ็ตจะต้องมีคีย์ที่เรียกว่า type โดยค่าเป็นหนึ่งในรายการวิดเจ็ตที่รู้จักกันดี คีย์วิดเจ็ตอื่นๆ จะเชื่อมโยงกับค่าที่อธิบายเส้นทางในออบเจ็กต์ JSON
สคีมาทั่วไป:
type JsonPath = number | string | (number | string)[];
type NameSpacedPath = { title: string; path: JsonPath }; // Using title to mimic json schema, but can use namespace
type OneOfPath = { oneOf: JsonPath[] }; type Widget = { type: string // Some well-known type (e.g., base64file, chat, etc.) [key: string]: JsonPath | NameSpacedPath | OneOfPath;
};
อนุญาตให้สร้างอินพุตการอัปโหลดไฟล์ใน UI Playground สำหรับไฟล์ที่อัปโหลดเป็นสตริงที่เข้ารหัส base64 นี่คือตัวอย่างแบบเต็ม
try: from pydantic.v1 import Field
except ImportError: from pydantic import Field from langserve import CustomUserType # ATTENTION: Inherit from CustomUserType instead of BaseModel otherwise
# the server will decode it into a dict instead of a pydantic model.
class FileProcessingRequest(CustomUserType): """Request including a base64 encoded file.""" # The extra field is used to specify a widget for the playground UI. file: str = Field(..., extra={"widget": {"type": "base64file"}}) num_chars: int = 100
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
ความรู้เบื้องต้นเกี่ยวกับแลงสมิธ
LangChain ทำให้การสร้างต้นแบบแอปพลิเคชันและตัวแทน LLM เป็นเรื่องง่าย อย่างไรก็ตาม การนำส่งแอปพลิเคชัน LLM ไปสู่การใช้งานจริงอาจเป็นเรื่องยาก คุณอาจต้องปรับแต่งและทำซ้ำกับพร้อมท์ เชน และส่วนประกอบอื่นๆ อย่างหนักเพื่อสร้างผลิตภัณฑ์คุณภาพสูง
เพื่อช่วยในกระบวนการนี้ จึงได้เปิดตัว LangSmith ซึ่งเป็นแพลตฟอร์มแบบครบวงจรสำหรับการดีบัก ทดสอบ และติดตามแอปพลิเคชัน LLM ของคุณ
สิ่งนี้จะมีประโยชน์เมื่อใด? คุณอาจพบว่ามีประโยชน์เมื่อคุณต้องการดีบักเชน เอเจนต์ หรือชุดเครื่องมือใหม่อย่างรวดเร็ว แสดงภาพว่าส่วนประกอบต่างๆ (เชน llms ตัวดึงข้อมูล ฯลฯ) เกี่ยวข้องและใช้งานอย่างไร ประเมินพร้อมท์และ LLM ที่แตกต่างกันสำหรับส่วนประกอบเดียว รันเชนที่กำหนดหลายครั้งบนชุดข้อมูลเพื่อให้แน่ใจว่าเป็นไปตามแถบคุณภาพอย่างสม่ำเสมอ หรือบันทึกการติดตามการใช้งาน และใช้ LLM หรือไปป์ไลน์การวิเคราะห์เพื่อสร้างข้อมูลเชิงลึก
ที่ต้องการ:
- สร้างบัญชี LangSmith และสร้างคีย์ API (ดูมุมซ้ายล่าง)
- ทำความคุ้นเคยกับแพลตฟอร์มโดยดูจากเอกสาร
เริ่มกันเลย!
ขั้นแรก กำหนดค่าตัวแปรสภาพแวดล้อมของคุณเพื่อบอกให้ LangChain บันทึกการติดตาม ซึ่งทำได้โดยการตั้งค่าตัวแปรสภาพแวดล้อม LANGCHAIN_TRACING_V2 ให้เป็นจริง คุณสามารถบอก LangChain ได้ว่าโครงการใดที่จะเข้าสู่ระบบโดยการตั้งค่าตัวแปรสภาพแวดล้อม LANGCHAIN_PROJECT (หากไม่ได้ตั้งค่าไว้ การรันจะถูกบันทึกเป็นโครงการเริ่มต้น) สิ่งนี้จะสร้างโปรเจ็กต์ให้คุณโดยอัตโนมัติหากไม่มีอยู่ คุณต้องตั้งค่าตัวแปรสภาพแวดล้อม LANGCHAIN_ENDPOINT และ LANGCHAIN_API_KEY ด้วย
หมายเหตุ: คุณยังสามารถใช้ตัวจัดการบริบทในหลามเพื่อบันทึกการติดตามโดยใช้:
from langchain.callbacks.manager import tracing_v2_enabled with tracing_v2_enabled(project_name="My Project"): agent.run("How many people live in canada as of 2023?")
อย่างไรก็ตาม ในตัวอย่างนี้ เราจะใช้ตัวแปรสภาพแวดล้อม
%pip install openai tiktoken pandas duckduckgo-search --quiet import os
from uuid import uuid4 unique_id = uuid4().hex[0:8]
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = f"Tracing Walkthrough - {unique_id}"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "<YOUR-API-KEY>" # Update to your API key # Used by the agent in this tutorial
os.environ["OPENAI_API_KEY"] = "<YOUR-OPENAI-API-KEY>"
สร้างไคลเอ็นต์ LangSmith เพื่อโต้ตอบกับ API:
from langsmith import Client client = Client()
สร้างส่วนประกอบ LangChain และบันทึกการทำงานไปยังแพลตฟอร์ม ในตัวอย่างนี้ เราจะสร้างเอเจนต์สไตล์ ReAct ที่สามารถเข้าถึงเครื่องมือค้นหาทั่วไป (DuckDuckGo) สามารถดูพร้อมท์ของตัวแทนได้ในฮับที่นี่:
from langchain import hub
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
from langchain.chat_models import ChatOpenAI
from langchain.tools import DuckDuckGoSearchResults
from langchain.tools.render import format_tool_to_openai_function # Fetches the latest version of this prompt
prompt = hub.pull("wfh/langsmith-agent-prompt:latest") llm = ChatOpenAI( model="gpt-3.5-turbo-16k", temperature=0,
) tools = [ DuckDuckGoSearchResults( name="duck_duck_go" ), # General internet search using DuckDuckGo
] llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools]) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
) agent_executor = AgentExecutor( agent=runnable_agent, tools=tools, handle_parsing_errors=True
)
เรากำลังเรียกใช้เอเจนต์พร้อมกันกับอินพุตหลายตัวเพื่อลดเวลาแฝง การรันจะถูกบันทึกไปที่ LangSmith ในเบื้องหลัง ดังนั้นเวลาแฝงในการดำเนินการจึงไม่ได้รับผลกระทบ:
inputs = [ "What is LangChain?", "What's LangSmith?", "When was Llama-v2 released?", "What is the langsmith cookbook?", "When did langchain first announce the hub?",
] results = agent_executor.batch([{"input": x} for x in inputs], return_exceptions=True) results[:2]
สมมติว่าคุณได้ตั้งค่าสภาพแวดล้อมของคุณสำเร็จแล้ว การติดตามตัวแทนของคุณควรแสดงในส่วนโครงการในแอป ยินดีด้วย!
ดูเหมือนว่าตัวแทนไม่ได้ใช้เครื่องมืออย่างมีประสิทธิภาพ ลองประเมินสิ่งนี้เพื่อให้เรามีพื้นฐาน
นอกเหนือจากการรันการบันทึกแล้ว LangSmith ยังให้คุณทดสอบและประเมินแอปพลิเคชัน LLM ของคุณอีกด้วย
ในส่วนนี้ คุณจะใช้ประโยชน์จาก LangSmith เพื่อสร้างชุดข้อมูลการวัดประสิทธิภาพและเรียกใช้ผู้ประเมินที่ได้รับความช่วยเหลือจาก AI บนตัวแทน คุณจะดำเนินการได้ในไม่กี่ขั้นตอน:
- สร้างชุดข้อมูล LangSmith:
ด้านล่างนี้ เราใช้ไคลเอ็นต์ LangSmith เพื่อสร้างชุดข้อมูลจากคำถามอินพุตจากด้านบนและป้ายกำกับรายการ คุณจะใช้สิ่งเหล่านี้ในภายหลังเพื่อวัดประสิทธิภาพของตัวแทนใหม่ ชุดข้อมูลคือชุดของตัวอย่าง ซึ่งไม่มีอะไรมากไปกว่าคู่อินพุต-เอาต์พุตที่คุณสามารถใช้เป็นกรณีทดสอบกับแอปพลิเคชันของคุณ:
outputs = [ "LangChain is an open-source framework for building applications using large language models. It is also the name of the company building LangSmith.", "LangSmith is a unified platform for debugging, testing, and monitoring language model applications and agents powered by LangChain", "July 18, 2023", "The langsmith cookbook is a github repository containing detailed examples of how to use LangSmith to debug, evaluate, and monitor large language model-powered applications.", "September 5, 2023",
] dataset_name = f"agent-qa-{unique_id}" dataset = client.create_dataset( dataset_name, description="An example dataset of questions over the LangSmith documentation.",
) for query, answer in zip(inputs, outputs): client.create_example( inputs={"input": query}, outputs={"output": answer}, dataset_id=dataset.id )
- เริ่มต้นเอเจนต์ใหม่เพื่อวัดประสิทธิภาพ:
LangSmith ช่วยให้คุณประเมิน LLM, เชน, เอเจนต์ หรือแม้แต่ฟังก์ชันแบบกำหนดเองได้ เจ้าหน้าที่การสนทนามีสถานะ (มีหน่วยความจำ) เพื่อให้แน่ใจว่าสถานะนี้จะไม่ถูกแชร์ระหว่างการรันชุดข้อมูล เราจะส่งผ่านใน chain_factory (
หรือที่เรียกว่า Constructor) เพื่อเริ่มต้นสำหรับการโทรแต่ละครั้ง:
# Since chains can be stateful (e.g. they can have memory), we provide
# a way to initialize a new chain for each row in the dataset. This is done
# by passing in a factory function that returns a new chain for each row.
def agent_factory(prompt): llm_with_tools = llm.bind( functions=[format_tool_to_openai_function(t) for t in tools] ) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser() ) return AgentExecutor(agent=runnable_agent, tools=tools, handle_parsing_errors=True)
- กำหนดค่าการประเมิน:
การเปรียบเทียบผลลัพธ์ของเชนใน UI ด้วยตนเองนั้นมีประสิทธิภาพ แต่อาจใช้เวลานาน การใช้ตัววัดอัตโนมัติและข้อเสนอแนะที่ได้รับความช่วยเหลือจาก AI เพื่อประเมินประสิทธิภาพของส่วนประกอบของคุณอาจเป็นประโยชน์:
from langchain.evaluation import EvaluatorType
from langchain.smith import RunEvalConfig evaluation_config = RunEvalConfig( evaluators=[ EvaluatorType.QA, EvaluatorType.EMBEDDING_DISTANCE, RunEvalConfig.LabeledCriteria("helpfulness"), RunEvalConfig.LabeledScoreString( { "accuracy": """
Score 1: The answer is completely unrelated to the reference.
Score 3: The answer has minor relevance but does not align with the reference.
Score 5: The answer has moderate relevance but contains inaccuracies.
Score 7: The answer aligns with the reference but has minor errors or omissions.
Score 10: The answer is completely accurate and aligns perfectly with the reference.""" }, normalize_by=10, ), ], custom_evaluators=[],
)
- รันตัวแทนและผู้ประเมิน:
ใช้ฟังก์ชัน run_on_dataset (หรือ arun_on_dataset แบบอะซิงโครนัส) เพื่อประเมินโมเดลของคุณ นี่จะ:
- ดึงแถวตัวอย่างจากชุดข้อมูลที่ระบุ
- เรียกใช้ตัวแทนของคุณ (หรือฟังก์ชันที่กำหนดเอง) ในแต่ละตัวอย่าง
- ใช้ตัวประเมินกับการติดตามการรันผลลัพธ์และตัวอย่างอ้างอิงที่เกี่ยวข้องเพื่อสร้างผลตอบรับอัตโนมัติ
ผลลัพธ์จะปรากฏในแอป LangSmith:
chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-5d466cbc-{unique_id}", tags=[ "testing-notebook", "prompt:5d466cbc", ],
)
ตอนนี้เรามีผลการทดสอบการทำงานแล้ว เราก็สามารถเปลี่ยนแปลงตัวแทนของเราและเปรียบเทียบมาตรฐานได้ ลองอีกครั้งโดยใช้ข้อความแจ้งอื่นและดูผลลัพธ์:
candidate_prompt = hub.pull("wfh/langsmith-agent-prompt:39f3bbd0") chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=candidate_prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-39f3bbd0-{unique_id}", tags=[ "testing-notebook", "prompt:39f3bbd0", ],
)
LangSmith ช่วยให้คุณสามารถส่งออกข้อมูลเป็นรูปแบบทั่วไป เช่น CSV หรือ JSONL ได้โดยตรงในเว็บแอป คุณยังสามารถใช้ไคลเอ็นต์เพื่อดึงข้อมูลการทำงานเพื่อการวิเคราะห์เพิ่มเติม จัดเก็บในฐานข้อมูลของคุณเอง หรือแชร์กับผู้อื่นได้ มาดึงข้อมูลการติดตามการรันจากการรันการประเมิน:
runs = client.list_runs(project_name=chain_results["project_name"], execution_order=1) # After some time, these will be populated.
client.read_project(project_name=chain_results["project_name"]).feedback_stats
นี่เป็นคำแนะนำโดยย่อในการเริ่มต้น แต่มีหลายวิธีในการใช้ LangSmith เพื่อเร่งการไหลของนักพัฒนาและให้ผลลัพธ์ที่ดีขึ้น
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่คุณสามารถใช้ LangSmith ให้เกิดประโยชน์สูงสุด โปรดดูเอกสารประกอบของ LangSmith
เพิ่มระดับด้วย Nanonets
แม้ว่า LangChain จะเป็นเครื่องมืออันทรงคุณค่าสำหรับการผสานรวมโมเดลภาษา (LLM) เข้ากับแอปพลิเคชันของคุณ แต่ก็อาจเผชิญกับข้อจำกัดในกรณีการใช้งานระดับองค์กร มาสำรวจว่า Nanonets ก้าวไปไกลกว่า LangChain เพื่อรับมือกับความท้าทายเหล่านี้ได้อย่างไร:
1. การเชื่อมต่อข้อมูลที่ครอบคลุม:
LangChain มีตัวเชื่อมต่อ แต่อาจไม่ครอบคลุมแอปพื้นที่ทำงานและรูปแบบข้อมูลทั้งหมดที่ธุรกิจพึ่งพา Nanonets มีตัวเชื่อมต่อข้อมูลสำหรับแอปพื้นที่ทำงานที่ใช้กันอย่างแพร่หลายกว่า 100 รายการ รวมถึง Slack, Notion, Google Suite, Salesforce, Zendesk และอื่นๆ อีกมากมาย นอกจากนี้ยังรองรับประเภทข้อมูลที่ไม่มีโครงสร้างทั้งหมด เช่น PDF, TXT, รูปภาพ, ไฟล์เสียง และไฟล์วิดีโอ รวมถึงประเภทข้อมูลที่มีโครงสร้าง เช่น CSV, สเปรดชีต, MongoDB และฐานข้อมูล SQL
2. งานอัตโนมัติสำหรับแอป Workspace:
แม้ว่าการสร้างข้อความ/การตอบกลับจะใช้งานได้ดี แต่ความสามารถของ LangChain นั้นมีจำกัดเมื่อใช้ภาษาธรรมชาติเพื่อดำเนินงานในแอปพลิเคชันต่างๆ Nanonets นำเสนอเอเจนต์ทริกเกอร์/การดำเนินการสำหรับแอปพื้นที่ทำงานยอดนิยม ช่วยให้คุณสามารถตั้งค่าเวิร์กโฟลว์ที่รับฟังเหตุการณ์และดำเนินการได้ ตัวอย่างเช่น คุณสามารถตอบกลับอีเมล รายการ CRM การสืบค้น SQL และอื่นๆ โดยอัตโนมัติผ่านคำสั่งภาษาธรรมชาติ
3. การซิงโครไนซ์ข้อมูลแบบเรียลไทม์:
LangChain ดึงข้อมูลคงที่ด้วยตัวเชื่อมต่อข้อมูล ซึ่งอาจไม่ทันกับการเปลี่ยนแปลงข้อมูลในฐานข้อมูลต้นทาง ในทางตรงกันข้าม Nanonets รับประกันการซิงโครไนซ์แบบเรียลไทม์กับแหล่งข้อมูล เพื่อให้มั่นใจว่าคุณจะทำงานกับข้อมูลล่าสุดอยู่เสมอ
3. การกำหนดค่าแบบง่าย:
การกำหนดค่าองค์ประกอบของไปป์ไลน์ LangChain เช่น รีทรีฟเวอร์และซินธิไซเซอร์ อาจเป็นกระบวนการที่ซับซ้อนและใช้เวลานาน Nanonets ช่วยปรับปรุงสิ่งนี้โดยมอบการนำเข้าข้อมูลและการจัดทำดัชนีที่เหมาะสมที่สุดสำหรับข้อมูลแต่ละประเภท ซึ่งทั้งหมดนี้จัดการในเบื้องหลังโดยผู้ช่วย AI ซึ่งจะช่วยลดภาระในการปรับแต่งแบบละเอียดและทำให้ติดตั้งและใช้งานได้ง่ายขึ้น
4. โซลูชันแบบครบวงจร:
แตกต่างจาก LangChain ซึ่งอาจต้องมีการใช้งานเฉพาะสำหรับแต่ละงาน Nanonets ทำหน้าที่เป็นโซลูชันแบบครบวงจรสำหรับการเชื่อมต่อข้อมูลของคุณกับ LLM ไม่ว่าคุณจะต้องการสร้างแอปพลิเคชัน LLM หรือเวิร์กโฟลว์ AI Nanonets นำเสนอแพลตฟอร์มแบบครบวงจรสำหรับความต้องการที่หลากหลายของคุณ
เวิร์กโฟลว์ AI ของ Nanonets
Nanonets Workflows เป็นผู้ช่วย AI อเนกประสงค์ที่ปลอดภัย ช่วยลดความยุ่งยากในการบูรณาการความรู้และข้อมูลของคุณกับ LLM และอำนวยความสะดวกในการสร้างแอปพลิเคชันและเวิร์กโฟลว์ที่ไม่ต้องเขียนโค้ด มีอินเทอร์เฟซผู้ใช้ที่ใช้งานง่าย ทำให้ทั้งบุคคลและองค์กรสามารถเข้าถึงได้
ในการเริ่มต้น คุณสามารถกำหนดเวลาการโทรกับผู้เชี่ยวชาญ AI ของเรา ซึ่งสามารถสาธิตแบบส่วนตัวและทดลองใช้เวิร์กโฟลว์ Nanonets ที่ปรับให้เหมาะกับกรณีการใช้งานเฉพาะของคุณ
เมื่อตั้งค่าแล้ว คุณจะสามารถใช้ภาษาธรรมชาติในการออกแบบและดำเนินการแอปพลิเคชันและเวิร์กโฟลว์ที่ซับซ้อนซึ่งขับเคลื่อนโดย LLM ได้ ซึ่งจะผสานรวมกับแอปและข้อมูลของคุณได้อย่างราบรื่น
เพิ่มพลังให้ทีมของคุณด้วย Nanonets AI เพื่อสร้างแอปและรวมข้อมูลของคุณเข้ากับแอปพลิเคชันและเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ช่วยให้ทีมของคุณมุ่งเน้นไปที่สิ่งที่สำคัญอย่างแท้จริง
ทำงานแบบแมนนวลและเวิร์กโฟลว์โดยอัตโนมัติด้วยตัวสร้างเวิร์กโฟลว์ที่ขับเคลื่อนด้วย AI ซึ่งออกแบบโดย Nanonets สำหรับคุณและทีมของคุณ
- เนื้อหาที่ขับเคลื่อนด้วย SEO และการเผยแพร่ประชาสัมพันธ์ รับการขยายวันนี้
- PlatoData.Network Vertical Generative Ai เพิ่มพลังให้กับตัวเอง เข้าถึงได้ที่นี่.
- เพลโตไอสตรีม. Web3 อัจฉริยะ ขยายความรู้ เข้าถึงได้ที่นี่.
- เพลโตESG. คาร์บอน, คลีนเทค, พลังงาน, สิ่งแวดล้อม แสงอาทิตย์, การจัดการของเสีย. เข้าถึงได้ที่นี่.
- เพลโตสุขภาพ เทคโนโลยีชีวภาพและข่าวกรองการทดลองทางคลินิก เข้าถึงได้ที่นี่.
- ที่มา: https://nanonets.com/blog/langchain/
- :มี
- :เป็น
- :ไม่
- :ที่ไหน
- $ ขึ้น
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- เอบีซี
- ความสามารถ
- สามารถ
- เกี่ยวกับเรา
- เกี่ยวกับมัน
- ข้างบน
- ยอมรับ
- ยอมรับ
- เข้า
- สามารถเข้าถึงได้
- การเข้าถึง
- บรรลุผล
- ตาม
- ลงชื่อเข้าใช้
- ความถูกต้อง
- ถูกต้อง
- แม่นยำ
- บรรลุ
- ประสบความสำเร็จ
- ประสบความสำเร็จ
- ข้าม
- กระทำ
- การกระทำ
- การปฏิบัติ
- คล่องแคล่ว
- การปรับตัว
- ปรับได้
- เพิ่ม
- ที่เพิ่ม
- เพิ่ม
- นอกจากนี้
- เพิ่มเติม
- นอกจากนี้
- ที่อยู่
- เพิ่ม
- ยอมรับ
- สูง
- การผจญภัย
- หลังจาก
- อีกครั้ง
- อายุ
- ตัวแทน
- ตัวแทน
- AI
- ผู้ช่วย AI
- โมเดล AI
- ช่วย
- การเล็ง
- อัลกอริทึม
- จัดแนว
- จัดแนว
- ทั้งหมด
- อนุญาต
- การอนุญาต
- ช่วยให้
- คนเดียว
- ตาม
- คู่ขนาน
- แล้ว
- ด้วย
- แม้ว่า
- เสมอ
- an
- การวิเคราะห์
- วิเคราะห์
- การวิเคราะห์
- และ
- Angeles
- ประกาศ
- ประจำปี
- อื่น
- คำตอบ
- คำตอบ
- เพลงชาติ
- มานุษยวิทยา
- ใด
- สิ่งใด
- API
- คีย์ API
- APIs
- app
- เหมาะสม
- การใช้งาน
- การพัฒนาโปรแกรมประยุกต์
- การใช้งาน
- ประยุกต์
- มีผลบังคับใช้
- เข้าใกล้
- วิธีการ
- เหมาะสม
- อย่างเหมาะสม
- ปพลิเคชัน
- สถาปัตยกรรม
- เป็น
- อาร์กิวเมนต์
- ข้อโต้แย้ง
- อาร์มสตรอง
- รอบ
- แถว
- ศิลปิน
- AS
- ถาม
- แง่มุม
- ด้าน
- ช่วยเหลือ
- ผู้ช่วย
- ที่เกี่ยวข้อง
- At
- แนบ
- ความสนใจ
- เสียง
- เติม
- การยืนยันตัวตน
- โดยอัตโนมัติ
- อัตโนมัติ
- โดยอัตโนมัติ
- อัตโนมัติ
- อัตโนมัติ
- ใช้ได้
- เฉลี่ย
- รอคอย
- ทราบ
- AWS
- กลับ
- กระดูกสันหลัง
- แบ็กเอนด์
- พื้นหลัง
- ไม่ดี
- ยอดคงเหลือ
- บาร์
- ฐาน
- ตาม
- baseline
- ทุบตี
- ขั้นพื้นฐาน
- ข้อมูลพื้นฐานเกี่ยวกับ
- BCG
- BE
- ชายหาด
- หมี
- เพราะ
- รับ
- ก่อน
- เริ่ม
- พฤติกรรม
- หลัง
- เบื้องหลัง
- กำลัง
- ด้านล่าง
- มาตรฐาน
- เป็นประโยชน์
- ที่ดีที่สุด
- ดีกว่า
- ระหว่าง
- เกิน
- ที่ใหญ่ที่สุด
- บิล
- บิลเกตส์
- ผูก
- Bing
- บิต
- Black
- หลุมดำ
- ปิดกั้น
- การปิดกั้น
- Blocks
- บล็อก
- เมล็ดข้าว
- บูต
- เกิด
- ธ ปท
- ทั้งสอง
- ด้านล่าง
- สาขา
- ทำลาย
- ลมโชย
- สั้น
- ที่กว้างขึ้น
- สีน้ำตาล
- เบราว์เซอร์
- กันชน
- สร้าง
- สร้าง
- การก่อสร้าง
- สร้าง
- ภาระ
- ธุรกิจ
- แต่
- by
- คำนวณ
- คำนวณ
- การคํานวณ
- การคำนวณ
- โทรศัพท์
- เรียกกลับ
- ที่เรียกว่า
- โทร
- โทร
- CAN
- สามารถรับ
- แคนาดา
- ความสามารถในการ
- สามารถ
- ความจุ
- จับ
- จับ
- กรณี
- กรณี
- แมว
- ให้ความบันเทิง
- ทำอาหารรับประทานเอง
- จัดเลี้ยง
- แมว
- ความระมัดระวัง
- ระมัดระวัง
- ศูนย์กลาง
- บาง
- โซ่
- ห่วงโซ่
- ความท้าทาย
- การเปลี่ยนแปลง
- ตัวอักษร
- chatbot
- chatbots
- ตรวจสอบ
- การตรวจสอบ
- Choose
- เลือก
- สถานการณ์
- เมือง
- ชั้น
- ชั้นเรียน
- ไคลเอนต์
- เมฆ
- รหัส
- การเข้ารหัส
- กาแฟ
- สอดคล้องกัน
- เหนียว
- ร่วมมือ
- ล่มสลาย
- ชุด
- มีสีสัน
- คอลัมน์
- คอลัมน์
- COM
- รวมกัน
- รวม
- รวม
- การรวมกัน
- อย่างไร
- มา
- สบาย
- ร่วมกัน
- การสื่อสาร
- บริษัท
- เปรียบเทียบ
- เปรียบเทียบ
- ความเข้ากันได้
- เข้ากันได้
- สมบูรณ์
- อย่างสมบูรณ์
- เสร็จสิ้น
- ซับซ้อน
- ความซับซ้อน
- ส่วนประกอบ
- ส่วนประกอบ
- สงบ
- ส่วนประกอบ
- ครอบคลุม
- ประกอบไปด้วย
- แนวคิด
- กระชับ
- พร้อมกัน
- สภาพ
- องค์ประกอบ
- ที่บรรจบกัน
- เชื่อมต่อ
- การเชื่อมต่อ
- การเชื่อมต่อ
- จุดด้อย
- พิจารณา
- เสมอต้นเสมอปลาย
- ประกอบ
- ปลอบใจ
- ไม่หยุดหย่อน
- โครงสร้าง
- บรรจุ
- มี
- เนื้อหา
- สิ่งแวดล้อม
- บริบท
- ตามบริบท
- ต่อ
- อย่างต่อเนื่อง
- ตรงกันข้าม
- ควบคุม
- การควบคุม
- สะดวกสบาย
- การสนทนา
- การสนทนา
- AI สนทนา
- การสนทนา
- การแปลง
- แปลง
- การแปลง
- แกน
- มุม
- แก้ไข
- ตรงกัน
- ได้
- การนับ
- ประเทศ
- คู่
- หน้าปก
- ปกคลุม
- สร้าง
- ที่สร้างขึ้น
- สร้าง
- การสร้าง
- การสร้าง
- หนังสือรับรอง
- เกณฑ์
- นักวิจารณ์
- CRM
- สำคัญมาก
- ปัจจุบัน
- ขณะนี้
- ประเพณี
- ลูกค้า
- การปรับแต่ง
- ปรับแต่ง
- การปรับแต่ง
- ตัดขอบ
- ข้อมูล
- โครงสร้างข้อมูล
- ฐานข้อมูล
- ฐานข้อมูล
- วันที่
- วันเวลา
- จัดการ
- การซื้อขาย
- ธันวาคม
- ตัดสินใจ
- กำลังตัดสินใจ
- การตัดสินใจ
- ถอดรหัส
- ทุ่มเท
- ลึก
- ค่าเริ่มต้น
- กำหนด
- กำหนด
- การกำหนด
- คำจำกัดความ
- การส่งมอบ
- มอบ
- คุ้ย
- สาธิต
- สาธิต
- แสดงให้เห็นถึง
- แสดงให้เห็นถึง
- ขึ้นอยู่กับ
- ทั้งนี้ขึ้นอยู่กับ
- ขึ้นอยู่กับ
- ปรับใช้
- นำไปใช้
- ปรับใช้
- การใช้งาน
- Deploys
- บรรยาย
- ลักษณะ
- ออกแบบ
- กำหนด
- ได้รับการออกแบบ
- ที่ต้องการ
- รายละเอียด
- รายละเอียด
- รายละเอียด
- กำหนด
- แน่นอน
- พัฒนา
- ผู้พัฒนา
- นักพัฒนา
- ที่กำลังพัฒนา
- พัฒนาการ
- แผนภาพ
- Dict
- DID
- แตกต่าง
- ต่าง
- ต่างกัน
- ยาก
- Dimension
- มิติ
- สั่ง
- โดยตรง
- สนทนา
- กล่าวถึง
- แสดง
- แตกต่าง
- การดำน้ำ
- หลาย
- DM
- do
- เอกสาร
- เอกสาร
- เอกสาร
- ทำ
- doesn
- การทำ
- สวม
- ทำ
- สอง
- ลง
- ดาวน์โหลด
- ดาวน์โหลด
- ร่าง
- ขับรถ
- สอง
- ในระหว่าง
- พลวัต
- แบบไดนามิก
- e
- แต่ละ
- ก่อน
- ก่อน
- ความสะดวก
- สะดวกในการใช้
- ง่ายดาย
- อย่างง่ายดาย
- ง่าย
- ง่ายต่อการใช้งาน
- เสียงสะท้อน
- ระบบนิเวศ
- มีประสิทธิภาพ
- มีประสิทธิภาพ
- อย่างมีประสิทธิภาพ
- ที่มีประสิทธิภาพ
- อย่างมีประสิทธิภาพ
- ง่าย
- ทั้ง
- ธาตุ
- องค์ประกอบ
- Elon
- Elon Musk
- อื่น
- อีเมล
- ฝัง
- ที่ฝัง
- การฝัง
- การจ้างงาน
- พนักงาน
- พนักงาน
- ให้อำนาจ
- ทำให้สามารถ
- ช่วยให้
- การเปิดใช้งาน
- ห่อหุ้ม
- เผชิญหน้า
- จบสิ้น
- ปลายทาง
- น่าสนใจ
- เครื่องยนต์
- เครื่องยนต์
- ประเทศอังกฤษ
- ภาษาอังกฤษ
- พรีเมียร์ลีกอังกฤษ
- เสริม
- ที่เพิ่มขึ้น
- การเสริมสร้าง
- ทำให้มั่นใจ
- เพื่อให้แน่ใจ
- การสร้างความมั่นใจ
- Enterprise
- หน่วยงาน
- เอกลักษณ์
- สิ่งแวดล้อม
- สภาพแวดล้อม
- เท่ากัน
- ยุค
- ความผิดพลาด
- ข้อผิดพลาด
- โดยเฉพาะอย่างยิ่ง
- จำเป็น
- ที่ทำให้เหินห่าง
- ฯลฯ
- ประเมินค่า
- การประเมินผล
- แม้
- เหตุการณ์
- ทุกๆ
- ตัวอย่าง
- ตัวอย่าง
- เกินกว่า
- ยกเว้น
- ดำเนินการ
- ดำเนินการ
- รัน
- การดำเนินงาน
- การปฏิบัติ
- เป็นตัวอย่าง
- การออกกำลังกาย
- มีอยู่
- คาดหวัง
- ความคาดหวัง
- ที่คาดหวัง
- คาดว่า
- ประสบการณ์
- การทดลอง
- ผู้เชี่ยวชาญ
- อธิบาย
- อธิบาย
- อย่างชัดเจน
- การสำรวจ
- สำรวจ
- สำรวจ
- ส่งออก
- การแสดงออก
- ขยายออก
- การขยาย
- กว้างขวาง
- ภายนอก
- พิเศษ
- สารสกัด
- การสกัด
- สารสกัดจาก
- ใบหน้า
- อำนวยความสะดวก
- อำนวยความสะดวก
- โรงงาน
- ข้อเท็จจริง
- ไกล
- FAST
- ที่ชื่นชอบ
- ลักษณะ
- คุณสมบัติ
- ข้อเสนอแนะ
- สองสาม
- สนาม
- สาขา
- มะเดื่อ
- รูป
- เนื้อไม่มีมัน
- ไฟล์
- ใส่
- ที่เต็มไป
- การกรอก
- กรอง
- กรอง
- สุดท้าย
- ในที่สุด
- หา
- หา
- ชื่อจริง
- ห้า
- ความยืดหยุ่น
- มีความยืดหยุ่น
- ไหล
- โฟกัส
- มุ่งเน้น
- มุ่งเน้นไปที่
- โดยมุ่งเน้น
- ปฏิบัติตาม
- ดังต่อไปนี้
- ดังต่อไปนี้
- อาหาร
- สำหรับ
- ฟอร์ม
- รูป
- ที่เกิดขึ้น
- โชคดี
- พบ
- กรอบ
- กรอบ
- มัก
- เพื่อน
- เพื่อน
- ราคาเริ่มต้นที่
- เต็ม
- เต็มที่
- ฟังก์ชัน
- ฟังก์ชันการทำงาน
- ฟังก์ชั่น
- ฟังก์ชั่น
- พื้นฐาน
- ตลก
- ต่อไป
- อนาคต
- ได้รับ
- เกม
- เกตส์
- General
- โดยทั่วไป
- สร้าง
- สร้าง
- สร้าง
- การสร้าง
- รุ่น
- ชนิด
- ประเทศเยอรมัน
- ได้รับ
- ได้รับ
- GIF
- GitHub
- กำหนด
- GMT
- Go
- ไป
- ไป
- ดี
- ละเอียด
- กราฟ
- ยิ่งใหญ่
- มากขึ้น
- คำแนะนำ
- ให้คำแนะนำ
- แนวทาง
- Hackathon
- จัดการ
- จัดการ
- การจัดการ
- มีประโยชน์
- ยาก
- อันตราย
- สายรัด
- มี
- มี
- หนัก
- จัดขึ้น
- ช่วย
- เป็นประโยชน์
- จะช่วยให้
- เธอ
- โปรดคลิกที่นี่เพื่ออ่านรายละเอียดเพิ่มเติม
- hi
- จุดสูง
- ระดับสูง
- ที่มีคุณภาพสูง
- ที่สูงที่สุด
- อย่างสูง
- ทางประวัติศาสตร์
- ประวัติ
- รู
- กระโปรงหน้ารถ
- เจ้าภาพ
- สรุป ความน่าเชื่อถือของ Olymp Trade?
- ทำอย่างไร
- อย่างไรก็ตาม
- HTML
- ที่ http
- HTTPS
- Hub
- เป็นมนุษย์
- ร้อย
- i
- ID
- ความคิด
- ในอุดมคติ
- รหัส
- if
- ii
- iii
- แสดง
- แสดงให้เห็นถึง
- ภาพ
- ทันที
- การดำเนินการ
- การดำเนินงาน
- การใช้งาน
- การดำเนินการ
- นำเข้า
- การปรับปรุง
- การปรับปรุง
- in
- ลึกซึ้ง
- ประกอบด้วย
- รวม
- รวมถึง
- รวมทั้ง
- รวมเข้าด้วยกัน
- ผสมผสาน
- เหลือเชื่อ
- ดัชนี
- ดัชนี
- แสดง
- บ่งชี้ว่า
- เป็นรายบุคคล
- บุคคล
- ข้อมูล
- แรกเริ่ม
- เริ่มต้น
- นวัตกรรม
- อินพุต
- ปัจจัยการผลิต
- ข้อมูลเชิงลึก
- ติดตั้ง
- การติดตั้ง
- การติดตั้ง
- ตัวอย่าง
- ด่วน
- แทน
- คำแนะนำการใช้
- สำคัญ
- รวบรวม
- แบบบูรณาการ
- รวม
- การบูรณาการ
- บูรณาการ
- การผสานรวม
- ฉลาด
- ตั้งใจว่า
- โต้ตอบ
- ปฏิสัมพันธ์
- ปฏิสัมพันธ์
- การโต้ตอบ
- เชิงโต้ตอบ
- อินเตอร์เฟซ
- อินเตอร์เฟซ
- ภายใน
- อินเทอร์เน็ต
- เข้าไป
- แนะนำ
- เปิดตัว
- ใช้งานง่าย
- ที่เกี่ยวข้องกับ
- ISN
- ปัญหา
- ปัญหา
- IT
- รายการ
- ซ้ำ
- ITS
- ตัวเอง
- แจ็คสัน
- JavaScript
- การสัมภาษณ์
- จอร์แดน
- การเดินทาง
- JSON
- กรกฎาคม
- เพียงแค่
- ความยุติธรรม
- เก็บ
- เก็บ
- คีย์
- กุญแจ
- ชนิด
- ทราบ
- ความรู้
- กราฟความรู้
- ที่รู้จักกัน
- ฉลาก
- ป้ายกำกับ
- ที่ดิน
- ภาษา
- ภาษา
- ใหญ่
- ที่มีขนาดใหญ่
- ชื่อสกุล
- ความแอบแฝง
- ต่อมา
- ล่าสุด
- พันธมิตร
- เรียนรู้
- การเรียนรู้
- ซ้าย
- มรดก
- ความยาว
- น้อยลง
- ให้
- ช่วยให้
- จดหมาย
- ชั้น
- ระดับ
- เลฟเวอเรจ
- ยกระดับ
- การใช้ประโยชน์
- ห้องสมุด
- ห้องสมุด
- กดไลก์
- น่าจะ
- LIMIT
- ข้อ จำกัด
- ถูก จำกัด
- การ จำกัด
- ขีด จำกัด
- การเชื่อมโยง
- รายการ
- ฟัง
- รายการ
- สด
- ll
- LLM
- โหลด
- loader
- ที่ตั้งอยู่
- ที่ตั้ง
- เข้าสู่ระบบ
- เข้า
- การเข้าสู่ระบบ
- ตรรกะ
- นาน
- อีกต่อไป
- ดู
- ที่ต้องการหา
- LOOKS
- ค้นหา
- ลอส
- Los Angeles
- ต่ำ
- เครื่อง
- เรียนรู้เครื่อง
- ทำ
- เก็บรักษา
- บำรุงรักษาได้
- การบำรุงรักษา
- รักษา
- ทำ
- ทำให้
- การทำ
- จัดการ
- การจัดการ
- ผู้จัดการ
- การจัดการ
- แมนเชสเตอร์
- แมนเชสเตอร์ยูไนเต็ด
- การจัดการ
- ลักษณะ
- คู่มือ
- ผู้ผลิต
- หลาย
- หลายคน
- แผนที่
- การทำแผนที่
- แผนที่
- การจับคู่
- การจับคู่
- คณิตศาสตร์
- คณิตศาสตร์
- เรื่อง
- สูงสุด
- อาจ..
- me
- หมายความ
- ความหมาย
- วิธี
- วัด
- ภาพบรรยากาศ
- ที่ประชุม
- มีคุณสมบัติตรงตาม
- ความทรงจำ
- หน่วยความจำ
- กล่าวถึง
- ผสาน
- การผสม
- ข่าวสาร
- ข้อความ
- ส่งข้อความ
- เมตาดาต้า
- วิธี
- วิธีการ
- ตัวชี้วัด
- อาจ
- ล้าน
- ต่ำสุด
- ผู้เยาว์
- หายไป
- ความผิดพลาด
- การผสม
- เอ็ม
- โทรศัพท์มือถือ
- แบบ
- โมเดล
- การกลั่นกรอง
- โมดูล
- โมดูล
- ขณะ
- MongoDB
- การตรวจสอบ
- การตรวจสอบ
- ดวงจันทร์
- ข้อมูลเพิ่มเติม
- มากที่สุด
- เป็นที่นิยม
- ย้าย
- หนัง
- มาก
- หลาย
- หลายโซ่
- ชะมด
- ต้อง
- my
- ชื่อ
- ที่มีชื่อ
- ชื่อ
- แห่งชาติ
- โดยธรรมชาติ
- ประมวลผลภาษาธรรมชาติ
- นำทาง
- การนำทาง
- ใกล้
- จำเป็น
- จำเป็นต้อง
- จำเป็น
- ความต้องการ
- เชิงลบ
- ใหม่
- นิวยอร์ก
- นิวยอร์กไทม์ส
- ถัดไป
- ไม่
- ไม่มี
- ไม่มีอะไร
- ความคิด
- ตอนนี้
- จำนวน
- โอบามา
- วัตถุ
- วัตถุประสงค์
- วัตถุ
- การสังเกต
- ได้รับ
- การได้รับ
- OCR
- of
- เสนอ
- การเสนอ
- เสนอ
- มักจะ
- oh
- ถูก
- การแข่งขันกีฬาโอลิมปิก
- on
- ครั้งเดียว
- ONE
- เพียง
- โอเพนซอร์ส
- OpenAI
- การดำเนินการ
- ผู้ประกอบการ
- การปรับให้เหมาะสม
- เพิ่มประสิทธิภาพ
- ตัวเลือกเสริม (Option)
- or
- ใบสั่ง
- อินทรีย์
- องค์กร
- เป็นต้นฉบับ
- OS
- อื่นๆ
- ผลิตภัณฑ์อื่นๆ
- มิฉะนั้น
- ของเรา
- ออก
- เอาท์พุต
- เอาท์พุท
- เกิน
- แทนที่
- ภาพรวม
- ของตนเอง
- แพ็คเกจ
- แพคเกจ
- หน้า
- หน้า
- คู่
- หมีแพนด้า
- กระดาษ
- Parallel
- พารามิเตอร์
- พารามิเตอร์
- สวนสาธารณะ
- ส่วนหนึ่ง
- โดยเฉพาะ
- ส่วน
- ส่ง
- ผ่าน
- ผ่าน
- ที่ผ่านไป
- อดีต
- เส้นทาง
- เส้นทาง
- รูปแบบ
- บัญชีเงินเดือน
- รูปแบบไฟล์ PDF
- คน
- ต่อ
- สมบูรณ์
- อย่างสมบูรณ์
- ดำเนินการ
- การปฏิบัติ
- ที่มีประสิทธิภาพ
- ดำเนินการ
- สิทธิ์
- วิริยะ
- คน
- ส่วนบุคคล
- มุมมอง
- ฟิสิกส์
- ชิ้น
- ท่อ
- พิซซ่า
- ตัวยึด
- เวที
- เพลโต
- เพลโตดาต้าอินเทลลิเจนซ์
- เพลโตดาต้า
- เล่น
- สนามเด็กเล่น
- เล่น
- กรุณา
- บวก
- จุด
- นโยบาย
- นโยบาย
- ทางการเมือง
- สระ
- ยอดนิยม
- ประชากร
- บวก
- เป็นไปได้
- โพสต์
- โพสต์
- ที่มีศักยภาพ
- อำนาจ
- ขับเคลื่อน
- ที่มีประสิทธิภาพ
- ประยุกต์
- การปฏิบัติ
- ชอบ
- นายกรัฐมนตรี
- นำเสนอ
- ประธาน
- ป้องกัน
- การป้องกัน
- ก่อน
- ส่วนใหญ่
- ประถม
- สำคัญ
- ส่วนตัว
- ปัญหา
- ปัญหาที่เกิดขึ้น
- ดำเนิน
- กระบวนการ
- แปรรูปแล้ว
- กระบวนการ
- การประมวลผล
- ก่อ
- ผลิตภัณฑ์
- การผลิต
- ศาสตราจารย์
- การเขียนโปรแกรม
- การเขียนโปรแกรมภาษา
- โครงการ
- โครงการ
- คุณสมบัติ
- คุณสมบัติ
- PROS
- ต้นแบบ
- การสร้างต้นแบบ
- ให้
- ให้
- ผู้จัดหา
- ผู้ให้บริการ
- ให้
- การให้
- สาธารณะ
- วัตถุประสงค์
- วัตถุประสงค์
- ใส่
- หลาม
- Q & A
- คุณภาพ
- คำสั่ง
- คำถาม
- คำถาม
- รวดเร็ว
- อย่างรวดเร็ว
- คำพูด
- R
- ยก
- พิสัย
- ตั้งแต่
- ค่อนข้าง
- อันดับ
- ดิบ
- RE
- มาถึง
- เกิดปฏิกิริยา
- อ่าน
- การอ่าน
- พร้อม
- จริง
- เรียลไทม์
- ข้อมูลตามเวลาจริง
- ดินแดน
- เหตุผล
- เหตุผล
- เมื่อเร็ว ๆ นี้
- แนะนำ
- บันทึก
- บันทึก
- กู้
- ลด
- ลด
- ลด
- การลดลง
- การอ้างอิง
- อ้างอิง
- ปรับแต่ง
- การฟอก
- ภูมิภาค
- ความสัมพันธ์
- การเผยแพร่
- ความสัมพันธ์กัน
- ตรงประเด็น
- ความเชื่อถือได้
- น่าเชื่อถือ
- วางใจ
- อาศัย
- ซากศพ
- จำ
- การแจ้งเตือน
- รีโมท
- ผล
- ทำซ้ำ
- ซ้ำแล้วซ้ำเล่า
- เรียบเรียงใหม่
- แทนที่
- รายงาน
- กรุ
- การแสดง
- เป็นตัวแทนของ
- แสดงให้เห็นถึง
- ขอ
- การร้องขอ
- ต้องการ
- จำเป็นต้องใช้
- ความต้องการ
- ต้อง
- ช่วยเหลือ
- การวิจัย
- แก้ไข
- ทรัพยากร
- ตอบสนอง
- การตอบสนอง
- คำตอบ
- การตอบสนอง
- รับผิดชอบ
- การตอบสนอง
- REST
- ผล
- ส่งผลให้
- ผลสอบ
- การรักษา
- ความจำ
- กลับ
- การคืน
- รับคืน
- นำมาใช้ใหม่
- ทบทวน
- หมุน
- ข้าว
- รวย
- หุ่นยนต์
- บทบาท
- บทบาท
- ราก
- การกำหนดเส้นทาง
- แถว
- วิ่ง
- วิ่ง
- ทำงาน
- รันไทม์
- s
- การป้องกัน
- ขาย
- Salesforce
- แซม
- เดียวกัน
- ลด
- กล่าว
- พูดว่า
- ที่ปรับขนาดได้
- ขนาด
- สถานการณ์
- สถานการณ์
- ฉาก
- กำหนด
- คะแนน
- รอยขีดข่วน
- ไร้รอยต่อ
- ได้อย่างลงตัว
- ค้นหา
- เครื่องมือค้นหา
- ค้นหา
- ค้นหา
- Section
- ส่วน
- ปลอดภัย
- ความปลอดภัย
- เห็น
- เลือก
- การเลือก
- Selling
- ส่ง
- มีความละเอียดอ่อน
- ความรู้สึก
- ความรู้สึก
- แยก
- กันยายน
- ลำดับ
- ชุด
- ให้บริการ
- เซิร์ฟเวอร์
- ให้บริการอาหาร
- บริการ
- ชุด
- ชุดอุปกรณ์
- การตั้งค่า
- การตั้งค่า
- การติดตั้ง
- เจ็ด
- หลาย
- Share
- ที่ใช้ร่วมกัน
- เปลือก
- ส่อง
- จัดส่ง
- น่า
- โชว์
- แสดง
- แสดง
- แสดงให้เห็นว่า
- ซิกม่า
- สำคัญ
- คล้ายคลึงกัน
- ง่าย
- ที่เรียบง่าย
- ลดความซับซ้อน
- ลดความซับซ้อน
- ง่ายดาย
- ตั้งแต่
- เดียว
- ขนาด
- หย่อน
- เล็ก
- มีขนาดเล็กกว่า
- สมาร์ท
- เศษเล็กเศษน้อย
- So
- จนถึงตอนนี้
- ฟุตบอล
- สังคม
- โซเชียลมีเดีย
- โพสต์โซเชียลมีเดีย
- เพียงผู้เดียว
- ของแข็ง
- ทางออก
- แก้
- บาง
- บางสิ่งบางอย่าง
- บางครั้ง
- ซับซ้อน
- เสียง
- แหล่ง
- แหล่งที่มา
- ช่องว่าง
- สเปน
- เฉพาะ
- โดยเฉพาะ
- เฉพาะ
- เฉพาะ
- ที่ระบุไว้
- ความเร็ว
- การใช้จ่าย
- แยก
- แยก
- กีฬา
- สี่เหลี่ยม
- ยืน
- สแตนด์อโลน
- มาตรฐาน
- เริ่มต้น
- ข้อความที่เริ่ม
- ที่เริ่มต้น
- สถานะ
- งบ
- คงที่
- ขั้นตอน
- ขั้นตอน
- ยังคง
- หยุด
- การหยุด
- หยุด
- การเก็บรักษา
- จัดเก็บ
- เก็บไว้
- ร้านค้า
- การเก็บรักษา
- เรื่องราว
- ซื่อตรง
- กระแส
- ที่พริ้ว
- เพรียวลม
- คล่องตัว
- จุดแข็ง
- การนัดหยุดงาน
- เชือก
- โครงสร้าง
- โครงสร้าง
- โครงสร้าง
- การจัดโครงสร้าง
- สไตล์
- หรือ
- ภายหลัง
- ประสบความสำเร็จ
- อย่างเช่น
- สูท
- เหมาะสม
- ชุด
- สรุป
- สรุป
- พระอาทิตย์ตกดิน
- สนับสนุน
- ที่สนับสนุน
- รองรับ
- แน่ใจ
- การพัฒนาอย่างยั่งยืน
- การประสาน
- สรุป
- วากยสัมพันธ์
- ระบบ
- ระบบ
- ตาราง
- ช่างตัดเสื้อ
- ปรับปรุง
- เอา
- ใช้เวลา
- เป้าหมาย
- งาน
- งาน
- ทีม
- ทีม
- บอก
- เทมเพลต
- แม่แบบ
- สถานีปลายทาง
- คำศัพท์
- เงื่อนไขการใช้บริการ
- ทดสอบ
- การทดสอบ
- ข้อความ
- กว่า
- ขอบคุณ
- ที่
- พื้นที่
- ข้อมูลพื้นฐานเกี่ยวกับ
- ฮับ
- ข้อมูล
- นิวนิวยอร์กไทม์
- โครงการ
- ที่มา
- โลก
- ของพวกเขา
- พวกเขา
- แล้วก็
- ที่นั่น
- ล้อยางขัดเหล่านี้ติดตั้งบนแกน XNUMX (มม.) ผลิตภัณฑ์นี้ถูกผลิตในหลายรูปทรง และหลากหลายเบอร์ความแน่นหนาของปริมาณอนุภาคขัดของมัน จะทำให้ท่านได้รับประสิทธิภาพสูงในการขัดและการใช้งานที่ยาวนาน
- พวกเขา
- สิ่ง
- นี้
- เหล่านั้น
- แต่?
- ตลอด
- ตลอด
- เวลา
- ต้องใช้เวลามาก
- ครั้ง
- ชื่อหนังสือ
- ไปยัง
- ร่วมกัน
- โทเค็น
- tokenization
- ราชสกุล
- เกินไป
- เครื่องมือ
- เครื่องมือ
- เครื่องมือ
- ด้านบน
- หัวข้อ
- หัวข้อ
- รวม
- ตัวเมือง
- การติดตาม
- ลู่
- แบบดั้งเดิม
- การฝึกอบรม
- แปลง
- การแปลง
- หม้อแปลงไฟฟ้า
- หม้อแปลง
- การเปลี่ยนแปลง
- การทดลอง
- จริง
- อย่างแท้จริง
- ลอง
- จูน
- กลับ
- การหมุน
- เกี่ยวกับการสอน
- สองครั้ง
- สอง
- ชนิด
- ชนิด
- ประเภท
- เป็นปกติ
- ui
- ในที่สุด
- ตรงไปตรงมา
- ภายใต้
- พื้นฐาน
- เข้าใจ
- ความเข้าใจ
- เข้าใจ
- ปึกแผ่น
- เป็นเอกลักษณ์
- พร้อมใจกัน
- สากล
- แตกต่าง
- จนกระทั่ง
- บันทึก
- การปรับปรุง
- อัปโหลด
- URL
- us
- การใช้งาน
- การใช้
- ใช้
- ใช้กรณี
- มือสอง
- ผู้ใช้งาน
- ส่วนติดต่อผู้ใช้
- ผู้ใช้
- ใช้
- การใช้
- ยูทิลิตี้
- นำไปใช้
- ใช้
- ใช้ประโยชน์
- การใช้ประโยชน์
- v1
- การตรวจสอบ
- ตรวจสอบ
- มีคุณค่า
- ความคุ้มค่า
- ความคุ้มค่า
- ตัวแปร
- ความหลากหลาย
- ต่างๆ
- Ve
- อเนกประสงค์
- รุ่น
- มาก
- ผ่านทาง
- วีดีโอ
- รายละเอียด
- การละเมิด
- มองเห็นได้
- เห็นภาพ
- จำเป็น
- vs
- เดิน
- คำแนะนำ
- ต้องการ
- คือ
- นาฬิกา
- ทาง..
- วิธี
- we
- สภาพอากาศ
- เว็บ
- เว็บเบราเซอร์
- บริการเว็บ
- เว็บไซต์
- ดี
- โด่งดัง
- คือ
- อะไร
- ความหมายของ
- อะไร
- เมื่อ
- ว่า
- ที่
- ในขณะที่
- WHO
- ทั้งหมด
- ทำไม
- กว้าง
- อย่างกว้างขวาง
- วิดเจ็ต
- วิกิพีเดีย
- จะ
- หน้าต่าง
- ชนะ
- กับ
- ภายใน
- ไม่มี
- คำ
- งาน
- ทำงาน
- เวิร์กโฟลว์
- ขั้นตอนการทำงาน
- การทำงาน
- โรงงาน
- โลก
- จะ
- เขียน
- การเขียน
- X
- ยัง
- นิวยอร์ก
- คุณ
- ของคุณ
- ด้วยตัวคุณเอง
- YouTube
- Zendesk
- ลมทะเล
- รหัสไปรษณีย์