Repository navigation
Add langchain samples #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| # LangChain Samples | ||
|
|
||
| These samples demonstrate how to use LangChain with OpenTelemetry tracing exported to Azure Monitor (Application Insights). | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Python 3.10+ | ||
| - An Azure OpenAI resource (or an OpenAI API key) | ||
| - An Application Insights resource (for the connection string) | ||
|
|
||
| ## Configuration | ||
|
|
||
| All samples require you to fill in placeholder values before running. | ||
|
|
||
| ### Option A: Azure OpenAI | ||
|
|
||
| Replace these placeholders in each sample file: | ||
|
|
||
| | Placeholder | Description | | ||
| |---|---| | ||
| | `<AZURE_OPENAI_ENDPOINT>` | Your Azure OpenAI endpoint URL (e.g., `https://<resource-name>.openai.azure.com/openai/deployments/<deployment-name>/v1`) | | ||
| | `<AZURE_OPENAI_API_KEY>` | Your Azure OpenAI API key | | ||
|
|
||
| ### Option B: OpenAI API Key | ||
|
|
||
| Set the environment variable `OPENAI_API_KEY` and remove the `api_key` and `base_url` parameters from the `ChatOpenAI(...)` calls in the sample files. | ||
|
|
||
| ### Azure Monitor Connection String | ||
|
|
||
| Replace `"InstrumentationKey=..."` with your full Application Insights connection string. You can find this in the Azure portal under your Application Insights resource > **Overview** > **Connection String**. Or you can | ||
| set it using the `APPLICATIONINISGHTS_CONNECTION_STRING` environment variable. | ||
|
|
||
| ## Samples | ||
|
|
||
| ### 1. `sample_opentelemetry.py` | ||
|
|
||
| Demonstrates the `opentelemetry-instrumentation-langchain` package with two differently configured LLMs (creative vs. precise). | ||
|
|
||
| **Placeholders to fill:** | ||
|
|
||
| | Placeholder | Value | | ||
| |---|---| | ||
| | `<AZURE_OPENAI_ENDPOINT>` | Azure OpenAI endpoint URL | | ||
| | `<AZURE_OPENAI_API_KEY>` | Azure OpenAI API key | | ||
|
|
||
| **What it does:** | ||
| - Creates two `ChatOpenAI` instances with different temperature/sampling settings | ||
| - Runs a multi-turn conversation (travel guide) | ||
| - Compares creative vs. precise outputs for the same prompt (haiku about observability) | ||
| - Each `invoke()` call produces its own OpenTelemetry span | ||
|
|
||
| **Run:** | ||
| ```bash | ||
| python sample_opentelemetry.py | ||
| ``` | ||
|
|
||
| ### 2. `sample_arise_langchain.py` | ||
|
|
||
| Demonstrates image description using a vision-capable model, with tracing via the `openinference-instrumentation-langchain` instrumentor. | ||
|
|
||
| **Placeholders to fill:** | ||
|
|
||
| | Placeholder | Value | | ||
| |---|---| | ||
| | `<AZURE_OPENAI_ENDPOINT>` | Azure OpenAI endpoint URL | | ||
| | `<AZURE_OPENAI_API_KEY>` | Azure OpenAI API key | | ||
| | `<IMAGE_URL>` | A publicly accessible URL to an image (e.g., `https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg`) | | ||
|
|
||
| **What it does:** | ||
| - Downloads and base64-encodes the image at the provided URL | ||
| - Sends a multimodal message (text + image) to the model | ||
| - Asks the model to describe the image | ||
|
|
||
| **Run:** | ||
| ```bash | ||
| python sample_arise_langchain.py | ||
| ``` | ||
|
|
||
| ### 3. `sample_langchain_azure.py` | ||
|
|
||
| Demonstrates a multi-agent travel planner using nested LangChain agents with the `AzureAIOpenTelemetryTracer`. | ||
|
|
||
| **Placeholders to fill:** | ||
|
|
||
| | Placeholder | Value | | ||
| |---|---| | ||
| | `<AZURE_OPENAI_ENDPOINT>` | Azure OpenAI endpoint URL | | ||
| | `<AZURE_OPENAI_API_KEY>` | Azure OpenAI API key | | ||
| | `"InstrumentationKey=..."` | Application Insights connection string | | ||
|
|
||
| **What it does:** | ||
| - Creates specialist agents for flights, hotels, and activities (with mock tool data) | ||
| - A coordinator agent delegates to the specialists to plan a weekend trip to Paris | ||
| - All agent calls are traced via the `AzureAIOpenTelemetryTracer` callback | ||
|
|
||
| **Run:** | ||
| ```bash | ||
| python sample_langchain_azure.py | ||
| ``` | ||
|
|
||
| ## Required Packages | ||
|
|
||
| ```bash | ||
| pip install langchain-openai langchain-core azure-monitor-opentelemetry httpx | ||
| # For sample_opentelemetry.py: | ||
| pip install opentelemetry-instrumentation-langchain | ||
|
|
||
| # For sample_arise_langchain.py: | ||
| pip install openinference-instrumentation-langchain | ||
|
|
||
| # For sample_langchain_azure.py: | ||
| pip install langchain-azure-ai langgraph | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # ------------------------------------------------------------------------- | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. See License.txt in the project root for | ||
| # license information. | ||
| # -------------------------------------------------------------------------- | ||
|
|
||
| import base64 | ||
| import httpx | ||
|
|
||
| from langchain_core.messages import HumanMessage | ||
| from langchain_openai import ChatOpenAI | ||
| from azure.monitor.opentelemetry import configure_azure_monitor | ||
|
|
||
| from openinference.instrumentation.langchain import LangChainInstrumentor | ||
|
|
||
| configure_azure_monitor(connection_string="InstrumentationKey=...") # TODO: This will be replaced with the opentelemetry distro | ||
|
|
||
| LangChainInstrumentor().instrument() | ||
|
|
||
| # If using Azure OpenAI endpoint and API KEY | ||
| endpoint = "<AZURE_OPENAI_ENDPOINT>" | ||
| model_name = "gpt-4.1" | ||
| api_key = "<AZURE_OPENAI_API_KEY>" | ||
|
|
||
| # Otherwise, set the env variable OPENAI_API_KEY | ||
|
|
||
| image_url = "<IMAGE_URL>" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to some URL here?, do we need a readme for samples so people understand how to run them?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the user can enter any URL they want the LLM to describe for them. Yes, I will add a readme. |
||
|
|
||
| model = ChatOpenAI(model=model_name, api_key=api_key, base_url=endpoint) # Do not include api_key and base_url if using the OPENAI_API_KEY environment variable | ||
| image_data = base64.b64encode(httpx.get(image_url).content).decode("utf-8") | ||
|
rads-1996 marked this conversation as resolved.
|
||
|
|
||
| message = HumanMessage( | ||
| content=[ | ||
| {"type": "text", "text": "describe this image"}, | ||
| { | ||
| "type": "image_url", | ||
| "image_url": {"url": f"data:image/jpeg;base64,{image_data}", "detail": "low"}, | ||
| }, | ||
| ], | ||
| ) | ||
|
|
||
| if __name__ == "__main__": | ||
| response = model.invoke([message]) | ||
| print(response.content) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| """Travel planner with nested agents — coordinator delegates to specialist agents.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import os | ||
|
rads-1996 marked this conversation as resolved.
|
||
| import random | ||
| from uuid import uuid4 | ||
|
|
||
| from azure.monitor.opentelemetry import configure_azure_monitor | ||
| from langchain_core.messages import HumanMessage | ||
| from langchain_core.tools import tool | ||
| from langchain_openai import ChatOpenAI | ||
| from langchain_azure_ai.callbacks.tracers import AzureAIOpenTelemetryTracer | ||
|
|
||
| try: | ||
| from langchain.agents import create_agent as create_react_agent | ||
| except ImportError: | ||
| from langgraph.prebuilt import create_react_agent | ||
|
|
||
| # If using Azure OpenAI endpoint and API KEY | ||
| endpoint = "<AZURE_OPENAI_ENDPOINT>" | ||
| api_key = "<AZURE_OPENAI_API_KEY>" | ||
| model_name = "gpt-4.1" | ||
|
|
||
| # Otherwise, set the env variable OPENAI_API_KEY | ||
|
|
||
| configure_azure_monitor( # TODO: This will be replaced with the opentelemetry distro | ||
| connection_string= | ||
| "InstrumentationKey=...", | ||
| ) | ||
|
rads-1996 marked this conversation as resolved.
|
||
|
|
||
| tracer = AzureAIOpenTelemetryTracer(name="travel_planner", provider_name="openai") | ||
|
|
||
|
|
||
| # --- Tools --- | ||
| @tool | ||
| def search_flights(origin: str, destination: str, date: str) -> str: | ||
| """Search for flights between two cities on a given date.""" | ||
| airline = random.choice(["SkyLine", "AeroJet", "CloudNine"]) | ||
| fare = random.randint(700, 1250) | ||
| return f"{airline} non-stop {origin} -> {destination}, {date} 09:05, fare ${fare}" | ||
|
|
||
|
|
||
| @tool | ||
| def search_hotels(destination: str, check_in: str, check_out: str) -> str: | ||
| """Search for hotels in a city for given dates.""" | ||
| hotel = random.choice(["Maison Azure", "Le Jardin", "Vista Royale"]) | ||
| rate = random.randint(220, 380) | ||
| return f"{hotel} in {destination}, ${rate}/night, {check_in} to {check_out}" | ||
|
|
||
|
|
||
| @tool | ||
| def search_activities(destination: str) -> str: | ||
| """Find popular activities in a destination city.""" | ||
| activities = { | ||
| "Paris": ["Eiffel Tower at sunset", "Seine dinner cruise", "Day trip to Versailles"], | ||
| "Tokyo": ["Sushi masterclass", "Ghibli Museum", "Hakone hot springs"], | ||
| "Rome": ["Colosseum tour", "Pasta masterclass", "Trastevere walk"], | ||
| } | ||
| items = activities.get(destination, ["Sightseeing", "Local cuisine", "Museum visit"]) | ||
| return "\n".join(f"- {a}" for a in items) | ||
|
|
||
|
|
||
| # --- Specialist Agents --- | ||
| def _make_llm(temperature: float = 0.3) -> ChatOpenAI: | ||
| return ChatOpenAI(model=model_name, api_key=api_key, base_url=endpoint, temperature=temperature) # Do not include api_key and base_url if using the OPENAI_API_KEY environment variable | ||
|
|
||
|
|
||
| flight_agent = create_react_agent(_make_llm(0.3), tools=[search_flights]) | ||
| hotel_agent = create_react_agent(_make_llm(0.3), tools=[search_hotels]) | ||
| activity_agent = create_react_agent(_make_llm(0.5), tools=[search_activities]) | ||
|
|
||
|
|
||
| # --- Coordinator tools that invoke sub-agents --- | ||
| @tool | ||
| def find_flights(origin: str, destination: str, date: str) -> str: | ||
| """Delegate to the flight specialist agent to find flights.""" | ||
| result = flight_agent.invoke( | ||
| {"messages": [HumanMessage(content=f"Find flights from {origin} to {destination} on {date}.")]}, | ||
| config={"callbacks": [tracer]}, | ||
| ) | ||
| return result["messages"][-1].content | ||
|
|
||
|
|
||
| @tool | ||
| def find_hotels(destination: str, check_in: str, check_out: str) -> str: | ||
| """Delegate to the hotel specialist agent to find hotels.""" | ||
| result = hotel_agent.invoke( | ||
| {"messages": [HumanMessage(content=f"Find a boutique hotel in {destination} from {check_in} to {check_out}.")]}, | ||
| config={"callbacks": [tracer]}, | ||
| ) | ||
| return result["messages"][-1].content | ||
|
|
||
|
|
||
| @tool | ||
| def find_activities(destination: str) -> str: | ||
| """Delegate to the activity specialist agent to find things to do.""" | ||
| result = activity_agent.invoke( | ||
| {"messages": [HumanMessage(content=f"Find fun activities in {destination}.")]}, | ||
| config={"callbacks": [tracer]}, | ||
| ) | ||
| return result["messages"][-1].content | ||
|
|
||
|
|
||
| # --- Coordinator Agent --- | ||
| coordinator = create_react_agent( | ||
| _make_llm(0.2), | ||
| tools=[find_flights, find_hotels, find_activities], | ||
| ) | ||
|
|
||
|
|
||
| def main(): | ||
| session_id = str(uuid4()) | ||
| user_request = ( | ||
| "Plan a weekend trip to Paris from Seattle next month. " | ||
| "Find flights, a boutique hotel, and fun activities." | ||
| ) | ||
|
|
||
| print("Travel Planner (Nested Agents)") | ||
| print("=" * 40) | ||
| print(f"Request: {user_request}\n") | ||
|
|
||
| result = coordinator.invoke( | ||
| {"messages": [HumanMessage(content=user_request)]}, | ||
| config={ | ||
| "metadata": {"session_id": session_id, "thread_id": session_id}, | ||
| "callbacks": [tracer], | ||
| }, | ||
| ) | ||
|
|
||
| final = result["messages"][-1].content | ||
| print("Plan:\n" + "-" * 40) | ||
| print(final) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
|
|
||
| from azure.monitor.opentelemetry import configure_azure_monitor | ||
| from opentelemetry.instrumentation.langchain import LangChainInstrumentor | ||
| from langchain_core.messages import AIMessage, HumanMessage, SystemMessage | ||
| from langchain_openai import ChatOpenAI | ||
|
|
||
| # This sample demonstrates the current state of the opentelemetry-instrumentation-langchain package (unreleased) and how it can be integrated with the opentelemetry distro | ||
| # If using Azure OpenAI endpoint and API KEY | ||
|
rads-1996 marked this conversation as resolved.
|
||
| endpoint = "<AZURE_OPENAI_ENDPOINT>" | ||
| model_name = "gpt-4.1" | ||
| api_key = "<AZURE_OPENAI_API_KEY>" | ||
|
|
||
| # Otherwise, set the env variable OPENAI_API_KEY | ||
|
|
||
| configure_azure_monitor() # TODO: This will be replaced with the opentelemetry distro | ||
|
rads-1996 marked this conversation as resolved.
|
||
| """ | ||
| configure_microsoft_opentelemetry( | ||
| connection_string="InstrumentationKey=...", | ||
| enable_genai_langchain=True, | ||
| ) | ||
| """ | ||
| LangChainInstrumentor().instrument() | ||
|
|
||
|
rads-1996 marked this conversation as resolved.
|
||
| # Two models with different configs — each call produces its own span | ||
| creative_llm = ChatOpenAI( | ||
| model=model_name, | ||
| temperature=0.9, | ||
| max_tokens=200, | ||
| top_p=0.95, | ||
| api_key=api_key, # Do not include if using the OPENAI_API_KEY environment variable | ||
| base_url=endpoint, # Do not include if using the OPENAI_API_KEY environment variable | ||
| ) | ||
|
|
||
| precise_llm = ChatOpenAI( | ||
| model=model_name, | ||
| temperature=0.0, | ||
| max_tokens=100, | ||
| top_p=0.1, | ||
| frequency_penalty=0.5, | ||
| presence_penalty=0.5, | ||
| seed=42, | ||
| api_key=api_key, # Do not include if using the OPENAI_API_KEY environment variable | ||
| base_url=endpoint, | ||
| ) | ||
|
|
||
|
|
||
| # --------------- Scenarios --------------- | ||
|
|
||
| def multi_turn_conversation(): | ||
| """Multi-turn chat — each invoke() is a separate instrumented span.""" | ||
| print("=== Multi-turn Conversation ===") | ||
| history = [ | ||
| SystemMessage(content="You are a travel guide. Be concise."), | ||
| HumanMessage(content="I'm planning a trip to Japan. Where should I start?"), | ||
| ] | ||
|
|
||
| response1 = creative_llm.invoke(history) | ||
| print(f"Turn 1: {response1.content}\n") | ||
|
|
||
| history.append(AIMessage(content=response1.content)) | ||
| history.append(HumanMessage(content="What food should I try there?")) | ||
|
|
||
| response2 = creative_llm.invoke(history) | ||
| print(f"Turn 2: {response2.content}\n") | ||
|
|
||
|
|
||
| def compare_temperatures(): | ||
| """Same prompt, different models — compare creative vs precise in telemetry.""" | ||
| print("=== Temperature Comparison ===") | ||
| messages = [ | ||
| SystemMessage(content="You are a poet."), | ||
| HumanMessage(content="Write a haiku about observability."), | ||
| ] | ||
|
|
||
| creative_result = creative_llm.invoke(messages) | ||
| print(f"Creative (temp=0.9): {creative_result.content}\n") | ||
|
|
||
| precise_result = precise_llm.invoke(messages) | ||
| print(f"Precise (temp=0.0): {precise_result.content}\n") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| multi_turn_conversation() | ||
| compare_temperatures() | ||
|
|
||
| LangChainInstrumentor().uninstrument() | ||
Uh oh!
There was an error while loading. Please reload this page.