Skip to content

Commit

Permalink
x
Browse files Browse the repository at this point in the history
  • Loading branch information
eyurtsev authored and nfcampos committed Oct 5, 2023
1 parent 08c3dd9 commit 8380c05
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 13 deletions.
156 changes: 152 additions & 4 deletions examples/chain/client.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"sys.path.insert(0, '/home/eugene/src/langchain/libs/langchain/')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"tags": []
},
Expand All @@ -20,12 +38,13 @@
"from langchain.prompts.chat import (\n",
" HumanMessagePromptTemplate,\n",
" SystemMessagePromptTemplate,\n",
"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 4,
"metadata": {
"tags": []
},
Expand All @@ -36,6 +55,23 @@
"remote_runnable = RemoteRunnable(\"http://localhost:8000/\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"title\":\"RunnableSequenceConfig\",\"type\":\"object\",\"properties\":{\"configurable\":{\"$ref\":\"#/definitions/Configurable\"}},\"definitions\":{\"Configurable\":{\"title\":\"Configurable\",\"type\":\"object\",\"properties\":{\"llm\":{\"title\":\"LLM\",\"default\":\"default\",\"anyOf\":[{\"enum\":[\"high_temp\"],\"type\":\"string\"},{\"enum\":[\"low_temp\"],\"type\":\"string\"},{\"enum\":[\"mid_temp\"],\"type\":\"string\"},{\"enum\":[\"default\"],\"type\":\"string\"}]},\"topic\":{\"title\":\"Topic\",\"description\":\"The topic of the joke\",\"default\":\"tell me a joke about {topic}\",\"type\":\"string\"}}}}}"
]
}
],
"source": [
"!curl localhost:8000/config_schema"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -45,13 +81,125 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'content': \"Why don't dogs make good dancers? \\n\\nBecause they have two left feet-paws!\",\n",
" 'additional_kwargs': {},\n",
" 'type': 'ai',\n",
" 'example': False,\n",
" 'is_chunk': False}"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# r = remote_runnable.with_config( {\"configurable\": {\"llm\": \"low_temp\"}})\n",
"remote_runnable.invoke({'topic': 'dog'}, config={\"configurable\": {\"llm\": \"low_temp\", \"template\": \"how to say {topic} in french\"}})"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'content': \"Why don't scientists trust atoms?\\n\\nBecause they make up everything!\",\n",
" 'additional_kwargs': {},\n",
" 'type': 'ai',\n",
" 'example': False,\n",
" 'is_chunk': False}"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r = remote_runnable.with_config( {\"configurable\": {\"template\": \"reverse the word {topic}\"}})\n",
"r.invoke({'topic': 'poof'})"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "unterminated string literal (detected at line 1) (522816454.py, line 1)",
"output_type": "error",
"traceback": [
"\u001b[0;36m Cell \u001b[0;32mIn[30], line 1\u001b[0;36m\u001b[0m\n\u001b[0;31m r.invoke({\"topic\": \"cats'})\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m unterminated string literal (detected at line 1)\n"
]
}
],
"source": [
"r.invoke({\"topic"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'content': \"Why don't cats play poker in the wild?\\n\\nToo many cheetahs!\",\n",
" 'additional_kwargs': {},\n",
" 'type': 'ai',\n",
" 'example': False,\n",
" 'is_chunk': False}"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {
"tags": []
},
"outputs": [],
"outputs": [
{
"ename": "HTTPStatusError",
"evalue": "Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 for Internal Server Error",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mHTTPStatusError\u001b[0m Traceback (most recent call last)",
"File \u001b[0;32m~/.pyenv/versions/3.11.4/envs/langchain_3_11_4/lib/python3.11/site-packages/langserve/client.py:40\u001b[0m, in \u001b[0;36m_raise_for_status\u001b[0;34m(response)\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 40\u001b[0m \u001b[43mresponse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mHTTPStatusError \u001b[38;5;28;01mas\u001b[39;00m e:\n",
"File \u001b[0;32m~/.pyenv/versions/3.11.4/envs/langchain_3_11_4/lib/python3.11/site-packages/httpx/_models.py:749\u001b[0m, in \u001b[0;36mResponse.raise_for_status\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 748\u001b[0m message \u001b[38;5;241m=\u001b[39m message\u001b[38;5;241m.\u001b[39mformat(\u001b[38;5;28mself\u001b[39m, error_type\u001b[38;5;241m=\u001b[39merror_type)\n\u001b[0;32m--> 749\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m HTTPStatusError(message, request\u001b[38;5;241m=\u001b[39mrequest, response\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n",
"\u001b[0;31mHTTPStatusError\u001b[0m: Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500",
"\nDuring handling of the above exception, another exception occurred:\n",
"\u001b[0;31mHTTPStatusError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[68], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m remote_runnable\u001b[38;5;241m.\u001b[39mainvoke({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtopic\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msports\u001b[39m\u001b[38;5;124m\"\u001b[39m}, {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconfigurable\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mprompt_template\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{topic}\u001b[39;00m\u001b[38;5;124m meow \u001b[39m\u001b[38;5;132;01m{topic}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m}})\n",
"File \u001b[0;32m~/.pyenv/versions/3.11.4/envs/langchain_3_11_4/lib/python3.11/site-packages/langserve/client.py:158\u001b[0m, in \u001b[0;36mRemoteRunnable.ainvoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs:\n\u001b[1;32m 157\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mNotImplementedError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mkwargs not implemented yet.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 158\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_acall_with_config(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ainvoke, \u001b[38;5;28minput\u001b[39m, config)\n",
"File \u001b[0;32m~/src/langchain/libs/langchain/langchain/schema/runnable/base.py:556\u001b[0m, in \u001b[0;36mRunnable._acall_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 549\u001b[0m run_manager \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m callback_manager\u001b[38;5;241m.\u001b[39mon_chain_start(\n\u001b[1;32m 550\u001b[0m dumpd(\u001b[38;5;28mself\u001b[39m),\n\u001b[1;32m 551\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m 552\u001b[0m run_type\u001b[38;5;241m=\u001b[39mrun_type,\n\u001b[1;32m 553\u001b[0m name\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_name\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 554\u001b[0m )\n\u001b[1;32m 555\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 556\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m acall_func_with_variable_args(\n\u001b[1;32m 557\u001b[0m func, \u001b[38;5;28minput\u001b[39m, run_manager, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[1;32m 558\u001b[0m )\n\u001b[1;32m 559\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 560\u001b[0m \u001b[38;5;28;01mawait\u001b[39;00m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
"File \u001b[0;32m~/src/langchain/libs/langchain/langchain/schema/runnable/config.py:195\u001b[0m, in \u001b[0;36macall_func_with_variable_args\u001b[0;34m(func, input, run_manager, config, **kwargs)\u001b[0m\n\u001b[1;32m 193\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 194\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--> 195\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m func(\u001b[38;5;28minput\u001b[39m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
"File \u001b[0;32m~/.pyenv/versions/3.11.4/envs/langchain_3_11_4/lib/python3.11/site-packages/langserve/client.py:150\u001b[0m, in \u001b[0;36mRemoteRunnable._ainvoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 139\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_ainvoke\u001b[39m(\n\u001b[1;32m 140\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Input, config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any\n\u001b[1;32m 141\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[1;32m 142\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masync_client\u001b[38;5;241m.\u001b[39mpost(\n\u001b[1;32m 143\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/invoke\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 144\u001b[0m json\u001b[38;5;241m=\u001b[39m{\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 148\u001b[0m },\n\u001b[1;32m 149\u001b[0m )\n\u001b[0;32m--> 150\u001b[0m \u001b[43m_raise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 151\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m load(response\u001b[38;5;241m.\u001b[39mjson())[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moutput\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n",
"File \u001b[0;32m~/.pyenv/versions/3.11.4/envs/langchain_3_11_4/lib/python3.11/site-packages/langserve/client.py:48\u001b[0m, in \u001b[0;36m_raise_for_status\u001b[0;34m(response)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext:\n\u001b[1;32m 46\u001b[0m message \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m for \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 48\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mHTTPStatusError(\n\u001b[1;32m 49\u001b[0m message\u001b[38;5;241m=\u001b[39mmessage,\n\u001b[1;32m 50\u001b[0m request\u001b[38;5;241m=\u001b[39me\u001b[38;5;241m.\u001b[39mrequest,\n\u001b[1;32m 51\u001b[0m response\u001b[38;5;241m=\u001b[39me\u001b[38;5;241m.\u001b[39mresponse,\n\u001b[1;32m 52\u001b[0m )\n",
"\u001b[0;31mHTTPStatusError\u001b[0m: Server error '500 Internal Server Error' for url 'http://localhost:8000/invoke'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 for Internal Server Error"
]
}
],
"source": [
"response = await remote_runnable.ainvoke({\"topic\": \"sports\"})"
"response = await remote_runnable.ainvoke({\"topic\": \"sports\"}, {\"configurable\": {\"prompt_template\": \"{topic} meow {topic}\"}})"
]
},
{
Expand Down
29 changes: 24 additions & 5 deletions examples/chain/server.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
#!/usr/bin/env python
"""Example LangChain server exposes a chain composed of a prompt and an LLM."""
from fastapi import FastAPI
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from typing_extensions import TypedDict

from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate, ChatPromptTemplate
from langchain.schema.runnable.utils import ConfigurableField
from langserve import add_routes

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
model = ChatOpenAI().configurable_alternatives(
ConfigurableField(id="llm", name="LLM"),
high_temp=ChatOpenAI(temperature=0.9),
low_temp=ChatOpenAI(temperature=0.1, max_tokens=1),
mid_temp=ChatOpenAI(temperature=0.5),
)

# prompt = ChatPromptTemplate.from_messages(
# [("system", "tell the user a joke about {topic}")]
# )
#

prompt = PromptTemplate.from_template(
"tell me a joke about {topic}"
).configurable_fields(
template=ConfigurableField(
id="topic", name="Topic", description="The topic of the joke"
)
)

chain = prompt | model

app = FastAPI(
Expand All @@ -28,7 +47,7 @@ class ChainInput(TypedDict):
"""The topic of the joke."""


add_routes(app, chain, input_type=ChainInput)
add_routes(app, chain, input_type=ChainInput, config_keys=["configurable"])

# Alternatively, you can rely on langchain's type inference
# to infer the input type from the runnable interface.
Expand Down
2 changes: 1 addition & 1 deletion langserve/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def create_invoke_request_model(
invoke_request_type = create_model(
f"{namespace}InvokeRequest",
input=(input_type, ...),
config=(config, Field(default_factory=dict)),
config=(dict, Field(default_factory=dict)),
kwargs=(dict, Field(default_factory=dict)),
)
invoke_request_type.update_forward_refs()
Expand Down
13 changes: 10 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8380c05

Please sign in to comment.