mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-25 00:52:25 +02:00
Create notebooks for creating cron jobs and stateless runs. (#797)
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Cron Jobs\n",
|
||||
"\n",
|
||||
"Sometimes you don't want to run your graph based on user interaction, but rather you would like to schedule your graph to run on a schedule - for example if you wish for your graph to compose and send out a weekly email of to-dos for your team. LangGraph Cloud allows you to do this without having to write your own script by using the `Crons` client. To schedule a graph job, you need to pass a [cron expression](https://crontab.cronhub.io/) to inform the client when you want to run the graph. `Cron` jobs are run in the background and do not interfere with normal invocations of the graph.\n",
|
||||
"\n",
|
||||
"## Setup\n",
|
||||
"\n",
|
||||
"First, let's setup our SDK client, assistant, and thread:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 110,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph_sdk import get_client\n",
|
||||
"client = get_client()\n",
|
||||
"assistants = await client.assistants.search()\n",
|
||||
"assistants = [a for a in assistants if not a['config']]\n",
|
||||
"assistant = assistants[0]\n",
|
||||
"thread = await client.threads.create()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cron job on a thread \n",
|
||||
"\n",
|
||||
"To create a cron job associated with a specific thread, you can write:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# This schedules a job to run at 15:27 (3:27PM) every day\n",
|
||||
"cron_1 = await client.crons.create_for_thread(thread['thread_id'],assistant['assistant_id'],schedule=\"27 15 * * *\",input={'messages':[{\"role\":\"user\",\"content\":\"What time is it?\"}]})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that it is **very** important to delete `Cron` jobs that are no longer useful. Otherwise you could rack up unwanted API charges to the LLM! You can delete a `Cron` job using the following code:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"await client.crons.delete(cron_1['cron_id'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cron job threadless\n",
|
||||
"\n",
|
||||
"You can also create threadless cron jobs by using the following code:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# This schedules a job to run at 15:27 (3:27PM) every day\n",
|
||||
"cron_2 = await client.crons.create(assistant['assistant_id'],schedule=\"27 15 * * *\",input={'messages':[{\"role\":\"user\",\"content\":\"What time is it?\"}]})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Again, remember to delete your job once you are done with it!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"await client.crons.delete(cron_2['cron_id'])"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Stateless Runs\n",
|
||||
"\n",
|
||||
"Most of the time, you provide a `thread_id` to your client when you run your graph in order to keep track of prior runs through the persistent state implemented in LangGraph Cloud. However, if you have your own database to save runs and don't need to use the built in persistent state, you can create stateless runs.\n",
|
||||
"\n",
|
||||
"## Setup\n",
|
||||
"\n",
|
||||
"First, let's setup our client"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 106,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langgraph_sdk import get_client\n",
|
||||
"client = get_client()\n",
|
||||
"assistants = await client.assistants.search()\n",
|
||||
"assistants = [a for a in assistants if not a['config']]\n",
|
||||
"assistant = assistants[0]\n",
|
||||
"thread = await client.threads.create()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Stateless streaming\n",
|
||||
"\n",
|
||||
"We can stream the results of a stateless run in an almost identical fashion to how we stream from a run with the state attribute, but instead of passing a value to the `thread_id` parameter, we pass `None`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 107,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'agent': {'messages': [{'content': \"Hello Bagatur! It's nice to meet you. Thank you for introducing yourself and sharing your age. Is there anything specific you'd like to know or discuss? I'm here to help with any questions or topics you're interested in.\", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-489ec573-1645-4ce2-a3b8-91b391d50a71', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"input = {\"messages\":[{\"role\": \"user\", \"content\": \"Hello! My name is Bagatur and I am 26 years old.\"}]}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async for chunk in client.runs.stream(\n",
|
||||
" # Don't pass in a thread_id and the stream will be stateless\n",
|
||||
" None,\n",
|
||||
" assistant[\"assistant_id\"], # graph_id\n",
|
||||
" input=input,\n",
|
||||
" stream_mode=\"updates\",\n",
|
||||
"):\n",
|
||||
" if chunk.data and \"run_id\" not in chunk.data:\n",
|
||||
" print(chunk.data)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Waiting for stateless results\n",
|
||||
"\n",
|
||||
"In addition to streaming, you can also wait for a stateless result by using the `.wait` function like follows:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 108,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"stateless_run_result = await client.runs.wait(\n",
|
||||
" None,\n",
|
||||
" assistant[\"assistant_id\"], # graph_id\n",
|
||||
" input=input,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 109,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'messages': [{'content': 'Hello! My name is Bagatur and I am 26 years old.',\n",
|
||||
" 'additional_kwargs': {},\n",
|
||||
" 'response_metadata': {},\n",
|
||||
" 'type': 'human',\n",
|
||||
" 'name': None,\n",
|
||||
" 'id': '5e088543-62c2-43de-9d95-6086ad7f8b48',\n",
|
||||
" 'example': False},\n",
|
||||
" {'content': \"Hello Bagatur! It's nice to meet you. Thank you for introducing yourself and sharing your age. Is there anything specific you'd like to know or discuss? I'm here to help with any questions or topics you'd like to explore.\",\n",
|
||||
" 'additional_kwargs': {},\n",
|
||||
" 'response_metadata': {},\n",
|
||||
" 'type': 'ai',\n",
|
||||
" 'name': None,\n",
|
||||
" 'id': 'run-d6361e8d-4d4c-45bd-ba47-39520257f773',\n",
|
||||
" 'example': False,\n",
|
||||
" 'tool_calls': [],\n",
|
||||
" 'invalid_tool_calls': [],\n",
|
||||
" 'usage_metadata': None}]}"
|
||||
]
|
||||
},
|
||||
"execution_count": 109,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"stateless_run_result"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
Reference in New Issue
Block a user