mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-30 11:49:38 +02:00
Add LLMCompiler
This commit is contained in:
@@ -0,0 +1,957 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0c8b472b-f3fb-46c2-841f-930a4692697b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Implementing LLMCompiler using LangGraph\n",
|
||||
"By Kim, et. al [🔗](https://arxiv.org/abs/2312.04511)\n",
|
||||
"\n",
|
||||
"LLMCompiler is an agent architecture intented on speeding up the latency of agentic tasks via fast, parallel tool execution.\n",
|
||||
"\n",
|
||||
"It has 3 main components:\n",
|
||||
"\n",
|
||||
"1. Planner: generate a DAG of tasks.\n",
|
||||
"2. Task Fetching Unit: schedules and executes the tasks\n",
|
||||
"3. Joiner: Responds to the user or triggers a second plan."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1abdedbd-d81b-4ee9-b46f-f29439ed1350",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Part 1: Planner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "278f76b0-a2e1-42dc-bd3e-6f624984e3dd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Output Parser\n",
|
||||
"\n",
|
||||
"Parses task lists in the following form:\n",
|
||||
"```plaintext\n",
|
||||
"1. tool_1(\"arg1\", 3.5, ...)\n",
|
||||
"Thought: I then want to find out Y by using tool_2\n",
|
||||
"2. tool_2(\"\", ${1})'\n",
|
||||
"3. join()<END_OF_PLAN>\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The \"Thought\" lines are optional. The `${#}` placeholders are variables. These are used to route tool (task) outputs to other tools."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "cc71b6c4-d701-4217-9701-95ac0857e4e1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import ast\n",
|
||||
"import json\n",
|
||||
"import re\n",
|
||||
"from typing import Any, Optional, Sequence, Union\n",
|
||||
"\n",
|
||||
"from langchain.agents.agent import AgentOutputParser\n",
|
||||
"from langchain.schema import OutputParserException\n",
|
||||
"from langchain_core.tools import BaseTool\n",
|
||||
"\n",
|
||||
"THOUGHT_PATTERN = r\"Thought: ([^\\n]*)\"\n",
|
||||
"# ACTION_PATTERN = r\"\\n*(\\d+)\\. (.*?})(\\s*#\\w+\\n)?\"\n",
|
||||
"# $1 or ${1} -> 1\n",
|
||||
"ID_PATTERN = r\"\\$\\{?(\\d+)\\}?\"\n",
|
||||
"END_OF_PLAN = \"<END_OF_PLAN>\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class ActionParserFSM:\n",
|
||||
" def __init__(self):\n",
|
||||
" self.reset()\n",
|
||||
"\n",
|
||||
" def reset(self):\n",
|
||||
" self.state = \"START\"\n",
|
||||
" self.task_index = \"\"\n",
|
||||
" self.action = \"\"\n",
|
||||
" self.comment = \"\"\n",
|
||||
" self.bracket_count = 0\n",
|
||||
" self.actions = []\n",
|
||||
"\n",
|
||||
" def parse(self, text: str):\n",
|
||||
" for char in text:\n",
|
||||
" action = self.process_char(char)\n",
|
||||
" if action:\n",
|
||||
" yield action\n",
|
||||
" action = self.save_action()\n",
|
||||
" if action:\n",
|
||||
" yield action\n",
|
||||
"\n",
|
||||
" def process_char(self, char: str) -> Optional[dict]:\n",
|
||||
" action = None\n",
|
||||
" if self.state == \"START\":\n",
|
||||
" if char.isdigit():\n",
|
||||
" self.state = \"NUMBER\"\n",
|
||||
" self.task_index += char\n",
|
||||
" elif char == \"\\n\":\n",
|
||||
" self.reset()\n",
|
||||
" elif self.state == \"NUMBER\":\n",
|
||||
" if char == \".\":\n",
|
||||
" self.state = \"ACTION\"\n",
|
||||
" elif char.isdigit():\n",
|
||||
" self.task_index += char\n",
|
||||
" else:\n",
|
||||
" self.reset()\n",
|
||||
" elif self.state == \"ACTION\":\n",
|
||||
" if char == \"{\":\n",
|
||||
" self.bracket_count += 1\n",
|
||||
" elif char == \"}\":\n",
|
||||
" self.bracket_count -= 1\n",
|
||||
" if self.bracket_count == 0:\n",
|
||||
" self.state = \"COMMENT\"\n",
|
||||
" self.action += char\n",
|
||||
" elif self.state == \"COMMENT\":\n",
|
||||
" if char == \"\\n\":\n",
|
||||
" action = self.save_action()\n",
|
||||
" self.reset()\n",
|
||||
" else:\n",
|
||||
" self.comment += char\n",
|
||||
" return action\n",
|
||||
"\n",
|
||||
" def save_action(self):\n",
|
||||
" if self.task_index and self.action:\n",
|
||||
" parsed_action = json.loads(self.action.strip())\n",
|
||||
" tool_name, args = next(iter(parsed_action.items()))\n",
|
||||
" return {\n",
|
||||
" \"task_index\": int(self.task_index),\n",
|
||||
" \"tool_name\": tool_name,\n",
|
||||
" \"args\": args,\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class LLMCompilerPlanParser(AgentOutputParser, extra=\"allow\"):\n",
|
||||
" \"\"\"Planning output parser.\"\"\"\n",
|
||||
"\n",
|
||||
" def __init__(self, tools: Sequence[BaseTool], **kwargs):\n",
|
||||
" super().__init__(**kwargs)\n",
|
||||
" self.tools = tools\n",
|
||||
"\n",
|
||||
" def parse(self, text: str) -> list[str]:\n",
|
||||
" parser = ActionParserFSM()\n",
|
||||
" graph_dict = {}\n",
|
||||
" for task in parser.parse(text):\n",
|
||||
" idx = int(task[\"task_index\"])\n",
|
||||
"\n",
|
||||
" task = instantiate_task(\n",
|
||||
" tools=self.tools,\n",
|
||||
" idx=idx,\n",
|
||||
" tool_name=task[\"tool_name\"],\n",
|
||||
" args=task[\"args\"],\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" graph_dict[idx] = task\n",
|
||||
" if task[\"tool\"] == \"join\":\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
" return graph_dict\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Helper functions\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def default_dependency_rule(idx, args: str):\n",
|
||||
" matches = re.findall(ID_PATTERN, args)\n",
|
||||
" numbers = [int(match) for match in matches]\n",
|
||||
" return idx in numbers\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _get_dependencies_from_graph(\n",
|
||||
" idx: int, tool_name: str, args: Sequence[Any]\n",
|
||||
") -> dict[str, list[str]]:\n",
|
||||
" \"\"\"Get dependencies from a graph.\"\"\"\n",
|
||||
" if tool_name == \"join\":\n",
|
||||
" return list(range(1, idx))\n",
|
||||
" return [i for i in range(1, idx) if default_dependency_rule(i, str(args))]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def instantiate_task(\n",
|
||||
" tools: Sequence[BaseTool],\n",
|
||||
" idx: int,\n",
|
||||
" tool_name: str,\n",
|
||||
" args: Union[dict, str, bool, None],\n",
|
||||
") -> dict:\n",
|
||||
" dependencies = _get_dependencies_from_graph(idx, tool_name, args)\n",
|
||||
" if tool_name == \"join\":\n",
|
||||
" tool = \"join\"\n",
|
||||
" else:\n",
|
||||
" try:\n",
|
||||
" tool = tools[[tool.name for tool in tools].index(tool_name)]\n",
|
||||
" except ValueError as e:\n",
|
||||
" raise OutputParserException(f\"Tool {tool_name} not found.\")\n",
|
||||
" return dict(\n",
|
||||
" tool=tool,\n",
|
||||
" args=args,\n",
|
||||
" dependencies=dependencies,\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "228a2f75-68b1-4dbf-95dc-4bfc738c3b3b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Planner Code\n",
|
||||
"\n",
|
||||
"This takes the input and outputs a plan."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "58af9746-1011-41e9-a77a-be9cef202aea",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import asyncio\n",
|
||||
"import json\n",
|
||||
"import re\n",
|
||||
"from typing import Any, Optional, Sequence, Union\n",
|
||||
"from uuid import UUID\n",
|
||||
"\n",
|
||||
"from langchain.callbacks.base import AsyncCallbackHandler, Callbacks\n",
|
||||
"from langchain.chat_models.base import BaseChatModel\n",
|
||||
"from langchain.schema import LLMResult\n",
|
||||
"from langchain.schema.messages import HumanMessage, SystemMessage\n",
|
||||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel\n",
|
||||
"from langchain_core.runnables import RunnableBranch\n",
|
||||
"from langchain_core.tools import BaseTool\n",
|
||||
"\n",
|
||||
"END_OF_PLAN = \"<END_OF_PLAN>\"\n",
|
||||
"\n",
|
||||
"JOINER_FINISH = \"Finish\"\n",
|
||||
"JOINER_REPLAN = \"Replan\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"JOIN_DESCRIPTION = (\n",
|
||||
" \"join():\\n\"\n",
|
||||
" \" - Collects and combines results from prior actions.\\n\"\n",
|
||||
" \" - A LLM agent is called upon invoking join to either finalize the user query or wait until the plans are executed.\\n\"\n",
|
||||
" \" - join should always be the last action in the plan, and will be called in two scenarios:\\n\"\n",
|
||||
" \" (a) if the answer can be determined by gathering the outputs from tasks to generate the final response.\\n\"\n",
|
||||
" \" (b) if the answer cannot be determined in the planning phase before you execute the plans. \"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"planner_prompt_tmpl_str = (\n",
|
||||
" \"Given a user query, create a plan to solve it with the utmost parallelizability. \"\n",
|
||||
" \"Each plan should comprise an action from the following {num_tools} types:\\n\"\n",
|
||||
" \"{tool_descriptions}\"\n",
|
||||
" f\"\\n{{num_toolsp1}}. {JOIN_DESCRIPTION}\"\n",
|
||||
" \"Guidelines:\\n\"\n",
|
||||
" \" - Each action described above contains input/output types and description.\\n\"\n",
|
||||
" \" - You must strictly adhere to the input and output types for each action.\\n\"\n",
|
||||
" \" - The action descriptions contain the guidelines. You MUST strictly follow those guidelines when you use the actions.\\n\"\n",
|
||||
" \" - Each action in the plan should strictly be one of the above types. Follow the Python conventions for each action.\\n\"\n",
|
||||
" \" - Pass arguments by keyword ONLY\\n\"\n",
|
||||
" \" - Each action MUST have a unique ID, which is strictly increasing.\\n\"\n",
|
||||
" \" - Inputs for actions can either be constants or outputs from preceding actions. \"\n",
|
||||
" \"In the latter case, use the format $id to denote the ID of the previous action whose output will be the input.\\n\"\n",
|
||||
" f\" - Always call join as the last action in the plan. Say '{END_OF_PLAN}' after you call join\\n\"\n",
|
||||
" \" - Ensure the plan maximizes parallelizability.\\n\"\n",
|
||||
" \" - Only use the provided action types. If a query cannot be addressed using these, invoke the join action for the next steps.\\n\"\n",
|
||||
" \" - Never explain the plan with comments (e.g. #).\\n\"\n",
|
||||
" \" - Never introduce new actions other than the ones provided.\\n\\n\"\n",
|
||||
" \"{replan}\"\n",
|
||||
" \"{examples}\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _generate_planner_prompt(\n",
|
||||
" tools: Sequence[BaseTool],\n",
|
||||
" example_prompt=str,\n",
|
||||
"):\n",
|
||||
" tool_descriptions = \"\\n\".join(\n",
|
||||
" f\"{i+1}. {tool.description}\" for i, tool in enumerate(tools)\n",
|
||||
" )\n",
|
||||
" planner_prompt_template = ChatPromptTemplate.from_messages(\n",
|
||||
" [(\"system\", planner_prompt_tmpl_str), (\"user\", \"Question: {input}{context}\")]\n",
|
||||
" ).partial(\n",
|
||||
" tool_descriptions=tool_descriptions,\n",
|
||||
" examples=\"Here are some examples:\\n\\n\" + example_prompt\n",
|
||||
" if example_prompt\n",
|
||||
" else \"\",\n",
|
||||
" num_tools=len(tools),\n",
|
||||
" num_toolsp1=len(tools) + 1,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" return planner_prompt_template\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def create_planner(\n",
|
||||
" llm: BaseChatModel,\n",
|
||||
" example_prompt: str,\n",
|
||||
" example_prompt_replan: str,\n",
|
||||
" tools: Sequence[Union[BaseTool]],\n",
|
||||
" stop: Optional[list[str]] = None,\n",
|
||||
"):\n",
|
||||
" og_planner_prompt = _generate_planner_prompt(tools, example_prompt).partial(\n",
|
||||
" replan=\"\",\n",
|
||||
" context=\"\",\n",
|
||||
" )\n",
|
||||
" replanner_prompt = _generate_planner_prompt(tools, example_prompt).partial(\n",
|
||||
" replan=' - You are given \"Previous Plan\" which is the plan that the previous agent created along with the execution results '\n",
|
||||
" \"(given as Observation) of each plan and a general thought (given as Thought) about the executed results.\"\n",
|
||||
" 'You MUST use these information to create the next plan under \"Current Plan\".\\n'\n",
|
||||
" ' - When starting the Current Plan, you should start with \"Thought\" that outlines the strategy for the next plan.\\n'\n",
|
||||
" \" - In the Current Plan, you should NEVER repeat the actions that are already executed in the Previous Plan.\\n\"\n",
|
||||
" )\n",
|
||||
" bound_llm = llm.bind(stop=stop)\n",
|
||||
" return (\n",
|
||||
" RunnableBranch(\n",
|
||||
" ((lambda x: x.get(\"replan\")), replanner_prompt),\n",
|
||||
" og_planner_prompt,\n",
|
||||
" )\n",
|
||||
" | bound_llm\n",
|
||||
" | LLMCompilerPlanParser(tools=tools)\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7feb5c82-b1a9-40ae-863a-0362fe3ce5ea",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Example usage\n",
|
||||
"\n",
|
||||
"Here's an example usage of the planner module"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "3fe074ea-7314-47a7-9a9f-a8e6191ea1f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.tools import tool\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@tool\n",
|
||||
"def get_user_id(first_name: str, last_name: Optional[str] = None):\n",
|
||||
" \"\"\"Query the user IDs of everyone with the provided name.\"\"\"\n",
|
||||
" return 4\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@tool\n",
|
||||
"def get_scores(class_name: str, user_id: int):\n",
|
||||
" \"\"\"Query the class registry for grades of the provided user ID.\"\"\"\n",
|
||||
" return \"A+\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"examples = (\n",
|
||||
" \"Question: What's the user ID for Johnny Drop Tables?\\n\"\n",
|
||||
" '1. {\"get_user_id\": {\"first_name\": \"Johnny\", \"last_name\":\"Drop Tables\"}}\\n'\n",
|
||||
" f'2. {{\"join\": null}}{END_OF_PLAN}\\n'\n",
|
||||
" \"###\\n\"\n",
|
||||
" \"\\n\"\n",
|
||||
" \"Question: What was Eric Zhang's score in Calc?\\n\"\n",
|
||||
" '1. {\"get_user_id\": {\"first_name\": \"Eric\", \"last_name\":\"Zhang\"}}\\n'\n",
|
||||
" '2. {\"get_scores\": {\"class_name\": \"calc\", \"user_id\": \"$1\"}}\\n'\n",
|
||||
" f'3. {{\"join\": null}}{END_OF_PLAN}\\n'\n",
|
||||
" \"###\\n\"\n",
|
||||
" \"\\n\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"planner = create_planner(\n",
|
||||
" ChatOpenAI(model=\"gpt-3.5-turbo\"),\n",
|
||||
" example_prompt=examples,\n",
|
||||
" example_prompt_replan=\"\",\n",
|
||||
" tools=[get_user_id, get_scores],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "55fb0f99-4e59-4e5a-b687-a90bb4d06d39",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{1: {'tool': StructuredTool(name='get_user_id', description='get_user_id(first_name: str, last_name: Optional[str] = None) - Query the user IDs of everyone with the provided name.', args_schema=<class 'pydantic.main.get_user_idSchemaSchema'>, func=<function get_user_id at 0x1242af240>),\n",
|
||||
" 'args': {'first_name': 'Sam', 'last_name': 'Van Damm'},\n",
|
||||
" 'dependencies': []},\n",
|
||||
" 2: {'tool': StructuredTool(name='get_user_id', description='get_user_id(first_name: str, last_name: Optional[str] = None) - Query the user IDs of everyone with the provided name.', args_schema=<class 'pydantic.main.get_user_idSchemaSchema'>, func=<function get_user_id at 0x1242af240>),\n",
|
||||
" 'args': {'first_name': 'Will', 'last_name': 'Van Damm'},\n",
|
||||
" 'dependencies': []},\n",
|
||||
" 3: {'tool': StructuredTool(name='get_scores', description='get_scores(class_name: str, user_id: int) - Query the class registry for grades of the provided user ID.', args_schema=<class 'pydantic.main.get_scoresSchemaSchema'>, func=<function get_scores at 0x1242af2e0>),\n",
|
||||
" 'args': {'class_name': 'Calc BC', 'user_id': '$1'},\n",
|
||||
" 'dependencies': [1]},\n",
|
||||
" 4: {'tool': StructuredTool(name='get_scores', description='get_scores(class_name: str, user_id: int) - Query the class registry for grades of the provided user ID.', args_schema=<class 'pydantic.main.get_scoresSchemaSchema'>, func=<function get_scores at 0x1242af2e0>),\n",
|
||||
" 'args': {'class_name': 'Calc BC', 'user_id': '$2'},\n",
|
||||
" 'dependencies': [2]},\n",
|
||||
" 5: {'tool': 'join', 'args': None, 'dependencies': [1, 2, 3, 4]}}"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"tasks = planner.invoke(\n",
|
||||
" {\"input\": \"What are the Calc BC grades for Sam and Will Van Damm?\"}\n",
|
||||
")\n",
|
||||
"tasks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d0e795f-61ff-4553-9823-23e7624ca180",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Task Fetching Unit\n",
|
||||
"\n",
|
||||
"This component scheudles the tasks. In the paper, it's kept separate from the \"executor\", but here we execute the tasks within the same DAG.\n",
|
||||
"\n",
|
||||
"Basic idea is that, given a list of dicts of the form:\n",
|
||||
"\n",
|
||||
"```typescript\n",
|
||||
"{\n",
|
||||
" tool: BaseTool,\n",
|
||||
" dependencies: number[],\n",
|
||||
"}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"1. Create a topological sort of the tasks\n",
|
||||
"2. Execute them on the previous step's output, ensuring to perform variable substitution where appropriate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "c70a0e28-43db-4ea2-af48-8a2f310dce83",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"\n",
|
||||
"from langchain_core.agents import AgentFinish\n",
|
||||
"from langchain_core.runnables import (\n",
|
||||
" RunnableLambda,\n",
|
||||
" RunnableParallel,\n",
|
||||
" RunnablePassthrough,\n",
|
||||
")\n",
|
||||
"from langgraph.graph import END, Graph\n",
|
||||
"\n",
|
||||
"logging.basicConfig(level=logging.INFO)\n",
|
||||
"logger = logging.getLogger()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _sort_tasks(data):\n",
|
||||
" sorted_tasks = []\n",
|
||||
" while data:\n",
|
||||
" no_deps = {k: v for k, v in data.items() if not v[\"dependencies\"]}\n",
|
||||
" if not no_deps:\n",
|
||||
" raise ValueError(\"We seem to have run into a circular dependency.\")\n",
|
||||
"\n",
|
||||
" sorted_tasks.append(no_deps)\n",
|
||||
" data = {\n",
|
||||
" k: {\n",
|
||||
" **v,\n",
|
||||
" \"dependencies\": [d for d in v[\"dependencies\"] if d not in no_deps],\n",
|
||||
" }\n",
|
||||
" for k, v in data.items()\n",
|
||||
" if k not in no_deps\n",
|
||||
" }\n",
|
||||
" return sorted_tasks\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _resolve_arg(x: dict, arg):\n",
|
||||
" return x[f\"task_{arg[1:]}\"] if isinstance(arg, str) and arg.startswith(\"$\") else arg\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _execute_task(task, x, config):\n",
|
||||
" tool_to_use = task[\"tool\"]\n",
|
||||
" args = task[\"args\"]\n",
|
||||
" if isinstance(args, str):\n",
|
||||
" resolved_args = _resolve_arg(x, args)\n",
|
||||
" elif isinstance(args, dict):\n",
|
||||
" resolved_args = {key: _resolve_arg(x, val) for key, val in args.items()}\n",
|
||||
" else:\n",
|
||||
" logger.warning(f\"Unsupported arg type: {args}\")\n",
|
||||
" return tool_to_use.invoke(resolved_args, config)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def construct_dag(tasks):\n",
|
||||
" sorted_tasks = _sort_tasks(tasks)\n",
|
||||
" chain = None\n",
|
||||
" for idx, task_group in enumerate(sorted_tasks):\n",
|
||||
" if len(task_group) == 1 and next(iter(task_group.values()))[\"tool\"] == \"join\":\n",
|
||||
" # TODO: actually join the values\n",
|
||||
" step = lambda x: {\"join\": x}\n",
|
||||
" else:\n",
|
||||
" # Cascade all results forward\n",
|
||||
" constructor = (\n",
|
||||
" RunnableParallel if chain is None else RunnablePassthrough.assign\n",
|
||||
" )\n",
|
||||
" step = constructor(\n",
|
||||
" **{\n",
|
||||
" f\"task_{idx}\": RunnableLambda(\n",
|
||||
" lambda x, config: _execute_task(task, x, config)\n",
|
||||
" ).with_config(run_name=f\"task_{idx}\")\n",
|
||||
" for idx, task in task_group.items()\n",
|
||||
" }\n",
|
||||
" ).with_config(run_name=f\"TaskGroup{idx}\")\n",
|
||||
" if chain is None:\n",
|
||||
" chain = step\n",
|
||||
" else:\n",
|
||||
" chain |= step\n",
|
||||
"\n",
|
||||
" if chain is not None:\n",
|
||||
" return chain | RunnablePassthrough.assign(tasks=lambda _: tasks)\n",
|
||||
" return chain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "6fecaefc-d904-4409-af63-53c5b7a3785f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" +------------------------------+ \n",
|
||||
" | Parallel<task_1,task_2>Input | \n",
|
||||
" +------------------------------+ \n",
|
||||
" ***** ***** \n",
|
||||
" **** **** \n",
|
||||
" *** *** \n",
|
||||
" +---------------------------------------+ +---------------------------------------+ \n",
|
||||
" | Lambda(lambda x, config: _execute_... | | Lambda(lambda x, config: _execute_... | \n",
|
||||
" +---------------------------------------+ +---------------------------------------+ \n",
|
||||
" ***** ***** \n",
|
||||
" **** **** \n",
|
||||
" *** *** \n",
|
||||
" +-------------------------------+ \n",
|
||||
" | Parallel<task_1,task_2>Output | \n",
|
||||
" +-------------------------------+ \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" +------------------------------+ \n",
|
||||
" | Parallel<task_3,task_4>Input | \n",
|
||||
" ****+------------------------------+***** \n",
|
||||
" ******** * ********* \n",
|
||||
" ******** * ******** \n",
|
||||
" ***** * ***** \n",
|
||||
"+---------------------------------------+ +---------------------------------------+ +-------------+ \n",
|
||||
"| Lambda(lambda x, config: _execute_... | | Lambda(lambda x, config: _execute_... | ****| Passthrough | \n",
|
||||
"+---------------------------------------+* +---------------------------------------+ ******** +-------------+ \n",
|
||||
" ******** * ********* \n",
|
||||
" ******** * ******** \n",
|
||||
" ***** * ***** \n",
|
||||
" +-------------------------------+ \n",
|
||||
" | Parallel<task_3,task_4>Output | \n",
|
||||
" +-------------------------------+ \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" +-------------------------------+ \n",
|
||||
" | Lambda(lambda x: {'join': x}) | \n",
|
||||
" +-------------------------------+ \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" * \n",
|
||||
" +----------------------+ \n",
|
||||
" | Parallel<tasks>Input | \n",
|
||||
" +----------------------+ \n",
|
||||
" *** *** \n",
|
||||
" *** *** \n",
|
||||
" ** ** \n",
|
||||
" +-------------------------+ +-------------+ \n",
|
||||
" | Lambda(lambda _: tasks) | | Passthrough | \n",
|
||||
" +-------------------------+ +-------------+ \n",
|
||||
" *** *** \n",
|
||||
" *** *** \n",
|
||||
" ** ** \n",
|
||||
" +-----------------------+ \n",
|
||||
" | Parallel<tasks>Output | \n",
|
||||
" +-----------------------+ \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"graph = construct_dag(tasks)\n",
|
||||
"graph.get_graph().print_ascii()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9efa15ae-817a-48c6-86ed-16bc112fedc5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Example\n",
|
||||
"\n",
|
||||
"We still haven't introduced any cycles in our computation graph, so this is all easily expressed in LCEL."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "133d124a-0d41-4c6d-a86a-34fa4cb1430f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain = planner | construct_dag"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "55142257-2674-4a47-988e-0d2810917329",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "KeyError",
|
||||
"evalue": "\"Input to ChatPromptTemplate is missing variables {'input'}. Expected: ['input', 'scratchpad'] Received: ['join', 'tasks', 'scratchpad']\"",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[15], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m example_question \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDid Aliya get a better score than Roger in Geology?\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m----> 2\u001b[0m task_results \u001b[38;5;241m=\u001b[39m \u001b[43mchain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minput\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mexample_question\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m task_results[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mjoin\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:456\u001b[0m, in \u001b[0;36mPregel.invoke\u001b[0;34m(self, input, config, output, **kwargs)\u001b[0m\n\u001b[1;32m 447\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 448\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 449\u001b[0m \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 454\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]:\n\u001b[1;32m 455\u001b[0m latest: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 456\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 457\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 458\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 459\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 460\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 461\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 462\u001b[0m \u001b[43m \u001b[49m\u001b[43mlatest\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n\u001b[1;32m 463\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m latest\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:483\u001b[0m, in \u001b[0;36mPregel.transform\u001b[0;34m(self, input, config, output, **kwargs)\u001b[0m\n\u001b[1;32m 475\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtransform\u001b[39m(\n\u001b[1;32m 476\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 477\u001b[0m \u001b[38;5;28minput\u001b[39m: Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 481\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 482\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]]:\n\u001b[0;32m--> 483\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform_stream_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 485\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 486\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01myield\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:1226\u001b[0m, in \u001b[0;36mRunnable._transform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 1224\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1225\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[0;32m-> 1226\u001b[0m chunk: Output \u001b[38;5;241m=\u001b[39m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43miterator\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 1227\u001b[0m \u001b[38;5;28;01myield\u001b[39;00m chunk\n\u001b[1;32m 1228\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m final_output_supported:\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:301\u001b[0m, in \u001b[0;36mPregel._transform\u001b[0;34m(self, input, run_manager, config, output)\u001b[0m\n\u001b[1;32m 291\u001b[0m done, inflight \u001b[38;5;241m=\u001b[39m concurrent\u001b[38;5;241m.\u001b[39mfutures\u001b[38;5;241m.\u001b[39mwait(\n\u001b[1;32m 292\u001b[0m [\n\u001b[1;32m 293\u001b[0m executor\u001b[38;5;241m.\u001b[39msubmit(proc\u001b[38;5;241m.\u001b[39minvoke, \u001b[38;5;28minput\u001b[39m, config)\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 297\u001b[0m timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstep_timeout,\n\u001b[1;32m 298\u001b[0m )\n\u001b[1;32m 300\u001b[0m \u001b[38;5;66;03m# interrupt on failure or timeout\u001b[39;00m\n\u001b[0;32m--> 301\u001b[0m \u001b[43m_interrupt_or_proceed\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdone\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minflight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstep\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 303\u001b[0m \u001b[38;5;66;03m# apply writes to channels\u001b[39;00m\n\u001b[1;32m 304\u001b[0m _apply_writes(checkpoint, channels, pending_writes, config, step \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m1\u001b[39m)\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:548\u001b[0m, in \u001b[0;36m_interrupt_or_proceed\u001b[0;34m(done, inflight, step)\u001b[0m\n\u001b[1;32m 546\u001b[0m inflight\u001b[38;5;241m.\u001b[39mpop()\u001b[38;5;241m.\u001b[39mcancel()\n\u001b[1;32m 547\u001b[0m \u001b[38;5;66;03m# raise the exception\u001b[39;00m\n\u001b[0;32m--> 548\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exc\n\u001b[1;32m 549\u001b[0m \u001b[38;5;66;03m# TODO this is where retry of an entire step would happen\u001b[39;00m\n\u001b[1;32m 551\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inflight:\n\u001b[1;32m 552\u001b[0m \u001b[38;5;66;03m# if we got here means we timed out\u001b[39;00m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/thread.py:58\u001b[0m, in \u001b[0;36m_WorkItem.run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 58\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfuture\u001b[38;5;241m.\u001b[39mset_exception(exc)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:3596\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 3590\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 3591\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 3592\u001b[0m \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[1;32m 3593\u001b[0m config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 3594\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m 3595\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[0;32m-> 3596\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbound\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 3597\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3598\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3599\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3600\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:1774\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 1772\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1773\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 1774\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1775\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1776\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 1777\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1778\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1779\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1780\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1781\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 1782\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/prompts/base.py:93\u001b[0m, in \u001b[0;36mBasePromptTemplate.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Dict, config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 92\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m PromptValue:\n\u001b[0;32m---> 93\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 94\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_format_prompt_with_error_handling\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 95\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 96\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 97\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mprompt\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 98\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:975\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 971\u001b[0m context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[1;32m 972\u001b[0m context\u001b[38;5;241m.\u001b[39mrun(var_child_runnable_config\u001b[38;5;241m.\u001b[39mset, child_config)\n\u001b[1;32m 973\u001b[0m output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[1;32m 974\u001b[0m Output,\n\u001b[0;32m--> 975\u001b[0m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 976\u001b[0m \u001b[43m \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 977\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 978\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 979\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 980\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 981\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 982\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 983\u001b[0m )\n\u001b[1;32m 984\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 985\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/config.py:323\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 322\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/prompts/base.py:83\u001b[0m, in \u001b[0;36mBasePromptTemplate._format_prompt_with_error_handling\u001b[0;34m(self, inner_input)\u001b[0m\n\u001b[1;32m 81\u001b[0m missing \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minput_variables)\u001b[38;5;241m.\u001b[39mdifference(inner_input)\n\u001b[1;32m 82\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing:\n\u001b[0;32m---> 83\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\n\u001b[1;32m 84\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInput to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m is missing variables \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmissing\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 85\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m Expected: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minput_variables\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m Received: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(inner_input\u001b[38;5;241m.\u001b[39mkeys())\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 87\u001b[0m )\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mformat_prompt(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39minner_input)\n",
|
||||
"\u001b[0;31mKeyError\u001b[0m: \"Input to ChatPromptTemplate is missing variables {'input'}. Expected: ['input', 'scratchpad'] Received: ['join', 'tasks', 'scratchpad']\""
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"example_question = \"Did Aliya get a better score than Roger in Geology?\"\n",
|
||||
"task_results = chain.invoke({\"input\": example_question})\n",
|
||||
"task_results[\"join\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "563d5311-55f0-4ca1-afbd-01fd970cf3e3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Agent Logic\n",
|
||||
"\n",
|
||||
"So now we have the planning and initial execution done. We need a component to process these outputs and either:\n",
|
||||
"1. Respond with the correct answer.\n",
|
||||
"2. Loop with a new plan.\n",
|
||||
"\n",
|
||||
"The paper calls this the \"joiner\"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "2978991e-45a4-44e6-9deb-f941f44fe93a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_core.output_parsers import StrOutputParser\n",
|
||||
"from typing_extensions import TypedDict\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def format_task(task, idx):\n",
|
||||
" thought = \"\" # TODO: Pass through CoT\n",
|
||||
" tool = task[\"tool\"]\n",
|
||||
" tool_name = tool if isinstance(tool, str) else tool.name # Handle join()\n",
|
||||
" return f\"{thought}{idx}. {{{tool_name}: {task['args']}}}\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def format_tasks(executor_output: dict):\n",
|
||||
" tasks = executor_output[\"tasks\"]\n",
|
||||
" formatted_plan = \"\\n\".join(format_task(task, idx) for idx, task in tasks.items())\n",
|
||||
" observations = \"\\n\".join(f\"{k}: {v}\" for k, v in executor_output[\"join\"].items())\n",
|
||||
" return f\"Original Plan:\\n{formatted_plan}\\nExecuted plan results:\\n{observations}\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _parse_joiner_output(raw_answer: str) -> str:\n",
|
||||
" thought, answer, is_replan = \"\", \"\", False # default values\n",
|
||||
" raw_answers = raw_answer.split(\"\\n\")\n",
|
||||
" for ans in raw_answers:\n",
|
||||
" if ans.startswith(\"Action:\"):\n",
|
||||
" answer = ans[ans.find(\"(\") + 1 : ans.find(\")\")]\n",
|
||||
" is_replan = JOINER_REPLAN in ans\n",
|
||||
" elif ans.startswith(\"Thought:\"):\n",
|
||||
" thought = ans.split(\"Thought:\")[1].strip()\n",
|
||||
" if is_replan:\n",
|
||||
" return {\"thought\": thought, \"context\": answer}\n",
|
||||
" else:\n",
|
||||
" return {\"thought\": thought, \"answer\": answer}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "b2feea5a-e0e4-4cff-8cb5-fdbfec95ba57",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def create_joiner(prompt, llm):\n",
|
||||
" return (\n",
|
||||
" (lambda x: {**x[\"plan\"], \"input\": x[\"input\"]})\n",
|
||||
" | RunnablePassthrough.assign(scratchpad=format_tasks)\n",
|
||||
" | ChatPromptTemplate.from_messages([(\"system\", prompt), (\"user\", \"{input}\")])\n",
|
||||
" | llm\n",
|
||||
" | StrOutputParser()\n",
|
||||
" | _parse_joiner_output\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "942dab42-ad42-4ba2-90d5-49edbe4fae68",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"system_prompt = (\n",
|
||||
" \"Solve a question answering task with interleaving Observation, Thought, and Action steps. Here are some guidelines:\\n\"\n",
|
||||
" \" - In the Assistant Scratchpad, you will be given results of a plan you have executed to answer the user's question.\\n\"\n",
|
||||
" \" - Thought needs to reason about the question based on the Observations in 1-2 sentences.\\n\"\n",
|
||||
" \" - There are cases where the Observations are unclear or irrelevant (in the case the task execution was unsuccessful or subpar). Only heed the relevant ones\\n\"\n",
|
||||
" \" Respond in the following format:\\n\\n\"\n",
|
||||
" \"Thought: <reason about the task results and whether you have sufficient information to answer the question>\\n\"\n",
|
||||
" \"Action: <action to take>\\n\"\n",
|
||||
" \"Available actions:\\n\"\n",
|
||||
" f\" (1) {JOINER_FINISH}(the final answer to return to the user): returns the answer and finishes the task.\\n\"\n",
|
||||
" f\" (2) {JOINER_REPLAN}(the reasoning and information to provide to make a better next plan): instructs why we must replan\\n\\n\"\n",
|
||||
" \" Examples:\\n\"\n",
|
||||
" \"Question: How many users are currently using the new product?\\n\"\n",
|
||||
" \"...task returns the number 32,000\\n\"\n",
|
||||
" \"Thought: I find no issue with the original plan, and the results satisfy everything in the user question.\\n\"\n",
|
||||
" f\"Action: {JOINER_FINISH}(32,000 users currently use the new product)\\n###\\n\"\n",
|
||||
" \"Question: Are the gophers beating the rabbits??\\n\"\n",
|
||||
" \"...task returns the a score of 7 for rabbits but no other value...\\n\"\n",
|
||||
" \"Thought: I need the gophers' score to make a final decision.\\n\"\n",
|
||||
" f\"Action: {JOINER_REPLAN}(The rabbits have a score of 7, but I need the gophers' score.)\"\n",
|
||||
" \"Assistant Scratchpad:\\n{scratchpad}\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "a07d0804-2ce5-4462-98eb-4473f36ef704",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'thought': 'Based on the executed plan, both Aliya and Roger received an A+ score in Geology. Therefore, Aliya did not get a better score than Roger in Geology.',\n",
|
||||
" 'answer': 'No, Aliya did not get a better score than Roger in Geology. They both received an A+.'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"joiner = create_joiner(system_prompt, ChatOpenAI(model=\"gpt-3.5-turbo\"))\n",
|
||||
"joiner.invoke({\"plan\": task_results, \"input\": example_question})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b099e5ee-2c23-47d9-9387-0f64e02627d3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Construct Agent\n",
|
||||
"\n",
|
||||
"Now we have all the required pieces!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "768b5f11-e3d2-47be-8143-a7dcd8765243",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph.graph import END, Graph\n",
|
||||
"\n",
|
||||
"workflow = Graph()\n",
|
||||
"\n",
|
||||
"# 1. Define vertices\n",
|
||||
"\n",
|
||||
"planner = create_planner(\n",
|
||||
" llm=ChatOpenAI(model=\"gpt-3.5-turbo\"),\n",
|
||||
" example_prompt=examples,\n",
|
||||
" # TODO: You can update and optimize the replanner prompt to\n",
|
||||
" # better critique the original plan\n",
|
||||
" example_prompt_replan=examples,\n",
|
||||
" tools=[get_user_id, get_scores],\n",
|
||||
")\n",
|
||||
"plan_and_execute = RunnablePassthrough.assign(plan=planner | construct_dag)\n",
|
||||
"joiner = create_joiner(system_prompt, ChatOpenAI(model=\"gpt-3.5-turbo\"))\n",
|
||||
"joiner_node = RunnablePassthrough.assign(joined_output=joiner)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"workflow.add_node(\"plan_and_execute\", plan_and_execute)\n",
|
||||
"workflow.add_node(\"join\", joiner_node)\n",
|
||||
"workflow.add_node(\"end\", lambda x: x[\"joined_output\"].get(\"answer\", x))\n",
|
||||
"\n",
|
||||
"## Define edges\n",
|
||||
"\n",
|
||||
"workflow.add_edge(\"plan_and_execute\", \"join\")\n",
|
||||
"\n",
|
||||
"### This condition determines looping logic\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def should_continue(joiner_output):\n",
|
||||
" if joiner_output[\"joined_output\"].get(\"context\"):\n",
|
||||
" return \"continue\"\n",
|
||||
" return \"end\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"workflow.add_conditional_edges(\n",
|
||||
" start_key=\"join\",\n",
|
||||
" # Next, we pass in the function that will determine which node is called next.\n",
|
||||
" condition=should_continue,\n",
|
||||
" conditional_edge_mapping={\n",
|
||||
" # If it generates context, we must replan\n",
|
||||
" \"continue\": \"plan_and_execute\",\n",
|
||||
" # Otherwise we finish.\n",
|
||||
" \"end\": \"end\",\n",
|
||||
" },\n",
|
||||
")\n",
|
||||
"workflow.set_entry_point(\"plan_and_execute\")\n",
|
||||
"workflow.set_finish_point(\"end\")\n",
|
||||
"chain = workflow.compile()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"id": "0b3a0916-d8ca-4092-b91c-d9e2b05259d8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# chain.invoke({\"input\": \"Did Aliya get a better score than Roger in Geology?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"id": "e3f3e409-11e7-4171-b2bc-7b0e82dfd10d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
|
||||
"INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "KeyError",
|
||||
"evalue": "\"Input to ChatPromptTemplate is missing variables {'input'}. Expected: ['input'] Received: ['thought', 'context']\"",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[29], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Try something to trigger replanning\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mchain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 3\u001b[0m \u001b[43m \u001b[49m\u001b[43m{\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minput\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDid the sum of Aliya and Roger\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ms grades in Calc map out to less than\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 5\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m the total grade for the class?\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 6\u001b[0m \u001b[43m \u001b[49m\u001b[43m}\u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:456\u001b[0m, in \u001b[0;36mPregel.invoke\u001b[0;34m(self, input, config, output, **kwargs)\u001b[0m\n\u001b[1;32m 447\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 448\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 449\u001b[0m \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 453\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 454\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]:\n\u001b[1;32m 455\u001b[0m latest: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 456\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 457\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 458\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 459\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 460\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 461\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 462\u001b[0m \u001b[43m \u001b[49m\u001b[43mlatest\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n\u001b[1;32m 463\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m latest\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:483\u001b[0m, in \u001b[0;36mPregel.transform\u001b[0;34m(self, input, config, output, **kwargs)\u001b[0m\n\u001b[1;32m 475\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtransform\u001b[39m(\n\u001b[1;32m 476\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 477\u001b[0m \u001b[38;5;28minput\u001b[39m: Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 481\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 482\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]]:\n\u001b[0;32m--> 483\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform_stream_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moutput\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 485\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 486\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01myield\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:1226\u001b[0m, in \u001b[0;36mRunnable._transform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 1224\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1225\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[0;32m-> 1226\u001b[0m chunk: Output \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(\u001b[38;5;28mnext\u001b[39m, iterator) \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 1227\u001b[0m \u001b[38;5;28;01myield\u001b[39;00m chunk\n\u001b[1;32m 1228\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m final_output_supported:\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:301\u001b[0m, in \u001b[0;36mPregel._transform\u001b[0;34m(self, input, run_manager, config, output)\u001b[0m\n\u001b[1;32m 291\u001b[0m done, inflight \u001b[38;5;241m=\u001b[39m concurrent\u001b[38;5;241m.\u001b[39mfutures\u001b[38;5;241m.\u001b[39mwait(\n\u001b[1;32m 292\u001b[0m [\n\u001b[1;32m 293\u001b[0m executor\u001b[38;5;241m.\u001b[39msubmit(proc\u001b[38;5;241m.\u001b[39minvoke, \u001b[38;5;28minput\u001b[39m, config)\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 297\u001b[0m timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstep_timeout,\n\u001b[1;32m 298\u001b[0m )\n\u001b[1;32m 300\u001b[0m \u001b[38;5;66;03m# interrupt on failure or timeout\u001b[39;00m\n\u001b[0;32m--> 301\u001b[0m \u001b[43m_interrupt_or_proceed\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdone\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minflight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstep\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 303\u001b[0m \u001b[38;5;66;03m# apply writes to channels\u001b[39;00m\n\u001b[1;32m 304\u001b[0m _apply_writes(checkpoint, channels, pending_writes, config, step \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m1\u001b[39m)\n",
|
||||
"File \u001b[0;32m~/code/lc/langgraph/langgraph/pregel/__init__.py:548\u001b[0m, in \u001b[0;36m_interrupt_or_proceed\u001b[0;34m(done, inflight, step)\u001b[0m\n\u001b[1;32m 546\u001b[0m inflight\u001b[38;5;241m.\u001b[39mpop()\u001b[38;5;241m.\u001b[39mcancel()\n\u001b[1;32m 547\u001b[0m \u001b[38;5;66;03m# raise the exception\u001b[39;00m\n\u001b[0;32m--> 548\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exc\n\u001b[1;32m 549\u001b[0m \u001b[38;5;66;03m# TODO this is where retry of an entire step would happen\u001b[39;00m\n\u001b[1;32m 551\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inflight:\n\u001b[1;32m 552\u001b[0m \u001b[38;5;66;03m# if we got here means we timed out\u001b[39;00m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/thread.py:58\u001b[0m, in \u001b[0;36m_WorkItem.run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 58\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfuture\u001b[38;5;241m.\u001b[39mset_exception(exc)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:3596\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 3590\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 3591\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 3592\u001b[0m \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[1;32m 3593\u001b[0m config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 3594\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m 3595\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[0;32m-> 3596\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbound\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 3597\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3598\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3599\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3600\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:1774\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 1772\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1773\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 1774\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1775\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1776\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 1777\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1778\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1779\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1780\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1781\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 1782\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/passthrough.py:415\u001b[0m, in \u001b[0;36mRunnableAssign.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 409\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 410\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 411\u001b[0m \u001b[38;5;28minput\u001b[39m: Dict[\u001b[38;5;28mstr\u001b[39m, Any],\n\u001b[1;32m 412\u001b[0m config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 413\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 414\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Dict[\u001b[38;5;28mstr\u001b[39m, Any]:\n\u001b[0;32m--> 415\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_invoke\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:975\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 971\u001b[0m context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[1;32m 972\u001b[0m context\u001b[38;5;241m.\u001b[39mrun(var_child_runnable_config\u001b[38;5;241m.\u001b[39mset, child_config)\n\u001b[1;32m 973\u001b[0m output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[1;32m 974\u001b[0m Output,\n\u001b[0;32m--> 975\u001b[0m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 976\u001b[0m \u001b[43m \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 977\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 978\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 979\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 980\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 981\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 982\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 983\u001b[0m )\n\u001b[1;32m 984\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 985\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/config.py:323\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 322\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/passthrough.py:402\u001b[0m, in \u001b[0;36mRunnableAssign._invoke\u001b[0;34m(self, input, run_manager, config, **kwargs)\u001b[0m\n\u001b[1;32m 389\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_invoke\u001b[39m(\n\u001b[1;32m 390\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 391\u001b[0m \u001b[38;5;28minput\u001b[39m: Dict[\u001b[38;5;28mstr\u001b[39m, Any],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 394\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 395\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Dict[\u001b[38;5;28mstr\u001b[39m, Any]:\n\u001b[1;32m 396\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\n\u001b[1;32m 397\u001b[0m \u001b[38;5;28minput\u001b[39m, \u001b[38;5;28mdict\u001b[39m\n\u001b[1;32m 398\u001b[0m ), \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe input to RunnablePassthrough.assign() must be a dict.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 400\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m {\n\u001b[1;32m 401\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28minput\u001b[39m,\n\u001b[0;32m--> 402\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmapper\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 403\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 404\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 405\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 406\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 407\u001b[0m }\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:2339\u001b[0m, in \u001b[0;36mRunnableParallel.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 2326\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m get_executor_for_config(config) \u001b[38;5;28;01mas\u001b[39;00m executor:\n\u001b[1;32m 2327\u001b[0m futures \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 2328\u001b[0m executor\u001b[38;5;241m.\u001b[39msubmit(\n\u001b[1;32m 2329\u001b[0m step\u001b[38;5;241m.\u001b[39minvoke,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2337\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key, step \u001b[38;5;129;01min\u001b[39;00m steps\u001b[38;5;241m.\u001b[39mitems()\n\u001b[1;32m 2338\u001b[0m ]\n\u001b[0;32m-> 2339\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[43m{\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mfuture\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mkey\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfuture\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mzip\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43msteps\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfutures\u001b[49m\u001b[43m)\u001b[49m\u001b[43m}\u001b[49m\n\u001b[1;32m 2340\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 2341\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:2339\u001b[0m, in \u001b[0;36m<dictcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2326\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m get_executor_for_config(config) \u001b[38;5;28;01mas\u001b[39;00m executor:\n\u001b[1;32m 2327\u001b[0m futures \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 2328\u001b[0m executor\u001b[38;5;241m.\u001b[39msubmit(\n\u001b[1;32m 2329\u001b[0m step\u001b[38;5;241m.\u001b[39minvoke,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 2337\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key, step \u001b[38;5;129;01min\u001b[39;00m steps\u001b[38;5;241m.\u001b[39mitems()\n\u001b[1;32m 2338\u001b[0m ]\n\u001b[0;32m-> 2339\u001b[0m output \u001b[38;5;241m=\u001b[39m {key: \u001b[43mfuture\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m key, future \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mzip\u001b[39m(steps, futures)}\n\u001b[1;32m 2340\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 2341\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/_base.py:456\u001b[0m, in \u001b[0;36mFuture.result\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 454\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CancelledError()\n\u001b[1;32m 455\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;241m==\u001b[39m FINISHED:\n\u001b[0;32m--> 456\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__get_result\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 457\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 458\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTimeoutError\u001b[39;00m()\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/_base.py:401\u001b[0m, in \u001b[0;36mFuture.__get_result\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception:\n\u001b[1;32m 400\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 401\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception\n\u001b[1;32m 402\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m 403\u001b[0m \u001b[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001b[39;00m\n\u001b[1;32m 404\u001b[0m \u001b[38;5;28mself\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/thread.py:58\u001b[0m, in \u001b[0;36m_WorkItem.run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 58\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfuture\u001b[38;5;241m.\u001b[39mset_exception(exc)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:1774\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 1772\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1773\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 1774\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1775\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1776\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 1777\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1778\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1779\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1780\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1781\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 1782\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/branch.py:211\u001b[0m, in \u001b[0;36mRunnableBranch.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 209\u001b[0m \u001b[38;5;28;01mbreak\u001b[39;00m\n\u001b[1;32m 210\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 211\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdefault\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 212\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 213\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 214\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtag\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mbranch:default\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 215\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 216\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 217\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 218\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 219\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/prompts/base.py:93\u001b[0m, in \u001b[0;36mBasePromptTemplate.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 90\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Dict, config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 92\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m PromptValue:\n\u001b[0;32m---> 93\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 94\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_format_prompt_with_error_handling\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 95\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 96\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 97\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mprompt\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 98\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/base.py:975\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 971\u001b[0m context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[1;32m 972\u001b[0m context\u001b[38;5;241m.\u001b[39mrun(var_child_runnable_config\u001b[38;5;241m.\u001b[39mset, child_config)\n\u001b[1;32m 973\u001b[0m output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[1;32m 974\u001b[0m Output,\n\u001b[0;32m--> 975\u001b[0m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 976\u001b[0m \u001b[43m \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 977\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 978\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 979\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 980\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 981\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 982\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 983\u001b[0m )\n\u001b[1;32m 984\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 985\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/runnables/config.py:323\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 322\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 323\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langchain_core/prompts/base.py:83\u001b[0m, in \u001b[0;36mBasePromptTemplate._format_prompt_with_error_handling\u001b[0;34m(self, inner_input)\u001b[0m\n\u001b[1;32m 81\u001b[0m missing \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minput_variables)\u001b[38;5;241m.\u001b[39mdifference(inner_input)\n\u001b[1;32m 82\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing:\n\u001b[0;32m---> 83\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\n\u001b[1;32m 84\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInput to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m is missing variables \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmissing\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 85\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m Expected: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minput_variables\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m Received: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(inner_input\u001b[38;5;241m.\u001b[39mkeys())\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 87\u001b[0m )\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mformat_prompt(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39minner_input)\n",
|
||||
"\u001b[0;31mKeyError\u001b[0m: \"Input to ChatPromptTemplate is missing variables {'input'}. Expected: ['input'] Received: ['thought', 'context']\""
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Try something to trigger replanning\n",
|
||||
"chain.invoke(\n",
|
||||
" {\n",
|
||||
" \"input\": \"Did the sum of Aliya and Roger's grades in Calc map out to less than\"\n",
|
||||
" \" the total grade for the class?\"\n",
|
||||
" }\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "201f3dc0-74ee-4ef0-908d-b71d0e11b080",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user