langchain-core 1.0.0a6__py3-none-any.whl → 1.0.3__py3-none-any.whl
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.
- langchain_core/__init__.py +1 -1
- langchain_core/_api/__init__.py +3 -4
- langchain_core/_api/beta_decorator.py +23 -26
- langchain_core/_api/deprecation.py +51 -64
- langchain_core/_api/path.py +3 -6
- langchain_core/_import_utils.py +3 -4
- langchain_core/agents.py +20 -22
- langchain_core/caches.py +65 -66
- langchain_core/callbacks/__init__.py +1 -8
- langchain_core/callbacks/base.py +321 -336
- langchain_core/callbacks/file.py +44 -44
- langchain_core/callbacks/manager.py +436 -513
- langchain_core/callbacks/stdout.py +29 -30
- langchain_core/callbacks/streaming_stdout.py +32 -32
- langchain_core/callbacks/usage.py +60 -57
- langchain_core/chat_history.py +53 -68
- langchain_core/document_loaders/base.py +27 -25
- langchain_core/document_loaders/blob_loaders.py +1 -1
- langchain_core/document_loaders/langsmith.py +44 -48
- langchain_core/documents/__init__.py +23 -3
- langchain_core/documents/base.py +98 -90
- langchain_core/documents/compressor.py +10 -10
- langchain_core/documents/transformers.py +34 -35
- langchain_core/embeddings/fake.py +50 -54
- langchain_core/example_selectors/length_based.py +1 -1
- langchain_core/example_selectors/semantic_similarity.py +28 -32
- langchain_core/exceptions.py +21 -20
- langchain_core/globals.py +3 -151
- langchain_core/indexing/__init__.py +1 -1
- langchain_core/indexing/api.py +121 -126
- langchain_core/indexing/base.py +73 -75
- langchain_core/indexing/in_memory.py +4 -6
- langchain_core/language_models/__init__.py +14 -29
- langchain_core/language_models/_utils.py +58 -61
- langchain_core/language_models/base.py +53 -162
- langchain_core/language_models/chat_models.py +298 -387
- langchain_core/language_models/fake.py +11 -11
- langchain_core/language_models/fake_chat_models.py +42 -36
- langchain_core/language_models/llms.py +125 -235
- langchain_core/load/dump.py +9 -12
- langchain_core/load/load.py +18 -28
- langchain_core/load/mapping.py +2 -4
- langchain_core/load/serializable.py +42 -40
- langchain_core/messages/__init__.py +10 -16
- langchain_core/messages/ai.py +148 -148
- langchain_core/messages/base.py +53 -51
- langchain_core/messages/block_translators/__init__.py +19 -22
- langchain_core/messages/block_translators/anthropic.py +6 -6
- langchain_core/messages/block_translators/bedrock_converse.py +5 -5
- langchain_core/messages/block_translators/google_genai.py +10 -7
- langchain_core/messages/block_translators/google_vertexai.py +4 -32
- langchain_core/messages/block_translators/groq.py +117 -21
- langchain_core/messages/block_translators/langchain_v0.py +5 -5
- langchain_core/messages/block_translators/openai.py +11 -11
- langchain_core/messages/chat.py +2 -6
- langchain_core/messages/content.py +337 -328
- langchain_core/messages/function.py +6 -10
- langchain_core/messages/human.py +24 -31
- langchain_core/messages/modifier.py +2 -2
- langchain_core/messages/system.py +19 -29
- langchain_core/messages/tool.py +74 -90
- langchain_core/messages/utils.py +474 -504
- langchain_core/output_parsers/__init__.py +13 -10
- langchain_core/output_parsers/base.py +61 -61
- langchain_core/output_parsers/format_instructions.py +9 -4
- langchain_core/output_parsers/json.py +12 -10
- langchain_core/output_parsers/list.py +21 -23
- langchain_core/output_parsers/openai_functions.py +49 -47
- langchain_core/output_parsers/openai_tools.py +16 -21
- langchain_core/output_parsers/pydantic.py +13 -14
- langchain_core/output_parsers/string.py +5 -5
- langchain_core/output_parsers/transform.py +15 -17
- langchain_core/output_parsers/xml.py +35 -34
- langchain_core/outputs/__init__.py +1 -1
- langchain_core/outputs/chat_generation.py +18 -18
- langchain_core/outputs/chat_result.py +1 -3
- langchain_core/outputs/generation.py +10 -11
- langchain_core/outputs/llm_result.py +10 -10
- langchain_core/prompt_values.py +11 -17
- langchain_core/prompts/__init__.py +3 -27
- langchain_core/prompts/base.py +48 -56
- langchain_core/prompts/chat.py +275 -325
- langchain_core/prompts/dict.py +5 -5
- langchain_core/prompts/few_shot.py +81 -88
- langchain_core/prompts/few_shot_with_templates.py +11 -13
- langchain_core/prompts/image.py +12 -14
- langchain_core/prompts/loading.py +4 -6
- langchain_core/prompts/message.py +3 -3
- langchain_core/prompts/prompt.py +24 -39
- langchain_core/prompts/string.py +26 -10
- langchain_core/prompts/structured.py +49 -53
- langchain_core/rate_limiters.py +51 -60
- langchain_core/retrievers.py +61 -198
- langchain_core/runnables/base.py +1476 -1626
- langchain_core/runnables/branch.py +53 -57
- langchain_core/runnables/config.py +72 -89
- langchain_core/runnables/configurable.py +120 -137
- langchain_core/runnables/fallbacks.py +83 -79
- langchain_core/runnables/graph.py +91 -97
- langchain_core/runnables/graph_ascii.py +27 -28
- langchain_core/runnables/graph_mermaid.py +38 -50
- langchain_core/runnables/graph_png.py +15 -16
- langchain_core/runnables/history.py +135 -148
- langchain_core/runnables/passthrough.py +124 -150
- langchain_core/runnables/retry.py +46 -51
- langchain_core/runnables/router.py +25 -30
- langchain_core/runnables/schema.py +75 -80
- langchain_core/runnables/utils.py +60 -67
- langchain_core/stores.py +85 -121
- langchain_core/structured_query.py +8 -8
- langchain_core/sys_info.py +27 -29
- langchain_core/tools/__init__.py +1 -14
- langchain_core/tools/base.py +284 -229
- langchain_core/tools/convert.py +160 -155
- langchain_core/tools/render.py +10 -10
- langchain_core/tools/retriever.py +12 -11
- langchain_core/tools/simple.py +19 -24
- langchain_core/tools/structured.py +32 -39
- langchain_core/tracers/__init__.py +1 -9
- langchain_core/tracers/base.py +97 -99
- langchain_core/tracers/context.py +29 -52
- langchain_core/tracers/core.py +49 -53
- langchain_core/tracers/evaluation.py +11 -11
- langchain_core/tracers/event_stream.py +65 -64
- langchain_core/tracers/langchain.py +21 -21
- langchain_core/tracers/log_stream.py +45 -45
- langchain_core/tracers/memory_stream.py +3 -3
- langchain_core/tracers/root_listeners.py +16 -16
- langchain_core/tracers/run_collector.py +2 -4
- langchain_core/tracers/schemas.py +0 -129
- langchain_core/tracers/stdout.py +3 -3
- langchain_core/utils/__init__.py +1 -4
- langchain_core/utils/_merge.py +2 -2
- langchain_core/utils/aiter.py +57 -61
- langchain_core/utils/env.py +9 -9
- langchain_core/utils/function_calling.py +89 -186
- langchain_core/utils/html.py +7 -8
- langchain_core/utils/input.py +6 -6
- langchain_core/utils/interactive_env.py +1 -1
- langchain_core/utils/iter.py +36 -40
- langchain_core/utils/json.py +4 -3
- langchain_core/utils/json_schema.py +9 -9
- langchain_core/utils/mustache.py +8 -10
- langchain_core/utils/pydantic.py +33 -35
- langchain_core/utils/strings.py +6 -9
- langchain_core/utils/usage.py +1 -1
- langchain_core/utils/utils.py +66 -62
- langchain_core/vectorstores/base.py +182 -216
- langchain_core/vectorstores/in_memory.py +101 -176
- langchain_core/vectorstores/utils.py +5 -5
- langchain_core/version.py +1 -1
- langchain_core-1.0.3.dist-info/METADATA +69 -0
- langchain_core-1.0.3.dist-info/RECORD +172 -0
- {langchain_core-1.0.0a6.dist-info → langchain_core-1.0.3.dist-info}/WHEEL +1 -1
- langchain_core/memory.py +0 -120
- langchain_core/messages/block_translators/ollama.py +0 -47
- langchain_core/prompts/pipeline.py +0 -138
- langchain_core/pydantic_v1/__init__.py +0 -30
- langchain_core/pydantic_v1/dataclasses.py +0 -23
- langchain_core/pydantic_v1/main.py +0 -23
- langchain_core/tracers/langchain_v1.py +0 -31
- langchain_core/utils/loading.py +0 -35
- langchain_core-1.0.0a6.dist-info/METADATA +0 -67
- langchain_core-1.0.0a6.dist-info/RECORD +0 -181
- langchain_core-1.0.0a6.dist-info/entry_points.txt +0 -4
langchain_core/prompts/string.py
CHANGED
|
@@ -4,8 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import warnings
|
|
6
6
|
from abc import ABC
|
|
7
|
+
from collections.abc import Callable, Sequence
|
|
7
8
|
from string import Formatter
|
|
8
|
-
from typing import Any,
|
|
9
|
+
from typing import Any, Literal
|
|
9
10
|
|
|
10
11
|
from pydantic import BaseModel, create_model
|
|
11
12
|
|
|
@@ -121,13 +122,16 @@ def mustache_formatter(template: str, /, **kwargs: Any) -> str:
|
|
|
121
122
|
def mustache_template_vars(
|
|
122
123
|
template: str,
|
|
123
124
|
) -> set[str]:
|
|
124
|
-
"""Get the variables from a mustache template.
|
|
125
|
+
"""Get the top-level variables from a mustache template.
|
|
126
|
+
|
|
127
|
+
For nested variables like `{{person.name}}`, only the top-level
|
|
128
|
+
key (`person`) is returned.
|
|
125
129
|
|
|
126
130
|
Args:
|
|
127
131
|
template: The template string.
|
|
128
132
|
|
|
129
133
|
Returns:
|
|
130
|
-
|
|
134
|
+
The top-level variables from the template.
|
|
131
135
|
"""
|
|
132
136
|
variables: set[str] = set()
|
|
133
137
|
section_depth = 0
|
|
@@ -148,9 +152,7 @@ def mustache_template_vars(
|
|
|
148
152
|
Defs = dict[str, "Defs"]
|
|
149
153
|
|
|
150
154
|
|
|
151
|
-
def mustache_schema(
|
|
152
|
-
template: str,
|
|
153
|
-
) -> type[BaseModel]:
|
|
155
|
+
def mustache_schema(template: str) -> type[BaseModel]:
|
|
154
156
|
"""Get the variables from a mustache template.
|
|
155
157
|
|
|
156
158
|
Args:
|
|
@@ -174,6 +176,11 @@ def mustache_schema(
|
|
|
174
176
|
fields[prefix] = False
|
|
175
177
|
elif type_ in {"variable", "no escape"}:
|
|
176
178
|
fields[prefix + tuple(key.split("."))] = True
|
|
179
|
+
|
|
180
|
+
for fkey, fval in fields.items():
|
|
181
|
+
fields[fkey] = fval and not any(
|
|
182
|
+
is_subsequence(fkey, k) for k in fields if k != fkey
|
|
183
|
+
)
|
|
177
184
|
defs: Defs = {} # None means leaf node
|
|
178
185
|
while fields:
|
|
179
186
|
field, is_leaf = fields.popitem()
|
|
@@ -272,10 +279,10 @@ class StringPromptTemplate(BasePromptTemplate, ABC):
|
|
|
272
279
|
|
|
273
280
|
@classmethod
|
|
274
281
|
def get_lc_namespace(cls) -> list[str]:
|
|
275
|
-
"""Get the namespace of the
|
|
282
|
+
"""Get the namespace of the LangChain object.
|
|
276
283
|
|
|
277
284
|
Returns:
|
|
278
|
-
|
|
285
|
+
`["langchain", "prompts", "base"]`
|
|
279
286
|
"""
|
|
280
287
|
return ["langchain", "prompts", "base"]
|
|
281
288
|
|
|
@@ -283,7 +290,7 @@ class StringPromptTemplate(BasePromptTemplate, ABC):
|
|
|
283
290
|
"""Format the prompt with the inputs.
|
|
284
291
|
|
|
285
292
|
Args:
|
|
286
|
-
kwargs: Any arguments to be passed to the prompt template.
|
|
293
|
+
**kwargs: Any arguments to be passed to the prompt template.
|
|
287
294
|
|
|
288
295
|
Returns:
|
|
289
296
|
A formatted string.
|
|
@@ -294,7 +301,7 @@ class StringPromptTemplate(BasePromptTemplate, ABC):
|
|
|
294
301
|
"""Async format the prompt with the inputs.
|
|
295
302
|
|
|
296
303
|
Args:
|
|
297
|
-
kwargs: Any arguments to be passed to the prompt template.
|
|
304
|
+
**kwargs: Any arguments to be passed to the prompt template.
|
|
298
305
|
|
|
299
306
|
Returns:
|
|
300
307
|
A formatted string.
|
|
@@ -326,3 +333,12 @@ class StringPromptTemplate(BasePromptTemplate, ABC):
|
|
|
326
333
|
def pretty_print(self) -> None:
|
|
327
334
|
"""Print a pretty representation of the prompt."""
|
|
328
335
|
print(self.pretty_repr(html=is_interactive_env())) # noqa: T201
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def is_subsequence(child: Sequence, parent: Sequence) -> bool:
|
|
339
|
+
"""Return True if child is subsequence of parent."""
|
|
340
|
+
if len(child) == 0 or len(parent) == 0:
|
|
341
|
+
return False
|
|
342
|
+
if len(parent) < len(child):
|
|
343
|
+
return False
|
|
344
|
+
return all(child[i] == parent[i] for i in range(len(child)))
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
"""Structured prompt template for a language model."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import AsyncIterator, Iterator, Mapping, Sequence
|
|
3
|
+
from collections.abc import AsyncIterator, Callable, Iterator, Mapping, Sequence
|
|
4
4
|
from typing import (
|
|
5
5
|
Any,
|
|
6
|
-
Callable,
|
|
7
|
-
Optional,
|
|
8
|
-
Union,
|
|
9
6
|
)
|
|
10
7
|
|
|
11
8
|
from pydantic import BaseModel, Field
|
|
@@ -31,16 +28,16 @@ from langchain_core.utils import get_pydantic_field_names
|
|
|
31
28
|
class StructuredPrompt(ChatPromptTemplate):
|
|
32
29
|
"""Structured prompt template for a language model."""
|
|
33
30
|
|
|
34
|
-
schema_:
|
|
31
|
+
schema_: dict | type
|
|
35
32
|
"""Schema for the structured prompt."""
|
|
36
33
|
structured_output_kwargs: dict[str, Any] = Field(default_factory=dict)
|
|
37
34
|
|
|
38
35
|
def __init__(
|
|
39
36
|
self,
|
|
40
37
|
messages: Sequence[MessageLikeRepresentation],
|
|
41
|
-
schema_:
|
|
38
|
+
schema_: dict | type[BaseModel] | None = None,
|
|
42
39
|
*,
|
|
43
|
-
structured_output_kwargs:
|
|
40
|
+
structured_output_kwargs: dict[str, Any] | None = None,
|
|
44
41
|
template_format: PromptTemplateFormat = "f-string",
|
|
45
42
|
**kwargs: Any,
|
|
46
43
|
) -> None:
|
|
@@ -66,13 +63,13 @@ class StructuredPrompt(ChatPromptTemplate):
|
|
|
66
63
|
|
|
67
64
|
@classmethod
|
|
68
65
|
def get_lc_namespace(cls) -> list[str]:
|
|
69
|
-
"""Get the namespace of the
|
|
66
|
+
"""Get the namespace of the LangChain object.
|
|
70
67
|
|
|
71
|
-
For example, if the class is
|
|
72
|
-
namespace is
|
|
68
|
+
For example, if the class is `langchain.llms.openai.OpenAI`, then the
|
|
69
|
+
namespace is `["langchain", "llms", "openai"]`
|
|
73
70
|
|
|
74
71
|
Returns:
|
|
75
|
-
The namespace of the
|
|
72
|
+
The namespace of the LangChain object.
|
|
76
73
|
"""
|
|
77
74
|
return cls.__module__.split(".")
|
|
78
75
|
|
|
@@ -80,7 +77,7 @@ class StructuredPrompt(ChatPromptTemplate):
|
|
|
80
77
|
def from_messages_and_schema(
|
|
81
78
|
cls,
|
|
82
79
|
messages: Sequence[MessageLikeRepresentation],
|
|
83
|
-
schema:
|
|
80
|
+
schema: dict | type,
|
|
84
81
|
**kwargs: Any,
|
|
85
82
|
) -> ChatPromptTemplate:
|
|
86
83
|
"""Create a chat prompt template from a variety of message formats.
|
|
@@ -88,71 +85,70 @@ class StructuredPrompt(ChatPromptTemplate):
|
|
|
88
85
|
Examples:
|
|
89
86
|
Instantiation from a list of message templates:
|
|
90
87
|
|
|
91
|
-
|
|
88
|
+
```python
|
|
89
|
+
from langchain_core.prompts import StructuredPrompt
|
|
92
90
|
|
|
93
|
-
from langchain_core.prompts import StructuredPrompt
|
|
94
91
|
|
|
92
|
+
class OutputSchema(BaseModel):
|
|
93
|
+
name: str
|
|
94
|
+
value: int
|
|
95
95
|
|
|
96
|
-
class OutputSchema(BaseModel):
|
|
97
|
-
name: str
|
|
98
|
-
value: int
|
|
99
96
|
|
|
97
|
+
template = StructuredPrompt(
|
|
98
|
+
[
|
|
99
|
+
("human", "Hello, how are you?"),
|
|
100
|
+
("ai", "I'm doing well, thanks!"),
|
|
101
|
+
("human", "That's good to hear."),
|
|
102
|
+
],
|
|
103
|
+
OutputSchema,
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
Args:
|
|
107
|
+
messages: Sequence of message representations.
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
[
|
|
103
|
-
("human", "Hello, how are you?"),
|
|
104
|
-
("ai", "I'm doing well, thanks!"),
|
|
105
|
-
("human", "That's good to hear."),
|
|
106
|
-
],
|
|
107
|
-
OutputSchema,
|
|
108
|
-
)
|
|
109
|
+
A message can be represented using the following formats:
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
schema:
|
|
118
|
-
kwargs: Any additional kwargs to pass through to
|
|
119
|
-
|
|
111
|
+
1. `BaseMessagePromptTemplate`
|
|
112
|
+
2. `BaseMessage`
|
|
113
|
+
3. 2-tuple of `(message type, template)`; e.g.,
|
|
114
|
+
`("human", "{user_input}")`
|
|
115
|
+
4. 2-tuple of `(message class, template)`
|
|
116
|
+
5. A string which is shorthand for `("human", template)`; e.g.,
|
|
117
|
+
`"{user_input}"`
|
|
118
|
+
schema: A dictionary representation of function call, or a Pydantic model.
|
|
119
|
+
**kwargs: Any additional kwargs to pass through to
|
|
120
|
+
`ChatModel.with_structured_output(schema, **kwargs)`.
|
|
120
121
|
|
|
121
122
|
Returns:
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
A structured prompt template
|
|
124
124
|
"""
|
|
125
125
|
return cls(messages, schema, **kwargs)
|
|
126
126
|
|
|
127
127
|
@override
|
|
128
128
|
def __or__(
|
|
129
129
|
self,
|
|
130
|
-
other:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Mapping[str, Union[Runnable[Any, Other], Callable[[Any], Other], Any]],
|
|
136
|
-
],
|
|
130
|
+
other: Runnable[Any, Other]
|
|
131
|
+
| Callable[[Iterator[Any]], Iterator[Other]]
|
|
132
|
+
| Callable[[AsyncIterator[Any]], AsyncIterator[Other]]
|
|
133
|
+
| Callable[[Any], Other]
|
|
134
|
+
| Mapping[str, Runnable[Any, Other] | Callable[[Any], Other] | Any],
|
|
137
135
|
) -> RunnableSerializable[dict, Other]:
|
|
138
136
|
return self.pipe(other)
|
|
139
137
|
|
|
140
138
|
def pipe(
|
|
141
139
|
self,
|
|
142
|
-
*others:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
],
|
|
149
|
-
name: Optional[str] = None,
|
|
140
|
+
*others: Runnable[Any, Other]
|
|
141
|
+
| Callable[[Iterator[Any]], Iterator[Other]]
|
|
142
|
+
| Callable[[AsyncIterator[Any]], AsyncIterator[Other]]
|
|
143
|
+
| Callable[[Any], Other]
|
|
144
|
+
| Mapping[str, Runnable[Any, Other] | Callable[[Any], Other] | Any],
|
|
145
|
+
name: str | None = None,
|
|
150
146
|
) -> RunnableSerializable[dict, Other]:
|
|
151
147
|
"""Pipe the structured prompt to a language model.
|
|
152
148
|
|
|
153
149
|
Args:
|
|
154
150
|
others: The language model to pipe the structured prompt to.
|
|
155
|
-
name: The name of the pipeline.
|
|
151
|
+
name: The name of the pipeline.
|
|
156
152
|
|
|
157
153
|
Returns:
|
|
158
154
|
A RunnableSequence object.
|
langchain_core/rate_limiters.py
CHANGED
|
@@ -6,7 +6,6 @@ import abc
|
|
|
6
6
|
import asyncio
|
|
7
7
|
import threading
|
|
8
8
|
import time
|
|
9
|
-
from typing import Optional
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class BaseRateLimiter(abc.ABC):
|
|
@@ -22,11 +21,8 @@ class BaseRateLimiter(abc.ABC):
|
|
|
22
21
|
Current limitations:
|
|
23
22
|
|
|
24
23
|
- Rate limiting information is not surfaced in tracing or callbacks. This means
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.. versionadded:: 0.2.24
|
|
24
|
+
that the total time it takes to invoke a chat model will encompass both
|
|
25
|
+
the time spent waiting for tokens and the time spent making the request.
|
|
30
26
|
"""
|
|
31
27
|
|
|
32
28
|
@abc.abstractmethod
|
|
@@ -34,18 +30,18 @@ class BaseRateLimiter(abc.ABC):
|
|
|
34
30
|
"""Attempt to acquire the necessary tokens for the rate limiter.
|
|
35
31
|
|
|
36
32
|
This method blocks until the required tokens are available if `blocking`
|
|
37
|
-
is set to True
|
|
33
|
+
is set to `True`.
|
|
38
34
|
|
|
39
|
-
If `blocking` is set to False
|
|
35
|
+
If `blocking` is set to `False`, the method will immediately return the result
|
|
40
36
|
of the attempt to acquire the tokens.
|
|
41
37
|
|
|
42
38
|
Args:
|
|
43
|
-
blocking: If True
|
|
44
|
-
If False
|
|
45
|
-
the attempt.
|
|
39
|
+
blocking: If `True`, the method will block until the tokens are available.
|
|
40
|
+
If `False`, the method will return immediately with the result of
|
|
41
|
+
the attempt.
|
|
46
42
|
|
|
47
43
|
Returns:
|
|
48
|
-
|
|
44
|
+
`True` if the tokens were successfully acquired, `False` otherwise.
|
|
49
45
|
"""
|
|
50
46
|
|
|
51
47
|
@abc.abstractmethod
|
|
@@ -53,18 +49,18 @@ class BaseRateLimiter(abc.ABC):
|
|
|
53
49
|
"""Attempt to acquire the necessary tokens for the rate limiter.
|
|
54
50
|
|
|
55
51
|
This method blocks until the required tokens are available if `blocking`
|
|
56
|
-
is set to True
|
|
52
|
+
is set to `True`.
|
|
57
53
|
|
|
58
|
-
If `blocking` is set to False
|
|
54
|
+
If `blocking` is set to `False`, the method will immediately return the result
|
|
59
55
|
of the attempt to acquire the tokens.
|
|
60
56
|
|
|
61
57
|
Args:
|
|
62
|
-
blocking: If True
|
|
63
|
-
If False
|
|
64
|
-
the attempt.
|
|
58
|
+
blocking: If `True`, the method will block until the tokens are available.
|
|
59
|
+
If `False`, the method will return immediately with the result of
|
|
60
|
+
the attempt.
|
|
65
61
|
|
|
66
62
|
Returns:
|
|
67
|
-
|
|
63
|
+
`True` if the tokens were successfully acquired, `False` otherwise.
|
|
68
64
|
"""
|
|
69
65
|
|
|
70
66
|
|
|
@@ -85,45 +81,40 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
85
81
|
not enough tokens in the bucket, the request is blocked until there are
|
|
86
82
|
enough tokens.
|
|
87
83
|
|
|
88
|
-
These
|
|
84
|
+
These tokens have nothing to do with LLM tokens. They are just
|
|
89
85
|
a way to keep track of how many requests can be made at a given time.
|
|
90
86
|
|
|
91
87
|
Current limitations:
|
|
92
88
|
|
|
93
89
|
- The rate limiter is not designed to work across different processes. It is
|
|
94
|
-
|
|
90
|
+
an in-memory rate limiter, but it is thread safe.
|
|
95
91
|
- The rate limiter only supports time-based rate limiting. It does not take
|
|
96
|
-
|
|
92
|
+
into account the size of the request or any other factors.
|
|
97
93
|
|
|
98
94
|
Example:
|
|
95
|
+
```python
|
|
96
|
+
import time
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
import time
|
|
103
|
-
|
|
104
|
-
from langchain_core.rate_limiters import InMemoryRateLimiter
|
|
105
|
-
|
|
106
|
-
rate_limiter = InMemoryRateLimiter(
|
|
107
|
-
requests_per_second=0.1, # <-- Can only make a request once every 10 seconds!!
|
|
108
|
-
check_every_n_seconds=0.1, # Wake up every 100 ms to check whether allowed to make a request,
|
|
109
|
-
max_bucket_size=10, # Controls the maximum burst size.
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
from langchain_anthropic import ChatAnthropic
|
|
113
|
-
|
|
114
|
-
model = ChatAnthropic(
|
|
115
|
-
model_name="claude-3-opus-20240229", rate_limiter=rate_limiter
|
|
116
|
-
)
|
|
98
|
+
from langchain_core.rate_limiters import InMemoryRateLimiter
|
|
117
99
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
100
|
+
rate_limiter = InMemoryRateLimiter(
|
|
101
|
+
requests_per_second=0.1, # <-- Can only make a request once every 10 seconds!!
|
|
102
|
+
check_every_n_seconds=0.1, # Wake up every 100 ms to check whether allowed to make a request,
|
|
103
|
+
max_bucket_size=10, # Controls the maximum burst size.
|
|
104
|
+
)
|
|
123
105
|
|
|
106
|
+
from langchain_anthropic import ChatAnthropic
|
|
124
107
|
|
|
125
|
-
|
|
108
|
+
model = ChatAnthropic(
|
|
109
|
+
model_name="claude-sonnet-4-5-20250929", rate_limiter=rate_limiter
|
|
110
|
+
)
|
|
126
111
|
|
|
112
|
+
for _ in range(5):
|
|
113
|
+
tic = time.time()
|
|
114
|
+
model.invoke("hello")
|
|
115
|
+
toc = time.time()
|
|
116
|
+
print(toc - tic)
|
|
117
|
+
```
|
|
127
118
|
""" # noqa: E501
|
|
128
119
|
|
|
129
120
|
def __init__(
|
|
@@ -135,7 +126,7 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
135
126
|
) -> None:
|
|
136
127
|
"""A rate limiter based on a token bucket.
|
|
137
128
|
|
|
138
|
-
These
|
|
129
|
+
These tokens have nothing to do with LLM tokens. They are just
|
|
139
130
|
a way to keep track of how many requests can be made at a given time.
|
|
140
131
|
|
|
141
132
|
This rate limiter is designed to work in a threaded environment.
|
|
@@ -148,11 +139,11 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
148
139
|
Args:
|
|
149
140
|
requests_per_second: The number of tokens to add per second to the bucket.
|
|
150
141
|
The tokens represent "credit" that can be used to make requests.
|
|
151
|
-
check_every_n_seconds:
|
|
142
|
+
check_every_n_seconds: Check whether the tokens are available
|
|
152
143
|
every this many seconds. Can be a float to represent
|
|
153
144
|
fractions of a second.
|
|
154
145
|
max_bucket_size: The maximum number of tokens that can be in the bucket.
|
|
155
|
-
Must be at least 1
|
|
146
|
+
Must be at least `1`. Used to prevent bursts of requests.
|
|
156
147
|
"""
|
|
157
148
|
# Number of requests that we can make per second.
|
|
158
149
|
self.requests_per_second = requests_per_second
|
|
@@ -163,7 +154,7 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
163
154
|
# at a given time.
|
|
164
155
|
self._consume_lock = threading.Lock()
|
|
165
156
|
# The last time we tried to consume tokens.
|
|
166
|
-
self.last:
|
|
157
|
+
self.last: float | None = None
|
|
167
158
|
self.check_every_n_seconds = check_every_n_seconds
|
|
168
159
|
|
|
169
160
|
def _consume(self) -> bool:
|
|
@@ -202,18 +193,18 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
202
193
|
"""Attempt to acquire a token from the rate limiter.
|
|
203
194
|
|
|
204
195
|
This method blocks until the required tokens are available if `blocking`
|
|
205
|
-
is set to True
|
|
196
|
+
is set to `True`.
|
|
206
197
|
|
|
207
|
-
If `blocking` is set to False
|
|
198
|
+
If `blocking` is set to `False`, the method will immediately return the result
|
|
208
199
|
of the attempt to acquire the tokens.
|
|
209
200
|
|
|
210
201
|
Args:
|
|
211
|
-
blocking: If True
|
|
212
|
-
If False
|
|
213
|
-
the attempt.
|
|
202
|
+
blocking: If `True`, the method will block until the tokens are available.
|
|
203
|
+
If `False`, the method will return immediately with the result of
|
|
204
|
+
the attempt.
|
|
214
205
|
|
|
215
206
|
Returns:
|
|
216
|
-
|
|
207
|
+
`True` if the tokens were successfully acquired, `False` otherwise.
|
|
217
208
|
"""
|
|
218
209
|
if not blocking:
|
|
219
210
|
return self._consume()
|
|
@@ -226,18 +217,18 @@ class InMemoryRateLimiter(BaseRateLimiter):
|
|
|
226
217
|
"""Attempt to acquire a token from the rate limiter. Async version.
|
|
227
218
|
|
|
228
219
|
This method blocks until the required tokens are available if `blocking`
|
|
229
|
-
is set to True
|
|
220
|
+
is set to `True`.
|
|
230
221
|
|
|
231
|
-
If `blocking` is set to False
|
|
222
|
+
If `blocking` is set to `False`, the method will immediately return the result
|
|
232
223
|
of the attempt to acquire the tokens.
|
|
233
224
|
|
|
234
225
|
Args:
|
|
235
|
-
blocking: If True
|
|
236
|
-
If False
|
|
237
|
-
the attempt.
|
|
226
|
+
blocking: If `True`, the method will block until the tokens are available.
|
|
227
|
+
If `False`, the method will return immediately with the result of
|
|
228
|
+
the attempt.
|
|
238
229
|
|
|
239
230
|
Returns:
|
|
240
|
-
|
|
231
|
+
`True` if the tokens were successfully acquired, `False` otherwise.
|
|
241
232
|
"""
|
|
242
233
|
if not blocking:
|
|
243
234
|
return self._consume()
|