LangChain Skills-ის მოდელის პრაქტიკული გამოყენება: SQL ასისტენტის შექმნა მოთხოვნისამებრ ცოდნის ჩატვირთვით
წინა სტატიაში ჩვენ განვიხილეთ, თუ როგორ შეიძლება Deep Agents CLI-ის საშუალებით Deep Agent-ის Skills-ის გამოყენების მოდელის სიმულირება. დღესდღეობით, LangChain-ი უკვე უზრუნველყოფს ამ ფუნქციის მხარდაჭერას, რაც მნიშვნელოვნად ამარტივებს განვითარების პროცესს. ეს სტატია დაგეხმარებათ ამ ფუნქციის სიღრმისეულად შესწავლაში და უფრო ჭკვიანი SQL ასისტენტის შექმნაში.
რთული AI Agent-ის შექმნისას, დეველოპერები ხშირად დილემის წინაშე დგანან: ჩატვირთონ ყველა კონტექსტი (მონაცემთა ბაზის ცხრილის სტრუქტურა, API დოკუმენტაცია, ბიზნეს წესები) ერთჯერადად System Prompt-ში, რაც გამოიწვევს კონტექსტის ფანჯრის (Context Window) გადატვირთვას და მოდელის ყურადღების გაფანტვას? თუ აირჩიონ ხშირი მიკრო-რეგულირება (Fine-tuning), რაც ძვირი ჯდება?
Skills-ის მოდელი (Skills Pattern) გთავაზობთ ელეგანტურ შუალედურ გზას. ის უზრუნველყოფს კონტექსტის ეფექტურ გამოყენებას საჭირო ცოდნის დინამიურად ჩატვირთვით. LangChain-ის მიერ ამ მოდელის მშობლიური მხარდაჭერა ნიშნავს, რომ ჩვენ შეგვიძლია უფრო მარტივად შევქმნათ Agent-ები, რომლებსაც აქვთ "მოთხოვნისამებრ სწავლის" უნარი.
ეს სტატია, ოფიციალურ დოკუმენტთან ერთად Build a SQL assistant with on-demand skills, დაეხმარება მკითხველს ნულიდან შექმნას SQL Assistant, რომელიც მხარს უჭერს "მოთხოვნისამებრ ცოდნის" ჩატვირთვას.
1. ძირითადი კონცეფცია: რატომ ავირჩიოთ Skills-ის მოდელი?
ტრადიციული SQL Agent-ის შეზღუდვები
ტრადიციულ SQL Agent-ის არქიტექტურაში, ჩვენ, როგორც წესი, უნდა მივაწოდოთ სრული Database Schema System Prompt-ში. ბიზნესის განვითარებასთან ერთად, როდესაც ცხრილების რაოდენობა ასობით იზრდება, ეს მიდგომა მნიშვნელოვან პრობლემებს იწვევს:
-
Token-ების დიდი მოხმარება: ყოველი დიალოგისთვის უამრავი შეუსაბამო ცხრილის სტრუქტურის ტარება, რაც იწვევს რესურსების ფლანგვას.
-
ჰალუცინაციების რისკის გაზრდა: ზედმეტი შეუსაბამო ინფორმაცია ამცირებს მოდელის მსჯელობის სიზუსტეს.
-
მოვლის სირთულე: ყველა ბიზნეს ხაზის ცოდნა მჭიდროდ არის დაკავშირებული, რაც ართულებს დამოუკიდებელ იტერაციას.
Skills-ის მოდელი: პროგრესული გამჟღავნების საფუძველზე დაფუძნებული გადაწყვეტა
Skills-ის მოდელი ეფუძნება პროგრესული გამჟღავნების (Progressive Disclosure) პრინციპს, რომელიც ცოდნის მიღების პროცესს ფენებად ყოფს:
-
Agent-ის საწყისი მდგომარეობა: მხოლოდ იცის, რა "უნარები" (Skills) არსებობს და მათი მოკლე აღწერა (Description), რათა შეინარჩუნოს სიმსუბუქე.
-
დროებითი ჩატვირთვა: როდესაც კონკრეტული პრობლემის (როგორიცაა "მარაგის მოკვლევა") წინაშე დგას, Agent-ი აქტიურად იძახებს ინსტრუმენტს (
load_skill) ამ უნარის დეტალური კონტექსტის (Schema + Prompt) ჩასატვირთად. -
დავალების შესრულება: ჩატვირთული ზუსტი კონტექსტის საფუძველზე, ასრულებს კონკრეტულ დავალებას (როგორიცაა SQL-ის დაწერა და შესრულება).
ეს მოდელი ეფექტურად უჭერს მხარს უსასრულო გაფართოებას და გუნდის გამოყოფას, რაც Agent-ს საშუალებას აძლევს მოერგოს მზარდ ბიზნეს სცენარებს.
2. სისტემის არქიტექტურის დიზაინი
ეს პრაქტიკული პროექტი შექმნის SQL Assistant-ს, რომელიც შეიცავს ორ ძირითად Skills-ს, რათა აჩვენოს ამ მოდელის რეალური გამოყენება:
-
Sales Analytics (გაყიდვების ანალიტიკა): პასუხისმგებელია
sales_dataცხრილზე, ამუშავებს შემოსავლების სტატისტიკას, შეკვეთების ტენდენციების ანალიზს და ა.შ. -
Inventory Management (მარაგების მართვა): პასუხისმგებელია
inventory_itemsცხრილზე, ამუშავებს მარაგების დონის მონიტორინგს, ადგილმდებარეობის მოკვლევას და ა.შ.
3. განვითარების გარემოს შექმნა
ეს პროექტი იყენებს Python-ისuv-ს ეფექტური დამოკიდებულების მართვისთვის.
ძირითადი დამოკიდებულებების ინსტალაცია
uv add langchain langchain-openai langgraph psycopg2-binary python-dotenv langchain-community
PostgreSQL გარემოს კონფიგურაცია
ლოკალურად გაუშვით Postgres-ის ინსტანცია და შექმენითagent_platformმონაცემთა ბაზა. ჩვენ გთავაზობთsetup_db.pyსკრიპტს ცხრილის სტრუქტურისა და სატესტო მონაცემების ავტომატურად ინიციალიზაციისთვის (დეტალებისთვის იხილეთ წყარო კოდი სტატიის ბოლოს).
4. ძირითადი განხორციელების ნაბიჯების დეტალური განხილვა### ნაბიჯი 1: დომენის უნარების განსაზღვრა (ცოდნა)
ჩვენ განვსაზღვრავთ უნარებს, როგორც ლექსიკონის სტრუქტურას, რომელიც ახდენს ფაილური სისტემიდან ან მონაცემთა ბაზიდან ჩატვირთვის სიმულაციას. გთხოვთ, გაითვალისწინოთ განსხვავება description-ს (გამოიყენება აგენტის მიერ გადაწყვეტილების მისაღებად) და content-ს (ფაქტობრივი დატვირთული დეტალური კონტექსტი) შორის.
SKILLS = {"sales_analytics": {"description":"სასარგებლოა გაყიდვების შემოსავლების, ტენდენციების ანალიზისთვის...","content":"""... ცხრილის სქემა: sales_data ..."" },"inventory_management": {"description":"სასარგებლოა მარაგების დონის შესამოწმებლად...","content":"""... ცხრილის სქემა: inventory_items ..."" }}
ნაბიჯი 2: ძირითადი ინსტრუმენტების განხორციელება (შესაძლებლობები)
აგენტი ეყრდნობა ორ მნიშვნელოვან ინსტრუმენტს ამოცანების შესასრულებლად:
-
load_skill(skill_name)**: განსაზღვრული უნარის დეტალების დინამიურად ჩატვირთვა გაშვების დროს. ** -
run_sql_query(query)**: კონკრეტული SQL განცხადებების შესრულება. **
ნაბიჯი 3: აგენტის ლოგიკის ორგანიზება (ტვინი)
LangGraph-ის გამოყენებით ReAct აგენტის აგება. System Prompt აქ მნიშვნელოვან როლს ასრულებს, ის აგენტს ავალებს მკაცრად დაიცვას Identify -> Load -> Query სტანდარტული საოპერაციო პროცედურა (SOP).
system_prompt ="""1. Identify the relevant skill.2. Use 'load_skill' to get schema.3. Write and execute SQL using 'run_sql_query'....Do not guess table names. Always load the skill first.""
5. გაშვების ეფექტის ვალიდაცია
test_agent.py-ის გაშვებით, ჩვენ გამოვცადეთ Sales-ისა და Inventory-ის ორი განსხვავებული დომენის შეკითხვა. ქვემოთ მოცემულია კონსოლის ფაქტობრივი გამომავალი ჟურნალი, რომელიც აჩვენებს, თუ როგორ ახდენს აგენტი უნარების დინამიურად ჩატვირთვას კითხვის მიხედვით:
Testing Sales Query...Agent calling tools: [{'name': 'load_skill', 'args': {'skill_name': 'sales_analytics'}, 'id': 'call_f270d76b7ce4404cb5f61bf2', 'type': 'tool_call'}]Tool output:You are a Sales Analytics Expert.You have access to the 'sales_data' table.Table Schema:- id: integer...Agent calling tools: [{'name': 'run_sql_query', 'args': {'query': 'SELECT SUM(amount) as total_revenue FROM sales_data;'}, 'id': 'call_b4f3e686cc7f4f22b3bb9ea7', 'type': 'tool_call'}]Tool output: [(Decimal('730.50'),)]...Agent response: The total revenue is $730.50.Testing Inventory Query...Agent calling tools: [{'name': 'load_skill', 'args': {'skill_name': 'inventory_management'}, 'id': 'call_18c823b2d5064e95a0cfe2e3', 'type': 'tool_call'}]Tool output:You are an Inventory Management Expert.You have access to the 'inventory_items' table.Table Schema...Agent calling tools: [{'name': 'run_sql_query', 'args': {'query': "SELECT warehouse_location FROM inventory_items WHERE product_name = 'Laptop';'}, 'id': 'call_647ee3a444804bd98a045f00', 'type': 'tool_call'}]Tool output: [('Warehouse A',)]...Agent response: The Laptop is located in **Warehouse A**.## 6. სრული საწყისი კოდის მითითება
ქვემოთ მოცემულია პროექტის სრული საწყისი კოდი, რომელიც შეიცავს მონაცემთა ბაზის ინიციალიზაციის სკრიპტს და Agent-ის მთავარ პროგრამას.
1. მონაცემთა ბაზის ინიციალიზაცია (setup_db.py)
`import psycopg2 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT import os from dotenv import load_dotenv
load_dotenv()
გთხოვთ, დარწმუნდეთ, რომ .env-ში კონფიგურირებულია მონაცემთა ბაზასთან კავშირის ინფორმაცია
DB_HOST = os.getenv("DB_HOST", "localhost") DB_PORT = os.getenv("DB_PORT", "5432") DB_USER = os.getenv("DB_USER", "postgres") DB_PASSWORD = os.getenv("DB_PASSWORD", "your_password") # გთხოვთ, შეცვალოთ რეალური პაროლით DB_NAME = os.getenv("DB_NAME", "agent_platform")
def create_database(): try: # დაუკავშირდით ნაგულისხმევ 'postgres' მონაცემთა ბაზას ახალი db-ის შესაქმნელად conn = psycopg2.connect( host=DB_HOST, port=DB_PORT, user=DB_USER, password=DB_PASSWORD, dbname="postgres", ) conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) cur = conn.cursor()
# შეამოწმეთ, არსებობს თუ არა მონაცემთა ბაზა
cur.execute(f"SELECT 1 FROM pg_catalog.pg_database WHERE datname = '{DB_NAME}'")
exists = cur.fetchone()
if not exists:
print(f"Creating database {DB_NAME}...")
cur.execute(f"CREATE DATABASE {DB_NAME}")
else:
print(f"Database {DB_NAME} already exists.")
cur.close()
conn.close()
except Exception as e:
print(f"Error creating database: {e}")
def create_tables_and_data(): try: conn = psycopg2.connect( host=DB_HOST, port=DB_PORT, user=DB_USER, password=DB_PASSWORD, dbname=DB_NAME, ) cur = conn.cursor()
# Sales Table-ის შექმნა
print("Creating sales_data table...")
cur.execute(
"""
CREATE TABLE IF NOT EXISTS sales_data (
id SERIAL PRIMARY KEY,
transaction_date DATE,
product_id VARCHAR(50),
amount DECIMAL(10, 2),
region VARCHAR(50)
)
"""
)
# Inventory Table-ის შექმნა
print("Creating inventory_items table...")
cur.execute(
"""
CREATE TABLE IF NOT EXISTS inventory_items (
id SERIAL PRIMARY KEY,
product_id VARCHAR(50),
product_name VARCHAR(100),
stock_count INTEGER,
warehouse_location VARCHAR(50)
)
"""
)
# Mock Data-ს ჩასმა
print("Inserting mock data...")
cur.execute("TRUNCATE sales_data, inventory_items")
sales_data = [
('2023-01-01', 'P001', 100.00, 'North'),
('2023-01-02', 'P002', 150.50, 'South'),
('2023-01-03', 'P001', 120.00, 'East'),
('2023-01-04', 'P003', 200.00, 'West'),
('2023-01-05', 'P002', 160.00, 'North'),
]
cur.executemany(
"INSERT INTO sales_data (transaction_date, product_id, amount, region) VALUES (%s, %s, %s, %s)",
sales_data,
)
inventory_data = [
('P001', 'Laptop', 50, 'Warehouse A'),
('P002', 'Mouse', 200, 'Warehouse B'),
('P003', 'Keyboard', 150, 'Warehouse A'),
('P004', 'Monitor', 30, 'Warehouse C'),
]
cur.executemany(
"INSERT INTO inventory_items (product_id, product_name, stock_count, warehouse_location) VALUES (%s, %s, %s, %s)",
inventory_data,
)
conn.commit()
cur.close()
conn.close()
print("Database setup complete.")
except Exception as e:
print(f"Error setting up tables: {e}")
if name == "main": create_database() create_tables_and_data() `### 2. Agent-ის მთავარი პროგრამა (main.py)
`import os from typing import Annotated, Literal, TypedDict, Union, Dict from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage from langchain_community.utilities import SQLDatabase from langchain_community.agent_toolkits import SQLDatabaseToolkit from langgraph.graph import StateGraph, START, END, MessagesState from langgraph.prebuilt import ToolNode, tools_condition
load_dotenv()
--- კონფიგურაცია ---
BASE_URL = os.getenv("BASIC_MODEL_BASE_URL") API_KEY = os.getenv("BASIC_MODEL_API_KEY") MODEL_NAME = os.getenv("BASIC_MODEL_MODEL") DB_URI = f"postgresql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
--- მონაცემთა ბაზის დაყენება ---
db = SQLDatabase.from_uri(DB_URI)
--- უნარების განსაზღვრა ---
SKILLS: Dict[str, Dict[str, str]] = { "sales_analytics": { "description": "სასარგებლოა გაყიდვების შემოსავლების, ტენდენციებისა და რეგიონული მაჩვენებლების ანალიზისთვის.", "content": """ თქვენ ხართ გაყიდვების ანალიტიკის ექსპერტი. თქვენ გაქვთ წვდომა 'sales_data' ცხრილზე. ცხრილის სქემა: - id: მთელი რიცხვი (პირველადი გასაღები) - transaction_date: თარიღი - product_id: varchar(50) - amount: ათობითი (10, 2) - region: varchar(50) საერთო მოთხოვნები: - მთლიანი შემოსავალი: SUM(amount) - შემოსავალი რეგიონის მიხედვით: GROUP BY region - გაყიდვების ტენდენცია: GROUP BY transaction_date """ }, "inventory_management": { "description": "სასარგებლოა მარაგების დონის, პროდუქტის ადგილმდებარეობისა და საწყობის მართვის შესამოწმებლად.", "content": """ თქვენ ხართ მარაგების მართვის ექსპერტი. თქვენ გაქვთ წვდომა 'inventory_items' table.Table Schema:- id: integer (პირველადი გასაღები)- product_id: varchar(50)- product_name: varchar(100)- stock_count: integer- warehouse_location: varchar(50)Common queries:- Check stock: WHERE product_name = '...'- Low stock: WHERE stock_count < threshold""" }}# --- Tools ---@tooldefload_skill(skill_name: str)-> str:e)workflow.add_node(\ke({"messages": messages}) last_msg = final_state["messages"][-1] if isinstance(last_msg, AIMessage): print(last_msg.content) messages = final_state["messages"]
Update history
print("-"*50) except Exception as e: print(f"\nError:{e}") break





