mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-13 13:17:52 +02:00
docs: update how-to to remove agent wrapper (#2721)
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
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
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -139,71 +139,117 @@
|
||||
"from typing_extensions import TypedDict, Literal\n",
|
||||
"\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"from langchain_core.messages import HumanMessage\n",
|
||||
"from langchain_core.messages import AnyMessage\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"from langgraph.graph import MessagesState, StateGraph, START, END\n",
|
||||
"from langgraph.types import Command, interrupt\n",
|
||||
"from langgraph.checkpoint.memory import MemorySaver\n",
|
||||
"from langgraph.prebuilt import create_react_agent\n",
|
||||
"\n",
|
||||
"model = ChatOpenAI(model=\"gpt-4o\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def make_agent_node(*, name: str, destinations: list[str], system_prompt: str):\n",
|
||||
" def agent_node(state: MessagesState) -> Command[Literal[*destinations, \"human\"]]:\n",
|
||||
" # define schema for the structured output:\n",
|
||||
" # - model's text response (`response`)\n",
|
||||
" # - name of the node to go to next (or 'finish')\n",
|
||||
" class Response(TypedDict):\n",
|
||||
" response: str\n",
|
||||
" goto: Literal[*destinations, \"finish\"]\n",
|
||||
"# Define a helper for each of the agent nodes to call\n",
|
||||
"def call_llm(messages: list[AnyMessage], target_agent_nodes: list[str]):\n",
|
||||
" \"\"\"Call LLM with structured output to get a natural language response as well as a target agent (node) to go to next.\n",
|
||||
"\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" response = model.with_structured_output(Response).invoke(messages)\n",
|
||||
" goto = response[\"goto\"]\n",
|
||||
" if goto == \"finish\":\n",
|
||||
" # When the agent is done, we should go to the\n",
|
||||
" goto = \"human\"\n",
|
||||
"\n",
|
||||
" # Handoff to another agent or halt\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": name}\n",
|
||||
" return Command(goto=goto, update={\"messages\": [ai_msg]})\n",
|
||||
"\n",
|
||||
" return agent_node\n",
|
||||
" Args:\n",
|
||||
" messages: list of messages to pass to the LLM\n",
|
||||
" target_agents: list of the node names of the target agents to navigate to\n",
|
||||
" \"\"\"\n",
|
||||
" # define JSON schema for the structured output:\n",
|
||||
" # - model's text response (`response`)\n",
|
||||
" # - name of the node to go to next (or 'finish')\n",
|
||||
" # see more on structured output here https://python.langchain.com/docs/concepts/structured_outputs\n",
|
||||
" json_schema = {\n",
|
||||
" \"name\": \"Response\",\n",
|
||||
" \"parameters\": {\n",
|
||||
" \"type\": \"object\",\n",
|
||||
" \"properties\": {\n",
|
||||
" \"response\": {\n",
|
||||
" \"type\": \"string\",\n",
|
||||
" \"description\": \"A human readable response to the original question. Does not need to be a final response. Will be streamed back to the user.\",\n",
|
||||
" },\n",
|
||||
" \"goto\": {\n",
|
||||
" \"enum\": [*target_agent_nodes, \"finish\"],\n",
|
||||
" \"type\": \"string\",\n",
|
||||
" \"description\": \"The next agent to call, or 'finish' if the user's query has been resolved. Must be one of the specified values.\",\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
" \"required\": [\"response\", \"goto\"],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
" response = model.with_structured_output(json_schema).invoke(messages)\n",
|
||||
" return response\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"travel_advisor = make_agent_node(\n",
|
||||
" name=\"travel_advisor\",\n",
|
||||
" destinations=[\"sightseeing_advisor\", \"hotel_advisor\", \"human\"],\n",
|
||||
" system_prompt=(\n",
|
||||
"def travel_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"sightseeing_advisor\", \"hotel_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n",
|
||||
" \"If you need specific sightseeing recommendations, ask 'sightseeing_advisor' for help. \"\n",
|
||||
" \"If you need hotel recommendations, ask 'hotel_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
"sightseeing_advisor = make_agent_node(\n",
|
||||
" name=\"sightseeing_advisor\",\n",
|
||||
" destinations=[\"travel_advisor\", \"hotel_advisor\", \"human\"],\n",
|
||||
" system_prompt=(\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"sightseeing_advisor\", \"hotel_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": \"travel_advisor\"}\n",
|
||||
" # handoff to another agent or go to the human when agent is done\n",
|
||||
" goto = response[\"goto\"]\n",
|
||||
" if goto == \"finish\":\n",
|
||||
" goto = \"human\"\n",
|
||||
"\n",
|
||||
" return Command(goto=goto, update={\"messages\": [ai_msg]})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def sightseeing_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"travel_advisor\", \"hotel_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a travel expert that can provide specific sightseeing recommendations for a given destination. \"\n",
|
||||
" \"If you need general travel help, go to 'travel_advisor' for help. \"\n",
|
||||
" \"If you need hotel recommendations, go to 'hotel_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
"hotel_advisor = make_agent_node(\n",
|
||||
" name=\"hotel_advisor\",\n",
|
||||
" destinations=[\"travel_advisor\", \"sightseeing_advisor\", \"human\"],\n",
|
||||
" system_prompt=(\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"travel_advisor\", \"hotel_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\n",
|
||||
" \"role\": \"ai\",\n",
|
||||
" \"content\": response[\"response\"],\n",
|
||||
" \"name\": \"sightseeing_advisor\",\n",
|
||||
" }\n",
|
||||
" # handoff to another agent or go to the human when agent is done\n",
|
||||
" goto = response[\"goto\"]\n",
|
||||
" if goto == \"finish\":\n",
|
||||
" goto = \"human\"\n",
|
||||
"\n",
|
||||
" return Command(goto=goto, update={\"messages\": [ai_msg]})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def hotel_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"travel_advisor\", \"sightseeing_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a travel expert that can provide hotel recommendations for a given destination. \"\n",
|
||||
" \"If you need general travel help, ask 'travel_advisor' for help. \"\n",
|
||||
" \"If you need specific sightseeing recommendations, ask 'sightseeing_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"travel_advisor\", \"sightseeing_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": \"hotel_advisor\"}\n",
|
||||
" # handoff to another agent or go to the human when agent is done\n",
|
||||
" goto = response[\"goto\"]\n",
|
||||
" if goto == \"finish\":\n",
|
||||
" goto = \"human\"\n",
|
||||
"\n",
|
||||
" return Command(goto=goto, update={\"messages\": [ai_msg]})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def human_node(\n",
|
||||
@@ -376,7 +422,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.4"
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -133,74 +133,110 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "aa4bdbff-9461-46cc-aee9-8a22d3c3d9ec",
|
||||
"id": "29e2a824-dbeb-4944-9df2-63fdbd883252",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing_extensions import TypedDict, Literal\n",
|
||||
"\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"from langchain_core.messages import AnyMessage\n",
|
||||
"from langgraph.graph import MessagesState, StateGraph, START, END\n",
|
||||
"from langgraph.types import Command\n",
|
||||
"\n",
|
||||
"model = ChatOpenAI(model=\"gpt-4o\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def make_agent_node(*, name: str, destinations: list[str], system_prompt: str):\n",
|
||||
" def agent_node(state: MessagesState) -> Command[Literal[*destinations, END]]:\n",
|
||||
" # define schema for the structured output:\n",
|
||||
" # - model's text response (`response`)\n",
|
||||
" # - name of the node to go to next (or 'finish')\n",
|
||||
" class Response(TypedDict):\n",
|
||||
" response: str\n",
|
||||
" goto: Literal[*destinations, \"finish\"]\n",
|
||||
"# Define a helper for each of the agent nodes to call\n",
|
||||
"def call_llm(messages: list[AnyMessage], target_agent_nodes: list[str]):\n",
|
||||
" \"\"\"Call LLM with structured output to get a natural language response as well as a target agent (node) to go to next.\n",
|
||||
"\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" response = model.with_structured_output(Response).invoke(messages)\n",
|
||||
" goto = response[\"goto\"]\n",
|
||||
" if goto == \"finish\":\n",
|
||||
" goto = END\n",
|
||||
"\n",
|
||||
" # handoff to another agent or halt\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": name}\n",
|
||||
" return Command(goto=goto, update={\"messages\": ai_msg})\n",
|
||||
"\n",
|
||||
" return agent_node\n",
|
||||
" Args:\n",
|
||||
" messages: list of messages to pass to the LLM\n",
|
||||
" target_agents: list of the node names of the target agents to navigate to\n",
|
||||
" \"\"\"\n",
|
||||
" # define JSON schema for the structured output:\n",
|
||||
" # - model's text response (`response`)\n",
|
||||
" # - name of the node to go to next (or 'finish')\n",
|
||||
" # see more on structured output here https://python.langchain.com/docs/concepts/structured_outputs\n",
|
||||
" json_schema = {\n",
|
||||
" \"name\": \"Response\",\n",
|
||||
" \"parameters\": {\n",
|
||||
" \"type\": \"object\",\n",
|
||||
" \"properties\": {\n",
|
||||
" \"response\": {\n",
|
||||
" \"type\": \"string\",\n",
|
||||
" \"description\": \"A human readable response to the original question. Does not need to be a final response. Will be streamed back to the user.\",\n",
|
||||
" },\n",
|
||||
" \"goto\": {\n",
|
||||
" \"enum\": [*target_agent_nodes, \"__end__\"],\n",
|
||||
" \"type\": \"string\",\n",
|
||||
" \"description\": \"The next agent to call, or __end__ if the user's query has been resolved. Must be one of the specified values.\",\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
" \"required\": [\"response\", \"goto\"],\n",
|
||||
" },\n",
|
||||
" }\n",
|
||||
" response = model.with_structured_output(json_schema).invoke(messages)\n",
|
||||
" return response\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"travel_advisor = make_agent_node(\n",
|
||||
" name=\"travel_advisor\",\n",
|
||||
" destinations=[\"sightseeing_advisor\", \"hotel_advisor\"],\n",
|
||||
" system_prompt=(\n",
|
||||
"def travel_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"sightseeing_advisor\", \"hotel_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n",
|
||||
" \"If you need specific sightseeing recommendations, ask 'sightseeing_advisor' for help. \"\n",
|
||||
" \"If you need hotel recommendations, ask 'hotel_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
"sightseeing_advisor = make_agent_node(\n",
|
||||
" name=\"sightseeing_advisor\",\n",
|
||||
" destinations=[\"travel_advisor\", \"hotel_advisor\"],\n",
|
||||
" system_prompt=(\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"sightseeing_advisor\", \"hotel_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": \"travel_advisor\"}\n",
|
||||
" # handoff to another agent or halt\n",
|
||||
" return Command(goto=response[\"goto\"], update={\"messages\": ai_msg})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def sightseeing_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"travel_advisor\", \"hotel_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a travel expert that can provide specific sightseeing recommendations for a given destination. \"\n",
|
||||
" \"If you need general travel help, go to 'travel_advisor' for help. \"\n",
|
||||
" \"If you need hotel recommendations, go to 'hotel_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
"hotel_advisor = make_agent_node(\n",
|
||||
" name=\"hotel_advisor\",\n",
|
||||
" destinations=[\"travel_advisor\", \"sightseeing_advisor\"],\n",
|
||||
" system_prompt=(\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"travel_advisor\", \"hotel_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\n",
|
||||
" \"role\": \"ai\",\n",
|
||||
" \"content\": response[\"response\"],\n",
|
||||
" \"name\": \"sightseeing_advisor\",\n",
|
||||
" }\n",
|
||||
" # handoff to another agent or halt\n",
|
||||
" return Command(goto=response[\"goto\"], update={\"messages\": ai_msg})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def hotel_advisor(\n",
|
||||
" state: MessagesState,\n",
|
||||
") -> Command[Literal[\"travel_advisor\", \"sightseeing_advisor\", \"__end__\"]]:\n",
|
||||
" system_prompt = (\n",
|
||||
" \"You are a travel expert that can provide hotel recommendations for a given destination. \"\n",
|
||||
" \"If you need general travel help, ask 'travel_advisor' for help. \"\n",
|
||||
" \"If you need specific sightseeing recommendations, ask 'sightseeing_advisor' for help. \"\n",
|
||||
" \"If you have enough information to respond to the user, return 'finish'. \"\n",
|
||||
" \"Never mention other agents by name.\"\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
" )\n",
|
||||
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n",
|
||||
" target_agent_nodes = [\"travel_advisor\", \"sightseeing_advisor\"]\n",
|
||||
" response = call_llm(messages, target_agent_nodes)\n",
|
||||
" ai_msg = {\"role\": \"ai\", \"content\": response[\"response\"], \"name\": \"hotel_advisor\"}\n",
|
||||
" # handoff to another agent or halt\n",
|
||||
" return Command(goto=response[\"goto\"], update={\"messages\": ai_msg})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"builder = StateGraph(MessagesState)\n",
|
||||
@@ -254,7 +290,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'travel_advisor': {'messages': {'role': 'ai', 'content': 'The Caribbean offers many warm destinations perfect for a relaxing getaway. Consider visiting Jamaica for its beautiful beaches and vibrant culture, the Bahamas for its stunning islands and clear waters, or the Dominican Republic for its all-inclusive resorts and rich history. Let me know if you need more information on sightseeing or hotel recommendations!', 'name': 'travel_advisor'}}}\n",
|
||||
"{'travel_advisor': {'messages': {'role': 'ai', 'content': 'The Caribbean offers many warm and beautiful destinations. Some popular ones include:\\n\\n1. **Jamaica** - Known for its beautiful beaches, reggae music, and vibrant culture.\\n2. **Bahamas** - Offers stunning beaches and clear turquoise waters, perfect for relaxation and water activities.\\n3. **Barbados** - Known for its friendly locals, delicious cuisine, and beautiful beaches.\\n4. **Dominican Republic** - Offers a mix of beaches, mountains, and historical sites.\\n5. **Aruba** - Known for its dry climate, beautiful beaches, and outdoor activities.\\n\\nWould you like recommendations for sightseeing or hotels in any of these destinations?', 'name': 'travel_advisor'}}}\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
@@ -286,13 +322,13 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'travel_advisor': {'messages': {'role': 'ai', 'content': 'I recommend visiting Jamaica, a beautiful Caribbean island known for its warm climate, stunning beaches, and vibrant culture.', 'name': 'travel_advisor'}}}\n",
|
||||
"{'travel_advisor': {'messages': {'role': 'ai', 'content': 'I recommend visiting Jamaica, a vibrant and warm destination in the Caribbean known for its beautiful beaches, rich culture, and exciting activities.', 'name': 'travel_advisor'}}}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"{'sightseeing_advisor': {'messages': {'role': 'ai', 'content': \"Jamaica is a fantastic choice for a warm Caribbean getaway. Here are some top things to do while you're there:\\n\\n1. **Dunn's River Falls**: Located near Ocho Rios, this is one of Jamaica's most famous waterfalls. You can climb the falls, swim in the refreshing pools, or simply enjoy the beautiful surroundings.\\n\\n2. **Seven Mile Beach**: Located in Negril, this is one of the most beautiful beaches in the Caribbean. It's perfect for sunbathing, swimming, and enjoying water sports.\\n\\n3. **Bob Marley Museum**: Situated in Kingston, this museum is dedicated to the life and legacy of the reggae legend Bob Marley and is a must-visit for music lovers.\\n\\n4. **Blue Mountains**: Go hiking or take a tour to explore the Blue Mountains, where you can enjoy breathtaking views and taste some of the world's best coffee.\\n\\n5. **Luminous Lagoon**: Experience the natural wonder of the Luminous Lagoon in Falmouth, where the water glows at night due to bioluminescent microorganisms.\\n\\nFor hotel recommendations, I suggest checking with a hotel advisor for the best options that suit your budget and preferences.\", 'name': 'sightseeing_advisor'}}}\n",
|
||||
"{'sightseeing_advisor': {'messages': {'role': 'ai', 'content': \"For a warm and vibrant Caribbean destination, I recommend Jamaica. It's renowned for its stunning beaches, lively culture, and exciting activities.\\n\\n### Things to Do in Jamaica:\\n1. **Explore Dunn’s River Falls**: A famous waterfall near Ocho Rios where you can climb the terraced steps and enjoy the natural pools.\\n2. **Visit Bob Marley Museum**: Located in Kingston, this museum offers a deep dive into the life of the reggae legend.\\n3. **Relax at Seven Mile Beach**: Known for its beautiful white sand and clear blue waters, it’s perfect for sunbathing and swimming.\\n4. **Experience Negril Cliffs**: Enjoy breathtaking views and adventurous cliff diving.\\n5. **Discover Blue Hole**: A hidden gem near Ocho Rios, offering a refreshing swim in stunning turquoise waters.\\n\\nI will now find some hotel recommendations for you in Jamaica.\", 'name': 'sightseeing_advisor'}}}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"{'hotel_advisor': {'messages': {'role': 'ai', 'content': 'For hotel recommendations in Jamaica, here are a few options across different areas: \\n\\n1. **Sandals Montego Bay** (Montego Bay): A luxurious all-inclusive resort ideal for couples, offering beautiful beachfront views and a variety of dining options.\\n\\n2. **Half Moon Resort** (Montego Bay): A family-friendly resort with a private beach, golf course, and various activities for all ages.\\n\\n3. **Jamaica Inn** (Ocho Rios): A charming boutique hotel known for its excellent service and tranquil atmosphere.\\n\\n4. **The Caves** (Negril): A unique and romantic cliff-side resort offering stunning ocean views and intimate dining experiences.\\n\\n5. **Trident Hotel** (Port Antonio): A luxurious and contemporary hotel offering privacy, elegance, and beautiful views of the Caribbean Sea.\\n\\nThese options cater to different tastes and budgets, ensuring a comfortable and enjoyable stay in Jamaica.', 'name': 'hotel_advisor'}}}\n",
|
||||
"{'hotel_advisor': {'messages': {'role': 'ai', 'content': 'For your stay in Jamaica, here are some hotel recommendations:\\n\\n1. **Sandals Montego Bay**: An all-inclusive resort offering luxury accommodations, private beaches, and various dining options.\\n\\n2. **Jamaica Inn**: Located in Ocho Rios, this boutique hotel offers a more intimate experience with stunning beach views and personalized service.\\n\\n3. **Half Moon Resort**: Situated in Montego Bay, this resort features a private beach, golf course, and a world-class spa.\\n\\n4. **The Caves Hotel**: In Negril, offering unique cliffside cottages and a romantic atmosphere.\\n\\n5. **Round Hill Hotel and Villas**: A classic resort near Montego Bay with luxurious villas and an elegant ambiance.\\n\\nEnjoy your trip to Jamaica, where warm weather and vibrant culture await!', 'name': 'hotel_advisor'}}}\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
@@ -374,7 +410,7 @@
|
||||
" guard_on_duty: bool\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def villager(state: GameState) -> Command[Literal[\"villager\", END]]:\n",
|
||||
"def villager(state: GameState) -> Command[Literal[\"villager\", \"__end__\"]]:\n",
|
||||
" \"\"\"Villager NPC that gathers wood and food.\"\"\"\n",
|
||||
" current_resources = state[\"wood\"] + state[\"food\"]\n",
|
||||
" if current_resources < 15: # Continue gathering until we have enough resources\n",
|
||||
@@ -387,7 +423,7 @@
|
||||
" return Command(goto=END)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def guard(state: GameState) -> Command[Literal[\"guard\", END]]:\n",
|
||||
"def guard(state: GameState) -> Command[Literal[\"guard\", \"__end__\"]]:\n",
|
||||
" \"\"\"Guard NPC that protects gold and consumes food.\"\"\"\n",
|
||||
" if not state[\"guard_on_duty\"]:\n",
|
||||
" return Command(goto=END)\n",
|
||||
@@ -404,7 +440,7 @@
|
||||
" return Command(goto=END, update={\"guard_on_duty\": False}) # Leave to get food\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def merchant(state: GameState) -> Command[Literal[\"merchant\", END]]:\n",
|
||||
"def merchant(state: GameState) -> Command[Literal[\"merchant\", \"__end__\"]]:\n",
|
||||
" \"\"\"Merchant NPC that trades wood for gold.\"\"\"\n",
|
||||
" if state[\"wood\"] >= 5: # Trade wood for gold when available\n",
|
||||
" print(\"Merchant trading wood for gold.\")\n",
|
||||
@@ -413,7 +449,7 @@
|
||||
" return Command(goto=END)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def thief(state: GameState) -> Command[Literal[\"thief\", END]]:\n",
|
||||
"def thief(state: GameState) -> Command[Literal[\"thief\", \"__end__\"]]:\n",
|
||||
" \"\"\"Thief NPC that steals gold if the guard leaves to get food.\"\"\"\n",
|
||||
" if not state[\"guard_on_duty\"]:\n",
|
||||
" print(\"Thief stealing gold.\")\n",
|
||||
@@ -561,7 +597,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
"version": "3.12.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
Generated
+9
-9
@@ -3005,18 +3005,18 @@ pillow = ">=10.3.0,<11.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "langchain-openai"
|
||||
version = "0.2.1"
|
||||
version = "0.2.12"
|
||||
description = "An integration package connecting OpenAI and LangChain"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.9"
|
||||
files = [
|
||||
{file = "langchain_openai-0.2.1-py3-none-any.whl", hash = "sha256:215efa4526c88f8105f002b43b7cbf98cebd9baeb4f62c3b58faebdb578715bc"},
|
||||
{file = "langchain_openai-0.2.1.tar.gz", hash = "sha256:a131ea18736f1a8792925391b91a8c8bd834431ffc2055c92ba49f59c3dcaaf0"},
|
||||
{file = "langchain_openai-0.2.12-py3-none-any.whl", hash = "sha256:916965c45584d9ea565825ad3bb7629b1ff57f12f36d4b937e5b7d65903839d6"},
|
||||
{file = "langchain_openai-0.2.12.tar.gz", hash = "sha256:8b92096623065a2820e89aa5fb0a262fb109d56c346e3b09ba319af424c45cd1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
langchain-core = ">=0.3,<0.4"
|
||||
openai = ">=1.40.0,<2.0.0"
|
||||
langchain-core = ">=0.3.21,<0.4.0"
|
||||
openai = ">=1.55.3,<2.0.0"
|
||||
tiktoken = ">=0.7,<1"
|
||||
|
||||
[[package]]
|
||||
@@ -4339,13 +4339,13 @@ sympy = "*"
|
||||
|
||||
[[package]]
|
||||
name = "openai"
|
||||
version = "1.50.1"
|
||||
version = "1.57.2"
|
||||
description = "The official Python library for the openai API"
|
||||
optional = false
|
||||
python-versions = ">=3.7.1"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "openai-1.50.1-py3-none-any.whl", hash = "sha256:7967fc8372d5e005ad61514586fb286d593facafccedbee00416bc38ee07c2e6"},
|
||||
{file = "openai-1.50.1.tar.gz", hash = "sha256:80cbdf275488894c70bfbad711dbba6f31ea71d579b97e364bfd99cdf030158e"},
|
||||
{file = "openai-1.57.2-py3-none-any.whl", hash = "sha256:f7326283c156fdee875746e7e54d36959fb198eadc683952ee05e3302fbd638d"},
|
||||
{file = "openai-1.57.2.tar.gz", hash = "sha256:5f49fd0f38e9f2131cda7deb45dafdd1aee4f52a637e190ce0ecf40147ce8cee"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
||||
Reference in New Issue
Block a user