Machine Learning

Ukwakha i-Сstom MCP Chatbot | Kubheke kwisayensi yedatha

Indlela yokulinganisa ukuxhumana phakathi kwezicelo ze-AI namathuluzi angaphandle noma imithombo yedatha. Lokhu okulinganise kusiza ukwehlisa inani lokuhlanganiswa okudingekayo (kusuka ku-n * m to n + m):

  • Ungasebenzisa amaseva we-MCP owakhelwe umphakathi lapho udinga ukusebenza okujwayelekile, ukonga isikhathi nokugwema isidingo sokuphinda usebenzise isondo ngaso sonke isikhathi.
  • Ungadalula futhi amathuluzi akho nezinsizakusebenza, ukuzenza zitholakale ukuze abanye bazisebenzise.

Esihlokweni sami esedlule, sakha i-Analytics Toolbox (iqoqo lamathuluzi angaguqula inqubo yakho yosuku nosuku). Sakhe iseva ye-MCP futhi sasebenzisa amakhono ayo namakhasimende akhona afana nomhloli we-MCP noma i-Claude Desktop.

Manje, sifuna ukusebenzisa lawo mathuluzi ngqo kuzinhlelo zethu ze-AI. Ukuze wenze lokho, ake sakhe iklayenti lethu le-MCP. Sizobhala ikhodi ephansi ephansi, okuzokunikeza isithombe esicacile sendlela amathuluzi afana ngayo nekhodi ye-Claude exhumana ne-MCP ngaphansi kwe-hood.

Ngokwengeziwe, ngithanda ukusebenzisa isici njengamanje (NgoJulayi 2025) Ukulahleka ku-Claude Desktop: Amandla we-LLM ukubheka ngokuzenzakalelayo ukuthi inethempulethi efanelekayo yomsebenzi ofanelekile futhi uyisebenzise. Njengamanje, kufanele ukhethe ithempulethi ngesandla, okungeyona elula kakhulu.

Njengebhonasi, ngizophinde ngabelane ngokuqaliswa kwezinga eliphakeme ngisebenzisa uhlaka lwe-smolagents, olulungele izimo lapho usebenza ngamathuluzi we-MCP futhi awudingi ukwenza ngokwezifiso okuningi.

Ukubuka konke kwe-MCP Protocol

Nakhu ukubuyiselwa okusheshayo kwe-MCP ukuqinisekisa ukuthi sesisekhasini elifanayo. I-MCP iyi-protocol ethuthukiswe yi-anthropic ukumisa indlela i-LLMS exhumana ngayo nomhlaba wangaphandle.

Kulandela ukusungulwa kweseva yamakhasimende futhi kuqukethe izakhi ezintathu eziphambili:

  • Impi uhlelo lokusebenza olubhekene nomsebenzisi.
  • Iklayenti le-MCP Ingxenye engaphakathi komgcini osungula ukuxhumana okukodwa neseva kanye nokuxhumana nokusebenzisa imiyalezo echazwe yi-MCP Protocol.
  • Iseva ye-MCP kudalula amakhono afana nezifanekiso ezisheshayo, izinsiza kanye namathuluzi.
Isithombe nguMlobi

Njengoba sesivele sisebenzise iseva ye-MCP ngaphambili, kulokhu sizogxila ekwakheni iklayenti le-MCP. Sizoqala ngokuqaliswa okulula futhi ngokuhamba kwesikhathi sengeza amandla okukhetha amathempulethi asheshayo empukane.

Ungathola ikhodi ephelele ku-GitHub.

Ukwakha i-MCP Chatbot

Ake siqale ngokusetha kokuqala: sizolayisha ukhiye we-anthropic API kusuka kufayela le-config bese ulungisa i-Python's asyncio Umcimbi we-loop ukusekela izingodo zemicimbi ebekiwe.

# Load configuration and environment
with open('../../config.json') as f:
    config = json.load(f)
os.environ["ANTHROPIC_API_KEY"] = config['ANTHROPIC_API_KEY']

nest_asyncio.apply()

Ake siqale ngokwakha umthambo wohlelo lwethu ukuthola isithombe esicacile sokwakhiwa kwezinga eliphezulu.

async def main():
    """Main entry point for the MCP ChatBot application."""
    chatbot = MCP_ChatBot()
    try:
        await chatbot.connect_to_servers()
        await chatbot.chat_loop()
    finally:
        await chatbot.cleanup()

if __name__ == "__main__":
    asyncio.run(main())

Siqala ngokwakha isibonelo se MCP_ChatBot isigaba. I-Chatbot iqala ngokuthola amandla atholakalayo we-MCP (i-iterating ngokusebenzisa wonke amaseva we-MCP amisiwe, ukusungula ukuxhumeka futhi acele uhlu lwawo lwamakhono).

Lapho ukuxhumeka sekumisiwe, sizoqala i-loop engapheli lapho i-chatbot ilalela imibuzo yomsebenzisi, ibiza amathuluzi lapho kudingeka futhi kuqhubeke lo mjikelezo kuze kube yilapho inqubo imiswa ngesandla.

Ekugcineni, sizokwenza isinyathelo sokuhlanza sokuvala konke ukuxhumana okuvulekile.

Manje ake sihambe esigabeni ngasinye ngemininingwane eminingi.

Iqala isigaba se-Chatbot

Ake siqale ngokwakha ikilasi futhi sichaze __init__ indlela. Izinkambu eziphambili zesigaba se-Chatbot yilezi:

  • exit_stack Ilawula impilo ye-LifectCH Threads Multiple ASYNC (ukuxhumana kumaseva we-MCP), ukuqinisekisa ukuthi konke ukuxhumana kuzovalwa ngendlela efanele, noma ngabe sibhekene nephutha ngesikhathi sokubulawa. Lo mqondo usetshenzisiwe ku cleanup sebenza.
  • anthropic iyiklayenti le-anthropic api esetshenziselwa ukuthumela imiyalezo ku-LLM.
  • available_tools na- available_prompts Ngabe uhlu lwamathuluzi kanye nokuphakanyiswa okuvezwe yibo bonke amaseva e-MCP esixhunyiwe kukho.
  • sessions Ingabe imephu yamathuluzi, ukushukumisa kanye nezinsizakusebenza kumaseshini awo afanayo e-MCP. Lokhu kuvumela i-Chatbot ukuthi icele izicelo zeseva ye-MCP efanele lapho i-LLM ikhetha ithuluzi elithile.
class MCP_ChatBot:
  """
  MCP (Model Context Protocol) ChatBot that connects to multiple MCP servers
  and provides a conversational interface using Anthropic's Claude.
    
  Supports tools, prompts, and resources from connected MCP servers.
  """
    
  def __init__(self):
    self.exit_stack = AsyncExitStack() 
    self.anthropic = Anthropic() # Client for Anthropic API
    self.available_tools = [] # Tools from all connected servers
    self.available_prompts = [] # Prompts from all connected servers  
    self.sessions = {} # Maps tool/prompt/resource names to MCP sessions

  async def cleanup(self):
    """Clean up resources and close all connections."""
    await self.exit_stack.aclose()

Ukuxhuma kumaseva

Umsebenzi wokuqala we-Chatbot yethu ukuqalisa ukuxhumana nawo wonke amaseva we-MCP amisiwe futhi uthole ukuthi imaphi amakhono esingawasebenzisa.

Uhlu lwamaseva e-MCP asetshenziswa yi-ejenti yethu ukuthi achazwa ku server_config.json Ifayela. Ngisethe ukuxhumana namaseva amathathu e-MCP:

  • I-Analyst_ToolKit ukuqaliswa kwami ​​kwamathuluzi wokuhlaziya nsuku zonke esixoxe ngawo esihlokweni esedlule,
  • I-FilePylystem ivumela i-ejenti ukuthi isebenze ngamafayela,
  • Ukulanda kusiza i-LLMS ukuthola okuqukethwe kwamakhasi wewebhu bese uyiguqula kusuka ku-HTML ukuya ekushakeni ukuze kufundwe kangcono.
{
  "mcpServers": {
    "analyst_toolkit": {
      "command": "uv",
      "args": [
        "--directory",
        "/path/to/github/mcp-analyst-toolkit/src/mcp_server",
        "run",
        "server.py"
      ],
      "env": {
          "GITHUB_TOKEN": "your_github_token"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/marie/Desktop",
        "/Users/marie/Documents/github"
      ]
    },
    "fetch": {
        "command": "uvx",
        "args": ["mcp-server-fetch"]
      }
  }
}

Okokuqala, sizofunda ifayela le-Config, lizilandele bese lixhuma kwiseva ngayinye ebhalwe phansi.

async def connect_to_servers(self):
  """Load server configuration and connect to all configured MCP servers."""
  try:
    with open("server_config.json", "r") as file:
      data = json.load(file)
    
    servers = data.get("mcpServers", {})
    for server_name, server_config in servers.items():
      await self.connect_to_server(server_name, server_config)
  except Exception as e:
    print(f"Error loading server config: {e}")
    traceback.print_exc()
    raise

Ngeseva ngayinye, senza izinyathelo eziningana zokusungula ukuxhumana:

  • Ezingeni lokuhamba, thina Hola iseva ye-MCP njengenqubo ye-STDIO futhi uthole imifudlana yokuthumela nokwamukela imiyalezo.
  • Ezingeni leseshinisakha a ClientSession kufaka imifudlana, bese senza ukuxhashazwa kwe-MCP ngokubiza initialize indlela.
  • Sibhalise zombili lezi zeshini nezinto zokuhamba kwimenenja yezomongo exit_stack Ukuqinisekisa ukuthi konke ukuxhumana kuzovalwa kahle ekugcineni.
  • Isinyathelo sokugcina ukuthi Bhalisa amakhono weseva. Sisonge lokhu ukusebenza sibe umsebenzi ohlukile, futhi sizoxoxa kungekudala.
async def connect_to_server(self, server_name, server_config):
    """Connect to a single MCP server and register its capabilities."""
    try:
      server_params = StdioServerParameters(**server_config)
      stdio_transport = await self.exit_stack.enter_async_context(
          stdio_client(server_params)
      )
      read, write = stdio_transport
      session = await self.exit_stack.enter_async_context(
          ClientSession(read, write)
      )
      await session.initialize()
      await self._register_server_capabilities(session, server_name)
            
    except Exception as e:
      print(f"Error connecting to {server_name}: {e}")
      traceback.print_exc()

Amandla okubhalisa afaka amathuluzi aphelele, ama-Products kanye nezinsizakusebenza ezibuyiselwe esifundweni. Ngenxa yalokho, sibuyekeza okuguquguqukayo kwangaphakathi sessions (Imephu phakathi kwezinsizakusebenza kanye neseshini ethile phakathi kweklayenti le-MCP neseva), available_prompts na- available_tools.

async def _register_server_capabilities(self, session, server_name):
  """Register tools, prompts and resources from a single server."""
  capabilities = [
    ("tools", session.list_tools, self._register_tools),
    ("prompts", session.list_prompts, self._register_prompts), 
    ("resources", session.list_resources, self._register_resources)
  ]
  
  for capability_name, list_method, register_method in capabilities:
    try:
      response = await list_method()
      await register_method(response, session)
    except Exception as e:
      print(f"Server {server_name} doesn't support {capability_name}: {e}")

async def _register_tools(self, response, session):
  """Register tools from server response."""
  for tool in response.tools:
    self.sessions[tool.name] = session
    self.available_tools.append({
        "name": tool.name,
        "description": tool.description,
        "input_schema": tool.inputSchema
    })

async def _register_prompts(self, response, session):
  """Register prompts from server response."""
  if response and response.prompts:
    for prompt in response.prompts:
        self.sessions[prompt.name] = session
        self.available_prompts.append({
            "name": prompt.name,
            "description": prompt.description,
            "arguments": prompt.arguments
        })

async def _register_resources(self, response, session):
  """Register resources from server response."""
  if response and response.resources:
    for resource in response.resources:
        resource_uri = str(resource.uri)
        self.sessions[resource_uri] = session

Ekupheleni kwalesi sigaba, kwethu MCP_ChatBot into inakho konke okudingayo ukuqala ukusebenzisana nabasebenzisi:

  • Ukuxhumeka kuwo wonke amaseva we-MCP ahleliwe asunguliwe,
  • Konke okushukumisayo, izinsizakusebenza namathuluzi abhalisiwe, kufaka phakathi izincazelo ezidingekayo ze-LLM ukuqonda ukuthi ungawasebenzisa kanjani la makhono,
  • Ama-mappings phakathi kwalezi zinsizakusebenza kanye namaseshini abo agcinwe, ngakho-ke sazi kahle ukuthi sizothumela kuphi isicelo ngasinye.

Chat loop

Ngakho-ke, sekuyisikhathi sokuqala ukuxoxa kwethu nabasebenzisi ngokwakha chat_loop sebenza.

Sizoqala sabelana ngayo yonke imiyalo etholakalayo nomsebenzisi:

  • Ukufakwa kuhlu izinsiza, amathuluzi kanye nokukhuthaza
  • Ukwenza ucingo lwamathuluzi
  • Ukubuka insiza
  • Usebenzisa ithempulethi esheshayo
  • ukuyeka ingxoxo (Kubalulekile ukuba nendlela ecacile yokuphuma ku-loop engapheli).

Ngemuva kwalokho, sizongena ku-loop engapheli lapho, ngokususelwa kokufaka komsebenzisi, sizokwenza isenzo esifanele: noma ngabe kungenye yemiyalo engenhla noma ukwenza isicelo ku-LLM.

async def chat_loop(self):
  """Main interactive chat loop with command processing."""
  print("nMCP Chatbot Started!")
  print("Commands:")
  print("  quit                           - Exit the chatbot")
  print("  @periods                       - Show available changelog periods") 
  print("  @                      - View changelog for specific period")
  print("  /tools                         - List available tools")
  print("  /tool       - Execute a tool with arguments")
  print("  /prompts                       - List available prompts")
  print("  /prompt     - Execute a prompt with arguments")
  
  while True:
    try:
      query = input("nQuery: ").strip()
      if not query:
          continue

      if query.lower() == 'quit':
          break
      
      # Handle resource requests (@command)
      if query.startswith('@'):
        period = query[1:]
        resource_uri = "changelog://periods" if period == "periods" else f"changelog://{period}"
        await self.get_resource(resource_uri)
        continue
      
      # Handle slash commands
      if query.startswith('/'):
        parts = self._parse_command_arguments(query)
        if not parts:
          continue
            
        command = parts[0].lower()
        
        if command == '/tools':
          await self.list_tools()
        elif command == '/tool':
          if len(parts) < 2:
            print("Usage: /tool   ")
            continue
            
          tool_name = parts[1]
          args = self._parse_prompt_arguments(parts[2:])
          await self.execute_tool(tool_name, args)
        elif command == '/prompts':
          await self.list_prompts()
        elif command == '/prompt':
          if len(parts) < 2:
            print("Usage: /prompt   ")
            continue
          
          prompt_name = parts[1]
          args = self._parse_prompt_arguments(parts[2:])
          await self.execute_prompt(prompt_name, args)
        else:
          print(f"Unknown command: {command}")
        continue
      
      # Process regular queries
      await self.process_query(query)
            
    except Exception as e:
      print(f"nError in chat loop: {e}")
      traceback.print_exc()

Kunenqwaba yemisebenzi ye-Helper ukubheka kabusha izimpikiswano futhi ubuyise uhlu lwamathuluzi atholakalayo kanye nokukhuthaza esibhalisile phambilini. Njengoba kuqondile kahle, ngeke ngikwazi ukungena kakhulu lapha. Ungahlola ikhodi ephelele uma unentshisekelo.

Esikhundleni salokho, ake sihlasele sijule ukuthi kube nokusebenzisana phakathi kweklayenti le-MCP kanye nomsebenzi weseva ezimweni ezihlukile.

Lapho sisebenza ngezinsizakusebenza, sisebenzisa self.sessions Imephu ukuthola iseshini efanelekile (ngenketho yokuwa uma kudingeka) bese usebenzisa leso sikhathi ukuze ufunde izinsiza.

async def get_resource(self, resource_uri):
  """Retrieve and display content from an MCP resource."""
  session = self.sessions.get(resource_uri)
  
  # Fallback: find any session that handles this resource type
  if not session and resource_uri.startswith("changelog://"):
    session = next(
        (sess for uri, sess in self.sessions.items() 
         if uri.startswith("changelog://")), 
        None
    )
      
  if not session:
    print(f"Resource '{resource_uri}' not found.")
    return

  try:
    result = await session.read_resource(uri=resource_uri)
    if result and result.contents:
        print(f"nResource: {resource_uri}")
        print("Content:")
        print(result.contents[0].text)
    else:
        print("No content available.")
  except Exception as e:
    print(f"Error reading resource: {e}")
    traceback.print_exc()

Ukuze wenze ithuluzi, silandela inqubo efanayo: Qala ngokuthola isikhathi bese usisebenzisa ukubiza ithuluzi, udlulise igama laso kanye nokuphikisana kwalo.

async def execute_tool(self, tool_name, args):
  """Execute an MCP tool directly with given arguments."""
  session = self.sessions.get(tool_name)
  if not session:
      print(f"Tool '{tool_name}' not found.")
      return
  
  try:
      result = await session.call_tool(tool_name, arguments=args)
      print(f"nTool '{tool_name}' result:")
      print(result.content)
  except Exception as e:
      print(f"Error executing tool: {e}")
      traceback.print_exc()

Akumangazi lapha. Indlela efanayo iyasebenza ngokwenza lokhu ngokushesha.

async def execute_prompt(self, prompt_name, args):
    """Execute an MCP prompt with given arguments and process the result."""
    session = self.sessions.get(prompt_name)
    if not session:
        print(f"Prompt '{prompt_name}' not found.")
        return
    
    try:
        result = await session.get_prompt(prompt_name, arguments=args)
        if result and result.messages:
            prompt_content = result.messages[0].content
            text = self._extract_prompt_text(prompt_content)
            
            print(f"nExecuting prompt '{prompt_name}'...")
            await self.process_query(text)
    except Exception as e:
        print(f"Error executing prompt: {e}")
        traceback.print_exc()

Icala eliwukuphela kokusetshenziswa esikhulu esingalimbozwanga lisisingatha ukufakwa okujwayelekile, kokufakwa kwamahhala kusuka kumsebenzisi (hhayi nemiyalo ethile).
Kulokhu, sithumela isicelo sokuqala ku-LLM kuqala, khona-ke sifaka umphumela, sichaza ukuthi ngabe kukhona yini amathuluzi. Uma amathuluzi ethuluzi ekhona, siyabakhipha. Ngaphandle kwalokho, siphuma ku-loop engapheli bese sibuyisela impendulo kumsebenzisi.

async def process_query(self, query):
  """Process a user query through Anthropic's Claude, handling tool calls iteratively."""
  messages = [{'role': 'user', 'content': query}]
  
  while True:
    response = self.anthropic.messages.create(
        max_tokens=2024,
        model='claude-3-7-sonnet-20250219', 
        tools=self.available_tools,
        messages=messages
    )
    
    assistant_content = []
    has_tool_use = False
    
    for content in response.content:
        if content.type == 'text':
            print(content.text)
            assistant_content.append(content)
        elif content.type == 'tool_use':
            has_tool_use = True
            assistant_content.append(content)
            messages.append({'role': 'assistant', 'content': assistant_content})
            
            # Execute the tool call
            session = self.sessions.get(content.name)
            if not session:
                print(f"Tool '{content.name}' not found.")
                break
                
            result = await session.call_tool(content.name, arguments=content.input)
            messages.append({
                "role": "user", 
                "content": [{
                    "type": "tool_result",
                    "tool_use_id": content.id,
                    "content": result.content
                }]
            })
      
      if not has_tool_use:
          break

Ngakho-ke, manje sesimboze ngokuphelele ukuthi i-MCP Chatbot isebenza kanjani ngaphansi kwe-hood. Manje, sekuyisikhathi sokuyihlola esenzweni. Ungayiqhuba kusuka ekubonisweni komugqa womyalo ngomyalo olandelayo.

python mcp_client_example_base.py

Lapho uqhuba i-Chatbot, uzoqala ukubona umyalezo olandelayo wesingeniso ochaza izinketho ezingaba khona:

MCP Chatbot Started!
Commands:
  quit                           - Exit the chatbot
  @periods                       - Show available changelog periods
  @                      - View changelog for specific period
  /tools                         - List available tools
  /tool       - Execute a tool with arguments
  /prompts                       - List available prompts
  /prompt     - Execute a prompt with arguments

Ukusuka lapho, ungazama imiyalo ehlukene, ngokwesibonelo,

  • shayela ithuluzi ukubhala imininingwane etholakala ku-DB
  • Bhala konke okutholakalayo okutholakalayo
  • Sebenzisa ithempulethi esheshayo, ukubizelwa kanjena /prompt sql_query_prompt question=”How many customers did we have in May 2024?”.

Ekugcineni, ngingaqeda ingxoxo yakho ngokuthayipha quit.

Query: /tool list_databases
[07/02/25 18:27:28] INFO     Processing request of type CallToolRequest                server.py:619
Tool 'list_databases' result:
[TextContent(type='text', text='INFORMATION_SCHEMAndatasetsndefaultnecommercenecommerce_dbninformation_schemansystemn', annotations=None, meta=None)]

Query: /prompts
Available prompts:
- sql_query_prompt: Create a SQL query prompt
  Arguments:
    - question

Query: /prompt sql_query_prompt question="How many customers did we have in May 2024?"
[07/02/25 18:28:21] INFO     Processing request of type GetPromptRequest               server.py:619
Executing prompt 'sql_query_prompt'...
I'll create a SQL query to find the number of customers in May 2024.
[07/02/25 18:28:25] INFO     Processing request of type CallToolRequest                server.py:619
Based on the query results, here's the final SQL query:
```sql
select uniqExact(user_id) as customer_count
from ecommerce.sessions
where toStartOfMonth(action_date) = '2024-05-01'
format TabSeparatedWithNames
```
Query: /tool execute_sql_query query="select uniqExact(user_id) as customer_count from ecommerce.sessions where toStartOfMonth(action_date) = '2024-05-01' format TabSeparatedWithNames"
I'll help you execute this SQL query to get the unique customer count for May 2024. Let me run this for you.
[07/02/25 18:30:09] INFO     Processing request of type CallToolRequest                server.py:619
The query has been executed successfully. The results show that there were 246,852 unique customers (unique user_ids) in May 2024 based on the ecommerce.sessions table.

Query: quit

Kubukeka kuhle! Uhlobo lwethu oluyisisekelo lusebenza kahle! Manje, sekuyisikhathi sokuthatha isinyathelo esisodwa futhi senze i-chatbot yethu ngobuhlakani ngokuyifundisa ukuphakamisa ukukhushulwa okufanele ku-fly okususelwa kokufakwa kwamakhasimende.

Iziphakamiso ezisheshayo

Empeleni, kuphakamisa izifanekiso ezisheshayo ezihambelana kahle nomsebenzi womsebenzisi zingasiza ngendlela emangalisayo. Njengamanje, abasebenzisi be-Chatbot yethu badinga ukuthi ngabe sebeyazi kakade mayelana nokuphakama okutholakalayo noma okungenani babe nelukuluku ngokwanele ukuba bazihlole ngokwabo ukuze bazuze kulokhu esibakheleyo kulokhu esikuzuze kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu esibakhele kulokhu. Ngokungeza isici sokusikisela okusheshayo, singakwenza lokhu ukutholakala kwabasebenzisi bethu futhi senze i-chatbot yethu ibe lula kakhulu futhi isebenziseka kalula.

Ake sicabange ngezindlela zokwengeza lokhu kusebenza. Ngingasondela kulesi sici ngale ndlela elandelayo:

Hlaziya ukuhambisana kokuphakanyiswa kusetshenziswa i-LLM. I-InTerate ngokusebenzisa zonke izifanekiso ezisheshayo ezikhona futhi, kulowo nalowo, hlola ukuthi ngabe i-Prompt ingumdlalo omuhle wombuzo womsebenzisi.

Phakamisa ngokushesha okufanayo kumsebenzisi. Uma sithola ithempulethi esheshayo esheshayo, yabelana ngomsebenzisi futhi ibuze ukuthi ingathanda ukuyikhipha yini.

Hlanganisa ithempulethi esheshayo ngokufaka komsebenzisi. Uma umsebenzisi amukela, hlanganisa ngokushesha okukhethiwe nombuzo wokuqala. Njengoba izifanekiso ezisheshayo zibe nezindawo zokugcina, singadinga i-LLM ukuze sizigcwalise. Uma sesihlanganise ithempulethi esheshayo nombuzo womsebenzisi, sizoba nomyalezo obuyekeziwe ukuthumela ku-LLM.

Sizokwengeza lo mqondo ku process_query sebenza. Ngenxa ye-Design yethu ye-Modular, kulula ukwengeza lokhu kuthuthukiswa ngaphandle kokuphazamisa enye ikhodi.

Ake siqale ngokusebenzisa umsebenzi ukuthola ithempulethi efanele kakhulu. Sizosebenzisa i-LLM ukuthi sihlole isinyathelo ngasinye futhi siyinikeze amaphuzu ahlobene kusuka ku-0 kuye ku-5

async def _find_matching_prompt(self, query):
  """Find a matching prompt for the given query using LLM evaluation."""
  if not self.available_prompts:
    return None
  
  # Use LLM to evaluate prompt relevance
  prompt_scores = []
  
  for prompt in self.available_prompts:
    # Create evaluation prompt for the LLM
    evaluation_prompt = f"""
You are an expert at evaluating whether a prompt template is relevant for a user query.

User Query: "{query}"

Prompt Template:
- Name: {prompt['name']}
- Description: {prompt['description']}

Rate the relevance of this prompt template for the user query on a scale of 0-5:
- 0: Completely irrelevant
- 1: Slightly relevant
- 2: Somewhat relevant  
- 3: Moderately relevant
- 4: Highly relevant
- 5: Perfect match

Consider:
- Does the prompt template address the user's intent?
- Would using this prompt template provide a better response than a generic query?
- Are the topics and context aligned?

Respond with only a single number (0-5) and no other text.
"""
      
    try:
      response = self.anthropic.messages.create(
          max_tokens=10,
          model='claude-3-7-sonnet-20250219',
          messages=[{'role': 'user', 'content': evaluation_prompt}]
      )
      
      # Extract the score from the response
      score_text = response.content[0].text.strip()
      score = int(score_text)
      
      if score >= 3:  # Only consider prompts with score >= 3
          prompt_scores.append((prompt, score))
            
    except Exception as e:
        print(f"Error evaluating prompt {prompt['name']}: {e}")
        continue
  
  # Return the prompt with the highest score
  if prompt_scores:
      best_prompt, best_score = max(prompt_scores, key=lambda x: x[1])
      return best_prompt
  
  return None

Umsebenzi olandelayo sidinga ukusisebenzisa sihlanganisa ithempulethi ekhethiwe ekhethiwe ngokufaka komsebenzisi. Sizoncika ku-LLM ukuze sizihlanganise ngokukhaliphile, sigcwalise bonke abalandeli njengoba kudingeka.

async def _combine_prompt_with_query(self, prompt_name, user_query):
  """Use LLM to combine prompt template with user query."""
  # First, get the prompt template content
  session = self.sessions.get(prompt_name)
  if not session:
      print(f"Prompt '{prompt_name}' not found.")
      return None
  
  try:
      # Find the prompt definition to get its arguments
      prompt_def = None
      for prompt in self.available_prompts:
          if prompt['name'] == prompt_name:
              prompt_def = prompt
              break
      
      # Prepare arguments for the prompt template
      args = {}
      if prompt_def and prompt_def.get('arguments'):
          for arg in prompt_def['arguments']:
              arg_name = arg.name if hasattr(arg, 'name') else arg.get('name', '')
              if arg_name:
                  # Use placeholder format for arguments
                  args[arg_name] = '<' + str(arg_name) + '>'
      
      # Get the prompt template with arguments
      result = await session.get_prompt(prompt_name, arguments=args)
      if not result or not result.messages:
          print(f"Could not retrieve prompt template for '{prompt_name}'")
          return None
      
      prompt_content = result.messages[0].content
      prompt_text = self._extract_prompt_text(prompt_content)
      
      # Create combination prompt for the LLM
      combination_prompt = f"""
You are an expert at combining prompt templates with user queries to create optimized prompts.

Original User Query: "{user_query}"

Prompt Template:
{prompt_text}

Your task:
1. Analyze the user's query and the prompt template
2. Combine them intelligently to create a single, coherent prompt
3. Ensure the user's specific question/request is addressed within the context of the template
4. Maintain the structure and intent of the template while incorporating the user's query

Respond with only the combined prompt text, no explanations or additional text.
"""
      
      response = self.anthropic.messages.create(
          max_tokens=2048,
          model='claude-3-7-sonnet-20250219',
          messages=[{'role': 'user', 'content': combination_prompt}]
      )
      
      return response.content[0].text.strip()
      
  except Exception as e:
      print(f"Error combining prompt with query: {e}")
      return None

Ngemuva kwalokho, sizomane sibuyekeze i- process_query I-Logic ukubheka ukuthuthumela okufanayo, buza umsebenzisi ukuze aqinisekise futhi anqume ukuthi yimuphi umyalezo ongawuthumela ku-LLM.

async def process_query(self, query):
  """Process a user query through Anthropic's Claude, handling tool calls iteratively."""
  # Check if there's a matching prompt first
  matching_prompt = await self._find_matching_prompt(query)
  
  if matching_prompt:
    print(f"Found matching prompt: {matching_prompt['name']}")
    print(f"Description: {matching_prompt['description']}")
    
    # Ask user if they want to use the prompt template
    use_prompt = input("Would you like to use this prompt template? (y/n): ").strip().lower()
    
    if use_prompt == 'y' or use_prompt == 'yes':
        print("Combining prompt template with your query...")
        
        # Use LLM to combine prompt template with user query
        combined_prompt = await self._combine_prompt_with_query(matching_prompt['name'], query)
        
        if combined_prompt:
            print(f"Combined prompt created. Processing...")
            # Process the combined prompt instead of the original query
            messages = [{'role': 'user', 'content': combined_prompt}]
        else:
            print("Failed to combine prompt template. Using original query.")
            messages = [{'role': 'user', 'content': query}]
    else:
        # Use original query if user doesn't want to use the prompt
        messages = [{'role': 'user', 'content': query}]
  else:
    # Process the original query if no matching prompt found
    messages = [{'role': 'user', 'content': query}]

  # print(messages)
  
  # Process the final query (either original or combined)
  while True:
    response = self.anthropic.messages.create(
        max_tokens=2024,
        model='claude-3-7-sonnet-20250219', 
        tools=self.available_tools,
        messages=messages
    )
    
    assistant_content = []
    has_tool_use = False
    
    for content in response.content:
      if content.type == 'text':
          print(content.text)
          assistant_content.append(content)
      elif content.type == 'tool_use':
          has_tool_use = True
          assistant_content.append(content)
          messages.append({'role': 'assistant', 'content': assistant_content})
          
          # Log tool call information
          print(f"n[TOOL CALL] Tool: {content.name}")
          print(f"[TOOL CALL] Arguments: {json.dumps(content.input, indent=2)}")
          
          # Execute the tool call
          session = self.sessions.get(content.name)
          if not session:
              print(f"Tool '{content.name}' not found.")
              break
              
          result = await session.call_tool(content.name, arguments=content.input)
          
          # Log tool result
          print(f"[TOOL RESULT] Tool: {content.name}")
          print(f"[TOOL RESULT] Content: {result.content}")
          
          messages.append({
              "role": "user", 
              "content": [{
                  "type": "tool_result",
                  "tool_use_id": content.id,
                  "content": result.content
              }]
          })
      
    if not has_tool_use:
        break

Manje, ake sihlole inguqulo yethu ebuyekeziwe ngombuzo mayelana nedatha yethu. Kuyamangaza, i-chatbot yakwazi ukuthola ngokushesha okulungile futhi iyisebenzise ukuthola impendulo efanele.

Query: How many customers did we have in May 2024?
Found matching prompt: sql_query_prompt
Description: Create a SQL query prompt
Would you like to use this prompt template? (y/n): y
Combining prompt template with your query...
[07/05/25 14:38:58] INFO     Processing request of type GetPromptRequest               server.py:619
Combined prompt created. Processing...
I'll write a query to count unique customers who had sessions in May 2024. Since this is a business metric, I'll exclude fraudulent sessions.

[TOOL CALL] Tool: execute_sql_query
[TOOL CALL] Arguments: {
  "query": "/* Count distinct users with non-fraudulent sessions in May 2024n   Using uniqExact for precise user countn   Filtering for May 2024 using toStartOfMonth and adding date range */nSELECT n    uniqExactIf(s.user_id, s.is_fraud = 0) AS active_customers_countnFROM ecommerce.sessions snWHERE toStartOfMonth(action_date) = toDate('2024-05-01')nFORMAT TabSeparatedWithNames"
}
[07/05/25 14:39:17] INFO     Processing request of type CallToolRequest                server.py:619
[TOOL RESULT] Tool: execute_sql_query
[TOOL RESULT] Content: [TextContent(type='text', text='active_customers_countn245287n', annotations=None, meta=None)]
The query shows we had 245,287 unique customers with legitimate (non-fraudulent) sessions in May 2024. Here's a breakdown of why I wrote the query this way:

1. Used uniqExactIf() to get precise count of unique users while excluding fraudulent sessions in one step
2. Used toStartOfMonth() to ensure we capture all days in May 2024
3. Specified the date format properly with toDate('2024-05-01')
4. Used TabSeparatedWithNames format as required
5. Provided a meaningful column alias

Would you like to see any variations of this analysis, such as including fraudulent sessions or breaking down the numbers by country?

Kuhlala kungumbono omuhle ukuvivinya izibonelo ezingezinhle. Kulokhu, i-Chatbot iziphatha njengoba bekulindelekile futhi ayiphakamisi ngokushesha okuhlobene ne-SQL lapho inikezwe umbuzo ongahlobene.

Query: How are you?
I should note that I'm an AI assistant focused on helping you work with the available tools, which include executing SQL queries, getting database/table information, and accessing GitHub PR data. I don't have a tool specifically for responding to personal questions.

I can help you:
- Query a ClickHouse database
- List databases and describe tables
- Get information about GitHub Pull Requests

What would you like to know about these areas?

Manje njengoba i-Chatbot yethu ivukile futhi iyasebenza, sikulungele ukusonga izinto phezulu.

Ibhonasi: Iklayenti elisheshayo nelula le-MCP elinama-smolagents

Sibheke ikhodi esezingeni eliphansi enika amandla amaklayenti enziwe ngokwezifiso ze-MCP, kepha amacala amaningi asebenzisa adinga ukusebenza okuyisisekelo kuphela. Ngakho-ke, nginqume ukuhlanganyela nawe ukusetshenziswa okusheshayo futhi okuqondile kwezimo lapho udinga amathuluzi nje. Sizosebenzisa enye yezinhlaka zami ezithandwayo ze-ejenti – ama-smolagents avela ku-guggainface (Ngixoxe ngohlaka ngokuningiliziwe ku I-athikili yami yangaphambilini).

# needed imports
from smolagents import CodeAgent, DuckDuckGoSearchTool, LiteLLMModel, VisitWebpageTool, ToolCallingAgent, ToolCollection
from mcp import StdioServerParameters
import json
import os

# setting OpenAI APIKey 
with open('../../config.json') as f:
    config = json.loads(f.read())

os.environ["OPENAI_API_KEY"] = config['OPENAI_API_KEY']

# defining the LLM 
model = LiteLLMModel(
    model_id="openai/gpt-4o-mini",  
    max_tokens=2048
)

# configuration for the MCP server
server_parameters = StdioServerParameters(
    command="uv",
    args=[
        "--directory",
        "/path/to/github/mcp-analyst-toolkit/src/mcp_server",
        "run",
        "server.py"
    ],
    env={"GITHUB_TOKEN": "github_"},
)

# prompt 
CLICKHOUSE_PROMPT_TEMPLATE = """
You are a senior data analyst with more than 10 years of experience writing complex SQL queries, specifically optimized for ClickHouse to answer user questions.

## Database Schema

You are working with an e-commerce analytics database containing the following tables:

### Table: ecommerce.users 
**Description:** Customer information for the online shop
**Primary Key:** user_id
**Fields:** 
- user_id (Int64) - Unique customer identifier (e.g., 1000004, 3000004)
- country (String) - Customer's country of residence (e.g., "Netherlands", "United Kingdom")
- is_active (Int8) - Customer status: 1 = active, 0 = inactive
- age (Int32) - Customer age in full years (e.g., 31, 72)

### Table: ecommerce.sessions 
**Description:** User session data and transaction records
**Primary Key:** session_id
**Foreign Key:** user_id (references ecommerce.users.user_id)
**Fields:** 
- user_id (Int64) - Customer identifier linking to users table (e.g., 1000004, 3000004)
- session_id (Int64) - Unique session identifier (e.g., 106, 1023)
- action_date (Date) - Session start date (e.g., "2021-01-03", "2024-12-02")
- session_duration (Int32) - Session duration in seconds (e.g., 125, 49)
- os (String) - Operating system used (e.g., "Windows", "Android", "iOS", "MacOS")
- browser (String) - Browser used (e.g., "Chrome", "Safari", "Firefox", "Edge")
- is_fraud (Int8) - Fraud indicator: 1 = fraudulent session, 0 = legitimate
- revenue (Float64) - Purchase amount in USD (0.0 for non-purchase sessions, >0 for purchases)

## ClickHouse-Specific Guidelines

1. **Use ClickHouse-optimized functions:**
   - uniqExact() for precise unique counts
   - uniqExactIf() for conditional unique counts
   - quantile() functions for percentiles
   - Date functions: toStartOfMonth(), toStartOfYear(), today()

2. **Query formatting requirements:**
   - Always end queries with "format TabSeparatedWithNames"
   - Use meaningful column aliases
   - Use proper JOIN syntax when combining tables
   - Wrap date literals in quotes (e.g., '2024-01-01')

3. **Performance considerations:**
   - Use appropriate WHERE clauses to filter data
   - Consider using HAVING for post-aggregation filtering
   - Use LIMIT when finding top/bottom results

4. **Data interpretation:**
   - revenue > 0 indicates a purchase session
   - revenue = 0 indicates a browsing session without purchase
   - is_fraud = 1 sessions should typically be excluded from business metrics unless specifically analyzing fraud

## Response Format
Provide only the SQL query as your answer. Include brief reasoning in comments if the query logic is complex. 

## Examples

**Question:** How many customers made purchase in December 2024?
**Answer:** select uniqExact(user_id) as customers from ecommerce.sessions where toStartOfMonth(action_date) = '2024-12-01' and revenue > 0 format TabSeparatedWithNames

**Question:** What was the fraud rate in 2023, expressed as a percentage?
**Answer:** select 100 * uniqExactIf(user_id, is_fraud = 1) / uniqExact(user_id) as fraud_rate from ecommerce.sessions where toStartOfYear(action_date) = '2023-01-01' format TabSeparatedWithNames

**Question:** What was the share of users using Windows yesterday?
**Answer:** select 100 * uniqExactIf(user_id, os = 'Windows') / uniqExact(user_id) as windows_share from ecommerce.sessions where action_date = today() - 1 format TabSeparatedWithNames

**Question:** What was the revenue from Dutch users aged 55 and older in December 2024?
**Answer:** select sum(s.revenue) as total_revenue from ecommerce.sessions as s inner join ecommerce.users as u on s.user_id = u.user_id where u.country = 'Netherlands' and u.age >= 55 and toStartOfMonth(s.action_date) = '2024-12-01' format TabSeparatedWithNames

**Question:** What are the median and interquartile range (IQR) of purchase revenue for each country?
**Answer:** select country, median(revenue) as median_revenue, quantile(0.25)(revenue) as q25_revenue, quantile(0.75)(revenue) as q75_revenue from ecommerce.sessions as s inner join ecommerce.users as u on u.user_id = s.user_id where revenue > 0 group by country format TabSeparatedWithNames

**Question:** What is the average number of days between the first session and the first purchase for users who made at least one purchase?
**Answer:** select avg(first_purchase - first_action_date) as avg_days_to_purchase from (select user_id, min(action_date) as first_action_date, minIf(action_date, revenue > 0) as first_purchase, max(revenue) as max_revenue from ecommerce.sessions group by user_id) where max_revenue > 0 format TabSeparatedWithNames

**Question:** What is the number of sessions in December 2024, broken down by operating systems, including the totals?
**Answer:** select os, uniqExact(session_id) as session_count from ecommerce.sessions where toStartOfMonth(action_date) = '2024-12-01' group by os with totals format TabSeparatedWithNames

**Question:** Do we have customers who used multiple browsers during 2024? If so, please calculate the number of customers for each combination of browsers.
**Answer:** select browsers, count(*) as customer_count from (select user_id, arrayStringConcat(arraySort(groupArray(distinct browser)), ', ') as browsers from ecommerce.sessions where toStartOfYear(action_date) = '2024-01-01' group by user_id) group by browsers order by customer_count desc format TabSeparatedWithNames

**Question:** Which browser has the highest share of fraud users?
**Answer:** select browser, 100 * uniqExactIf(user_id, is_fraud = 1) / uniqExact(user_id) as fraud_rate from ecommerce.sessions group by browser order by fraud_rate desc limit 1 format TabSeparatedWithNames

**Question:** Which country had the highest number of first-time users in 2024?
**Answer:** select country, count(distinct user_id) as new_users from (select user_id, min(action_date) as first_date from ecommerce.sessions group by user_id having toStartOfYear(first_date) = '2024-01-01') as t inner join ecommerce.users as u on t.user_id = u.user_id group by country order by new_users desc limit 1 format TabSeparatedWithNames

---

**Your Task:** Using all the provided information above, write a ClickHouse SQL query to answer the following customer question: 
{question}
"""

with ToolCollection.from_mcp(server_parameters, trust_remote_code=True) as tool_collection:
  agent = ToolCallingAgent(tools=[*tool_collection.tools], model=model)
  prompt = CLICKHOUSE_PROMPT_TEMPLATE.format(
      question = 'How many customers did we have in May 2024?'
  )
  response = agent.run(prompt)

Ngenxa yalokho, sathola impendulo efanele.

Isithombe nguMlobi

Uma ungadingi ukwenza ngokwezifiso noma ukuhlanganiswa okuhambisana nezinsizakusebenza kanye nezinsizakusebenza, lokhu kuqaliswa yindlela okufanele uhambe ngayo.

Ukubeka kafushane

Kulesi sihloko, sakha i-chatbot ehlanganisa namaseva we-MCP futhi sibekezelela zonke izinzuzo zokuma okulula ukufinyelela amathuluzi, okuvuselelwayo, kanye nezinsizakusebenza ngomthungo.

Siqale ngokuqaliswa okuyisisekelo okukwazi ukufakwa kuhlu nokufinyelela amakhono e-MCP. Ngemuva kwalokho, sathuthukisa i-Chatbot yethu ngesici esihlakaniphile esibonisa izifanekiso ezifanele ezisheshayo kubasebenzisi ngokuya ngokufaka kwabo. Lokhu kwenza umkhiqizo wethu unembile futhi ube nobungane, ikakhulukazi abasebenzisi abangajwayele umtapo wolwazi ophelele wezikhuthazo ezikhona.

Ukuze usebenzise i-Chatbot yethu, sisebenzise ikhodi esezingeni eliphansi, sikunikeza ukuqonda okungcono kokuthi i-MCP protocol isebenza kanjani ngaphansi kwe-hood nokuthi kwenzekani lapho usebenzisa amathuluzi e-Claude Desktop noma isikhombisi.

Njengebhonasi, siphinde saxoxa ngokusetshenziswa kweSmolagents okuvumela ukuthi usebenzise masinyane iklayenti le-MCP elihlanganiswe namathuluzi.

Ngiyabonga ngokufunda. Ngiyethemba ukuthi le ndatshana yayinokuqonda. Khumbula izeluleko zika-Einstein: “Into ebalulekile ukungayeki ukubuza imibuzo. Ilukuluku linesizathu salo sokuthi likhona.” Kwangathi ilukuluku lakho lingakuholela ekuqondiseni okuhle kwakho okuhle.

Inkomba

Le ndatshana iphefumulelwe yi I-MCP: Yakha iRich-Contines-Contect AI Apps nge-anthropic inkambo emfushane evela Deeplealing.ai.

Source link

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button