variably-sdk 2.6.0__tar.gz → 2.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/PKG-INFO +143 -37
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/README.md +142 -36
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/pyproject.toml +1 -1
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/client.py +51 -33
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/observe.py +72 -42
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/version.py +1 -1
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably_sdk.egg-info/PKG-INFO +143 -37
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/setup.cfg +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/setup.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/__init__.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/cache.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/config.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/errors.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/http_client.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/logger.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably/types.py +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably_sdk.egg-info/SOURCES.txt +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably_sdk.egg-info/dependency_links.txt +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably_sdk.egg-info/requires.txt +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/src/variably_sdk.egg-info/top_level.txt +0 -0
- {variably_sdk-2.6.0 → variably_sdk-2.7.0}/tests/test_streaming.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: variably-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: Official Python SDK for Variably feature flags, LLM experimentation, and prompt optimization platform
|
|
5
5
|
Author: Variably
|
|
6
6
|
Author-email: Variably <support@variably.com>
|
|
@@ -45,7 +45,7 @@ Dynamic: requires-python
|
|
|
45
45
|
|
|
46
46
|
# Variably Python SDK
|
|
47
47
|
|
|
48
|
-
Official Python SDK for Variably —
|
|
48
|
+
Official Python SDK for Variably — LLM evaluation, experimentation, and prompt optimization.
|
|
49
49
|
|
|
50
50
|
## Installation
|
|
51
51
|
|
|
@@ -53,52 +53,158 @@ Official Python SDK for Variably — feature flags, LLM experimentation, and pro
|
|
|
53
53
|
pip install variably-sdk
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
For Docker/Kubernetes deployments, add to your `requirements.txt`:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
variably-sdk>=2.6.1
|
|
60
|
+
```
|
|
61
|
+
## Quick Start — Observe Mode
|
|
62
|
+
|
|
63
|
+
Add **one line** to your existing LLM app and get **multi-dimension evaluation** across 40+ metrics in 6 categories: Quality, Safety, Semantic, Grounding, Coherence, and Advanced.
|
|
64
|
+
|
|
65
|
+
No experiment setup. No prompt migration. Just log and see scores.
|
|
66
|
+
|
|
67
|
+
### 1. Set your environment variables
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
VARIABLY_API_KEY=vbl_your_key_here
|
|
71
|
+
VARIABLY_BASE_URL=https://api.variably.tech
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Add one line after your LLM call
|
|
57
75
|
|
|
58
76
|
```python
|
|
59
|
-
from variably import
|
|
77
|
+
from variably import observe
|
|
60
78
|
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
"api_key": "your-api-key",
|
|
64
|
-
"base_url": "https://api.variably.com", # optional, defaults to localhost:8080
|
|
65
|
-
"environment": "production" # optional
|
|
66
|
-
})
|
|
79
|
+
# Your existing code (unchanged)
|
|
80
|
+
response = your_llm_call(user_query)
|
|
67
81
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
82
|
+
# Add this line:
|
|
83
|
+
observe(prompt=user_query, response=response)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Auto-extract tokens & model from provider response
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
```python
|
|
89
|
+
# OpenAI
|
|
90
|
+
from openai import OpenAI
|
|
91
|
+
from variably import observe
|
|
92
|
+
|
|
93
|
+
client = OpenAI()
|
|
94
|
+
completion = client.chat.completions.create(
|
|
95
|
+
model="gpt-4o",
|
|
96
|
+
messages=[{"role": "user", "content": user_query}],
|
|
79
97
|
)
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
observe(
|
|
100
|
+
prompt=user_query,
|
|
101
|
+
response=completion.choices[0].message.content,
|
|
102
|
+
provider_response=completion, # auto-extracts model, tokens
|
|
103
|
+
)
|
|
104
|
+
```
|
|
84
105
|
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
```python
|
|
107
|
+
# Anthropic
|
|
108
|
+
import anthropic
|
|
109
|
+
from variably import observe
|
|
110
|
+
|
|
111
|
+
client = anthropic.Anthropic()
|
|
112
|
+
message = client.messages.create(
|
|
113
|
+
model="claude-sonnet-4-20250514",
|
|
114
|
+
max_tokens=1024,
|
|
115
|
+
messages=[{"role": "user", "content": user_query}],
|
|
116
|
+
)
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
})
|
|
118
|
+
observe(
|
|
119
|
+
prompt=user_query,
|
|
120
|
+
response=message.content[0].text,
|
|
121
|
+
provider_response=message, # auto-extracts model, tokens
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### RAG applications — grounding & hallucination scoring
|
|
97
126
|
|
|
98
|
-
|
|
99
|
-
|
|
127
|
+
```python
|
|
128
|
+
observe(
|
|
129
|
+
prompt=user_query,
|
|
130
|
+
response=llm_answer,
|
|
131
|
+
provider_response=completion,
|
|
132
|
+
reference_materials=[
|
|
133
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
134
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
135
|
+
],
|
|
136
|
+
retrieval_query=user_query,
|
|
137
|
+
)
|
|
100
138
|
```
|
|
101
139
|
|
|
140
|
+
### Multi-turn chat — coherence scoring
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
observe(
|
|
144
|
+
prompt=latest_user_message,
|
|
145
|
+
response=llm_answer,
|
|
146
|
+
provider_response=completion,
|
|
147
|
+
conversation_history=[
|
|
148
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
149
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
150
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
151
|
+
],
|
|
152
|
+
session_id="conv-123",
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### RAG applications — grounding & hallucination scoring
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
observe(
|
|
160
|
+
prompt=user_query,
|
|
161
|
+
response=llm_answer,
|
|
162
|
+
provider_response=completion,
|
|
163
|
+
reference_materials=[
|
|
164
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
165
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
166
|
+
],
|
|
167
|
+
retrieval_query=user_query,
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Multi-turn chat — coherence scoring
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
observe(
|
|
175
|
+
prompt=latest_user_message,
|
|
176
|
+
response=llm_answer,
|
|
177
|
+
provider_response=completion,
|
|
178
|
+
conversation_history=[
|
|
179
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
180
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
181
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
182
|
+
],
|
|
183
|
+
session_id="conv-123",
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Parameter | Type | Required | Description |
|
|
188
|
+
|-----------|------|----------|-------------|
|
|
189
|
+
| `prompt` | str | Yes | The user's input / question |
|
|
190
|
+
| `response` | str | Yes | The LLM's generated response |
|
|
191
|
+
| `provider_response` | object | No | Raw OpenAI/Anthropic/Google response — auto-extracts model, tokens |
|
|
192
|
+
| `model` | str | No | Model name (auto-extracted if provider_response given) |
|
|
193
|
+
| `provider` | str | No | "openai", "anthropic", etc. (auto-detected) |
|
|
194
|
+
| `latency_ms` | int | No | Response generation time in milliseconds |
|
|
195
|
+
| `prompt_tokens` | int | No | Input token count (auto-extracted if provider_response given) |
|
|
196
|
+
| `completion_tokens` | int | No | Output token count (auto-extracted) |
|
|
197
|
+
| `cost` | float | No | Cost in USD |
|
|
198
|
+
| `reference_materials` | list[dict] | No | RAG chunks: `[{"id", "content", "source"}]` — enables grounding scoring |
|
|
199
|
+
| `retrieval_query` | str | No | Query sent to retriever — enables retrieval quality scoring |
|
|
200
|
+
| `conversation_history` | list[dict] | No | Prior turns: `[{"role", "content"}]` — enables coherence scoring |
|
|
201
|
+
| `tags` | list[str] | No | Grouping labels, e.g. `["production", "rag"]` |
|
|
202
|
+
| `user_id` | str | No | Your user's ID |
|
|
203
|
+
| `session_id` | str | No | Conversation session ID (groups multi-turn) |
|
|
204
|
+
| `metadata` | dict | No | Any extra key-value data |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
102
208
|
## Prompt Experimentation
|
|
103
209
|
|
|
104
210
|
Variably provides two modes for LLM prompt experimentation:
|
|
@@ -293,7 +399,7 @@ result = client.submit_response(
|
|
|
293
399
|
| `workflow_history[].content` | `str` | Message content |
|
|
294
400
|
| `retrieval_query` | `str` (optional) | The rewritten query sent to the retriever |
|
|
295
401
|
|
|
296
|
-
See [Context-Aware RAG Evaluation](../../docs/concepts/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
402
|
+
See [Context-Aware RAG Evaluation](../../docs/concepts/LLM%20Evaluation/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
297
403
|
|
|
298
404
|
#### Integration with LangGraph / FastAPI streaming
|
|
299
405
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Variably Python SDK
|
|
2
2
|
|
|
3
|
-
Official Python SDK for Variably —
|
|
3
|
+
Official Python SDK for Variably — LLM evaluation, experimentation, and prompt optimization.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,52 +8,158 @@ Official Python SDK for Variably — feature flags, LLM experimentation, and pro
|
|
|
8
8
|
pip install variably-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For Docker/Kubernetes deployments, add to your `requirements.txt`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
variably-sdk>=2.6.1
|
|
15
|
+
```
|
|
16
|
+
## Quick Start — Observe Mode
|
|
17
|
+
|
|
18
|
+
Add **one line** to your existing LLM app and get **multi-dimension evaluation** across 40+ metrics in 6 categories: Quality, Safety, Semantic, Grounding, Coherence, and Advanced.
|
|
19
|
+
|
|
20
|
+
No experiment setup. No prompt migration. Just log and see scores.
|
|
21
|
+
|
|
22
|
+
### 1. Set your environment variables
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
VARIABLY_API_KEY=vbl_your_key_here
|
|
26
|
+
VARIABLY_BASE_URL=https://api.variably.tech
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Add one line after your LLM call
|
|
12
30
|
|
|
13
31
|
```python
|
|
14
|
-
from variably import
|
|
32
|
+
from variably import observe
|
|
15
33
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
"api_key": "your-api-key",
|
|
19
|
-
"base_url": "https://api.variably.com", # optional, defaults to localhost:8080
|
|
20
|
-
"environment": "production" # optional
|
|
21
|
-
})
|
|
34
|
+
# Your existing code (unchanged)
|
|
35
|
+
response = your_llm_call(user_query)
|
|
22
36
|
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
37
|
+
# Add this line:
|
|
38
|
+
observe(prompt=user_query, response=response)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Auto-extract tokens & model from provider response
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
```python
|
|
44
|
+
# OpenAI
|
|
45
|
+
from openai import OpenAI
|
|
46
|
+
from variably import observe
|
|
47
|
+
|
|
48
|
+
client = OpenAI()
|
|
49
|
+
completion = client.chat.completions.create(
|
|
50
|
+
model="gpt-4o",
|
|
51
|
+
messages=[{"role": "user", "content": user_query}],
|
|
34
52
|
)
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
observe(
|
|
55
|
+
prompt=user_query,
|
|
56
|
+
response=completion.choices[0].message.content,
|
|
57
|
+
provider_response=completion, # auto-extracts model, tokens
|
|
58
|
+
)
|
|
59
|
+
```
|
|
39
60
|
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
```python
|
|
62
|
+
# Anthropic
|
|
63
|
+
import anthropic
|
|
64
|
+
from variably import observe
|
|
65
|
+
|
|
66
|
+
client = anthropic.Anthropic()
|
|
67
|
+
message = client.messages.create(
|
|
68
|
+
model="claude-sonnet-4-20250514",
|
|
69
|
+
max_tokens=1024,
|
|
70
|
+
messages=[{"role": "user", "content": user_query}],
|
|
71
|
+
)
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
73
|
+
observe(
|
|
74
|
+
prompt=user_query,
|
|
75
|
+
response=message.content[0].text,
|
|
76
|
+
provider_response=message, # auto-extracts model, tokens
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### RAG applications — grounding & hallucination scoring
|
|
52
81
|
|
|
53
|
-
|
|
54
|
-
|
|
82
|
+
```python
|
|
83
|
+
observe(
|
|
84
|
+
prompt=user_query,
|
|
85
|
+
response=llm_answer,
|
|
86
|
+
provider_response=completion,
|
|
87
|
+
reference_materials=[
|
|
88
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
89
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
90
|
+
],
|
|
91
|
+
retrieval_query=user_query,
|
|
92
|
+
)
|
|
55
93
|
```
|
|
56
94
|
|
|
95
|
+
### Multi-turn chat — coherence scoring
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
observe(
|
|
99
|
+
prompt=latest_user_message,
|
|
100
|
+
response=llm_answer,
|
|
101
|
+
provider_response=completion,
|
|
102
|
+
conversation_history=[
|
|
103
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
104
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
105
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
106
|
+
],
|
|
107
|
+
session_id="conv-123",
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### RAG applications — grounding & hallucination scoring
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
observe(
|
|
115
|
+
prompt=user_query,
|
|
116
|
+
response=llm_answer,
|
|
117
|
+
provider_response=completion,
|
|
118
|
+
reference_materials=[
|
|
119
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
120
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
121
|
+
],
|
|
122
|
+
retrieval_query=user_query,
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Multi-turn chat — coherence scoring
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
observe(
|
|
130
|
+
prompt=latest_user_message,
|
|
131
|
+
response=llm_answer,
|
|
132
|
+
provider_response=completion,
|
|
133
|
+
conversation_history=[
|
|
134
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
135
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
136
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
137
|
+
],
|
|
138
|
+
session_id="conv-123",
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Parameter | Type | Required | Description |
|
|
143
|
+
|-----------|------|----------|-------------|
|
|
144
|
+
| `prompt` | str | Yes | The user's input / question |
|
|
145
|
+
| `response` | str | Yes | The LLM's generated response |
|
|
146
|
+
| `provider_response` | object | No | Raw OpenAI/Anthropic/Google response — auto-extracts model, tokens |
|
|
147
|
+
| `model` | str | No | Model name (auto-extracted if provider_response given) |
|
|
148
|
+
| `provider` | str | No | "openai", "anthropic", etc. (auto-detected) |
|
|
149
|
+
| `latency_ms` | int | No | Response generation time in milliseconds |
|
|
150
|
+
| `prompt_tokens` | int | No | Input token count (auto-extracted if provider_response given) |
|
|
151
|
+
| `completion_tokens` | int | No | Output token count (auto-extracted) |
|
|
152
|
+
| `cost` | float | No | Cost in USD |
|
|
153
|
+
| `reference_materials` | list[dict] | No | RAG chunks: `[{"id", "content", "source"}]` — enables grounding scoring |
|
|
154
|
+
| `retrieval_query` | str | No | Query sent to retriever — enables retrieval quality scoring |
|
|
155
|
+
| `conversation_history` | list[dict] | No | Prior turns: `[{"role", "content"}]` — enables coherence scoring |
|
|
156
|
+
| `tags` | list[str] | No | Grouping labels, e.g. `["production", "rag"]` |
|
|
157
|
+
| `user_id` | str | No | Your user's ID |
|
|
158
|
+
| `session_id` | str | No | Conversation session ID (groups multi-turn) |
|
|
159
|
+
| `metadata` | dict | No | Any extra key-value data |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
57
163
|
## Prompt Experimentation
|
|
58
164
|
|
|
59
165
|
Variably provides two modes for LLM prompt experimentation:
|
|
@@ -248,7 +354,7 @@ result = client.submit_response(
|
|
|
248
354
|
| `workflow_history[].content` | `str` | Message content |
|
|
249
355
|
| `retrieval_query` | `str` (optional) | The rewritten query sent to the retriever |
|
|
250
356
|
|
|
251
|
-
See [Context-Aware RAG Evaluation](../../docs/concepts/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
357
|
+
See [Context-Aware RAG Evaluation](../../docs/concepts/LLM%20Evaluation/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
252
358
|
|
|
253
359
|
#### Integration with LangGraph / FastAPI streaming
|
|
254
360
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "variably-sdk"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.7.0"
|
|
8
8
|
description = "Official Python SDK for Variably feature flags, LLM experimentation, and prompt optimization platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.7"
|
|
@@ -464,16 +464,26 @@ class VariablyClient:
|
|
|
464
464
|
experiment_key, dict(user_context), input_variables
|
|
465
465
|
)
|
|
466
466
|
|
|
467
|
+
# API returns nested structure: {"experiment": {...}, "selected_variant": {...}}
|
|
468
|
+
experiment = response.get("experiment", {})
|
|
469
|
+
variant = response.get("selected_variant", {})
|
|
470
|
+
params = variant.get("parameters", {})
|
|
471
|
+
|
|
472
|
+
# Extract model/provider from nested parameters.llmConfig
|
|
473
|
+
llm_config = params.get("llmConfig", params)
|
|
474
|
+
model = llm_config.get("model", "")
|
|
475
|
+
provider = llm_config.get("provider", "")
|
|
476
|
+
|
|
467
477
|
return PromptVariant(
|
|
468
|
-
experiment_id=
|
|
469
|
-
experiment_key=
|
|
470
|
-
variant_id=
|
|
471
|
-
variant_key=
|
|
472
|
-
prompt_template=
|
|
473
|
-
model=
|
|
474
|
-
provider=
|
|
475
|
-
parameters=
|
|
476
|
-
is_control=
|
|
478
|
+
experiment_id=experiment.get("experiment_id", experiment.get("id", "")),
|
|
479
|
+
experiment_key=experiment_key,
|
|
480
|
+
variant_id=variant.get("variant_id", variant.get("id", "")),
|
|
481
|
+
variant_key=variant.get("variant_key", variant.get("name", "")),
|
|
482
|
+
prompt_template=variant.get("prompt_template", variant.get("prompt", "")),
|
|
483
|
+
model=model,
|
|
484
|
+
provider=provider,
|
|
485
|
+
parameters=params,
|
|
486
|
+
is_control=variant.get("is_control", variant.get("isControl", False)),
|
|
477
487
|
)
|
|
478
488
|
|
|
479
489
|
def evaluate_prompt(
|
|
@@ -601,41 +611,49 @@ class VariablyClient:
|
|
|
601
611
|
prompt: Union[str, List[Dict[str, Any]]],
|
|
602
612
|
response: str,
|
|
603
613
|
*,
|
|
604
|
-
|
|
605
|
-
reference_materials: Optional[List[Dict[str, Any]]] = None,
|
|
606
|
-
retrieval_query: Optional[str] = None,
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
614
|
+
# RAG / Grounding context
|
|
615
|
+
reference_materials: Optional[List[Dict[str, Any]]] = None, # Retrieved docs for grounding scoring
|
|
616
|
+
retrieval_query: Optional[str] = None, # The actual search query (if rewritten/expanded)
|
|
617
|
+
# Multi-turn / Session context
|
|
618
|
+
session_id: Optional[str] = None, # Groups conversation turns into sessions
|
|
619
|
+
conversation_history: Optional[List[Dict[str, Any]]] = None, # Prior turns for coherence scoring
|
|
620
|
+
# User & organization context
|
|
621
|
+
user_id: Optional[str] = None, # End-user ID for per-user analytics
|
|
622
|
+
tags: Optional[List[str]] = None, # Grouping labels, e.g. ["production", "rag"]
|
|
623
|
+
metadata: Optional[Dict[str, Any]] = None, # Arbitrary key-value data
|
|
624
|
+
# LLM metadata
|
|
625
|
+
provider: Optional[str] = None, # e.g. "openai", "anthropic"
|
|
626
|
+
model: Optional[str] = None, # e.g. "gpt-4o", "claude-3.5-sonnet"
|
|
627
|
+
latency_ms: Optional[int] = None, # Response time in ms
|
|
628
|
+
prompt_tokens: Optional[int] = None, # Input token count
|
|
629
|
+
completion_tokens: Optional[int] = None, # Output token count
|
|
630
|
+
cost: Optional[float] = None, # Cost in USD
|
|
617
631
|
) -> LogResult:
|
|
618
|
-
"""Log a prompt/response pair for
|
|
632
|
+
"""Log a prompt/response pair for multi-dimensional evaluation (Observe Mode).
|
|
619
633
|
|
|
620
634
|
Zero-friction entry point — no experiment creation needed. Just log your
|
|
621
635
|
prompts and responses and see quality scores in the dashboard.
|
|
622
636
|
|
|
623
637
|
Args:
|
|
624
|
-
prompt: The
|
|
625
|
-
response: The
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
retrieval_query: The query sent to
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
638
|
+
prompt: The user's input / question (str or messages list).
|
|
639
|
+
response: The AI's generated response text.
|
|
640
|
+
reference_materials: Retrieved docs (RAG chunks) for grounding scoring.
|
|
641
|
+
Enables: faithfulness, hallucination rate, attribution accuracy.
|
|
642
|
+
retrieval_query: The query sent to your retriever/search.
|
|
643
|
+
If your pipeline rewrites queries, pass the rewritten version.
|
|
644
|
+
session_id: Conversation/thread ID — groups turns into sessions.
|
|
645
|
+
conversation_history: Prior turns for coherence scoring.
|
|
646
|
+
Each dict: {"role": "user"/"assistant", "content": "..."}.
|
|
647
|
+
Not needed if session_id is provided (auto-built from stored turns).
|
|
648
|
+
user_id: End-user ID for per-user quality analytics.
|
|
649
|
+
tags: Grouping labels for filtering (e.g. ["production", "chatbot"]).
|
|
650
|
+
metadata: Arbitrary key-value data attached to this evaluation.
|
|
632
651
|
provider: LLM provider name (e.g. "openai", "anthropic").
|
|
633
|
-
model: Model name (e.g. "gpt-
|
|
652
|
+
model: Model name (e.g. "gpt-4o", "claude-3.5-sonnet").
|
|
634
653
|
latency_ms: LLM call latency in milliseconds.
|
|
635
654
|
prompt_tokens: Number of input tokens.
|
|
636
655
|
completion_tokens: Number of output tokens.
|
|
637
656
|
cost: Cost in USD for this LLM call.
|
|
638
|
-
metadata: Arbitrary key-value metadata.
|
|
639
657
|
|
|
640
658
|
Returns:
|
|
641
659
|
LogResult with observation_id and status.
|
|
@@ -142,58 +142,85 @@ def observe(
|
|
|
142
142
|
prompt: str,
|
|
143
143
|
response: str,
|
|
144
144
|
*,
|
|
145
|
-
# Auto-extraction
|
|
145
|
+
# --- Auto-extraction ---
|
|
146
|
+
# Pass the raw LLM response object (OpenAI, Anthropic, Google).
|
|
147
|
+
# Model name, token counts, and provider are auto-detected — no manual setup needed.
|
|
146
148
|
provider_response: Any = None,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
#
|
|
155
|
-
|
|
149
|
+
|
|
150
|
+
# --- LLM metadata (manual overrides — take precedence over auto-extracted values) ---
|
|
151
|
+
model: Optional[str] = None, # e.g. "gpt-4o", "claude-3.5-sonnet"
|
|
152
|
+
provider: Optional[str] = None, # e.g. "openai", "anthropic", "google"
|
|
153
|
+
latency_ms: Optional[int] = None, # Response time in milliseconds
|
|
154
|
+
prompt_tokens: Optional[int] = None, # Input token count
|
|
155
|
+
completion_tokens: Optional[int] = None, # Output token count
|
|
156
|
+
cost: Optional[float] = None, # Cost in USD for this LLM call
|
|
157
|
+
|
|
158
|
+
# --- RAG / Grounding context ---
|
|
159
|
+
# Pass your retrieved documents to enable grounding scoring:
|
|
160
|
+
# faithfulness, hallucination rate, attribution accuracy, context utilization.
|
|
161
|
+
reference_materials: Optional[List[Dict[str, Any]]] = None, # [{"id": "chunk-1", "content": "...", "source": "docs.pdf"}]
|
|
162
|
+
# If your pipeline rewrites/expands queries before search, pass the actual search query here.
|
|
163
|
+
# Enables retrieval relevance scoring. If not provided, the raw prompt is used.
|
|
156
164
|
retrieval_query: Optional[str] = None,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
|
|
166
|
+
# --- Multi-turn / Session context ---
|
|
167
|
+
# Groups conversation turns into sessions. Enables session-level metrics,
|
|
168
|
+
# quality trend tracking, and automatic coherence scoring across turns.
|
|
169
|
+
# Use your conversation/thread ID — any unique string per conversation.
|
|
162
170
|
session_id: Optional[str] = None,
|
|
163
|
-
|
|
171
|
+
# Explicit prior turns for coherence scoring. Each dict: {"role": "user"/"assistant", "content": "..."}.
|
|
172
|
+
# Advanced: not needed if you pass session_id (variA/Bly auto-builds history from previous turns).
|
|
173
|
+
prior_turns: Optional[List[Dict[str, str]]] = None,
|
|
174
|
+
|
|
175
|
+
# --- User & organization context ---
|
|
176
|
+
user_id: Optional[str] = None, # Your end-user's ID — enables per-user analytics
|
|
177
|
+
tags: Optional[List[str]] = None, # Grouping labels, e.g. ["production", "rag", "v2"]
|
|
178
|
+
metadata: Optional[Dict[str, Any]] = None, # Any arbitrary key-value data for filtering
|
|
179
|
+
|
|
180
|
+
# --- Backward compatibility ---
|
|
181
|
+
conversation_history: Optional[List[Dict[str, str]]] = None, # Deprecated: use prior_turns instead
|
|
164
182
|
) -> Optional[Dict[str, Any]]:
|
|
165
|
-
"""Log a prompt/response pair to
|
|
183
|
+
"""Log a prompt/response pair to variA/Bly for multi-dimensional evaluation.
|
|
184
|
+
|
|
185
|
+
Add this one call after your LLM generates a response. All parameters are
|
|
186
|
+
optional except ``prompt`` and ``response``. The more context you provide,
|
|
187
|
+
the deeper the evaluation.
|
|
166
188
|
|
|
167
189
|
Never raises. Returns ``{"observation_id": "...", "status": "queued"}``
|
|
168
190
|
on success, or ``None`` on any error (missing API key, network failure, etc.).
|
|
169
191
|
|
|
170
192
|
Args:
|
|
171
|
-
prompt: The user's input / question
|
|
172
|
-
response: The
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
provider: Provider override (e.g. ``"openai"``).
|
|
179
|
-
Takes precedence over auto-detected value.
|
|
193
|
+
prompt: The user's input / question — exactly what the user typed.
|
|
194
|
+
response: The AI's generated response text.
|
|
195
|
+
|
|
196
|
+
provider_response: Raw LLM response object (OpenAI, Anthropic, Google).
|
|
197
|
+
Auto-extracts model name, token counts, and provider via duck typing.
|
|
198
|
+
|
|
199
|
+
model: Model name override (e.g. ``"gpt-4o"``). Overrides auto-extracted value.
|
|
200
|
+
provider: Provider override (e.g. ``"openai"``). Overrides auto-detected value.
|
|
180
201
|
latency_ms: Response generation time in milliseconds.
|
|
181
|
-
prompt_tokens: Input token count
|
|
182
|
-
|
|
183
|
-
completion_tokens: Output token count override.
|
|
184
|
-
Takes precedence over auto-extracted value.
|
|
202
|
+
prompt_tokens: Input token count. Overrides auto-extracted value.
|
|
203
|
+
completion_tokens: Output token count. Overrides auto-extracted value.
|
|
185
204
|
cost: Cost in USD for this LLM call.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
|
|
206
|
+
reference_materials: Retrieved documents (RAG chunks) for grounding scoring.
|
|
207
|
+
Enables: faithfulness, hallucination rate, attribution accuracy.
|
|
208
|
+
Each dict should have ``"id"``, ``"content"``, and optionally ``"source"``.
|
|
209
|
+
retrieval_query: The query your pipeline sent to the retriever/search.
|
|
210
|
+
If your pipeline rewrites queries before search, pass the rewritten version.
|
|
211
|
+
Enables accurate retrieval relevance scoring.
|
|
212
|
+
|
|
213
|
+
session_id: Conversation/thread ID — groups multi-turn interactions into sessions.
|
|
214
|
+
Enables: session tracing, quality trends, degradation detection, auto-coherence.
|
|
215
|
+
prior_turns: Explicit prior conversation turns for coherence scoring.
|
|
216
|
+
Each dict: ``{"role": "user"/"assistant", "content": "..."}``.
|
|
217
|
+
Not needed if you pass ``session_id`` (history is auto-built from stored turns).
|
|
218
|
+
|
|
219
|
+
user_id: Your end-user's ID for per-user quality analytics.
|
|
220
|
+
tags: Grouping labels for filtering (e.g. ``["production", "rag"]``).
|
|
221
|
+
metadata: Arbitrary key-value data attached to this evaluation.
|
|
222
|
+
|
|
223
|
+
conversation_history: Deprecated — use ``prior_turns`` instead.
|
|
197
224
|
|
|
198
225
|
Returns:
|
|
199
226
|
Dict with ``observation_id`` and ``status`` on success, or ``None``.
|
|
@@ -217,6 +244,9 @@ def observe(
|
|
|
217
244
|
else auto.get("completion_tokens")
|
|
218
245
|
)
|
|
219
246
|
|
|
247
|
+
# Resolve prior_turns: prefer prior_turns, fall back to deprecated conversation_history
|
|
248
|
+
resolved_prior_turns = prior_turns or conversation_history
|
|
249
|
+
|
|
220
250
|
result = client.log(
|
|
221
251
|
prompt=prompt,
|
|
222
252
|
response=response,
|
|
@@ -228,7 +258,7 @@ def observe(
|
|
|
228
258
|
cost=cost,
|
|
229
259
|
reference_materials=reference_materials,
|
|
230
260
|
retrieval_query=retrieval_query,
|
|
231
|
-
conversation_history=conversation_history
|
|
261
|
+
conversation_history=resolved_prior_turns, # client.log still uses conversation_history internally
|
|
232
262
|
tags=tags,
|
|
233
263
|
user_id=user_id,
|
|
234
264
|
session_id=session_id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: variably-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: Official Python SDK for Variably feature flags, LLM experimentation, and prompt optimization platform
|
|
5
5
|
Author: Variably
|
|
6
6
|
Author-email: Variably <support@variably.com>
|
|
@@ -45,7 +45,7 @@ Dynamic: requires-python
|
|
|
45
45
|
|
|
46
46
|
# Variably Python SDK
|
|
47
47
|
|
|
48
|
-
Official Python SDK for Variably —
|
|
48
|
+
Official Python SDK for Variably — LLM evaluation, experimentation, and prompt optimization.
|
|
49
49
|
|
|
50
50
|
## Installation
|
|
51
51
|
|
|
@@ -53,52 +53,158 @@ Official Python SDK for Variably — feature flags, LLM experimentation, and pro
|
|
|
53
53
|
pip install variably-sdk
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
For Docker/Kubernetes deployments, add to your `requirements.txt`:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
variably-sdk>=2.6.1
|
|
60
|
+
```
|
|
61
|
+
## Quick Start — Observe Mode
|
|
62
|
+
|
|
63
|
+
Add **one line** to your existing LLM app and get **multi-dimension evaluation** across 40+ metrics in 6 categories: Quality, Safety, Semantic, Grounding, Coherence, and Advanced.
|
|
64
|
+
|
|
65
|
+
No experiment setup. No prompt migration. Just log and see scores.
|
|
66
|
+
|
|
67
|
+
### 1. Set your environment variables
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
VARIABLY_API_KEY=vbl_your_key_here
|
|
71
|
+
VARIABLY_BASE_URL=https://api.variably.tech
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Add one line after your LLM call
|
|
57
75
|
|
|
58
76
|
```python
|
|
59
|
-
from variably import
|
|
77
|
+
from variably import observe
|
|
60
78
|
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
"api_key": "your-api-key",
|
|
64
|
-
"base_url": "https://api.variably.com", # optional, defaults to localhost:8080
|
|
65
|
-
"environment": "production" # optional
|
|
66
|
-
})
|
|
79
|
+
# Your existing code (unchanged)
|
|
80
|
+
response = your_llm_call(user_query)
|
|
67
81
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
82
|
+
# Add this line:
|
|
83
|
+
observe(prompt=user_query, response=response)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Auto-extract tokens & model from provider response
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
```python
|
|
89
|
+
# OpenAI
|
|
90
|
+
from openai import OpenAI
|
|
91
|
+
from variably import observe
|
|
92
|
+
|
|
93
|
+
client = OpenAI()
|
|
94
|
+
completion = client.chat.completions.create(
|
|
95
|
+
model="gpt-4o",
|
|
96
|
+
messages=[{"role": "user", "content": user_query}],
|
|
79
97
|
)
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
observe(
|
|
100
|
+
prompt=user_query,
|
|
101
|
+
response=completion.choices[0].message.content,
|
|
102
|
+
provider_response=completion, # auto-extracts model, tokens
|
|
103
|
+
)
|
|
104
|
+
```
|
|
84
105
|
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
```python
|
|
107
|
+
# Anthropic
|
|
108
|
+
import anthropic
|
|
109
|
+
from variably import observe
|
|
110
|
+
|
|
111
|
+
client = anthropic.Anthropic()
|
|
112
|
+
message = client.messages.create(
|
|
113
|
+
model="claude-sonnet-4-20250514",
|
|
114
|
+
max_tokens=1024,
|
|
115
|
+
messages=[{"role": "user", "content": user_query}],
|
|
116
|
+
)
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
})
|
|
118
|
+
observe(
|
|
119
|
+
prompt=user_query,
|
|
120
|
+
response=message.content[0].text,
|
|
121
|
+
provider_response=message, # auto-extracts model, tokens
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### RAG applications — grounding & hallucination scoring
|
|
97
126
|
|
|
98
|
-
|
|
99
|
-
|
|
127
|
+
```python
|
|
128
|
+
observe(
|
|
129
|
+
prompt=user_query,
|
|
130
|
+
response=llm_answer,
|
|
131
|
+
provider_response=completion,
|
|
132
|
+
reference_materials=[
|
|
133
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
134
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
135
|
+
],
|
|
136
|
+
retrieval_query=user_query,
|
|
137
|
+
)
|
|
100
138
|
```
|
|
101
139
|
|
|
140
|
+
### Multi-turn chat — coherence scoring
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
observe(
|
|
144
|
+
prompt=latest_user_message,
|
|
145
|
+
response=llm_answer,
|
|
146
|
+
provider_response=completion,
|
|
147
|
+
conversation_history=[
|
|
148
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
149
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
150
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
151
|
+
],
|
|
152
|
+
session_id="conv-123",
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### RAG applications — grounding & hallucination scoring
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
observe(
|
|
160
|
+
prompt=user_query,
|
|
161
|
+
response=llm_answer,
|
|
162
|
+
provider_response=completion,
|
|
163
|
+
reference_materials=[
|
|
164
|
+
{"id": "chunk-1", "content": "Retrieved text...", "source": "docs.pdf"},
|
|
165
|
+
{"id": "chunk-2", "content": "Another chunk...", "source": "faq.md"},
|
|
166
|
+
],
|
|
167
|
+
retrieval_query=user_query,
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Multi-turn chat — coherence scoring
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
observe(
|
|
175
|
+
prompt=latest_user_message,
|
|
176
|
+
response=llm_answer,
|
|
177
|
+
provider_response=completion,
|
|
178
|
+
conversation_history=[
|
|
179
|
+
{"role": "user", "content": "What is diabetes?"},
|
|
180
|
+
{"role": "assistant", "content": "Diabetes is a chronic condition..."},
|
|
181
|
+
{"role": "user", "content": "What are the symptoms?"},
|
|
182
|
+
],
|
|
183
|
+
session_id="conv-123",
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Parameter | Type | Required | Description |
|
|
188
|
+
|-----------|------|----------|-------------|
|
|
189
|
+
| `prompt` | str | Yes | The user's input / question |
|
|
190
|
+
| `response` | str | Yes | The LLM's generated response |
|
|
191
|
+
| `provider_response` | object | No | Raw OpenAI/Anthropic/Google response — auto-extracts model, tokens |
|
|
192
|
+
| `model` | str | No | Model name (auto-extracted if provider_response given) |
|
|
193
|
+
| `provider` | str | No | "openai", "anthropic", etc. (auto-detected) |
|
|
194
|
+
| `latency_ms` | int | No | Response generation time in milliseconds |
|
|
195
|
+
| `prompt_tokens` | int | No | Input token count (auto-extracted if provider_response given) |
|
|
196
|
+
| `completion_tokens` | int | No | Output token count (auto-extracted) |
|
|
197
|
+
| `cost` | float | No | Cost in USD |
|
|
198
|
+
| `reference_materials` | list[dict] | No | RAG chunks: `[{"id", "content", "source"}]` — enables grounding scoring |
|
|
199
|
+
| `retrieval_query` | str | No | Query sent to retriever — enables retrieval quality scoring |
|
|
200
|
+
| `conversation_history` | list[dict] | No | Prior turns: `[{"role", "content"}]` — enables coherence scoring |
|
|
201
|
+
| `tags` | list[str] | No | Grouping labels, e.g. `["production", "rag"]` |
|
|
202
|
+
| `user_id` | str | No | Your user's ID |
|
|
203
|
+
| `session_id` | str | No | Conversation session ID (groups multi-turn) |
|
|
204
|
+
| `metadata` | dict | No | Any extra key-value data |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
102
208
|
## Prompt Experimentation
|
|
103
209
|
|
|
104
210
|
Variably provides two modes for LLM prompt experimentation:
|
|
@@ -293,7 +399,7 @@ result = client.submit_response(
|
|
|
293
399
|
| `workflow_history[].content` | `str` | Message content |
|
|
294
400
|
| `retrieval_query` | `str` (optional) | The rewritten query sent to the retriever |
|
|
295
401
|
|
|
296
|
-
See [Context-Aware RAG Evaluation](../../docs/concepts/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
402
|
+
See [Context-Aware RAG Evaluation](../../docs/concepts/LLM%20Evaluation/context-aware-rag-evaluation.md) for the full concept doc with architecture diagrams and integration examples.
|
|
297
403
|
|
|
298
404
|
#### Integration with LangGraph / FastAPI streaming
|
|
299
405
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|