teackle_fleaky

Untitled

Oct 26th, 2026
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.84 KB | None | 0 0
  1. from langchain_mcp_adapters.client import MultiServerMCPClient
  2. import asyncio
  3. from dotenv import load_dotenv
  4. from langchain_google_genai import ChatGoogleGenerativeAI
  5. from langchain_community.utilities import SQLDatabase
  6. from langchain.tools import ToolRuntime
  7. from langchain.messages import HumanMessage
  8. from langchain.tools import ToolRuntime
  9. from langchain.messages import HumanMessage, ToolMessage
  10. from langgraph.types import Command
  11. from langchain.messages import HumanMessage, ToolMessage
  12. from langgraph.types import Command
  13. from typing import Dict, Any
  14. from langchain.agents import AgentState
  15. from tavily import TavilyClient
  16. from langchain.tools import tool
  17. from langchain.agents import create_agent
  18. import os
  19.  
  20. load_dotenv()
  21.  
  22. db = SQLDatabase.from_uri("sqlite:///resources/Chinook.db")
  23. gemini_api = os.getenv("GOOGLE_API_KEY")
  24. gemini_model = ChatGoogleGenerativeAI(model= "gemini-3.8-flash",api_key=gemini_api)
  25. @tool
  26. def query_playlist_db(query: str) -> str:
  27. """Query the database for playlist information"""
  28. try:
  29. return db.run(query)
  30. except Exception as e:
  31. return f"Error querying database: {e}"
  32. tavily_client = TavilyClient()
  33.  
  34. @tool
  35. def web_search(query: str, search_number: int, max_search_number: int) -> Dict[str, Any]:
  36. """Search the web for information. You must track your search count by providing
  37. search_number (starting at 1) and max_search_number on every call.
  38. Queries must use only plain text characters. Do not use accented or special characters
  39. (e.g., use 'capacite' instead of 'capacité').
  40. """
  41. if search_number > max_search_number:
  42. return {"message": "Search limit reached. Please summarize your findings and provide your final answer."}
  43. try:
  44. return tavily_client.search(query)
  45. except Exception as e:
  46. return {"error": str(e)}
  47.  
  48.  
  49.  
  50.  
  51. # the thing i did is wrong as of now and i need to learn how to fix the async
  52.  
  53.  
  54. # create a state
  55.  
  56.  
  57. class WeddingState(AgentState):
  58. origin: str
  59. destination: str
  60. guest_count: str
  61. genre: str
  62.  
  63.  
  64. async def main():
  65. client = MultiServerMCPClient(
  66. {
  67. "travel_server": {
  68. "transport":"streamable_http",
  69. "url":"https://mcp.kiwi.com"
  70. }
  71. }
  72. )
  73. tools = await client.get_tools()
  74.  
  75.  
  76.  
  77. # Travel agent
  78. travel_agent = create_agent(
  79. model=gemini_model,
  80. tools=tools,
  81. system_prompt="""
  82. You are a travel agent. Search for flights to the desired destination wedding location.
  83. You are not allowed to ask any more follow up questions, you must find the best flight options based on the following criteria:
  84. - Price (lowest, economy class)
  85. - Duration (shortest)
  86. - Date (time of year which you believe is best for a wedding at this location)
  87. To make things easy, only look for one ticket, one way.
  88. You may need to make multiple searches to iteratively find the best options.
  89. You will be given no extra information, only the origin and destination. It is your job to think critically about the best options.
  90. If the MCP tool fails, returns malformed output, or does not give you usable flight results, try the tool again.
  91. Once you have found the best options, let the user know your shortlist of options.
  92. """
  93. )
  94.  
  95. # Venue agent
  96. venue_agent = create_agent(
  97. model=gemini_model,
  98. tools=[web_search],
  99. system_prompt="""
  100. You are a venue specialist. Search for venues in the desired location, and with the desired capacity.
  101. You are not allowed to ask any more follow up questions, you must find the best venue options based on the following criteria:
  102. - Price (lowest)
  103. - Capacity (exact match)
  104. - Reviews (highest)
  105. You may need to make multiple searches to iteratively find the best options.
  106. You have a suggested limit of 12 web searches. Count every web_search call you make.
  107. After 12 searches, you should stop searching and summarize the best options you have
  108. found so far.
  109. """
  110. )
  111.  
  112. # Playlist agent
  113. playlist_agent = create_agent(
  114. model=gemini_model,
  115. tools=[query_playlist_db],
  116. system_prompt="""
  117. You are a playlist specialist. Query the sql database and curate the perfect playlist for a wedding given a genre.
  118. Once you have your playlist, calculate the total duration and cost of the playlist, each song has an associated price.
  119. If you run into errors when querying the database, try to fix them by making changes to the query.
  120. Do not come back empty handed, keep trying to query the db until you find a list of songs.
  121.  
  122. This is a SQLite database. Before writing any data queries, first discover the schema.
  123. """
  124. )
  125.  
  126.  
  127.  
  128. @tool
  129. async def search_flights(runtime: ToolRuntime) -> str:
  130. """Travel agent searches for flights to the desired destination wedding location."""
  131. origin = runtime.state["origin"]
  132. destination = runtime.state["destination"]
  133. response = await travel_agent.ainvoke({"messages": [HumanMessage(content=f"Find flights from {origin} to {destination}")]})
  134. return response['messages'][-1].content
  135.  
  136. @tool
  137. def search_venues(runtime: ToolRuntime) -> str:
  138. """Venue agent chooses the best venue for the given location and capacity."""
  139. destination = runtime.state["destination"]
  140. capacity = runtime.state["guest_count"]
  141. query = f"Find wedding venues in {destination} for {capacity} guests"
  142. response = venue_agent.invoke({"messages": [HumanMessage(content=query)]})
  143. return response['messages'][-1].content
  144.  
  145. @tool
  146. def suggest_playlist(runtime: ToolRuntime) -> str:
  147. """Playlist agent curates the perfect playlist for the given genre."""
  148. genre = runtime.state["genre"]
  149. query = f"Find {genre} tracks for wedding playlist"
  150. response = playlist_agent.invoke({"messages": [HumanMessage(content=query)]})
  151. return response['messages'][-1].content
  152.  
  153. @tool
  154. def update_state(origin: str, destination: str, guest_count: str, genre: str, runtime: ToolRuntime) -> str:
  155. """Update the state when you know all of the values: origin, destination, guest_count, genre.
  156. This tool must be called alone, without any other tool calls. It must complete and return to make,
  157. the information available to other tools."""
  158. return Command(update={
  159. "origin": origin,
  160. "destination": destination,
  161. "guest_count": guest_count,
  162. "genre": genre,
  163. "messages": [ToolMessage("Successfully updated state", tool_call_id=runtime.tool_call_id)]}
  164. )
  165.  
  166. coordinator = create_agent(
  167. model=gemini_model,
  168. tools=[search_flights, search_venues, suggest_playlist, update_state],
  169. state_schema=WeddingState,
  170. system_prompt="""
  171. You are a wedding coordinator.
  172. First find all the information you need to update the state. When you have the information, update the state.
  173. Once that has completed and returned, you can delegate the tasks
  174. to your specialists for flights, venues, and playlists.
  175. Once you have received their answers, coordinate the perfect wedding for me.
  176. """
  177. )
  178.  
  179. response = await coordinator.ainvoke(
  180. {
  181. "messages": [HumanMessage(content="I'm from London and I'd like a wedding in Paris for 100 guests, jazz-genre")],
  182. },
  183. config={"tags": ["WP"], "recursion_limit": 40}, #tag traces to make them easy to find in Langsmith. Increase number of steps the agent can take to 40.
  184. )
  185. print(response["messages"][-1].content)
  186.  
  187. if __name__ == "__main__":
  188. asyncio.run(main())
Advertisement
Add Comment
Please, Sign In to add comment