From 8b2a82b5ce1ac51bf358a090ae9f942dd8a8bcf1 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:22:49 -0800 Subject: [PATCH] Bagatur/docs smith context (#13139) --- cookbook/Multi_modal_RAG.ipynb | 83 ++++++----- cookbook/extraction_openai_tools.ipynb | 2 + cookbook/multi_modal_QA.ipynb | 26 ++-- cookbook/openai_v1_cookbook.ipynb | 45 ++++-- docs/docs/get_started/installation.mdx | 34 +++++ docs/docs/get_started/introduction.mdx | 27 ++-- docs/docs/get_started/quickstart.mdx | 138 +++++++++--------- .../retrievers/fleet_context.ipynb | 68 +++++---- .../text_embedding/azureopenai.ipynb | 4 +- docs/docs/integrations/tools/memorize.ipynb | 12 +- .../integrations/vectorstores/astradb.ipynb | 12 +- .../agents/agent_types/openai_tools.ipynb | 12 +- .../modules/model_io/models/chat/index.ipynb | 30 +++- .../model_io/models/chat/llm_chain.mdx | 20 --- .../model_io/models/chat/streaming.ipynb | 88 +++++++++++ .../model_io/models/chat/streaming.mdx | 63 -------- docs/vercel.json | 4 + .../openai_assistant/base.py | 1 - 18 files changed, 386 insertions(+), 283 deletions(-) delete mode 100644 docs/docs/modules/model_io/models/chat/llm_chain.mdx create mode 100644 docs/docs/modules/model_io/models/chat/streaming.ipynb delete mode 100644 docs/docs/modules/model_io/models/chat/streaming.mdx diff --git a/cookbook/Multi_modal_RAG.ipynb b/cookbook/Multi_modal_RAG.ipynb index 3a2bb1206c6..60e2c4d1f66 100644 --- a/cookbook/Multi_modal_RAG.ipynb +++ b/cookbook/Multi_modal_RAG.ipynb @@ -108,6 +108,7 @@ "outputs": [], "source": [ "from unstructured.partition.pdf import partition_pdf\n", + "\n", "# Extract images, tables, and chunk text\n", "raw_pdf_elements = partition_pdf(\n", " filename=path + \"wildfire_stats.pdf\",\n", @@ -189,8 +190,8 @@ "outputs": [], "source": [ "# Apply to text\n", - "# Typically this is reccomended only if you have large text chunks \n", - "text_summaries = texts # Skip it\n", + "# Typically this is reccomended only if you have large text chunks\n", + "text_summaries = texts # Skip it\n", "\n", "# Apply to tables\n", "table_summaries = summarize_chain.batch(tables, {\"max_concurrency\": 5})" @@ -228,26 +229,25 @@ "from langchain.chat_models import ChatOpenAI\n", "from langchain.schema.messages import HumanMessage, SystemMessage\n", "\n", - "def encode_image(image_path):\n", - " ''' Getting the base64 string '''\n", - " with open(image_path, \"rb\") as image_file:\n", - " return base64.b64encode(image_file.read()).decode('utf-8')\n", "\n", - "def image_summarize(img_base64,prompt):\n", - " ''' Image summary '''\n", - " chat = ChatOpenAI(model=\"gpt-4-vision-preview\",\n", - " max_tokens=1024)\n", - " \n", + "def encode_image(image_path):\n", + " \"\"\"Getting the base64 string\"\"\"\n", + " with open(image_path, \"rb\") as image_file:\n", + " return base64.b64encode(image_file.read()).decode(\"utf-8\")\n", + "\n", + "\n", + "def image_summarize(img_base64, prompt):\n", + " \"\"\"Image summary\"\"\"\n", + " chat = ChatOpenAI(model=\"gpt-4-vision-preview\", max_tokens=1024)\n", + "\n", " msg = chat.invoke(\n", " [\n", " HumanMessage(\n", " content=[\n", - " {\"type\": \"text\", \"text\":prompt},\n", + " {\"type\": \"text\", \"text\": prompt},\n", " {\n", " \"type\": \"image_url\",\n", - " \"image_url\": {\n", - " \"url\": f\"data:image/jpeg;base64,{img_base64}\"\n", - " },\n", + " \"image_url\": {\"url\": f\"data:image/jpeg;base64,{img_base64}\"},\n", " },\n", " ]\n", " )\n", @@ -255,6 +255,7 @@ " )\n", " return msg.content\n", "\n", + "\n", "# Store base64 encoded images\n", "img_base64_list = []\n", "\n", @@ -262,15 +263,15 @@ "image_summaries = []\n", "\n", "# Prompt\n", - "prompt = \"Describe the image in detail. Be specific about graphs, such as bar plots.\" \n", + "prompt = \"Describe the image in detail. Be specific about graphs, such as bar plots.\"\n", "\n", "# Read images, encode to base64 strings\n", "for img_file in sorted(os.listdir(path)):\n", - " if img_file.endswith('.jpg'):\n", + " if img_file.endswith(\".jpg\"):\n", " img_path = os.path.join(path, img_file)\n", " base64_image = encode_image(img_path)\n", " img_base64_list.append(base64_image)\n", - " image_summaries.append(image_summarize(base64_image,prompt))" + " image_summaries.append(image_summarize(base64_image, prompt))" ] }, { @@ -295,14 +296,15 @@ "source": [ "from IPython.display import display, HTML\n", "\n", - "def plt_img_base64(img_base64):\n", "\n", + "def plt_img_base64(img_base64):\n", " # Create an HTML img tag with the base64 string as the source\n", " image_html = f''\n", - " \n", + "\n", " # Display the image by rendering the HTML\n", " display(HTML(image_html))\n", "\n", + "\n", "plt_img_base64(img_base64_list[1])" ] }, @@ -352,8 +354,9 @@ "from langchain.retrievers.multi_vector import MultiVectorRetriever\n", "\n", "# The vectorstore to use to index the child chunks\n", - "vectorstore = Chroma(collection_name=\"multi_modal_rag\", \n", - " embedding_function=OpenAIEmbeddings())\n", + "vectorstore = Chroma(\n", + " collection_name=\"multi_modal_rag\", embedding_function=OpenAIEmbeddings()\n", + ")\n", "\n", "# The storage layer for the parent documents\n", "store = InMemoryStore()\n", @@ -478,8 +481,10 @@ ], "source": [ "from base64 import b64decode\n", + "\n", + "\n", "def split_image_text_types(docs):\n", - " ''' Split base64-encoded images and texts '''\n", + " \"\"\"Split base64-encoded images and texts\"\"\"\n", " b64 = []\n", " text = []\n", " for doc in docs:\n", @@ -488,10 +493,9 @@ " b64.append(doc)\n", " except Exception as e:\n", " text.append(doc)\n", - " return {\n", - " \"images\": b64,\n", - " \"texts\": text\n", - " }\n", + " return {\"images\": b64, \"texts\": text}\n", + "\n", + "\n", "docs_by_type = split_image_text_types(docs)\n", "plt_img_base64(docs_by_type[\"images\"][0])" ] @@ -522,27 +526,40 @@ "from operator import itemgetter\n", "from langchain.schema.runnable import RunnablePassthrough, RunnableLambda\n", "\n", + "\n", "def prompt_func(dict):\n", " format_texts = \"\\n\".join(dict[\"context\"][\"texts\"])\n", " return [\n", " HumanMessage(\n", " content=[\n", - " {\"type\": \"text\", \"text\": f\"\"\"Answer the question based only on the following context, which can include text, tables, and the below image:\n", + " {\n", + " \"type\": \"text\",\n", + " \"text\": f\"\"\"Answer the question based only on the following context, which can include text, tables, and the below image:\n", "Question: {dict[\"question\"]}\n", "\n", "Text and tables:\n", "{format_texts}\n", - "\"\"\"},\n", - " {\"type\": \"image_url\", \"image_url\": {\"url\": f\"data:image/jpeg;base64,{dict['context']['images'][0]}\"}},\n", + "\"\"\",\n", + " },\n", + " {\n", + " \"type\": \"image_url\",\n", + " \"image_url\": {\n", + " \"url\": f\"data:image/jpeg;base64,{dict['context']['images'][0]}\"\n", + " },\n", + " },\n", " ]\n", " )\n", " ]\n", "\n", + "\n", "model = ChatOpenAI(temperature=0, model=\"gpt-4-vision-preview\", max_tokens=1024)\n", "\n", "# RAG pipeline\n", "chain = (\n", - " {\"context\": retriever | RunnableLambda(split_image_text_types), \"question\": RunnablePassthrough()}\n", + " {\n", + " \"context\": retriever | RunnableLambda(split_image_text_types),\n", + " \"question\": RunnablePassthrough(),\n", + " }\n", " | RunnableLambda(prompt_func)\n", " | model\n", " | StrOutputParser()\n", @@ -574,9 +591,7 @@ } ], "source": [ - "chain.invoke(\n", - " \"What is the change in wild fires from 1993 to 2022?\"\n", - ")" + "chain.invoke(\"What is the change in wild fires from 1993 to 2022?\")" ] }, { diff --git a/cookbook/extraction_openai_tools.ipynb b/cookbook/extraction_openai_tools.ipynb index e45a81ccba2..a4fd2cc7d45 100644 --- a/cookbook/extraction_openai_tools.ipynb +++ b/cookbook/extraction_openai_tools.ipynb @@ -46,6 +46,7 @@ "# Pydantic is an easy way to define a schema\n", "class Person(BaseModel):\n", " \"\"\"Information about people to extract.\"\"\"\n", + "\n", " name: str\n", " age: Optional[int] = None" ] @@ -91,6 +92,7 @@ "# Let's define another element\n", "class Class(BaseModel):\n", " \"\"\"Information about classes to extract.\"\"\"\n", + "\n", " teacher: str\n", " students: List[str]" ] diff --git a/cookbook/multi_modal_QA.ipynb b/cookbook/multi_modal_QA.ipynb index 2c248dd1d85..135cdad8f14 100644 --- a/cookbook/multi_modal_QA.ipynb +++ b/cookbook/multi_modal_QA.ipynb @@ -7,7 +7,7 @@ "metadata": {}, "outputs": [], "source": [ - "! pip install \"openai>=1\" \"langchain>=0.0.331rc2\" matplotlib pillow " + "! pip install \"openai>=1\" \"langchain>=0.0.331rc2\" matplotlib pillow" ] }, { @@ -47,22 +47,24 @@ "from PIL import Image\n", "from IPython.display import display, HTML\n", "\n", + "\n", "def encode_image(image_path):\n", - " ''' Getting the base64 string '''\n", - " \n", + " \"\"\"Getting the base64 string\"\"\"\n", + "\n", " with open(image_path, \"rb\") as image_file:\n", - " return base64.b64encode(image_file.read()).decode('utf-8')\n", + " return base64.b64encode(image_file.read()).decode(\"utf-8\")\n", "\n", "\n", "def plt_img_base64(img_base64):\n", - " ''' Display the base64 image '''\n", + " \"\"\"Display the base64 image\"\"\"\n", "\n", " # Create an HTML img tag with the base64 string as the source\n", " image_html = f''\n", - " \n", + "\n", " # Display the image by rendering the HTML\n", " display(HTML(image_html))\n", "\n", + "\n", "# Image for QA\n", "path = \"/Users/rlm/Desktop/Multimodal_Eval/qa/llm_strategies.jpeg\"\n", "img_base64 = encode_image(path)\n", @@ -99,19 +101,19 @@ "metadata": {}, "outputs": [], "source": [ - "chat = ChatOpenAI(model=\"gpt-4-vision-preview\",\n", - " max_tokens=1024)\n", + "chat = ChatOpenAI(model=\"gpt-4-vision-preview\", max_tokens=1024)\n", "\n", "msg = chat.invoke(\n", " [\n", " HumanMessage(\n", " content=[\n", - " {\"type\": \"text\", \"text\":\"Based on the image, what is the difference in training strategy between a small and a large base model?\"},\n", + " {\n", + " \"type\": \"text\",\n", + " \"text\": \"Based on the image, what is the difference in training strategy between a small and a large base model?\",\n", + " },\n", " {\n", " \"type\": \"image_url\",\n", - " \"image_url\": {\n", - " \"url\": f\"data:image/jpeg;base64,{img_base64}\"\n", - " },\n", + " \"image_url\": {\"url\": f\"data:image/jpeg;base64,{img_base64}\"},\n", " },\n", " ]\n", " )\n", diff --git a/cookbook/openai_v1_cookbook.ipynb b/cookbook/openai_v1_cookbook.ipynb index da1928feaf9..f55d44ffb27 100644 --- a/cookbook/openai_v1_cookbook.ipynb +++ b/cookbook/openai_v1_cookbook.ipynb @@ -134,7 +134,7 @@ " name=\"langchain assistant\",\n", " instructions=\"You are a personal math tutor. Write and run code to answer math questions.\",\n", " tools=[{\"type\": \"code_interpreter\"}],\n", - " model=\"gpt-4-1106-preview\"\n", + " model=\"gpt-4-1106-preview\",\n", ")\n", "output = interpreter_assistant.invoke({\"content\": \"What's 10 - 4 raised to the 2.7\"})\n", "output" @@ -184,7 +184,7 @@ " instructions=\"You are a personal math tutor. Write and run code to answer math questions. You can also search the internet.\",\n", " tools=tools,\n", " model=\"gpt-4-1106-preview\",\n", - " as_agent=True\n", + " as_agent=True,\n", ")" ] }, @@ -241,7 +241,7 @@ " instructions=\"You are a personal math tutor. Write and run code to answer math questions.\",\n", " tools=tools,\n", " model=\"gpt-4-1106-preview\",\n", - " as_agent=True\n", + " as_agent=True,\n", ")" ] }, @@ -254,6 +254,7 @@ "source": [ "from langchain.schema.agent import AgentFinish\n", "\n", + "\n", "def execute_agent(agent, tools, input):\n", " tool_map = {tool.name: tool for tool in tools}\n", " response = agent.invoke(input)\n", @@ -262,9 +263,17 @@ " for action in response:\n", " tool_output = tool_map[action.tool].invoke(action.tool_input)\n", " print(action.tool, action.tool_input, tool_output, end=\"\\n\\n\")\n", - " tool_outputs.append({\"output\": tool_output, \"tool_call_id\": action.tool_call_id})\n", - " response = agent.invoke({\"tool_outputs\": tool_outputs, \"run_id\": action.run_id, \"thread_id\": action.thread_id})\n", - " \n", + " tool_outputs.append(\n", + " {\"output\": tool_output, \"tool_call_id\": action.tool_call_id}\n", + " )\n", + " response = agent.invoke(\n", + " {\n", + " \"tool_outputs\": tool_outputs,\n", + " \"run_id\": action.run_id,\n", + " \"thread_id\": action.thread_id,\n", + " }\n", + " )\n", + "\n", " return response" ] }, @@ -306,7 +315,9 @@ } ], "source": [ - "next_response = execute_agent(agent, tools, {\"content\": \"now add 17.241\", \"thread_id\": response.thread_id})\n", + "next_response = execute_agent(\n", + " agent, tools, {\"content\": \"now add 17.241\", \"thread_id\": response.thread_id}\n", + ")\n", "print(next_response.return_values[\"output\"])" ] }, @@ -449,16 +460,22 @@ "from langchain.prompts import ChatPromptTemplate\n", "from langchain.pydantic_v1 import BaseModel, Field\n", "\n", + "\n", "class GetCurrentWeather(BaseModel):\n", " \"\"\"Get the current weather in a location.\"\"\"\n", + "\n", " location: str = Field(description=\"The city and state, e.g. San Francisco, CA\")\n", - " unit: Literal[\"celsius\", \"fahrenheit\"] = Field(default=\"fahrenheit\", description=\"The temperature unit, default to fahrenheit\")\n", - " \n", - "prompt = ChatPromptTemplate.from_messages([\n", - " (\"system\", \"You are a helpful assistant\"),\n", - " (\"user\", \"{input}\")\n", - "])\n", - "model = ChatOpenAI(model=\"gpt-3.5-turbo-1106\").bind(tools=[convert_pydantic_to_openai_tool(GetCurrentWeather)])\n", + " unit: Literal[\"celsius\", \"fahrenheit\"] = Field(\n", + " default=\"fahrenheit\", description=\"The temperature unit, default to fahrenheit\"\n", + " )\n", + "\n", + "\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [(\"system\", \"You are a helpful assistant\"), (\"user\", \"{input}\")]\n", + ")\n", + "model = ChatOpenAI(model=\"gpt-3.5-turbo-1106\").bind(\n", + " tools=[convert_pydantic_to_openai_tool(GetCurrentWeather)]\n", + ")\n", "chain = prompt | model | PydanticToolsParser(tools=[GetCurrentWeather])\n", "\n", "chain.invoke({\"input\": \"what's the weather in NYC, LA, and SF\"})" diff --git a/docs/docs/get_started/installation.mdx b/docs/docs/get_started/installation.mdx index 895e6187831..f40a0217637 100644 --- a/docs/docs/get_started/installation.mdx +++ b/docs/docs/get_started/installation.mdx @@ -28,3 +28,37 @@ If you want to install from source, you can do so by cloning the repo and be sur ```bash pip install -e . ``` + +## Langchain experimental +The `langchain-experimental` package holds experimental LangChain code, intended for research and experimental uses. +Install with: + +```bash +pip install langchain-experimental +``` + +## LangChain CLI +The LangChain CLI is useful for working with LangChain templates and other LangServe projects. +Install with: + +```bash +pip install langchain-cli +``` + +## LangServe +LangServe helps developers deploy LangChain runnables and chains as a REST API. +LangServe is automatically installed by LangChain CLI. +If not using LangChain CLI, install with: + +```bash +pip install "langserve[all]" +``` +for both client and server dependencies. Or `pip install "langserve[client]"` for client code, and `pip install "langserve[server]"` for server code. + +## LangSmith SDK +The LangSmith SDK is automatically installed by LangChain. +If not using LangChain, install with: + +```bash +pip install langsmith +``` \ No newline at end of file diff --git a/docs/docs/get_started/introduction.mdx b/docs/docs/get_started/introduction.mdx index 89642795d8e..d232340af28 100644 --- a/docs/docs/get_started/introduction.mdx +++ b/docs/docs/get_started/introduction.mdx @@ -9,23 +9,19 @@ sidebar_position: 0 - **Reason**: rely on a language model to reason (about how to answer based on provided context, what actions to take, etc.) This framework consists of several parts. -You can see how the parts interact with each other below: - -![LangChain Diagram](/img/langchain_stack.png) - -These parts include: - -- **[LangChain Packages]**: The Python and JavaScript packages. Contains interfaces and integrations for a myriad of components, a basic run time for combining these components into chains and agents, and off-the-shelf implementations of chains and agents. +- **LangChain Libraries**: The Python and JavaScript libraries. Contains interfaces and integrations for a myriad of components, a basic run time for combining these components into chains and agents, and off-the-shelf implementations of chains and agents. - **[LangChain Templates](https://github.com/langchain-ai/langchain/tree/master/templates)**: A collection of easily deployable reference architectures for a wide variety of tasks. - **[LangServe](https://github.com/langchain-ai/langserve)**: A library for deploying LangChain chains as a REST API. - **[LangSmith](https://smith.langchain.com/)**: A developer platform that lets you debug, test, evaluate, and monitor chains built on any LLM framework and seamlessly integrates with LangChain. +![LangChain Diagram](/img/langchain_stack.png) + Together, these products simplify the entire application lifecycle: - **Develop**: Write your applications in LangChain/LangChain.js. Hit the ground running using Templates for reference. - **Productionize**: Use LangSmith to inspect, test and monitor your chains, so that you can constantly improve and deploy with confidence. - **Deploy**: Turn any chain into an API with LangServe. -## LangChain Packages +## LangChain Libraries The main value props of the LangChain packages are: 1. **Components**: composable tools and integrations for working with language models. Components are modular and easy-to-use, whether you are using the rest of the LangChain framework or not @@ -33,13 +29,20 @@ The main value props of the LangChain packages are: Off-the-shelf chains make it easy to get started. Components make it easy to customize existing chains and build new ones. - ## Get started [Here’s](/docs/get_started/installation) how to install LangChain, set up your environment, and start building. We recommend following our [Quickstart](/docs/get_started/quickstart) guide to familiarize yourself with the framework by building your first LangChain application. +Read up on our [Security](/docs/security) best practices to make sure you're developing safely with LangChain. + +:::note + +These docs focus on the Python LangChain library. [Head here](https://js.langchain.com) for docs on the JavaScript LangChain library. + +::: + ## Modules LangChain provides standard, extendable interfaces and integrations for the following modules, listed from least to most complex: @@ -65,12 +68,12 @@ Walkthroughs and techniques for common end-to-end use cases, like: - [Analyzing structured data](/docs/use_cases/qa_structured/sql/) - and much more... +### [Integrations](/docs/integrations/providers/) +LangChain is part of a rich ecosystem of tools that integrate with our framework and build on top of it. Check out our growing list of [integrations](/docs/integrations/providers/) and [dependent repos](/docs/additional_resources/dependents). + ### [Guides](/docs/guides/adapters/openai) Best practices for developing with LangChain. -### [Ecosystem](/docs/integrations/providers/) -LangChain is part of a rich ecosystem of tools that integrate with our framework and build on top of it. Check out our growing list of [integrations](/docs/integrations/providers/) and [dependent repos](/docs/additional_resources/dependents). - ### [Community](/docs/community) Head to the [Community navigator](/docs/community) to find places to ask questions, share feedback, meet other developers, and dream about the future of LLM’s. diff --git a/docs/docs/get_started/quickstart.mdx b/docs/docs/get_started/quickstart.mdx index 29be8265aad..6e355cc261c 100644 --- a/docs/docs/get_started/quickstart.mdx +++ b/docs/docs/get_started/quickstart.mdx @@ -39,12 +39,12 @@ export OPENAI_API_KEY="..." If you'd prefer not to set an environment variable you can pass the key in directly via the `openai_api_key` named parameter when initiating the OpenAI LLM class: ```python -from langchain.llms import OpenAI +from langchain.chat_models import ChatOpenAI -llm = OpenAI(openai_api_key="...") +llm = ChatOpenAI(openai_api_key="...") ``` -## LangSmith Setup +## LangSmith setup Many of the applications you build with LangChain will contain multiple steps with multiple invocations of LLM calls. As these applications get more and more complex, it becomes crucial to be able to inspect what exactly is going on inside your chain or agent. @@ -60,48 +60,49 @@ export LANGCHAIN_API_KEY=... ## Building an application -Now we can start building our language model application. LangChain provides many modules that can be used to build language model applications. -Modules can be used as standalones in simple applications and they can be combined for more complex use cases. +LangChain provides many modules that can be used to build language model applications. +Modules can be used as standalones in simple applications and they can be composed for more complex use cases. +Composition is powered by **LangChain Expression Language** (LCEL), which defines a unified `Runnable` interface that many modules implement, making it possible to seamlessly chain components. -The most common and most important chain that LangChain helps create contains three things: -- LLM: The language model is the core reasoning engine here. In order to work with LangChain, you need to understand the different types of language models and how to work with them. -- Prompt Templates: This provides instructions to the language model. This controls what the language model outputs, so understanding how to construct prompts and different prompting strategies is crucial. -- Output Parsers: These translate the raw response from the LLM to a more workable format, making it easy to use the output downstream. +The simplest and most common chain contains three things: +- LLM/Chat Model: The language model is the core reasoning engine here. In order to work with LangChain, you need to understand the different types of language models and how to work with them. +- Prompt Template: This provides instructions to the language model. This controls what the language model outputs, so understanding how to construct prompts and different prompting strategies is crucial. +- Output Parser: These translate the raw response from the language model to a more workable format, making it easy to use the output downstream. -In this getting started guide we will cover those three components by themselves, and then go over how to combine all of them. +In this guide we'll cover those three components individually, and then go over how to combine them. Understanding these concepts will set you up well for being able to use and customize LangChain applications. -Most LangChain applications allow you to configure the LLM and/or the prompt used, so knowing how to take advantage of this will be a big enabler. +Most LangChain applications allow you to configure the model and/or the prompt, so knowing how to take advantage of this will be a big enabler. -## LLMs +## LLM / Chat Model -There are two types of language models, which in LangChain are called: +There are two types of language models: -- LLMs: this is a language model which takes a string as input and returns a string -- ChatModels: this is a language model which takes a list of messages as input and returns a message +- `LLM`: underlying model takes a string as input and returns a string +- `ChatModel`: underlying model takes a list of messages as input and returns a message -The input/output for LLMs is simple and easy to understand - a string. -But what about ChatModels? The input there is a list of `ChatMessages`, and the output is a single `ChatMessage`. -A `ChatMessage` has two required components: +Strings are simple, but what exactly are messages? The base message interface is defined by `BaseMessage`, which has two required attributes: -- `content`: This is the content of the message. -- `role`: This is the role of the entity from which the `ChatMessage` is coming from. +- `content`: The content of the message. Usually a string. +- `role`: The entity from which the `BaeMessage` is coming. LangChain provides several objects to easily distinguish between different roles: -- `HumanMessage`: A `ChatMessage` coming from a human/user. -- `AIMessage`: A `ChatMessage` coming from an AI/assistant. -- `SystemMessage`: A `ChatMessage` coming from the system. -- `FunctionMessage`: A `ChatMessage` coming from a function call. +- `HumanMessage`: A `BaseMessage` coming from a human/user. +- `AIMessage`: A `BaseMessage` coming from an AI/assistant. +- `SystemMessage`: A `BaseMessage` coming from the system. +- `FunctionMessage` / `ToolMessage`: A `BaseMessage` containing the output of a function or tool call. If none of those roles sound right, there is also a `ChatMessage` class where you can specify the role manually. -For more information on how to use these different messages most effectively, see our prompting guide. -Langchain provides a common interface that's shared by both LLMs and ChatModels. -However it's useful to understand this difference in order to construct prompts for a given language model. +LangChain provides a common interface that's shared by both `LLM`s and `ChatModel`s. +However it's useful to understand the difference in order to most effectively construct prompts for a given language model. -The standard interface that LangChain provides has two methods: -- `predict`: Takes in a string, returns a string -- `predict_messages`: Takes in a list of messages, returns a message. +The simplest way to call an `LLM` or `ChatModel` is using `.invoke()`, the universal synchronous call method for all LangChain Expression Language (LCEL) objects: +- `LLM.invoke`: Takes in a string, returns a string. +- `ChatModel.invoke`: Takes in a list of `BaseMessage`, returns a `BaseMessage`. + +The input types for these methods are actually more general than this, but for simplicity here we can assume LLMs only take strings and Chat models only takes lists of messages. +Check out the "Go deeper" section below to learn more about model invocation. Let's see how to work with these different types of models and these different types of inputs. First, let's import an LLM and a ChatModel. @@ -112,48 +113,34 @@ from langchain.chat_models import ChatOpenAI llm = OpenAI() chat_model = ChatOpenAI() - -llm.predict("hi!") ->>> "Hi" - -chat_model.predict("hi!") ->>> "Hi" ``` -The `OpenAI` and `ChatOpenAI` objects are basically just configuration objects. +`LLM` and `ChatModel` objects are effectively configuration objects. You can initialize them with parameters like `temperature` and others, and pass them around. -Next, let's use the `predict` method to run over a string input. - -```python -text = "What would be a good company name for a company that makes colorful socks?" - -llm.predict(text) -# >> Feetful of Fun - -chat_model.predict(text) -# >> Socks O'Color -``` - -Finally, let's use the `predict_messages` method to run over a list of messages. - ```python from langchain.schema import HumanMessage text = "What would be a good company name for a company that makes colorful socks?" messages = [HumanMessage(content=text)] -llm.predict_messages(messages) +llm.invoke(text) # >> Feetful of Fun -chat_model.predict_messages(messages) -# >> Socks O'Color +chat_model.invoke(messages) +# >> AIMessage(content="Socks O'Color") ``` -For both these methods, you can also pass in parameters as keyword arguments. -For example, you could pass in `temperature=0` to adjust the temperature that is used from what the object was configured with. -Whatever values are passed in during run time will always override what the object was configured with. +
Go deeper +`LLM.invoke` and `ChatModel.invoke` actually both support as input any of `Union[str, List[BaseMessage], PromptValue]`. +`PromptValue` is an object that defines it's own custom logic for returning it's inputs either as a string or as messages. +`LLM`s have logic for coercing any of these into a string, and `ChatModel`s have logic for coercing any of these to messages. +The fact that `LLM` and `ChatModel` accept the same inputs means that you can directly swap them for one another in most chains without breaking anything, +though it's of course important to think about how inputs are being coerced and how that may affect model performance. +To dive deeper on models head to the [Language models](/docs/modules/model_io/models) section. + +
## Prompt templates @@ -181,10 +168,10 @@ You can "partial" out variables - e.g. you can format only some of the variables You can compose them together, easily combining different templates into a single prompt. For explanations of these functionalities, see the [section on prompts](/docs/modules/model_io/prompts) for more detail. -PromptTemplates can also be used to produce a list of messages. +`PromptTemplate`s can also be used to produce a list of messages. In this case, the prompt not only contains information about the content, but also each message (its role, its position in the list, etc.). -Here, what happens most often is a ChatPromptTemplate is a list of ChatMessageTemplates. -Each ChatMessageTemplate contains instructions for how to format that ChatMessage - its role, and then also its content. +Here, what happens most often is a `ChatPromptTemplate` is a list of `ChatMessageTemplates`. +Each `ChatMessageTemplate` contains instructions for how to format that `ChatMessage` - its role, and then also its content. Let's take a look at this below: ```python @@ -213,11 +200,11 @@ ChatPromptTemplates can also be constructed in other ways - see the [section on ## Output parsers -OutputParsers convert the raw output of an LLM into a format that can be used downstream. -There are few main types of OutputParsers, including: +`OutputParsers` convert the raw output of a language model into a format that can be used downstream. +There are few main types of `OutputParser`s, including: -- Convert text from LLM into structured information (e.g. JSON) -- Convert a ChatMessage into just a string +- Convert text from `LLM` into structured information (e.g. JSON) +- Convert a `ChatMessage` into just a string - Convert the extra information returned from a call besides the message (like OpenAI function invocation) into a string. For full information on this, see the [section on output parsers](/docs/modules/model_io/output_parsers). @@ -239,7 +226,7 @@ CommaSeparatedListOutputParser().parse("hi, bye") # >> ['hi', 'bye'] ``` -## PromptTemplate + LLM + OutputParser +## Prompt template + model + output parser We can now combine all these into one chain. This chain will take input variables, pass those to a prompt template to create a prompt, pass the prompt to a language model, and then pass the output through an (optional) output parser. @@ -273,20 +260,27 @@ chain.invoke({"text": "colors"}) # >> ['red', 'blue', 'green', 'yellow', 'orange'] ``` - Note that we are using the `|` syntax to join these components together. -This `|` syntax is called the LangChain Expression Language. +This `|` syntax is powered by the LangChain Expression Language (LCEL) and relies on the universal `Runnable` interface that all of these objects implement. To learn more about this syntax, read the documentation [here](/docs/expression_language). +## Seeing this in LangSmith + +Assuming we've set our environment variables as shown in the beginning, all of the model and chain calls we've been making will have been automatically logged to LangSmith. +Once there, we can use LangSmith to debug and annotate our application traces, then turn them into datasets for evaluating future iterations of the application. + +Check out what the trace for the above chain would look like: +https://smith.langchain.com/public/09370280-4330-4eb4-a7e8-c91817f6aa13/r + ## Next steps -This is it! -We've now gone over how to create the core building block of LangChain applications. -There is a lot more nuance in all these components (LLMs, prompts, output parsers) and a lot more different components to learn about as well. +We've gone over how to create the core building block of LangChain applications. +There are a lot of features in all these components (LLMs, prompts, output parsers) we didn't cover and a lot of other components to learn about. To continue on your journey: +- Read up on [LangChain Expression Language (LCEL)](/docs/expression_language) to learn how to chain these components together - [Dive deeper](/docs/modules/model_io) into LLMs, prompts, and output parsers - Learn the other [key components](/docs/modules) -- Read up on [LangChain Expression Language](/docs/expression_language) to learn how to chain these components together -- Check out our [helpful guides](/docs/guides) for detailed walkthroughs on particular topics - Explore [end-to-end use cases](/docs/use_cases/qa_structured/sql) +- Check out our [helpful guides](/docs/guides) for detailed walkthroughs on particular topics +- [Read up on LangSmith](/docs/langsmith/), the platform for debugging, testing, monitoring and more diff --git a/docs/docs/integrations/retrievers/fleet_context.ipynb b/docs/docs/integrations/retrievers/fleet_context.ipynb index ba6f611b117..10f4145b7c1 100644 --- a/docs/docs/integrations/retrievers/fleet_context.ipynb +++ b/docs/docs/integrations/retrievers/fleet_context.ipynb @@ -45,9 +45,9 @@ "def load_fleet_retriever(\n", " url: str,\n", " *,\n", - " vectorstore_cls: Type[VectorStore]=FAISS, \n", - " docstore: Optional[BaseStore]=None,\n", - " **kwargs: Any\n", + " vectorstore_cls: Type[VectorStore] = FAISS,\n", + " docstore: Optional[BaseStore] = None,\n", + " **kwargs: Any,\n", "):\n", " df = pd.read_parquet(url)\n", " vectorstore = _populate_vectorstore(df, vectorstore_cls)\n", @@ -56,16 +56,13 @@ " else:\n", " _populate_docstore(df, docstore)\n", " return MultiVectorRetriever(\n", - " vectorstore=vectorstore, \n", - " docstore=docstore, \n", - " id_key=\"parent\", \n", - " **kwargs\n", + " vectorstore=vectorstore, docstore=docstore, id_key=\"parent\", **kwargs\n", " )\n", "\n", "\n", "def _populate_vectorstore(\n", " df: pd.DataFrame,\n", - " vectorstore_cls: Type[VectorStore], \n", + " vectorstore_cls: Type[VectorStore],\n", ") -> VectorStore:\n", " if not hasattr(vectorstore_cls, \"from_embeddings\"):\n", " raise ValueError(\n", @@ -75,11 +72,11 @@ " texts_embeddings = []\n", " metadatas = []\n", " for _, row in df.iterrows():\n", - " texts_embeddings.append((row.metadata['text'], row['dense_embeddings']))\n", + " texts_embeddings.append((row.metadata[\"text\"], row[\"dense_embeddings\"]))\n", " metadatas.append(row.metadata)\n", " return vectorstore_cls.from_embeddings(\n", - " texts_embeddings, \n", - " OpenAIEmbeddings(model='text-embedding-ada-002'), \n", + " texts_embeddings,\n", + " OpenAIEmbeddings(model=\"text-embedding-ada-002\"),\n", " metadatas=metadatas,\n", " )\n", "\n", @@ -87,15 +84,19 @@ "def _populate_docstore(df: pd.DataFrame, docstore: BaseStore) -> None:\n", " parent_docs = []\n", " df = df.copy()\n", - " df['parent'] = df.metadata.apply(itemgetter('parent'))\n", - " for parent_id, group in df.groupby('parent'):\n", - " sorted_group = group.iloc[group.metadata.apply(itemgetter('section_index')).argsort()]\n", - " text = \"\".join(sorted_group.metadata.apply(itemgetter('text')))\n", - " metadata = {k: sorted_group.iloc[0].metadata[k] for k in ('title', 'type', 'url')}\n", - " text = metadata['title'] + \"\\n\" + text\n", - " metadata['id'] = parent_id\n", + " df[\"parent\"] = df.metadata.apply(itemgetter(\"parent\"))\n", + " for parent_id, group in df.groupby(\"parent\"):\n", + " sorted_group = group.iloc[\n", + " group.metadata.apply(itemgetter(\"section_index\")).argsort()\n", + " ]\n", + " text = \"\".join(sorted_group.metadata.apply(itemgetter(\"text\")))\n", + " metadata = {\n", + " k: sorted_group.iloc[0].metadata[k] for k in (\"title\", \"type\", \"url\")\n", + " }\n", + " text = metadata[\"title\"] + \"\\n\" + text\n", + " metadata[\"id\"] = parent_id\n", " parent_docs.append(Document(page_content=text, metadata=metadata))\n", - " docstore.mset(((d.metadata['id'], d) for d in parent_docs))" + " docstore.mset(((d.metadata[\"id\"], d) for d in parent_docs))" ] }, { @@ -175,7 +176,7 @@ "\n", "parent_retriever = load_fleet_retriever(\n", " \"https://www.dropbox.com/scl/fi/4rescpkrg9970s3huz47l/libraries_langchain_release.parquet?rlkey=283knw4wamezfwiidgpgptkep&dl=1\",\n", - " docstore=InMemoryStore()\n", + " docstore=InMemoryStore(),\n", ")" ] }, @@ -225,8 +226,11 @@ "from langchain.schema import StrOutputParser\n", "from langchain.schema.runnable import RunnablePassthrough\n", "\n", - "prompt = ChatPromptTemplate.from_messages([\n", - " (\"system\", \"\"\"You are a great software engineer who is very familiar \\\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " \"\"\"You are a great software engineer who is very familiar \\\n", "with Python. Given a user question or request about a new Python library called LangChain and \\\n", "parts of the LangChain documentation, answer the question or generate the requested code. \\\n", "Your answers must be accurate, should include code whenever possible, and should assume anything \\\n", @@ -236,17 +240,21 @@ "LangChain Documentation\n", "------------------\n", "\n", - "{context}\"\"\"),\n", - " (\"human\", \"{question}\")\n", - "])\n", + "{context}\"\"\",\n", + " ),\n", + " (\"human\", \"{question}\"),\n", + " ]\n", + ")\n", "\n", "model = ChatOpenAI(model=\"gpt-3.5-turbo-16k\")\n", "\n", "chain = (\n", " {\n", " \"question\": RunnablePassthrough(),\n", - " \"context\": parent_retriever | (lambda docs: \"\\n\\n\".join(d.page_content for d in docs))\n", - " } | prompt\n", + " \"context\": parent_retriever\n", + " | (lambda docs: \"\\n\\n\".join(d.page_content for d in docs)),\n", + " }\n", + " | prompt\n", " | model\n", " | StrOutputParser()\n", ")" @@ -289,8 +297,10 @@ } ], "source": [ - "for chunk in chain.invoke(\"How do I create a FAISS vector store retriever that returns 10 documents per search query\"):\n", - " print(chunk, end='', flush=True)" + "for chunk in chain.invoke(\n", + " \"How do I create a FAISS vector store retriever that returns 10 documents per search query\"\n", + "):\n", + " print(chunk, end=\"\", flush=True)" ] } ], diff --git a/docs/docs/integrations/text_embedding/azureopenai.ipynb b/docs/docs/integrations/text_embedding/azureopenai.ipynb index 3ee98dc28a0..6c500f0d779 100644 --- a/docs/docs/integrations/text_embedding/azureopenai.ipynb +++ b/docs/docs/integrations/text_embedding/azureopenai.ipynb @@ -33,8 +33,8 @@ "from langchain.embeddings import AzureOpenAIEmbeddings\n", "\n", "embeddings = AzureOpenAIEmbeddings(\n", - " azure_deployment=\"\", \n", - " openai_api_version=\"2023-05-15\"\n", + " azure_deployment=\"\",\n", + " openai_api_version=\"2023-05-15\",\n", ")" ] }, diff --git a/docs/docs/integrations/tools/memorize.ipynb b/docs/docs/integrations/tools/memorize.ipynb index 7ec5f2b6fbb..5dbf66a8af8 100644 --- a/docs/docs/integrations/tools/memorize.ipynb +++ b/docs/docs/integrations/tools/memorize.ipynb @@ -48,14 +48,14 @@ "from getpass import getpass\n", "\n", "\n", - "if not os.environ.get(\"GRADIENT_ACCESS_TOKEN\",None):\n", + "if not os.environ.get(\"GRADIENT_ACCESS_TOKEN\", None):\n", " # Access token under https://auth.gradient.ai/select-workspace\n", " os.environ[\"GRADIENT_ACCESS_TOKEN\"] = getpass(\"gradient.ai access token:\")\n", - "if not os.environ.get(\"GRADIENT_WORKSPACE_ID\",None):\n", + "if not os.environ.get(\"GRADIENT_WORKSPACE_ID\", None):\n", " # `ID` listed in `$ gradient workspace list`\n", " # also displayed after login at at https://auth.gradient.ai/select-workspace\n", " os.environ[\"GRADIENT_WORKSPACE_ID\"] = getpass(\"gradient.ai workspace id:\")\n", - "if not os.environ.get(\"GRADIENT_MODEL_ADAPTER_ID\",None):\n", + "if not os.environ.get(\"GRADIENT_MODEL_ADAPTER_ID\", None):\n", " # `ID` listed in `$ gradient model list --workspace-id \"$GRADIENT_WORKSPACE_ID\"`\n", " os.environ[\"GRADIENT_MODEL_ID\"] = getpass(\"gradient.ai model id:\")" ] @@ -82,7 +82,7 @@ "outputs": [], "source": [ "llm = GradientLLM(\n", - " model_id=os.environ['GRADIENT_MODEL_ID'],\n", + " model_id=os.environ[\"GRADIENT_MODEL_ID\"],\n", " # # optional: set new credentials, they default to environment variables\n", " # gradient_workspace_id=os.environ[\"GRADIENT_WORKSPACE_ID\"],\n", " # gradient_access_token=os.environ[\"GRADIENT_ACCESS_TOKEN\"],\n", @@ -169,7 +169,9 @@ } ], "source": [ - "agent.run(\"Please remember the fact in detail:\\nWith astonishing dexterity, Zara Tubikova set a world record by solving a 4x4 Rubik's Cube variation blindfolded in under 20 seconds, employing only their feet.\")" + "agent.run(\n", + " \"Please remember the fact in detail:\\nWith astonishing dexterity, Zara Tubikova set a world record by solving a 4x4 Rubik's Cube variation blindfolded in under 20 seconds, employing only their feet.\"\n", + ")" ] } ], diff --git a/docs/docs/integrations/vectorstores/astradb.ipynb b/docs/docs/integrations/vectorstores/astradb.ipynb index 1e4d1cb2518..ea291af7f93 100644 --- a/docs/docs/integrations/vectorstores/astradb.ipynb +++ b/docs/docs/integrations/vectorstores/astradb.ipynb @@ -57,7 +57,9 @@ "import os\n", "from getpass import getpass\n", "\n", - "from datasets import load_dataset # if not present yet, run: pip install \"datasets==2.14.6\"\n", + "from datasets import (\n", + " load_dataset,\n", + ") # if not present yet, run: pip install \"datasets==2.14.6\"\n", "\n", "from langchain.schema import Document\n", "from langchain.embeddings import OpenAIEmbeddings\n", @@ -374,7 +376,7 @@ "metadata": {}, "outputs": [], "source": [ - "retriever = vstore.as_retriever(search_kwargs={'k': 3})\n", + "retriever = vstore.as_retriever(search_kwargs={\"k\": 3})\n", "\n", "philo_template = \"\"\"\n", "You are a philosopher that draws inspiration from great thinkers of the past\n", @@ -394,9 +396,9 @@ "llm = ChatOpenAI()\n", "\n", "chain = (\n", - " {\"context\": retriever, \"question\": RunnablePassthrough()} \n", - " | philo_prompt \n", - " | llm \n", + " {\"context\": retriever, \"question\": RunnablePassthrough()}\n", + " | philo_prompt\n", + " | llm\n", " | StrOutputParser()\n", ")" ] diff --git a/docs/docs/modules/agents/agent_types/openai_tools.ipynb b/docs/docs/modules/agents/agent_types/openai_tools.ipynb index 9cdadfc0abd..36014188c8b 100644 --- a/docs/docs/modules/agents/agent_types/openai_tools.ipynb +++ b/docs/docs/modules/agents/agent_types/openai_tools.ipynb @@ -38,7 +38,9 @@ "outputs": [], "source": [ "from langchain.agents import initialize_agent, AgentType, Tool\n", - "from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages\n", + "from langchain.agents.format_scratchpad.openai_tools import (\n", + " format_to_openai_tool_messages,\n", + ")\n", "from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser\n", "from langchain.chat_models import ChatOpenAI\n", "from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder\n", @@ -90,7 +92,7 @@ "metadata": {}, "outputs": [], "source": [ - "llm_with_tools = llm.bind(tools=[format_tool_to_openai_tool(t)for t in tools])" + "llm_with_tools = llm.bind(tools=[format_tool_to_openai_tool(t) for t in tools])" ] }, { @@ -182,11 +184,7 @@ } ], "source": [ - "agent_executor.invoke(\n", - " {\n", - " \"input\": \"What's the weather in LA, NYC, and SF today\"\n", - " }\n", - ")" + "agent_executor.invoke({\"input\": \"What's the weather in LA, NYC, and SF today\"})" ] }, { diff --git a/docs/docs/modules/model_io/models/chat/index.ipynb b/docs/docs/modules/model_io/models/chat/index.ipynb index 3a060745213..56ec08a245c 100644 --- a/docs/docs/modules/model_io/models/chat/index.ipynb +++ b/docs/docs/modules/model_io/models/chat/index.ipynb @@ -24,9 +24,7 @@ "While chat models use language models under the hood, the interface they use is a bit different.\n", "Rather than using a \"text in, text out\" API, they use an interface where \"chat messages\" are the inputs and outputs.\n", "\n", - "## Get started\n", - "\n", - "### Setup\n", + "## Setup\n", "\n", "For this example we'll need to install the OpenAI Python package:\n", "\n", @@ -79,7 +77,7 @@ "id": "4ca3a777-8641-42fb-9e02-a7770a633d29", "metadata": {}, "source": [ - "### Messages\n", + "## Messages\n", "\n", "The chat model interface is based around messages rather than raw text.\n", "The types of messages currently supported in LangChain are `AIMessage`, `HumanMessage`, `SystemMessage`, `FunctionMessage` and `ChatMessage` -- `ChatMessage` takes in an arbitrary role parameter. Most of the time, you'll just be dealing with `HumanMessage`, `AIMessage`, and `SystemMessage`" @@ -90,7 +88,7 @@ "id": "54e5088f-98dd-437e-bac8-99b750946b29", "metadata": {}, "source": [ - "### LCEL\n", + "## LCEL\n", "\n", "Chat models implement the [Runnable interface](/docs/expression_language/interface), the basic building block of the [LangChain Expression Language (LCEL)](/docs/expression_language/). This means they support `invoke`, `ainvoke`, `stream`, `astream`, `batch`, `abatch`, `astream_log` calls.\n", "\n", @@ -590,12 +588,30 @@ " print(chunk)" ] }, + { + "cell_type": "markdown", + "id": "a4a7d783-4ddf-42e7-b143-8050891663c2", + "metadata": {}, + "source": [ + "## [LangSmith](https://smith.langchain.com)\n", + "\n", + "All `ChatModel`s come with built-in LangSmith tracing. Just set the following environment variables:\n", + "```bash\n", + "export LANGCHAIN_TRACING_V2=\"true\"\n", + "export LANGCHAIN_API_KEY=\n", + "```\n", + "\n", + "and any `ChatModel` invocation (whether it's nested in a chain or not) will automatically be traced. A trace will include inputs, outputs, latency, token usage, invocation params, environment params, and more. See an example here: https://smith.langchain.com/public/a54192ae-dd5c-4f7a-88d1-daa1eaba1af7/r.\n", + "\n", + "In LangSmith you can then provide feedback for any trace, compile annotated datasets for evals, debug performance in the playground, and more." + ] + }, { "cell_type": "markdown", "id": "7b289727-3983-43f7-a8b2-dd5582d49b6a", "metadata": {}, "source": [ - "### `__call__`\n", + "## [Legacy] `__call__`\n", "#### Messages in -> message out\n", "\n", "For convenience you can also treat chat models as callables. You can get chat completions by passing one or more messages to the chat model. The response will be a message." @@ -670,7 +686,7 @@ "id": "2b996c69-fd5d-4889-af4a-19dfd2833021", "metadata": {}, "source": [ - "### `generate`\n", + "## [Legacy] `generate`\n", "#### Batch calls, richer outputs\n", "\n", "You can go one step further and generate completions for multiple sets of messages using `generate`. This returns an `LLMResult` with an additional `message` parameter. This will include additional information about each generation beyond the returned message (e.g. the finish reason) and additional information about the full API call (e.g. total tokens used)." diff --git a/docs/docs/modules/model_io/models/chat/llm_chain.mdx b/docs/docs/modules/model_io/models/chat/llm_chain.mdx deleted file mode 100644 index fa1ec1a0425..00000000000 --- a/docs/docs/modules/model_io/models/chat/llm_chain.mdx +++ /dev/null @@ -1,20 +0,0 @@ -# LLMChain - -You can use the existing LLMChain in a very similar way to before - provide a prompt and a model. - -```python -chain = LLMChain(llm=chat, prompt=chat_prompt) -``` - - -```python -chain.run(input_language="English", output_language="French", text="I love programming.") -``` - - - -``` - "J'adore la programmation." -``` - - diff --git a/docs/docs/modules/model_io/models/chat/streaming.ipynb b/docs/docs/modules/model_io/models/chat/streaming.ipynb new file mode 100644 index 00000000000..51f3a9c09f4 --- /dev/null +++ b/docs/docs/modules/model_io/models/chat/streaming.ipynb @@ -0,0 +1,88 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d0df7646-b1e1-4014-a841-6dae9b3c50d9", + "metadata": {}, + "source": [ + "# Streaming\n", + "\n", + "All ChatModels implement the Runnable interface, which comes with default implementations of all methods, ie. ainvoke, batch, abatch, stream, astream. This gives all ChatModels basic support for streaming.\n", + "\n", + "Streaming support defaults to returning an Iterator (or AsyncIterator in the case of async streaming) of a single value, the final result returned by the underlying ChatModel provider. This obviously doesn't give you token-by-token streaming, which requires native support from the ChatModel provider, but ensures your code that expects an iterator of tokens can work for any of our ChatModel integrations.\n", + "\n", + "See which [integrations support token-by-token streaming here](/docs/integrations/chat/)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "03080a2c-45e8-45b9-a367-62816eae54c4", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chat_models import ChatAnthropic" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "975c4f32-21f6-4a71-9091-f87b56347c33", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Here's a song I just improvised about goldfish on the moon:\n", + "\n", + "Floating in space, looking for a place \n", + "To call their home, all alone\n", + "Swimming through stars, these goldfish from Mars\n", + "Left their fishbowl behind, a new life to find\n", + "On the moon, where the craters loom\n", + "Searching for food, maybe some lunar food\n", + "Out of their depth, close to death\n", + "How they wish, for just one small fish\n", + "To join them up here, their future unclear\n", + "On the moon, where the Earth looms\n", + "Dreaming of home, filled with foam\n", + "Their bodies adapt, continuing to last \n", + "On the moon, where they learn to swoon\n", + "Over cheese that astronauts tease\n", + "As they stare back at Earth, the planet of birth\n", + "These goldfish out of water, swim on and on\n", + "Lunar pioneers, conquering their fears\n", + "On the moon, where they happily swoon" + ] + } + ], + "source": [ + "chat = ChatAnthropic(model=\"claude-2\")\n", + "for chunk in chat.stream(\"Write me a song about goldfish on the moon\"):\n", + " print(chunk.content, end=\"\", flush=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "poetry-venv", + "language": "python", + "name": "poetry-venv" + }, + "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.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/modules/model_io/models/chat/streaming.mdx b/docs/docs/modules/model_io/models/chat/streaming.mdx deleted file mode 100644 index c9bf9ec2a54..00000000000 --- a/docs/docs/modules/model_io/models/chat/streaming.mdx +++ /dev/null @@ -1,63 +0,0 @@ -# Streaming - -Some chat models provide a streaming response. This means that instead of waiting for the entire response to be returned, you can start processing it as soon as it's available. This is useful if you want to display the response to the user as it's being generated, or if you want to process the response as it's being generated. - -```python -from langchain.chat_models import ChatOpenAI -from langchain.schema import ( - HumanMessage, -) - - -from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler -chat = ChatOpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0) -resp = chat([HumanMessage(content="Write me a song about sparkling water.")]) -``` - - - -``` - Verse 1: - Bubbles rising to the top - A refreshing drink that never stops - Clear and crisp, it's pure delight - A taste that's sure to excite - - Chorus: - Sparkling water, oh so fine - A drink that's always on my mind - With every sip, I feel alive - Sparkling water, you're my vibe - - Verse 2: - No sugar, no calories, just pure bliss - A drink that's hard to resist - It's the perfect way to quench my thirst - A drink that always comes first - - Chorus: - Sparkling water, oh so fine - A drink that's always on my mind - With every sip, I feel alive - Sparkling water, you're my vibe - - Bridge: - From the mountains to the sea - Sparkling water, you're the key - To a healthy life, a happy soul - A drink that makes me feel whole - - Chorus: - Sparkling water, oh so fine - A drink that's always on my mind - With every sip, I feel alive - Sparkling water, you're my vibe - - Outro: - Sparkling water, you're the one - A drink that's always so much fun - I'll never let you go, my friend - Sparkling -``` - - diff --git a/docs/vercel.json b/docs/vercel.json index cb9592b7bb5..035db509b31 100644 --- a/docs/vercel.json +++ b/docs/vercel.json @@ -1,5 +1,9 @@ { "redirects": [ + { + "source": "/docs/modules/model_io/chat/llm_chain", + "destination": "/docs/modules/chains/foundational/llm_chain" + }, { "source": "/docs/guides/langsmith(/?)", "destination": "/docs/langsmith/" diff --git a/libs/experimental/langchain_experimental/openai_assistant/base.py b/libs/experimental/langchain_experimental/openai_assistant/base.py index 265bdca70ab..60f6653b1b2 100644 --- a/libs/experimental/langchain_experimental/openai_assistant/base.py +++ b/libs/experimental/langchain_experimental/openai_assistant/base.py @@ -119,7 +119,6 @@ class OpenAIAssistantRunnable(RunnableSerializable[Dict, OutputType]): tool_outputs = [] for action in response: tool_output = tool_map[action.tool].invoke(action.tool_input) - print(action.tool, action.tool_input, tool_output, end="\n\n") tool_outputs.append({"output": tool_output, "tool_call_id": action.tool_call_id}) response = agent.invoke( {