LangChain Skills Mode Praktiskā Realizācija: SQL Palīga Izveide ar Pēc Pieprasījuma Ielādējamām Zināšanām

2/13/2026
7 min read

Iepriekšējā rakstā mēs izpētījām, kā simulēt Deep Agent Skills režīmu, izmantojot Deep Agents CLI. Tagad LangChain to atbalsta vietēji, ievērojami vienkāršojot izstrādes procesu. Šis raksts palīdzēs jums padziļināti izpētīt šo funkciju, izveidojot viedāku SQL palīgu.

Veidojot sarežģītus AI aģentus, izstrādātāji bieži nonāk dilemma: vai nu vienreizēji ievadīt visu kontekstu (datubāzes tabulu struktūras, API dokumentāciju, biznesa noteikumus) System Prompt, izraisot konteksta loga (Context Window) pārpildīšanu un modeļa uzmanības novēršanu? Vai arī izvēlēties dārgu biežu precizēšanu (Fine-tuning)?

Skills režīms (Skills Pattern) piedāvā elegantu vidusceļu. Tas nodrošina efektīvu konteksta izmantošanu, dinamiski ielādējot nepieciešamās zināšanas. LangChain vietējais atbalsts šim režīmam nozīmē, ka mēs varam vieglāk izveidot aģentu ar "pēc pieprasījuma mācīšanās" iespējām.

Šis raksts apvienos oficiālo dokumentāciju Build a SQL assistant with on-demand skills, lai palīdzētu lasītājiem no nulles izveidot SQL Assistant, kas atbalsta "pēc pieprasījuma zināšanu ielādi".

1. Galvenie jēdzieni: Kāpēc izvēlēties Skills režīmu?

Tradicionālā SQL aģenta ierobežojumi

Tradicionālajā SQL aģenta arhitektūrā mums parasti System Prompt jānorāda pilna datubāzes shēma. Attīstoties biznesam, kad tabulu skaits paplašinās līdz simtiem, šī metode rada būtiskas problēmas:

  • Milzīgs Token patēriņš: katra saruna ietver lielu skaitu nesaistītu tabulu struktūru, izšķērdējot resursus.

  • Palielināts halucināciju risks: pārmērīga nesaistīta traucējoša informācija samazinās modeļa secinājumu precizitāti.

  • Grūta uzturēšana: visas biznesa līniju zināšanas ir cieši saistītas, un tās ir grūti atkārtot neatkarīgi.

Skills režīms: risinājums, kas balstīts uz pakāpenisku atklāšanu

Skills režīms ir balstīts uz pakāpeniskas atklāšanas (Progressive Disclosure) principu, kas sadala zināšanu iegūšanas procesu slāņos:

  • Aģenta sākotnējais stāvoklis: tikai zina, kādas "prasmes" (Skills) pastāv un to īss apraksts (Description), saglabājot vieglu svaru.

  • Ielāde izpildlaikā: saskaroties ar konkrētu problēmu (piemēram, "vaicājums par krājumiem"), aģents aktīvi izsauc rīku (load_skill) lai ielādētu detalizētu šīs prasmes kontekstu (Schema + Prompt).

  • Uzdevuma izpilde: pamatojoties uz ielādēto precīzo kontekstu, veiciet konkrētus uzdevumus (piemēram, SQL rakstīšana un izpilde).

Šis režīms efektīvi atbalsta bezgalīgu paplašināšanu un komandas atsaisti, ļaujot aģentam pielāgoties arvien sarežģītākiem biznesa scenārijiem.

2. Sistēmas arhitektūras dizains

Šis praktiskais projekts izveidos SQL Assistant, kas ietver divas galvenās Skills, lai demonstrētu šī režīma praktisko pielietojumu:

  • Sales Analytics (Pārdošanas analītika): atbild parsales_datatabulu, apstrādājot ieņēmumu statistiku, pasūtījumu tendenču analīzi utt.

  • Inventory Management (Krājumu pārvaldība): atbild parinventory_itemstabulu, apstrādājot krājumu līmeņa uzraudzību, atrašanās vietas vaicājumus utt.

3. Izstrādes vides izveide

Šis projekts izmanto Pythonuv, lai efektīvi pārvaldītu atkarības.

Galveno atkarību instalēšana

uv add langchain langchain-openai langgraph psycopg2-binary python-dotenv langchain-community

PostgreSQL vides konfigurācija

Lokāli palaidiet Postgres instanci un izveidojietagent_platformdatubāzi. Mēs nodrošināmsetup_db.pyskriptu, lai automātiski inicializētu tabulu struktūras un testa datus (sīkāku informāciju skatiet pirmkoda beigās).

4. Detalizēti izskaidroti galvenie ieviešanas soļi### 1. solis: Definējiet domēna prasmes (Zināšanas)

Mēs definēsim prasmes kā vārdnīcas struktūru, simulējot ielādes procesu no failu sistēmas vai datu bāzes. Lūdzu, ņemiet vērā atšķirību starp description (ko aģents izmanto lēmumu pieņemšanai) un content (faktiskais ielādētais detalizētais konteksts).

SKILLS = {"sales_analytics": {"description":"Noderīgi pārdošanas ieņēmumu, tendenču analīzei...","content":"""... Tabulas shēma: sales_data ..."" },"inventory_management": {"description":"Noderīgi krājumu līmeņu pārbaudei...","content":"""... Tabulas shēma: inventory_items ..."" }}

2. solis: Īstenojiet galvenos rīkus (Iespējas)

Aģents paļaujas uz diviem galvenajiem rīkiem, lai pabeigtu uzdevumus:

  • load_skill(skill_name)**: Dinamiski ielādē norādītās prasmes detaļas izpildlaikā. **

  • run_sql_query(query)**: Izpilda konkrētus SQL priekšrakstus. **

3. solis: Organizējiet aģenta loģiku (Smadzenes)

Izmantojiet LangGraph, lai izveidotu ReAct aģentu. Sistēmas uzvedne šeit spēlē galveno lomu, vadot aģentu stingri ievērot Identify -> Load -> Query standarta darbības procedūru (SOP).

system_prompt ="""1. Identificējiet atbilstošo prasmi.2. Izmantojiet 'load_skill', lai iegūtu shēmu.3. Rakstiet un izpildiet SQL, izmantojot 'run_sql_query'....Nemēģiniet uzminēt tabulu nosaukumus. Vienmēr vispirms ielādējiet prasmi.""

5. Darbības efektu pārbaude

Izpildot test_agent.py, mēs pārbaudījām vaicājumus divās dažādās jomās: pārdošanas un krājumu. Zemāk ir konsoles faktiskās izvades žurnāli, kas parāda, kā aģents dinamiski ielādē prasmes atkarībā no jautājuma:

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. Pilns avota koda atsauce\n\nZemāk ir projekta pilns avota kods, kas ietver datubāzes inicializācijas skriptu un Agent galveno programmu.\n\n### 1. Datubāzes inicializācija (setup_db.py)\n\n`importpsycopg2frompsycopg2.extensionsimportISOLATION_LEVEL_AUTOCOMMITimportosfromdotenvimportload_dotenvload_dotenv()# Lūdzu, pārliecinieties, vai .env ir konfigurēta datubāzes savienojuma informācijaDB_HOST = os.getenv(### 2. Aģenta galvenā programma (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()

--- 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": "Useful for analyzing sales revenue, trends, and regional performance.", "content": """You are a Sales Analytics Expert. You have access to the 'sales_data' table. Table Schema:

  • id: integer (primary key)
  • transaction_date: date
  • product_id: varchar(50)
  • amount: decimal(10, 2)
  • region: varchar(50) Common queries:
  • Total revenue: SUM(amount)
  • Revenue by region: GROUP BY region
  • Sales trend: GROUP BY transaction_date""" }, "inventory_management": { "description": "Useful for checking stock levels, product locations, and warehouse management.", "content": """You are an Inventory Management Expert. You have access to the 'inventory_items' table.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)ifnotskill:returnf"Error: Skill '{skill_name}' not found. Available skills:{list(SKILLS.keys())}"returnskill["content"]@tooldefrun_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:returndb.run(query)exceptExceptionase:returnf"Error executing SQL:{e}"@tooldeflist_tables()-> str:"""List all available tables in the database."""returnstr(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 ---classAgentState(MessagesState):# We can add custom state if needed, but MessagesState is sufficient for simple chatpassdefagent_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()# --- Galvenā izpilde ---if__name__ =="main": system_prompt ="""Jūs esat noderīgs SQL palīgs.Jums ir pieejamas specializētas prasmes, kas satur datubāzes shēmas un domēna zināšanas.Lai atbildētu uz lietotāja jautājumu:1. Identificējiet atbilstošo prasmi (sales_analytics vai inventory_management).2. Izmantojiet rīku 'load_skill', lai iegūtu shēmu un instrukcijas.3. Pamatojoties uz ielādēto prasmi, rakstiet un izpildiet SQL vaicājumu, izmantojot 'run_sql_query'.4. Atbildiet uz lietotāja jautājumu, pamatojoties uz vaicājuma rezultātiem.Nemēģiniet uzminēt tabulu nosaukumus. Vienmēr vispirms ielādējiet prasmi.""" print("SQL palīgs ir inicializēts. Ierakstiet 'quit', lai izietu.") print("-"*50) messages = [SystemMessage(content=system_prompt)]# Iepriekšēja savienojuma pārbaude mēģinājumamtry: print(f"Savienots ar datubāzi:{DB_URI.split('@')[-1]}")exceptExceptionase: print(f"Datubāzes savienojuma brīdinājums:{e}")whileTrue:try: user_input = input("Lietotājs: ")ifuser_input.lower()in["quit","exit"]:break messages.append(HumanMessage(content=user_input))# Straumējiet izpildi print("Aģents: ", end="", flush=True) final_response =Noneforeventinapp.stream({"messages": messages}, stream_mode="values"):# Režīmā 'values' mēs iegūstam pilnu stāvokli. Mēs vēlamies redzēt tikai pēdējo ziņojumu, ja tas ir jauns. last_message = event["messages"][-1]# Atjauniniet mūsu ziņojumu vēsturi ar jaunāko stāvoklipass# Pēc straumes pabeigšanas pēdējā stāvoklī ir galīgā atbilde 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`
Published in Technology

You Might Also Like