Skip to content
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

feature(dspy): dspy-integration-with-langfuse #1186

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5d2728b
dspy-integration-with-langfuse
Jun 21, 2024
7941e3a
ollama support langfuse
Jun 22, 2024
8d02e99
ollama support langfuse
Jun 22, 2024
3890b9d
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jun 24, 2024
1164399
new BaseTracker && use LangfuseTracker
Jun 24, 2024
6063d0f
new BaseTracker && use LangfuseTracker && edit README.md
Jun 24, 2024
479e7a1
new BaseTracker && new LangfuseTracker && edit README.md
Jun 24, 2024
d000151
new BaseTracker && new LangfuseTracker && edit README.md
Jun 24, 2024
9f33208
new BaseTracker && new LangfuseTracker && edit README.md
Jun 24, 2024
c34a323
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jun 25, 2024
7dbeedb
langfuse:think of kwargs as metadata
Jun 25, 2024
16d6934
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jun 26, 2024
4d10a2d
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jun 28, 2024
2c78181
support tracker_decorator
Jul 4, 2024
f0fadac
support tracker_decorator
Jul 4, 2024
4341f2d
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jul 4, 2024
b23818b
support tracker_decorator
Jul 4, 2024
3f72c09
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jul 9, 2024
12af731
LM module adds tracker parameters & Mapping kwargs to metadata
Jul 9, 2024
b4ad853
tracker should be placed outside of kwargs(issubclass(args[0].tracker…
Jul 9, 2024
5aca3f2
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Jul 31, 2024
1af665f
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Aug 2, 2024
2ae10c7
Supports users to manually call the tracker.
Aug 3, 2024
0243368
Support manual call of tracker & supplementary document
Aug 4, 2024
6661e19
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Aug 9, 2024
2a73b0d
Support langfuse & add md file
Aug 13, 2024
9db9564
Merge branch 'main' of https://github.com/xucailiang/dspy into featur…
Aug 13, 2024
b9aa5b7
Support langfuse & add md file
Aug 14, 2024
c0853ec
Support langfuse & add md file
Aug 14, 2024
ea3d37a
Support langfuse & add md file
Aug 14, 2024
e542950
Update about_prompt_visible.md
arnavsinghvi11 Aug 15, 2024
bc0af45
Update gpt3.py
arnavsinghvi11 Aug 15, 2024
47a7c0a
Update azure_openai.py
arnavsinghvi11 Aug 15, 2024
500ff5e
Update azure_openai.py
arnavsinghvi11 Aug 15, 2024
78afb06
Update gpt3.py
arnavsinghvi11 Aug 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/api/language_model_clients/about_prompt_visible.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Prompt Visiblity through Langfuse

We have now integrated Langfuse as one of the trackers.

How to configure Langfuse?[Langfuse details](https://langfuse.com/docs/deployment/self-host) .

### Install Langfuse.

```shell
pip install langfuse
```

Additionally, configure the following environment variables: `LANGFUSE_SECRET_KEY`、`LANGFUSE_PUBLIC_KEY` and `LANGFUSE_HOST`.

If you are using **openai** or **azure_openai**, your LMs are configured.

For other LM providers, you need to configure the Langfuse tracker and call it manually.

### example

```python
import dspy
from dsp.trackers.langfuse_tracker import LangfuseTracker
# e.g:
# Assuming the environment variables have been set
langfuse = LangfuseTracker()
turbo = dspy.OllamaLocal()
dspy.settings.configure(lm=turbo)

completions = turbo("Hi,how's it going today?")
turbo.tracker_call(tracker=langfuse)
```

## Custom Tracker

We also provide `BaseTracker`: simply inherit it and override the `call()` method
```python
# custom_tracker.py
from dsp.trackers.base import BaseTracker

class CustomTracker(BaseTracker):

def call(self, *args, **kwargs):
pass

```
11 changes: 10 additions & 1 deletion dsp/modules/azure_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
from typing import Any, Callable, Literal, Optional, cast

import backoff
import openai

try:
"""
If there is any error in the langfuse configuration, it will turn to request the real address(openai or azure endpoint)
"""
import langfuse
from langfuse.openai import openai
logging.info(f"You are using Langfuse,version{langfuse.__version__}")
except:
import openai

from dsp.modules.cache_utils import CacheMemory, NotebookCacheMemory, cache_turn_on
from dsp.modules.lm import LM
Expand Down
11 changes: 9 additions & 2 deletions dsp/modules/gpt3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
import json
import logging
from typing import Any, Literal, Optional, cast

import backoff
import openai
import httpx
try:
"""
If there is any error in the langfuse configuration, it will turn to request the real address(openai or azure endpoint)
"""
import langfuse
from langfuse.openai import openai
logging.info(f"You are using Langfuse,version{langfuse.__version__}")
except:
import openai

from dsp.modules.cache_utils import CacheMemory, NotebookCacheMemory, cache_turn_on
from dsp.modules.lm import LM
Expand Down
19 changes: 17 additions & 2 deletions dsp/modules/lm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class LM(ABC):
"""Abstract class for language models."""

def __init__(self, model):
def __init__(self, model, tracker=None):
self.kwargs = {
"model": model,
"temperature": 0.0,
Expand All @@ -15,6 +15,7 @@ def __init__(self, model):
"n": 1,
}
self.provider = "default"
self.tracker = tracker

self.history = []

Expand Down Expand Up @@ -135,9 +136,23 @@ def inspect_history(self, n: int = 1, skip: int = 0, color_format: bool = True):
def __call__(self, prompt, only_completed=True, return_sorted=False, **kwargs):
pass

def tracker_call(self, tracker, prompt=None, output=None, name=None, **kwargs):
from dsp.trackers.base import BaseTracker
assert issubclass(tracker.__class__, BaseTracker), "tracker must be a subclass of BaseTracker"
assert self.history, "tracker.call() requires a previous request"

last_req = self.history[-1]
if not prompt:
prompt = last_req.get('prompt', None)
if not output:
output = last_req.get('response', None)
kwargs = {**self.kwargs, **kwargs}
name = name if name else self.__class__.__name__
tracker.call(i=prompt, o=output, name=name, **kwargs)

def copy(self, **kwargs):
"""Returns a copy of the language model with the same parameters."""
kwargs = {**self.kwargs, **kwargs}
model = kwargs.pop("model")

return self.__class__(model=model, **kwargs)
return self.__class__(model=model, **kwargs)
10 changes: 5 additions & 5 deletions dsp/modules/ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,18 @@ def basic_request(self, prompt: str, **kwargs):
"options": {k: v for k, v in kwargs.items() if k not in ["n", "max_tokens"]},
"stream": False,
}

# Set the format if it was defined
if self.format:
settings_dict["format"] = self.format

if self.model_type == "chat":
settings_dict["messages"] = [{"role": "user", "content": prompt}]
else:
# Overwrite system prompt defined in modelfile
if self.system:
settings_dict["system"] = self.system

settings_dict["prompt"] = prompt

urlstr = f"{self.base_url}/api/chat" if self.model_type == "chat" else f"{self.base_url}/api/generate"
Expand Down Expand Up @@ -195,7 +195,7 @@ def __call__(
completions = [self._get_choice_text(c) for c in choices]

return completions

def copy(self, **kwargs):
"""Returns a copy of the language model with the same parameters."""
kwargs = {**self.kwargs, **kwargs}
Expand All @@ -206,4 +206,4 @@ def copy(self, **kwargs):
base_url=self.base_url,
timeout_s=self.timeout_s,
**kwargs,
)
)
Empty file added dsp/trackers/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions dsp/trackers/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

class BaseTracker:
def __init__(self):
pass

@classmethod
def call(cls, *args, **kwargs):
pass
87 changes: 87 additions & 0 deletions dsp/trackers/langfuse_tracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from typing import Optional, Union, List, Any
import httpx
import logging
import os
from langfuse.client import Langfuse, StatefulTraceClient, StatefulSpanClient, StateType
from dsp.trackers.base import BaseTracker


class LangfuseTracker(BaseTracker):
log = logging.getLogger("langfuse")

def __init__(self, *, public_key: Optional[str] = None, secret_key: Optional[str] = None,
host: Optional[str] = None, debug: bool = False, stateful_client: Optional[
Union[StatefulTraceClient, StatefulSpanClient]
] = None, update_stateful_client: bool = False, version: Optional[str] = None,
session_id: Optional[str] = None, user_id: Optional[str] = None, trace_name: Optional[str] = None,
release: Optional[str] = None, metadata: Optional[Any] = None, tags: Optional[List[str]] = None,
threads: Optional[int] = None, flush_at: Optional[int] = None, flush_interval: Optional[int] = None,
max_retries: Optional[int] = None, timeout: Optional[int] = None, enabled: Optional[bool] = None,
httpx_client: Optional[httpx.Client] = None, sdk_integration: str = "default") -> None:
super().__init__()
self.version = version
self.session_id = session_id
self.user_id = user_id
self.trace_name = trace_name
self.release = release
self.metadata = metadata
self.tags = tags

self.root_span = None
self.update_stateful_client = update_stateful_client
self.langfuse = None

prio_public_key = public_key or os.environ.get("LANGFUSE_PUBLIC_KEY")
prio_secret_key = secret_key or os.environ.get("LANGFUSE_SECRET_KEY")
prio_host = host or os.environ.get(
"LANGFUSE_HOST", "https://cloud.langfuse.com"
)

if stateful_client and isinstance(stateful_client, StatefulTraceClient):
self.trace = stateful_client
self._task_manager = stateful_client.task_manager
return

elif stateful_client and isinstance(stateful_client, StatefulSpanClient):
self.root_span = stateful_client
self.trace = StatefulTraceClient(
stateful_client.client,
stateful_client.trace_id,
StateType.TRACE,
stateful_client.trace_id,
stateful_client.task_manager,
)
self._task_manager = stateful_client.task_manager
return

args = {
"public_key": prio_public_key,
"secret_key": prio_secret_key,
"host": prio_host,
"debug": debug,
}

if release is not None:
args["release"] = release
if threads is not None:
args["threads"] = threads
if flush_at is not None:
args["flush_at"] = flush_at
if flush_interval is not None:
args["flush_interval"] = flush_interval
if max_retries is not None:
args["max_retries"] = max_retries
if timeout is not None:
args["timeout"] = timeout
if enabled is not None:
args["enabled"] = enabled
if httpx_client is not None:
args["httpx_client"] = httpx_client
args["sdk_integration"] = sdk_integration

self.langfuse = Langfuse(**args)
self.trace: Optional[StatefulTraceClient] = None
self._task_manager = self.langfuse.task_manager

def call(self, i, o, name=None, **kwargs):
self.langfuse.trace(input=i, output=o, name=name, metadata=kwargs)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ requests
structlog
tqdm
ujson
httpx
magicattr~=0.1.6
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"snowflake": ["snowflake-snowpark-python"],
"fastembed": ["fastembed"],
"groq": ["groq~=0.8.0"],
},
"langfuse": ["langfuse~=2.36.1"]
},
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research",
Expand Down
Loading