forked from Archives/langchain
parent
3ec6400d70
commit
77c286cf02
@ -8,61 +8,16 @@ from datetime import datetime
|
|||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import requests
|
from langchainplus_sdk import LangChainPlusClient
|
||||||
from requests.exceptions import HTTPError
|
|
||||||
from tenacity import (
|
|
||||||
before_sleep_log,
|
|
||||||
retry,
|
|
||||||
retry_if_exception_type,
|
|
||||||
stop_after_attempt,
|
|
||||||
wait_exponential,
|
|
||||||
)
|
|
||||||
|
|
||||||
from langchain.callbacks.tracers.base import BaseTracer
|
from langchain.callbacks.tracers.base import BaseTracer
|
||||||
from langchain.callbacks.tracers.schemas import (
|
from langchain.callbacks.tracers.schemas import Run, RunTypeEnum, TracerSession
|
||||||
Run,
|
from langchain.env import get_runtime_environment
|
||||||
RunCreate,
|
|
||||||
RunTypeEnum,
|
|
||||||
RunUpdate,
|
|
||||||
TracerSession,
|
|
||||||
)
|
|
||||||
from langchain.schema import BaseMessage, messages_to_dict
|
from langchain.schema import BaseMessage, messages_to_dict
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_headers() -> Dict[str, Any]:
|
|
||||||
"""Get the headers for the LangChain API."""
|
|
||||||
headers: Dict[str, Any] = {"Content-Type": "application/json"}
|
|
||||||
if os.getenv("LANGCHAIN_API_KEY"):
|
|
||||||
headers["x-api-key"] = os.getenv("LANGCHAIN_API_KEY")
|
|
||||||
return headers
|
|
||||||
|
|
||||||
|
|
||||||
def get_endpoint() -> str:
|
|
||||||
return os.getenv("LANGCHAIN_ENDPOINT", "http://localhost:1984")
|
|
||||||
|
|
||||||
|
|
||||||
class LangChainTracerAPIError(Exception):
|
|
||||||
"""An error occurred while communicating with the LangChain API."""
|
|
||||||
|
|
||||||
|
|
||||||
class LangChainTracerUserError(Exception):
|
|
||||||
"""An error occurred while communicating with the LangChain API."""
|
|
||||||
|
|
||||||
|
|
||||||
class LangChainTracerError(Exception):
|
|
||||||
"""An error occurred while communicating with the LangChain API."""
|
|
||||||
|
|
||||||
|
|
||||||
retry_decorator = retry(
|
|
||||||
stop=stop_after_attempt(3),
|
|
||||||
wait=wait_exponential(multiplier=1, min=4, max=10),
|
|
||||||
retry=retry_if_exception_type(LangChainTracerAPIError),
|
|
||||||
before_sleep=before_sleep_log(logger, logging.WARNING),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LangChainTracer(BaseTracer):
|
class LangChainTracer(BaseTracer):
|
||||||
"""An implementation of the SharedTracer that POSTS to the langchain endpoint."""
|
"""An implementation of the SharedTracer that POSTS to the langchain endpoint."""
|
||||||
|
|
||||||
@ -70,19 +25,19 @@ class LangChainTracer(BaseTracer):
|
|||||||
self,
|
self,
|
||||||
example_id: Optional[Union[UUID, str]] = None,
|
example_id: Optional[Union[UUID, str]] = None,
|
||||||
session_name: Optional[str] = None,
|
session_name: Optional[str] = None,
|
||||||
|
client: Optional[LangChainPlusClient] = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the LangChain tracer."""
|
"""Initialize the LangChain tracer."""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.session: Optional[TracerSession] = None
|
self.session: Optional[TracerSession] = None
|
||||||
self._endpoint = get_endpoint()
|
|
||||||
self._headers = get_headers()
|
|
||||||
self.example_id = (
|
self.example_id = (
|
||||||
UUID(example_id) if isinstance(example_id, str) else example_id
|
UUID(example_id) if isinstance(example_id, str) else example_id
|
||||||
)
|
)
|
||||||
self.session_name = session_name or os.getenv("LANGCHAIN_SESSION", "default")
|
self.session_name = session_name or os.getenv("LANGCHAIN_SESSION", "default")
|
||||||
# set max_workers to 1 to process tasks in order
|
# set max_workers to 1 to process tasks in order
|
||||||
self.executor = ThreadPoolExecutor(max_workers=1)
|
self.executor = ThreadPoolExecutor(max_workers=1)
|
||||||
|
self.client = client or LangChainPlusClient()
|
||||||
|
|
||||||
def on_chat_model_start(
|
def on_chat_model_start(
|
||||||
self,
|
self,
|
||||||
@ -114,60 +69,19 @@ class LangChainTracer(BaseTracer):
|
|||||||
def _persist_run(self, run: Run) -> None:
|
def _persist_run(self, run: Run) -> None:
|
||||||
"""The Langchain Tracer uses Post/Patch rather than persist."""
|
"""The Langchain Tracer uses Post/Patch rather than persist."""
|
||||||
|
|
||||||
@retry_decorator
|
|
||||||
def _persist_run_single(self, run: Run) -> None:
|
def _persist_run_single(self, run: Run) -> None:
|
||||||
"""Persist a run."""
|
"""Persist a run."""
|
||||||
if run.parent_run_id is None:
|
if run.parent_run_id is None:
|
||||||
run.reference_example_id = self.example_id
|
run.reference_example_id = self.example_id
|
||||||
run_dict = run.dict()
|
run_dict = run.dict(exclude={"child_runs"})
|
||||||
del run_dict["child_runs"]
|
extra = run_dict.get("extra", {})
|
||||||
run_create = RunCreate(**run_dict, session_name=self.session_name)
|
extra["runtime"] = get_runtime_environment()
|
||||||
response = None
|
run_dict["extra"] = extra
|
||||||
try:
|
run = self.client.create_run(**run_dict, session_name=self.session_name)
|
||||||
# TODO: Add retries when async
|
|
||||||
response = requests.post(
|
|
||||||
f"{self._endpoint}/runs",
|
|
||||||
data=run_create.json(),
|
|
||||||
headers=self._headers,
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
except HTTPError as e:
|
|
||||||
if response is not None and response.status_code == 500:
|
|
||||||
raise LangChainTracerAPIError(
|
|
||||||
f"Failed to upsert persist run to LangChain API. {e}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise LangChainTracerUserError(
|
|
||||||
f"Failed to persist run to LangChain API. {e}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
raise LangChainTracerError(
|
|
||||||
f"Failed to persist run to LangChain API. {e}"
|
|
||||||
) from e
|
|
||||||
|
|
||||||
@retry_decorator
|
|
||||||
def _update_run_single(self, run: Run) -> None:
|
def _update_run_single(self, run: Run) -> None:
|
||||||
"""Update a run."""
|
"""Update a run."""
|
||||||
run_update = RunUpdate(**run.dict())
|
self.client.update_run(run.id, **run.dict())
|
||||||
response = None
|
|
||||||
try:
|
|
||||||
response = requests.patch(
|
|
||||||
f"{self._endpoint}/runs/{run.id}",
|
|
||||||
data=run_update.json(),
|
|
||||||
headers=self._headers,
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
except HTTPError as e:
|
|
||||||
if response is not None and response.status_code == 500:
|
|
||||||
raise LangChainTracerAPIError(
|
|
||||||
f"Failed to update run to LangChain API. {e}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise LangChainTracerUserError(f"Failed to run to LangChain API. {e}")
|
|
||||||
except Exception as e:
|
|
||||||
raise LangChainTracerError(
|
|
||||||
f"Failed to update run to LangChain API. {e}"
|
|
||||||
) from e
|
|
||||||
|
|
||||||
def _on_llm_start(self, run: Run) -> None:
|
def _on_llm_start(self, run: Run) -> None:
|
||||||
"""Persist an LLM run."""
|
"""Persist an LLM run."""
|
||||||
|
@ -2,12 +2,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Dict, Optional, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from langchain.callbacks.tracers.base import BaseTracer
|
from langchain.callbacks.tracers.base import BaseTracer
|
||||||
from langchain.callbacks.tracers.langchain import get_headers
|
|
||||||
from langchain.callbacks.tracers.schemas import (
|
from langchain.callbacks.tracers.schemas import (
|
||||||
ChainRun,
|
ChainRun,
|
||||||
LLMRun,
|
LLMRun,
|
||||||
@ -21,6 +20,14 @@ from langchain.schema import get_buffer_string
|
|||||||
from langchain.utils import raise_for_status_with_text
|
from langchain.utils import raise_for_status_with_text
|
||||||
|
|
||||||
|
|
||||||
|
def get_headers() -> Dict[str, Any]:
|
||||||
|
"""Get the headers for the LangChain API."""
|
||||||
|
headers: Dict[str, Any] = {"Content-Type": "application/json"}
|
||||||
|
if os.getenv("LANGCHAIN_API_KEY"):
|
||||||
|
headers["x-api-key"] = os.getenv("LANGCHAIN_API_KEY")
|
||||||
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def _get_endpoint() -> str:
|
def _get_endpoint() -> str:
|
||||||
return os.getenv("LANGCHAIN_ENDPOINT", "http://localhost:8000")
|
return os.getenv("LANGCHAIN_ENDPOINT", "http://localhost:8000")
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ def get_runtime_environment() -> dict:
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"library_version": __version__,
|
"library_version": __version__,
|
||||||
|
"library": "langchain",
|
||||||
"platform": platform.platform(),
|
"platform": platform.platform(),
|
||||||
"runtime": "python",
|
"runtime": "python",
|
||||||
"runtime_version": platform.python_version(),
|
"runtime_version": platform.python_version(),
|
||||||
|
18
poetry.lock
generated
18
poetry.lock
generated
@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "absl-py"
|
name = "absl-py"
|
||||||
@ -4005,14 +4005,14 @@ tests = ["pytest", "pytest-mock"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchainplus-sdk"
|
name = "langchainplus-sdk"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
description = "Client library to connect to the LangChainPlus LLM Tracing and Evaluation Platform."
|
description = "Client library to connect to the LangChainPlus LLM Tracing and Evaluation Platform."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.1,<4.0"
|
python-versions = ">=3.8.1,<4.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "langchainplus_sdk-0.0.6-py3-none-any.whl", hash = "sha256:43fe01c66442b88403c969b8812f6be81e023c0d2a6d5d3572a8d87961438658"},
|
{file = "langchainplus_sdk-0.0.7-py3-none-any.whl", hash = "sha256:aefc471058648bf9fc51f659117d33ef905d25a304d5a021f7e32c30f5921076"},
|
||||||
{file = "langchainplus_sdk-0.0.6.tar.gz", hash = "sha256:c911a98fd2d02baa48f742b7d700fd6a55f11c9a545ee5d66b08825940c9a32e"},
|
{file = "langchainplus_sdk-0.0.7.tar.gz", hash = "sha256:b58565bdcaf301d2e6e7dd8898f0b8ccf549a35476258e0c14d871d6de02d210"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -11340,13 +11340,13 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\
|
|||||||
cffi = ["cffi (>=1.11)"]
|
cffi = ["cffi (>=1.11)"]
|
||||||
|
|
||||||
[extras]
|
[extras]
|
||||||
all = ["anthropic", "cohere", "openai", "nlpcloud", "huggingface_hub", "jina", "manifest-ml", "elasticsearch", "opensearch-py", "google-search-results", "faiss-cpu", "sentence-transformers", "transformers", "spacy", "nltk", "wikipedia", "beautifulsoup4", "tiktoken", "torch", "jinja2", "pinecone-client", "pinecone-text", "pymongo", "weaviate-client", "redis", "google-api-python-client", "google-auth", "wolframalpha", "qdrant-client", "tensorflow-text", "pypdf", "networkx", "nomic", "aleph-alpha-client", "deeplake", "pgvector", "psycopg2-binary", "pyowm", "pytesseract", "html2text", "atlassian-python-api", "gptcache", "duckduckgo-search", "arxiv", "azure-identity", "clickhouse-connect", "azure-cosmos", "lancedb", "langkit", "lark", "pexpect", "pyvespa", "O365", "jq", "docarray", "steamship", "pdfminer-six", "lxml", "requests-toolbelt", "neo4j", "openlm", "azure-ai-formrecognizer", "azure-ai-vision", "azure-cognitiveservices-speech", "momento", "singlestoredb", "tigrisdb", "nebula3-python"]
|
all = ["O365", "aleph-alpha-client", "anthropic", "arxiv", "atlassian-python-api", "azure-ai-formrecognizer", "azure-ai-vision", "azure-cognitiveservices-speech", "azure-cosmos", "azure-identity", "beautifulsoup4", "clickhouse-connect", "cohere", "deeplake", "docarray", "duckduckgo-search", "elasticsearch", "faiss-cpu", "google-api-python-client", "google-auth", "google-search-results", "gptcache", "html2text", "huggingface_hub", "jina", "jinja2", "jq", "lancedb", "langkit", "lark", "lxml", "manifest-ml", "momento", "nebula3-python", "neo4j", "networkx", "nlpcloud", "nltk", "nomic", "openai", "openlm", "opensearch-py", "pdfminer-six", "pexpect", "pgvector", "pinecone-client", "pinecone-text", "psycopg2-binary", "pymongo", "pyowm", "pypdf", "pytesseract", "pyvespa", "qdrant-client", "redis", "requests-toolbelt", "sentence-transformers", "singlestoredb", "spacy", "steamship", "tensorflow-text", "tigrisdb", "tiktoken", "torch", "transformers", "weaviate-client", "wikipedia", "wolframalpha"]
|
||||||
azure = ["azure-identity", "azure-cosmos", "openai", "azure-core", "azure-ai-formrecognizer", "azure-ai-vision", "azure-cognitiveservices-speech"]
|
azure = ["azure-ai-formrecognizer", "azure-ai-vision", "azure-cognitiveservices-speech", "azure-core", "azure-cosmos", "azure-identity", "openai"]
|
||||||
cohere = ["cohere"]
|
cohere = ["cohere"]
|
||||||
docarray = ["docarray"]
|
docarray = ["docarray"]
|
||||||
embeddings = ["sentence-transformers"]
|
embeddings = ["sentence-transformers"]
|
||||||
extended-testing = ["beautifulsoup4", "bibtexparser", "chardet", "jq", "pdfminer-six", "pypdf", "pymupdf", "pypdfium2", "tqdm", "lxml", "atlassian-python-api", "beautifulsoup4", "pandas", "telethon", "psychicapi", "zep-python", "gql", "requests-toolbelt", "html2text", "py-trello", "scikit-learn", "pyspark"]
|
extended-testing = ["atlassian-python-api", "beautifulsoup4", "beautifulsoup4", "bibtexparser", "chardet", "gql", "html2text", "jq", "lxml", "pandas", "pdfminer-six", "psychicapi", "py-trello", "pymupdf", "pypdf", "pypdfium2", "pyspark", "requests-toolbelt", "scikit-learn", "telethon", "tqdm", "zep-python"]
|
||||||
llms = ["anthropic", "cohere", "openai", "openlm", "nlpcloud", "huggingface_hub", "manifest-ml", "torch", "transformers"]
|
llms = ["anthropic", "cohere", "huggingface_hub", "manifest-ml", "nlpcloud", "openai", "openlm", "torch", "transformers"]
|
||||||
openai = ["openai", "tiktoken"]
|
openai = ["openai", "tiktoken"]
|
||||||
qdrant = ["qdrant-client"]
|
qdrant = ["qdrant-client"]
|
||||||
text-helpers = ["chardet"]
|
text-helpers = ["chardet"]
|
||||||
@ -11354,4 +11354,4 @@ text-helpers = ["chardet"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.8.1,<4.0"
|
python-versions = ">=3.8.1,<4.0"
|
||||||
content-hash = "0da3585d7f3216764f396c162c8f9456423b9f80a6dc9af46040c3e5eec0b79e"
|
content-hash = "dbbaa2907bf2ac09ed111ce712772bba0fe56901627f41c53aef71ae5a38d1c6"
|
||||||
|
@ -105,7 +105,7 @@ singlestoredb = {version = "^0.6.1", optional = true}
|
|||||||
pyspark = {version = "^3.4.0", optional = true}
|
pyspark = {version = "^3.4.0", optional = true}
|
||||||
tigrisdb = {version = "^1.0.0b6", optional = true}
|
tigrisdb = {version = "^1.0.0b6", optional = true}
|
||||||
nebula3-python = {version = "^3.4.0", optional = true}
|
nebula3-python = {version = "^3.4.0", optional = true}
|
||||||
langchainplus-sdk = ">=0.0.6"
|
langchainplus-sdk = ">=0.0.7"
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.group.docs.dependencies]
|
[tool.poetry.group.docs.dependencies]
|
||||||
|
Loading…
Reference in New Issue
Block a user