ความคิดหลักของ LangChain Agent คือการใช้ LLM เป็นสมองในการคิดโดยอัตโนมัติ ตัดสินการตัดสินใจ และดำเนินการต่าง ๆ เพื่อสำเร็จภารกิจเป้าหมายของเรา

เกร็ดคำแนะนำ: จากมุมมองการพัฒนา นี่หมายความว่าเราจะพัฒนา API ต่าง ๆ ล่วงหน้า แล้วทำให้เอเจนต์เป็นเหมือนคน โดยที่ LLM จะวิเคราะห์ว่าต้องเรียกใช้ API ไหนเพื่อทำภารกิจ

เพื่อที่จะเข้าใจปัญหาที่ LangChain Agent มีเป้าหมายที่จะแก้, เรามาพิจารณาตัวอย่างกัน

ตัวอย่าง:

ถ้าเราต้องการวิจัยว่า "Docker สามารถใช้เป็นโซลูชันการถ่ายโอนข้อมูลในการใช้งานจริงหรือไม่" เราจะค้นหา "ข้อความนำเสนอ Docker" ใน Baidu และดูผลการค้นหา และจากนั้นค้นหา "ข้อดีและข้อเสียของการใช้ Docker ในการถ่ายโอนข้อมูล" และดูผลการค้นหาเพิ่มเติม และอีกหลายอย่าง จนกระทั่งเราตรวจสอบว่าถึงข้อสรุป

LangChain Agent มีเป้าหมายที่จะจำลองกระบวนการนี้ ฉันสามารถเตรียมชุดเครื่องมือ (เช่น การค้นหาใน Baidu, เครื่องมือแตกต่างสำหรับการสกัดเนื้อหา URL) แล้วให้เอเจนต์เป้าหมาย "Docker สามารถใช้เป็นโซลูชันการถ่ายโอนข้อมูลในการใช้งานจริงหรือไม่?" เจนต์จะสร้างข้อความให้เรียกใช้ LLM โดยเพื่อที่จะทำภารกิจนี้ขั้นต่อไปคือดำเนินการใด (เช่นเรียกใช้เครื่องมือใด) จากระบบจะส่งเครื่องมือที่จะเรียกใช้ออกมา โค้ดจะดำเนินการเครื่องมือนี้และส่งผลการดำเนินการของเครื่องมือกลับไปที่ระบบ และขอคำสั่งการดำเนินการต่อไปของเครื่องมือใด การทำซ้ำกระบวนการนี้จะสำเร็จภารกิจที่กล่าวถึงไว้มีที่สุด

เกร็ดคำแนะนำ: ตั้งแต่การปล่อยมาแบบ GPT นี้เป็นคุณสมบัติที่ดีมาก ทำให้ LLM ทำหน้าที่เป็นสมอง คิดเองและเรียกใช้ API ต่าง ๆ ที่เราพัฒนาไว้ ซึ่งทำให้เสริมความสามารถของ LLM อย่างมาก ปัจจุบันคุณลักษณะนี้อยู่ในช่วงทดลองและจะเรียกใช้ LLM บ่อยครั้ง ดังนั้นจะใช้โทเคนเป็นจำนวนมากในเวลาไม่กี่นาที หากต้องการประหยัดเงิน แนะนำให้ทำให้ LLM ทำงานให้เพียงการตัดสินใจตามตรรกะที่ง่ายง่ายเท่านั้น

หลักการหลัก

ขอนำเสนอว่าง่ายดายคอนเซ็ปต์และองค์บริษัทที่เกี่ยวข้อง

เอเจนต์

เอเจนต์สามารถเข้าใจได้ว่าเป็นผู้ช่วยของเรา ทำงานแทนเราในการตัดสินการตัดสินใจ ในการดำเนินการที่อย่ในระดับล่างของ LangChain Agent, LLM คือบันทึกการตัดสินการตัดสินใจของ AI ผู้ที่สนใจสามารถศึกษาได้ต่อไป

LangChain จะมีการให้บริการเอเจนต์ที่หลากหลายประเภทสำหรับกรณีการใช้งานที่แตกต่างกัน

เครื่องมือ

คิดว่าเครื่องมือนั้นเป็น APIs ที่ถูกเตรียมไว้ก่อนแล้ว มีหลายฟังกชันที่ถูกออกแบบไว้เพื่อขยายความสามารถของ LLM ขณะนี้ LLM กำหนดสิ่อการเรียกใช้ API ที่จะทำภารกิจ

ชุดเครื่องมือ

ชุดเครื่องมือจะให้ LLM มีอย่างน้อย ๆ เครื่องมือไม่ใช่หรือสองเพื่อให้ LLM มีเลือกทำภารกิตมากขึ้นเมื่ทำภารกิจ

ผู้ดำเนินเอเจนต์

ผู้ดำเนินเอเจนต์แทนตัวทำหน้าที่ทำงานในการปฏิบัติตามเครื่องมือ (API) ที่ถูกเลือกโดย LLM โค้ดประสบการณ์การทำงานหาเจนต์คือต่อไป

next_action = agent.get_action(...)
while next_action != AgentFinish:
    observation = run(next_action)
    next_action = agent.get_action(..., next_action, observation)
return next_action

แม้กระบวนการดำเนินการไม่ใช้ยุ่งยาก แต่ผู้ดำเนินหมุนโฟกัสในประกอบปัญหาที่มีรายละเอียดมากๆ โดยที่เป็นที่สำคัญก็มีด้วย:

  1. การจัดการโดยที่เอเจนต์เลือกเครื่องมือที่ไม่อยู่ในท้อง
  2. การจัดการกับสถานการณ์ข้อผิดพลาดของเครื่องมือ
  3. การจัดการกับสถานการณ์ข้อผิดพลาดของเอเจนต์ที่สร้างผลลัพธ์ที่ไม่สามารถแก้ไขเป็นการเรียกใช้เครื่องมือ
  4. ปัญหาที่เกิดในช่วงการแก้ปัญหา

การเริ่มต้นการว่างด้วย

ส่วนนี้จะนำเสนอการใช้งานขั้นต้นของเอเจนต์ของ LangChain

1. โหลด LLM

ก่อนอื่นเราจะโหลดภาษาแบบจำลอง (LLM) ที่เราจะใช้ควบคุมเอเจนต์

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

2. กำหนดเครื่องมือ

ต่อมาเราจะกำหนดเครื่องมือบางอย่างเพื่อให้เอเจนต์เรียกใช้ โดยเราจะเขียนฟังก์ชันไพธอนที่ง่ายมาเพื่อคำนวณความยาวของคำที่รับเข้ามา

from langchain.agents import tool

@tool
def get_word_length(word: str) -> int:
    """Returns the length of the word."""
    return len(word)

get_word_length.invoke("abc")

หมายเหตุ: คำอธิบายฟังก์ชันเป็นสิ่งที่สำคัญมาก มันบอกให้ LLM รู้ว่ามันสามารถคำนวณความยาวของคำ ซึ่งฟังก์ชัน get_word_length บอก LLM ว่ามันสามารถคำนวณคุณค่าของคำ

3

กำหนดชุดเครื่องมือ

tools = [get_word_length]

3. สร้างโปรมป์โปรด

ตอนนี้เรามาสร้างโปรมป์ค่ะ โดยเนื่องจาก OpenAI Function Calling ได้รับการปรับปรุงให้เหมาะสมกับการใช้เครื่องมือมากขึ้น เราไม่จำเป็นต้องมีคำแนะนำเกี่ยวกับการคิดหรือรูปแบบเอ้าท์พุตเลย เรามีเพียงตัวแปรอินพุต 2 ตัว: input แทนคำถามที่ผู้ใช้ป้อนเข้ามา และ agency_scratchpad คือตัวยึดยอดสำหรับคำสั่งการเรียกของเอเจนต์ ซึ่งจะถูกแทรกระหว่างโปรมป์ตัวแบบเมื่อรันคำสั่งเรียกเครื่องมือนะคะ

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a very powerful assistant but do not understand the current situation.",
        ),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

4. ผูกเครื่องมือกับ LLM

เอเจนต์ทรงประสิทธิภาพอย่างไรที่จะทราบว่ามีเครื่องมือใดที่สามารถใช้ได้?

นั่นอยู่ที่การเรียกใช้เครื่องมือ OpenAI (แบบโมเดลมากมายรองรับคุณลักษณะที่เหมือนกัน) เราเพียงจำเป็นที่จะต้องบอกโมเดลรูปแบบการเรียกใช้ของเครื่องมือที่ได้กำหนดไว้เท่านั้นค่ะ

llm_with_tools = llm.bind_tools(tools)

5. สร้างเอเจนต์

ตอนนี้ที่เราได้นำเนื้อหาก่อนหน้านี้ผสมเข้าด้วยกันแล้ว เราจึงสามารถดำเนินการสร้างโปรแกรมพร็อกซีตัวแทนได้เลยนะคะ เราจะนำฟังก์ชันยูทิลิตีของสองฟังก์ชันเช่นกันมาใช้: ฟังก์ชันหนึ่งสำหรับจัดรูปแบบขั้นตอนกลาง (การกระทำพร็อกซี, เอ้าท์พุตของเครื่องมือ) เข้าไปในข้อความอินพุตที่สามารถส่งถึงโมเดลได้ และอีกอันสำหรับการแปลงข้อความเอ้าท์พุตให้เป็นการกระทำพร็อกซี/สิ้นสุดของเพร็กซี

from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
    }
    | prompt
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)

กำหนดตัวประมวลผลเอเจนต์

from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

เรามาสาธิตการดำเนินการของโปรแกรมพร็อกซีเลยค่ะ:

list(agent_executor.stream({"input": "How many letters are there in the word 'eudca'?"}))

ตัวอย่างบันทึกเอ้าท์พุตของเอเจนต์

> เข้าสู่โซนปฏิบัติการของอีเจนต์ใหม่...

การเรียกใช้: กำลังรัน `get_word_length` โดยใช้พารามิเตอร์ `{'word': 'educa'}`

คำว่า "educa" มี 5 ตัวอักษรค่ะ

> สิ้นสุดโซนปฏิบัติการ

ผ่านตัวอย่างนี้เราได้อธิบายกระบวนการทั้งหมดของโปรแกรมพร็อกซีเป็นที่เรียบร้อยแล้วนะคะ

เพิ่มความสามารถในการจดจำให้กับเอเจนต์

หากเราต้องการให้เอเจนต์จำข้อความที่สนทนาไปก่อนหน้านี้ เราสามารถทำได้ง่ายๆเพียงที่เพิ่มเนื้อหาที่ AI ส่งออกมาไปใส่ในโปรมป์ และส่งต่อไปยัง AI พร้อมๆกัน

การปรับเปลี่ยนแม่แบบโปรมป์

ด้านล่างเป็นการปรับเปลี่ยนแม่แบบโปรมป์เพื่อรวมเทมเพลทประวัติการสนทนาด้วยค่ะ

from langchain.prompts import MessagesPlaceholder

MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a great assistant, but not good at calculating the length of words.",
        ),
        MessagesPlaceholder(variable_name=MEMORY_KEY),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

การปรับเปลี่ยนการนิยามกระบวนการเอเจนต์

ปรับเปลี่ยนการนิยามกระบวนการของเอเจนต์เพื่อให้สามารถให้ข้อมูลประวัติการสนทนาสำหรับเทมเพลทโปรมป์ ดังโค้ดด้านล่างค่ะ การเตรียม chat_history parameter handling เข้าไป

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(
            x["intermediate_steps"]
        ),
        "chat_history": lambda x: x["chat_history"],
    }
    | prompt
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
chat_history = []

input1 = "How many letters are there 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": "Does this word really exist?", "chat_history": chat_history})

ในกรณีธุรกิจจริง ๆ คุณสามารถบันทึกประวัติการสนทนาไปยังฐานข้อมูล และแทรกข้อมูลลงในโพรมป์ตามต้องการของธุรกิจ

เคล็ดลับ: ฟังก์ชันการจดจำของโมเดลขนาดใหญ่ (LLM) ในปัจจุบันมักปฏิบัติโดยการแทรกเนื้อหาการสนทนาประวัติเก่าลงในโพรมป์ และส่งข้อมูลไปยัง LLM ได้อย่างง่ายดาย แต่ LangChain ยังมีการห่อหุ้มบางส่วน คุณสามารถเลือกที่จะไม่ใช้หรือเชื่อมต่อประวัติการสนทนาอย่างด้วยตัวและเชื่อมต่อโดยตนเองเข้ากับแม่แบบโพรม ณ คราวนั้น