LangChain Skills Qaabka Dhaqan-gelinta: Dhisidda Kaaliyaha SQL ee Xogta Ku-soo-rogashada Baahida
Maqaalkii hore, waxaan ku sahaminnay sida loo ekaysiiyo Deep Agent iyadoo la isticmaalayo Skills iyadoo la adeegsanayo Deep Agents CLI. Maanta, LangChain waxay si dabiici ah u taageertaa muuqaalkan, taasoo si weyn u fududaynaysa habka horumarinta. Maqaalkani wuxuu ku hogaamin doonaa inaad si qoto dheer ula kulanto shaqadan oo aad dhisto kaaliye SQL oo caqli badan.
Marka la dhisayo Wakiil AI oo adag, horumariyayaashu waxay inta badan ku dhacaan laba-geesood: Ma in dhammaan macnaha guud (qaab-dhismeedka miiska xogta, dukumentiyada API, xeerarka ganacsiga) lagu duro System Prompt hal mar, taasoo keenta daaqad macnaha guud (Context Window) oo buux dhaafiya oo kala firdhisa dareenka moodeelka? Mise dooro hagaajin joogto ah oo qaali ah (Fine-tuning)?
Qaabka Skills (Skills Pattern) wuxuu bixiyaa dariiq dhexe oo qurux badan. Waxay ku gaartaa isticmaalka hufan ee macnaha guud iyadoo si firfircoon loo soo rogayo aqoonta loo baahan yahay. Taageerada dabiiciga ah ee LangChain ee qaabkan waxay la macno tahay inaan si fudud u dhisi karno Wakiil leh awood "barasho baahi ku saleysan".
Maqaalkani wuxuu ku darayaa dukumeentiga rasmiga ah Dhis kaaliye SQL ah oo leh xirfado baahi ku saleysan, wuxuu ku hogaamin doonaa akhristayaasha inay ka bilaabaan xoq, iyagoo dhisaya Kaaliye SQL ah oo taageera "soo rogista aqoonta baahi ku saleysan".
1. Fikradaha Asaasiga ah: Maxaa loo Doortay Qaabka Skills?
Xaddidaadaha Wakiilka SQL ee Dhaqanka
Qaab dhismeedka Wakiilka SQL ee dhaqanka, waxaan sida caadiga ah u baahanahay inaan ku bixinno Database Schema oo dhammaystiran System Prompt. Marka ganacsigu koro, marka tirada miisasku ay ballaaraan boqolaal, habkani wuxuu keeni doonaa dhibaatooyin la taaban karo:
-
Isticmaalka Token-ka oo aad u badan: Wada hadal kastaa wuxuu wataa qaab-dhismeedka miisaska aan khusayn, taasoo keenta khasaare kheyraad.
-
Kordhinta Khatarta Khayaaliga: Macluumaadka faragelinta aan khusayn ee xad-dhaafka ah ayaa yareyn doona saxnaanta sababaynta moodeelka.
-
Dayactirka oo adag: Aqoonta dhammaan khadadka ganacsiga si dhow ayaa isugu xiran, taasoo adkeynaysa in si madaxbanaan loo celceliyo.
Qaabka Skills: Xalka ku saleysan Daahfurka Horumarsan
Qaabka Skills wuxuu ku saleysan yahay mabda'a Daahfurka Horumarsan (Progressive Disclosure), kaasoo kala saaraya habka helitaanka aqoonta:
-
Xaaladda Bilowga ah ee Wakiilka: Kaliya faham waxa "xirfadaha" (Skills) ay yihiin iyo sharraxaadooda kooban (Description), iyadoo la ilaalinayo miisaanka fudud.
-
Soo rogista Waqtiga Shaqada: Marka la wajahayo dhibaato gaar ah (sida "raadinta kaydka"), Wakiilku wuxuu si firfircoon u yeeraa qalabka (
load_skill) si uu u soo rogo macnaha guud ee faahfaahsan ee xirfadda (Schema + Prompt). -
Fulinta Hawsha: Iyadoo lagu salaynayo macnaha guud ee saxda ah ee la soo rogay, fuli hawl gaar ah (sida qorista iyo fulinta SQL).
Qaabkani wuxuu si wax ku ool ah u taageeraa ballaarinta aan xadka lahayn iyo kala saarista kooxda, taasoo awood u siinaysa Wakiilka inuu la qabsado xaaladaha ganacsi ee sii kordhaya.
2. Naqshadeynta Qaab dhismeedka Nidaamka
Mashruucan dhaqan-gelinta wuxuu dhisi doonaa Kaaliye SQL ah oo ka kooban laba Skills oo muhiim ah si loo muujiyo codsiga dhabta ah ee qaabkan:
-
Sales Analytics (Falanqaynta Iibka): Mas'uul ka ah miiska
sales_data, oo ka shaqeeya tirakoobyada dakhliga, falanqaynta isbeddellada dalabaadka, iwm. -
Inventory Management (Maareynta Kaydka): Mas'uul ka ah miiska
inventory_items, oo ka shaqeeya la socodka heerka kaydka, raadinta goobta, iwm.
3. Dhisidda Deegaanka Horumarinta
Mashruucani wuxuu adeegsadaa Pythonuv si loo maareeyo ku tiirsanaanta si hufan.
Rakibidda Ku Tiirsanaanta Muhiimka ah
uv add langchain langchain-openai langgraph psycopg2-binary python-dotenv langchain-community
Habeynta Deegaanka PostgreSQL
Bilow tusaale Postgres ah oo maxalli ah oo samee xogtaagent_platform. Waxaan bixinaa qoraalkasetup_db.py si toos ah loo bilaabo qaab-dhismeedka miiska iyo xogta tijaabada (eeg koodhka isha ee dhamaadka maqaalka).
4. Faahfaahin Faahfaahsan oo ku Saabsan Tallaabooyinka Hirgelinta Muhiimka ah### Tallaabada Koowaad: Qeexida Xirfadaha Domain-ka (Aqoonta)
Waxaan xirfadaha u qeexeynaa qaab qaamuus ah, anagoo ku dayeyna habka looga soo dejiyo faylasha ama xog ururinta. Fadlan kala sooc description (oo loo isticmaalo Wakiilka go'aan qaadashada) iyo content (macluumaadka faahfaahsan ee dhabta ah).
SKILLS = {"sales_analytics": {"description":"Waxaa faa'iido leh falanqaynta dakhliga iibka, isbeddellada...","content":"""... Jadwalka Schema: sales_data ..."" },"inventory_management": {"description":"Waxaa faa'iido leh hubinta heerarka kaydka...","content":"""... Jadwalka Schema: inventory_items ..."" }}
Tallaabada Labaad: Hirgelinta Qalabka Muhiimka ah (Awoodaha)
Wakiilku wuxuu ku tiirsan yahay laba qalab oo muhiim ah si uu u dhammaystiro hawlaha:
-
load_skill(skill_name): Waxay si firfircoon u soo dejisaa faahfaahinta xirfadda la cayimay xilliga shaqada. -
run_sql_query(query): Waxay fulisaa weedhaha SQL ee gaarka ah.
Tallaabada Saddexaad: Abaabulka Macquulka Wakiilka (Maskaxda)
Isticmaal LangGraph si aad u dhisto Wakiilka ReAct. System Prompt wuxuu door muhiim ah ka ciyaaraa halkan, isagoo hagaya Wakiilka inuu si adag u raaco habka caadiga ah ee shaqada (SOP) ee ah Identify -> Load -> Query.
system_prompt ="""1. Aqoonso xirfadda ku habboon.2. Isticmaal 'load_skill' si aad u hesho schema.3. Qor oo fuli SQL adigoo isticmaalaya 'run_sql_query'....Ha qiyaasin magacyada jadwalka. Had iyo jeer xirfadda soo deji marka hore.""
5. Xaqiijinta Saamaynta Shaqada
Adigoo socodsiinaya test_agent.py, waxaan tijaabinay su'aalaha laba domain oo kala duwan oo ah Iibka iyo Kaydka. Hoos waxaa ku yaal diiwaanka wax soo saarka dhabta ah ee konsole-ka, oo muujinaya sida Wakiilku si firfircoon u soo dejiyo xirfadaha iyadoo ku saleysan su'aasha:
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. Tixraaca Isha Buuxda
Hoos waxaa ku yaal koodhka isha oo buuxa ee mashruuca, oo ay ku jiraan qoraalka bilowga ah ee xog ururinta iyo barnaamijka ugu muhiimsan ee Agent.
1. Bilowga Xog ururinta (setup_db.py)
`import psycopg2 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT import os from dotenv import load_dotenv
load_dotenv()
Fadlan hubi in macluumaadka isku xirka xog ururinta lagu habeeyay .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") # Fadlan ku beddel erayga sirta ah ee dhabta ah DB_NAME = os.getenv("DB_NAME", "agent_platform")
def create_database(): try: # Ku xir xog ururinta caadiga ah ee 'postgres' si loo abuuro DB cusub 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()
# Hubi haddii xog ururinta ay jirto
cur.execute(f"SELECT 1 FROM pg_catalog.pg_database WHERE datname = '{DB_NAME}'")
exists = cur.fetchone()
if not exists:
print(f"Abuurista xog ururinta {DB_NAME}...")
cur.execute(f"CREATE DATABASE {DB_NAME}")
else:
print(f"Xog ururinta {DB_NAME} horey ayey u jirtaa.")
cur.close()
conn.close()
except Exception as e:
print(f"Khalad abuurista xog ururinta: {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()
# Abuur Jadwalka Iibka
print("Abuurista jadwalka sales_data...")
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)
)
""")
# Abuur Jadwalka Alaabta
print("Abuurista jadwalka inventory_items...")
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)
)
""")
# Geli Xog been abuur ah
print("Gelin xog been abuur ah...")
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("Habeynta xog ururinta waa dhamaatay.")
except Exception as e:
print(f"Khalad habeynta jadwalka: {e}")
if name == "main": create_database() create_tables_and_data() `### 2. Agent 主程序 (main.py)
`importosfromtypingimportAnnotated, Literal, TypedDict, Union, Dictfromdotenvimportload_dotenvfromlangchain_openaiimportChatOpenAIfromlangchain_core.toolsimporttoolfromlangchain_core.messagesimportSystemMessage, HumanMessage, AIMessage, ToolMessagefromlangchain_community.utilitiesimportSQLDatabasefromlangchain_community.agent_toolkitsimportSQLDatabaseToolkitfromlanggraph.graphimportStateGraph, START, END, MessagesStatefromlanggraph.prebuiltimportToolNode, tools_conditionload_dotenv()# --- Configuration ---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')}"# --- Database Setup ---db = SQLDatabase.from_uri(DB_URI)# --- Skills Definition ---SKILLS: Dict[str, Dict[str, str]] = {"sales_analytics": {"description":"Waxaa faa'iido leh falanqaynta dakhliga iibka, isbeddellada, iyo waxqabadka gobolka.","content":"""Waxaad tahay Khabiir ku takhasusay Falanqaynta Iibka.Waxaad heli kartaa miiska 'sales_data'.Shaxda Shaxda:- id: integer (furaha koowaad)- transaction_date: taariikh- product_id: varchar(50)- amount: decimal(10, 2)- region: varchar(50)Su'aalaha caadiga ah:- Wadarta dakhliga: SUM(amount)- Dakhliga gobol ahaan: GROUP BY region- Isbeddelka iibka: GROUP BY transaction_date""" },"inventory_management": {"description":"Waxaa faa'iido leh hubinta heerarka kaydka, goobaha alaabta, iyo maamulka bakhaarka.","content":"""Waxaad tahay Khabiir ku takhasusay Maareynta Kaydka"""Table Schema:
- id: integer (primary key)
- 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:"""
Load the detailed prompt and schema for a specific skill.
Available skills:
- sales_analytics: For sales, revenue, and transaction analysis.
- inventory_management: For stock, products, and warehouse queries. """ skill = SKILLS.get(skill_name) if not skill: return f"Error: Skill '{skill_name}' not found. Available skills: {list(SKILLS.keys())}" return skill["content"]
@tool def run_sql_query(query: str) -> str: """ Execute a SQL query against the database. Only use this tool AFTER loading the appropriate skill to understand the schema. """ try: return db.run(query) except Exception as e: return f"Error executing SQL: {e}"
@tool def list_tables() -> str: """List all available tables in the database.""" return str(db.get_usable_table_names())
tools = [load_skill, run_sql_query, list_tables]
--- Agent Setup ---
llm = ChatOpenAI( base_url=BASE_URL, api_key=API_KEY, model=MODEL_NAME, temperature=0 )
llm_with_tools = llm.bind_tools(tools)
--- Graph Definition ---
class AgentState(MessagesState):
We can add custom state if needed, but MessagesState is sufficient for simple chat
pass
def agent_node(state: AgentState): messages = state["messages"] response = llm_with_tools.invoke(messages) return {"messages": [response]}
workflow = StateGraph(AgentState) workflow.add_node("agent", agent_node)workflow.add_node("tools", ToolNode(tools))workflow.add_edge(START,"agent")workflow.add_conditional_edges("agent", tools_condition)workflow.add_edge("tools","agent")app = workflow.compile()# --- Main Execution ---if__name__ =="main": system_prompt ="""Waxaad tahay Kaaliyaha SQL ee caawimaadka badan.Waxaad heli kartaa xirfado gaar ah oo ay ku jiraan jaantusyada xogta iyo aqoonta domainka.Si aad uga jawaabto su'aasha isticmaalaha:1. Aqoonso xirfadda ku habboon (sales_analytics ama inventory_management).2. Isticmaal qalabka 'load_skill' si aad u hesho jaantuska iyo tilmaamaha.3. Iyadoo lagu saleynayo xirfadda la raray, qor oo fuli weydiinta SQL adoo isticmaalaya 'run_sql_query'.4. U jawaab su'aasha isticmaalaha adoo ku saleynaya natiijooyinka weydiinta.Ha qiyaasin magacyada jadwalka. Had iyo jeer xirfadda rarto marka hore.""" print("Kaaliyaha SQL waa la bilaabay. Ku qor 'quit' si aad uga baxdo.") print("-"*50) messages = [SystemMessage(content=system_prompt)]# Hubinta isku xirka hore-diirin isku dayga: print(f"Waxaa lagu xiray xogta:{DB_URI.split('@')[-1]}")exceptExceptionase: print(f"Digniinta isku xirka xogta:{e}")whileTrue:try: user_input = input("Isticmaale: ")ifuser_input.lower()in["quit","exit"]:break messages.append(HumanMessage(content=user_input))# Daadi fulinta print("Wakiil: ", end="", flush=True) final_response =Noneforeventinapp.stream({"messages": messages}, stream_mode="values"):# Qaabka 'values', waxaan helnaa xaaladda buuxda. Waxaan kaliya dooneynaa inaan aragno fariinta ugu dambeysa haddii ay cusub tahay. last_message = event["messages"][-1]# Cusbooneysii taariikhda fariintayada xaaladda ugu dambeysapass# Ka dib marka daadku dhammaado, xaaladda ugu dambeysa waxay leedahay jawaabta ugu dambeysa final_state = app.invoke({"messages": messages}) last_msg = final_state["messages"][-1]ifisinstance(last_msg, AIMessage): print(last_msg.content) messages = final_state["messages"]# Update history print("-"*50)exceptExceptionase: print(f"\nError:{e}")break`





