langchain-dev-utils 1.2.6__py3-none-any.whl → 1.2.8__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_dev_utils/__init__.py +1 -1
- langchain_dev_utils/_utils.py +9 -5
- langchain_dev_utils/agents/__init__.py +0 -1
- langchain_dev_utils/agents/factory.py +2 -10
- langchain_dev_utils/agents/file_system.py +1 -1
- langchain_dev_utils/agents/middleware/__init__.py +2 -0
- langchain_dev_utils/agents/middleware/model_fallback.py +1 -1
- langchain_dev_utils/agents/middleware/model_router.py +37 -46
- langchain_dev_utils/agents/middleware/plan.py +17 -18
- langchain_dev_utils/agents/middleware/summarization.py +6 -4
- langchain_dev_utils/agents/middleware/tool_call_repair.py +96 -0
- langchain_dev_utils/agents/middleware/tool_emulator.py +3 -3
- langchain_dev_utils/agents/middleware/tool_selection.py +3 -3
- langchain_dev_utils/agents/plan.py +1 -1
- langchain_dev_utils/agents/wrap.py +8 -20
- langchain_dev_utils/chat_models/adapters/openai_compatible.py +105 -59
- langchain_dev_utils/chat_models/base.py +30 -15
- langchain_dev_utils/chat_models/types.py +6 -3
- langchain_dev_utils/embeddings/base.py +35 -18
- langchain_dev_utils/message_convert/__init__.py +0 -1
- langchain_dev_utils/message_convert/content.py +8 -11
- langchain_dev_utils/message_convert/format.py +2 -2
- langchain_dev_utils/pipeline/parallel.py +10 -41
- langchain_dev_utils/pipeline/sequential.py +6 -21
- langchain_dev_utils/tool_calling/human_in_the_loop.py +6 -6
- langchain_dev_utils/tool_calling/utils.py +3 -3
- {langchain_dev_utils-1.2.6.dist-info → langchain_dev_utils-1.2.8.dist-info}/METADATA +24 -119
- langchain_dev_utils-1.2.8.dist-info/RECORD +37 -0
- langchain_dev_utils-1.2.6.dist-info/RECORD +0 -36
- {langchain_dev_utils-1.2.6.dist-info → langchain_dev_utils-1.2.8.dist-info}/WHEEL +0 -0
- {langchain_dev_utils-1.2.6.dist-info → langchain_dev_utils-1.2.8.dist-info}/licenses/LICENSE +0 -0
langchain_dev_utils/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.2.
|
|
1
|
+
__version__ = "1.2.8"
|
langchain_dev_utils/_utils.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
from importlib import util
|
|
2
|
+
from typing import Literal
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
def _check_pkg_install(
|
|
8
|
+
pkg: Literal["langchain_openai", "json_repair"],
|
|
9
|
+
) -> None:
|
|
10
|
+
if not util.find_spec(pkg):
|
|
11
|
+
if pkg == "langchain_openai":
|
|
12
|
+
msg = "Please install langchain_dev_utils[standard],when use 'openai-compatible'"
|
|
13
|
+
else:
|
|
14
|
+
msg = "Please install langchain_dev_utils[standard] to use ToolCallRepairMiddleware."
|
|
11
15
|
raise ImportError(msg)
|
|
12
16
|
|
|
13
17
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
from typing import Any, Sequence
|
|
2
|
-
from typing import Callable
|
|
1
|
+
from typing import Any, Callable, Sequence
|
|
3
2
|
|
|
4
3
|
from langchain.agents import create_agent as _create_agent
|
|
5
4
|
from langchain.agents.middleware.types import (
|
|
@@ -63,21 +62,14 @@ def create_agent( # noqa: PLR0915
|
|
|
63
62
|
Example:
|
|
64
63
|
>>> from langchain_dev_utils.chat_models import register_model_provider
|
|
65
64
|
>>> from langchain_dev_utils.agents import create_agent
|
|
66
|
-
>>> from langchain_core.tools import tool
|
|
67
|
-
>>> import datetime
|
|
68
65
|
>>>
|
|
69
|
-
|
|
66
|
+
# Register a model provider, must be done before creating the agent
|
|
70
67
|
>>> register_model_provider(
|
|
71
68
|
... provider_name="vllm",
|
|
72
69
|
... chat_model="openai-compatible",
|
|
73
70
|
... base_url="http://localhost:8000/v1",
|
|
74
71
|
... )
|
|
75
72
|
>>>
|
|
76
|
-
>>> @tool
|
|
77
|
-
... def get_current_time() -> str:
|
|
78
|
-
... \"\"\"Get current time.\"\"\"
|
|
79
|
-
... return str(datetime.datetime.now().timestamp())
|
|
80
|
-
>>>
|
|
81
73
|
>>> agent = create_agent(
|
|
82
74
|
... "vllm:qwen3-4b",
|
|
83
75
|
... tools=[get_current_time],
|
|
@@ -7,6 +7,7 @@ from .plan import (
|
|
|
7
7
|
create_write_plan_tool,
|
|
8
8
|
)
|
|
9
9
|
from .summarization import SummarizationMiddleware
|
|
10
|
+
from .tool_call_repair import ToolCallRepairMiddleware
|
|
10
11
|
from .tool_emulator import LLMToolEmulator
|
|
11
12
|
from .tool_selection import LLMToolSelectorMiddleware
|
|
12
13
|
|
|
@@ -20,4 +21,5 @@ __all__ = [
|
|
|
20
21
|
"ModelFallbackMiddleware",
|
|
21
22
|
"LLMToolEmulator",
|
|
22
23
|
"ModelRouterMiddleware",
|
|
24
|
+
"ToolCallRepairMiddleware",
|
|
23
25
|
]
|
|
@@ -68,11 +68,15 @@ class ModelRouterState(AgentState):
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
class ModelRouterMiddleware(AgentMiddleware):
|
|
71
|
-
"""Model routing middleware that automatically selects the most suitable model
|
|
71
|
+
"""Model routing middleware that automatically selects the most suitable model
|
|
72
|
+
based on input content.
|
|
72
73
|
|
|
73
74
|
Args:
|
|
74
|
-
router_model: Model identifier used for routing selection, it can be a
|
|
75
|
-
|
|
75
|
+
router_model: Model identifier used for routing selection, it can be a
|
|
76
|
+
model name or a BaseChatModel instance
|
|
77
|
+
model_list: List of available routing models, each containing model_name,
|
|
78
|
+
model_description, tools(Optional), model_kwargs(Optional),
|
|
79
|
+
model_system_prompt(Optional)
|
|
76
80
|
router_prompt: Routing prompt template, uses default template if None
|
|
77
81
|
|
|
78
82
|
Examples:
|
|
@@ -145,9 +149,7 @@ class ModelRouterMiddleware(AgentMiddleware):
|
|
|
145
149
|
model_name = await self._aselect_model(state["messages"])
|
|
146
150
|
return {"router_model_selection": model_name}
|
|
147
151
|
|
|
148
|
-
def
|
|
149
|
-
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
|
|
150
|
-
) -> ModelCallResult:
|
|
152
|
+
def _get_override_kwargs(self, request: ModelRequest) -> dict[str, Any]:
|
|
151
153
|
model_dict = {
|
|
152
154
|
item["model_name"]: {
|
|
153
155
|
"tools": item.get("tools", None),
|
|
@@ -159,49 +161,38 @@ class ModelRouterMiddleware(AgentMiddleware):
|
|
|
159
161
|
select_model_name = request.state.get("router_model_selection", "default-model")
|
|
160
162
|
|
|
161
163
|
override_kwargs = {}
|
|
162
|
-
if select_model_name != "default-model":
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return
|
|
164
|
+
if select_model_name != "default-model" and select_model_name in model_dict:
|
|
165
|
+
model_values = model_dict.get(select_model_name, {})
|
|
166
|
+
if model_values["kwargs"] is not None:
|
|
167
|
+
model = load_chat_model(select_model_name, **model_values["kwargs"])
|
|
168
|
+
else:
|
|
169
|
+
model = load_chat_model(select_model_name)
|
|
170
|
+
override_kwargs["model"] = model
|
|
171
|
+
if model_values["tools"] is not None:
|
|
172
|
+
override_kwargs["tools"] = model_values["tools"]
|
|
173
|
+
if model_values["system_prompt"] is not None:
|
|
174
|
+
override_kwargs["system_message"] = SystemMessage(
|
|
175
|
+
content=model_values["system_prompt"]
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return override_kwargs
|
|
179
|
+
|
|
180
|
+
def wrap_model_call(
|
|
181
|
+
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
|
|
182
|
+
) -> ModelCallResult:
|
|
183
|
+
override_kwargs = self._get_override_kwargs(request)
|
|
184
|
+
if override_kwargs:
|
|
185
|
+
return handler(request.override(**override_kwargs))
|
|
186
|
+
else:
|
|
187
|
+
return handler(request)
|
|
177
188
|
|
|
178
189
|
async def awrap_model_call(
|
|
179
190
|
self,
|
|
180
191
|
request: ModelRequest,
|
|
181
192
|
handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
|
|
182
193
|
) -> ModelCallResult:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
for item in self.model_list
|
|
190
|
-
}
|
|
191
|
-
select_model_name = request.state.get("router_model_selection", "default-model")
|
|
192
|
-
override_kwargs = {}
|
|
193
|
-
if select_model_name != "default-model":
|
|
194
|
-
if select_model_name in model_dict:
|
|
195
|
-
model_values = model_dict.get(select_model_name, {})
|
|
196
|
-
if model_values["kwargs"] is not None:
|
|
197
|
-
model = load_chat_model(select_model_name, **model_values["kwargs"])
|
|
198
|
-
else:
|
|
199
|
-
model = load_chat_model(select_model_name)
|
|
200
|
-
override_kwargs["model"] = model
|
|
201
|
-
if model_values["tools"] is not None:
|
|
202
|
-
override_kwargs["tools"] = model_values["tools"]
|
|
203
|
-
if model_values["system_prompt"] is not None:
|
|
204
|
-
override_kwargs["system_message"] = SystemMessage(
|
|
205
|
-
content=model_values["system_prompt"]
|
|
206
|
-
)
|
|
207
|
-
return await handler(request.override(**override_kwargs))
|
|
194
|
+
override_kwargs = self._get_override_kwargs(request)
|
|
195
|
+
if override_kwargs:
|
|
196
|
+
return await handler(request.override(**override_kwargs))
|
|
197
|
+
else:
|
|
198
|
+
return await handler(request)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import Awaitable, Callable, Literal, Optional, cast
|
|
3
|
-
from typing import NotRequired
|
|
2
|
+
from typing import Awaitable, Callable, Literal, NotRequired, Optional, cast
|
|
4
3
|
|
|
5
4
|
from langchain.agents.middleware import ModelRequest, ModelResponse
|
|
6
5
|
from langchain.agents.middleware.types import (
|
|
@@ -160,7 +159,8 @@ def create_finish_sub_plan_tool(
|
|
|
160
159
|
) -> BaseTool:
|
|
161
160
|
"""Create a tool for finishing sub-plan tasks.
|
|
162
161
|
|
|
163
|
-
This function creates a tool that allows agents to update the status of sub-plans in a plan.
|
|
162
|
+
This function creates a tool that allows agents to update the status of sub-plans in a plan.
|
|
163
|
+
Sub-plans can be marked as "done" to track progress.
|
|
164
164
|
|
|
165
165
|
Args:
|
|
166
166
|
description: The description of the tool. Uses default description if not provided.
|
|
@@ -273,16 +273,20 @@ _PLAN_SYSTEM_PROMPT = """You can manage task plans using three simple tools:
|
|
|
273
273
|
class PlanMiddleware(AgentMiddleware):
|
|
274
274
|
"""Middleware that provides plan management capabilities to agents.
|
|
275
275
|
|
|
276
|
-
This middleware adds a `write_plan` and `finish_sub_plan` (and `read_plan`
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
into task completion
|
|
276
|
+
This middleware adds a `write_plan` and `finish_sub_plan` (and `read_plan`
|
|
277
|
+
optional) tool that allows agents to create and manage structured plan lists
|
|
278
|
+
for complex multi-step operations. It's designed to help agents track progress,
|
|
279
|
+
organize complex tasks, and provide users with visibility into task completion
|
|
280
|
+
status.
|
|
280
281
|
|
|
281
|
-
The middleware automatically injects system prompts that guide the agent on
|
|
282
|
+
The middleware automatically injects system prompts that guide the agent on
|
|
283
|
+
how to use the plan functionality effectively.
|
|
282
284
|
|
|
283
285
|
Args:
|
|
284
|
-
system_prompt: Custom system prompt to guide the agent on using the plan
|
|
285
|
-
If not provided, uses the default `_PLAN_SYSTEM_PROMPT` or
|
|
286
|
+
system_prompt: Custom system prompt to guide the agent on using the plan
|
|
287
|
+
tool. If not provided, uses the default `_PLAN_SYSTEM_PROMPT` or
|
|
288
|
+
`_PLAN_SYSTEM_PROMPT_NOT_READ_PLAN` based on the `use_read_plan_tool`
|
|
289
|
+
parameter.
|
|
286
290
|
write_plan_tool_description: Description of the `write_plan` tool.
|
|
287
291
|
If not provided, uses the default `_DEFAULT_WRITE_PLAN_TOOL_DESCRIPTION`.
|
|
288
292
|
finish_sub_plan_tool_description: Description of the `finish_sub_plan` tool.
|
|
@@ -291,7 +295,7 @@ class PlanMiddleware(AgentMiddleware):
|
|
|
291
295
|
If not provided, uses the default `_DEFAULT_READ_PLAN_TOOL_DESCRIPTION`.
|
|
292
296
|
use_read_plan_tool: Whether to use the `read_plan` tool.
|
|
293
297
|
If not provided, uses the default `True`.
|
|
294
|
-
|
|
298
|
+
|
|
295
299
|
Example:
|
|
296
300
|
```python
|
|
297
301
|
from langchain_dev_utils.agents.middleware import PlanMiddleware
|
|
@@ -316,7 +320,6 @@ class PlanMiddleware(AgentMiddleware):
|
|
|
316
320
|
finish_sub_plan_tool_description: Optional[str] = None,
|
|
317
321
|
read_plan_tool_description: Optional[str] = None,
|
|
318
322
|
use_read_plan_tool: bool = True,
|
|
319
|
-
message_key: Optional[str] = None,
|
|
320
323
|
) -> None:
|
|
321
324
|
super().__init__()
|
|
322
325
|
|
|
@@ -332,12 +335,8 @@ class PlanMiddleware(AgentMiddleware):
|
|
|
332
335
|
)
|
|
333
336
|
|
|
334
337
|
tools = [
|
|
335
|
-
create_write_plan_tool(
|
|
336
|
-
|
|
337
|
-
),
|
|
338
|
-
create_finish_sub_plan_tool(
|
|
339
|
-
description=finish_sub_plan_tool_description, message_key=message_key
|
|
340
|
-
),
|
|
338
|
+
create_write_plan_tool(description=write_plan_tool_description),
|
|
339
|
+
create_finish_sub_plan_tool(description=finish_sub_plan_tool_description),
|
|
341
340
|
]
|
|
342
341
|
|
|
343
342
|
if use_read_plan_tool:
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
from langchain.agents.middleware.summarization import (
|
|
4
|
-
ContextSize,
|
|
5
|
-
DEFAULT_SUMMARY_PROMPT,
|
|
6
|
-
SummarizationMiddleware as _SummarizationMiddleware,
|
|
7
|
-
TokenCounter,
|
|
8
4
|
_DEFAULT_MESSAGES_TO_KEEP,
|
|
9
5
|
_DEFAULT_TRIM_TOKEN_LIMIT,
|
|
6
|
+
DEFAULT_SUMMARY_PROMPT,
|
|
7
|
+
ContextSize,
|
|
8
|
+
TokenCounter,
|
|
9
|
+
)
|
|
10
|
+
from langchain.agents.middleware.summarization import (
|
|
11
|
+
SummarizationMiddleware as _SummarizationMiddleware,
|
|
10
12
|
)
|
|
11
13
|
from langchain_core.messages.utils import count_tokens_approximately
|
|
12
14
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from typing import Any, Awaitable, Callable, cast
|
|
2
|
+
|
|
3
|
+
from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse
|
|
4
|
+
from langchain.agents.middleware.types import ModelCallResult
|
|
5
|
+
from langchain_core.messages import AIMessage, BaseMessage
|
|
6
|
+
|
|
7
|
+
from langchain_dev_utils._utils import _check_pkg_install
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ToolCallRepairMiddleware(AgentMiddleware):
|
|
11
|
+
"""Middleware to repair invalid tool calls in AIMessages.
|
|
12
|
+
|
|
13
|
+
This middleware attempts to repair JSON-formatted tool arguments in
|
|
14
|
+
AIMessages that have invalid tool calls. It uses the `json_repair`
|
|
15
|
+
package to fix common JSON errors.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
```python
|
|
19
|
+
from langchain_dev_utils.agents.middleware import ToolCallRepairMiddleware
|
|
20
|
+
|
|
21
|
+
middleware = ToolCallRepairMiddleware()
|
|
22
|
+
```
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def _repair_msgs(self, messages: list[BaseMessage]) -> list[BaseMessage]:
|
|
26
|
+
_check_pkg_install("json_repair")
|
|
27
|
+
from json import JSONDecodeError
|
|
28
|
+
|
|
29
|
+
from json_repair import loads
|
|
30
|
+
|
|
31
|
+
results = []
|
|
32
|
+
for msg in messages:
|
|
33
|
+
if (
|
|
34
|
+
isinstance(msg, AIMessage)
|
|
35
|
+
and hasattr(msg, "invalid_tool_calls")
|
|
36
|
+
and len(msg.invalid_tool_calls) > 0
|
|
37
|
+
):
|
|
38
|
+
new_invalid_toolcalls = []
|
|
39
|
+
new_tool_calls = [*msg.tool_calls]
|
|
40
|
+
|
|
41
|
+
for invalid_tool_call in msg.invalid_tool_calls:
|
|
42
|
+
args = invalid_tool_call.get("args")
|
|
43
|
+
if args:
|
|
44
|
+
try:
|
|
45
|
+
args = cast(dict[str, Any], loads(args))
|
|
46
|
+
new_tool_calls.append(
|
|
47
|
+
{
|
|
48
|
+
"name": invalid_tool_call.get(
|
|
49
|
+
"name",
|
|
50
|
+
)
|
|
51
|
+
or "",
|
|
52
|
+
"id": invalid_tool_call.get("id", ""),
|
|
53
|
+
"type": "tool_call",
|
|
54
|
+
"args": args,
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
except JSONDecodeError:
|
|
58
|
+
new_invalid_toolcalls.append(invalid_tool_call)
|
|
59
|
+
else:
|
|
60
|
+
new_invalid_toolcalls.append(invalid_tool_call)
|
|
61
|
+
|
|
62
|
+
new_msg = msg.model_copy(
|
|
63
|
+
update={
|
|
64
|
+
"tool_calls": new_tool_calls,
|
|
65
|
+
"invalid_tool_calls": new_invalid_toolcalls,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
results.append(new_msg)
|
|
69
|
+
else:
|
|
70
|
+
results.append(msg)
|
|
71
|
+
|
|
72
|
+
return results
|
|
73
|
+
|
|
74
|
+
def wrap_model_call(
|
|
75
|
+
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
|
|
76
|
+
) -> ModelCallResult:
|
|
77
|
+
response = handler(request)
|
|
78
|
+
results = self._repair_msgs(response.result)
|
|
79
|
+
|
|
80
|
+
return ModelResponse(
|
|
81
|
+
result=results,
|
|
82
|
+
structured_response=response.structured_response,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
async def awrap_model_call(
|
|
86
|
+
self,
|
|
87
|
+
request: ModelRequest,
|
|
88
|
+
handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
|
|
89
|
+
) -> ModelCallResult:
|
|
90
|
+
response = await handler(request)
|
|
91
|
+
results = self._repair_msgs(response.result)
|
|
92
|
+
|
|
93
|
+
return ModelResponse(
|
|
94
|
+
result=results,
|
|
95
|
+
structured_response=response.structured_response,
|
|
96
|
+
)
|
|
@@ -20,7 +20,7 @@ class LLMToolEmulator(_LLMToolEmulator):
|
|
|
20
20
|
model: Model to use for emulation. Must be a string identifier.
|
|
21
21
|
|
|
22
22
|
Examples:
|
|
23
|
-
Emulate all tools (default behavior):
|
|
23
|
+
# Emulate all tools (default behavior):
|
|
24
24
|
```python
|
|
25
25
|
from langchain_dev_utils.agents import create_agent
|
|
26
26
|
from langchain_dev_utils.agents.middleware import LLMToolEmulator
|
|
@@ -36,12 +36,12 @@ class LLMToolEmulator(_LLMToolEmulator):
|
|
|
36
36
|
)
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Emulate specific tools by name:
|
|
39
|
+
# Emulate specific tools by name:
|
|
40
40
|
```python
|
|
41
41
|
middleware = LLMToolEmulator(model="vllm:qwen3-4b", tools=["get_weather", "get_user_location"])
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Emulate specific tools by passing tool instances:
|
|
44
|
+
# Emulate specific tools by passing tool instances:
|
|
45
45
|
```python
|
|
46
46
|
middleware = LLMToolEmulator(model="vllm:qwen3-4b", tools=[get_weather, get_user_location])
|
|
47
47
|
```
|
|
@@ -30,7 +30,7 @@ class LLMToolSelectorMiddleware(_LLMToolSelectorMiddleware):
|
|
|
30
30
|
against the max_tools limit.
|
|
31
31
|
|
|
32
32
|
Examples:
|
|
33
|
-
Basic usage with tool limit:
|
|
33
|
+
# Basic usage with tool limit:
|
|
34
34
|
```python
|
|
35
35
|
from langchain_dev_utils.agents.middleware import LLMToolSelectorMiddleware
|
|
36
36
|
|
|
@@ -40,7 +40,7 @@ class LLMToolSelectorMiddleware(_LLMToolSelectorMiddleware):
|
|
|
40
40
|
)
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
With always-included tools:
|
|
43
|
+
# With always-included tools:
|
|
44
44
|
```python
|
|
45
45
|
middleware = LLMToolSelectorMiddleware(
|
|
46
46
|
model="vllm:qwen3-4b",
|
|
@@ -49,7 +49,7 @@ class LLMToolSelectorMiddleware(_LLMToolSelectorMiddleware):
|
|
|
49
49
|
)
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
With custom system prompt:
|
|
52
|
+
# With custom system prompt:
|
|
53
53
|
```python
|
|
54
54
|
custom_prompt = "Select tools that can help answer user questions about data."
|
|
55
55
|
middleware = LLMToolSelectorMiddleware(
|
|
@@ -54,30 +54,18 @@ def wrap_agent_as_tool(
|
|
|
54
54
|
BaseTool: The wrapped agent as a tool
|
|
55
55
|
|
|
56
56
|
Example:
|
|
57
|
-
>>> import datetime
|
|
58
|
-
>>> from langchain_core.messages import HumanMessage
|
|
59
|
-
>>> from langchain_core.tools import tool
|
|
60
57
|
>>> from langchain_dev_utils.agents import wrap_agent_as_tool, create_agent
|
|
61
|
-
|
|
62
|
-
>>>
|
|
63
|
-
...
|
|
64
|
-
... "
|
|
65
|
-
...
|
|
66
|
-
|
|
67
|
-
>>> # Define an agent for querying the time
|
|
68
|
-
>>> time_agent = create_agent(
|
|
69
|
-
... "vllm:qwen3-4b", tools=[get_current_time], name="time_agent"
|
|
58
|
+
>>>
|
|
59
|
+
>>> call_time_agent_tool = wrap_agent_as_tool(
|
|
60
|
+
... time_agent,
|
|
61
|
+
... tool_name="call_time_agent",
|
|
62
|
+
... tool_description="Used to invoke the time sub-agent to perform time-related tasks"
|
|
70
63
|
... )
|
|
71
|
-
>>>
|
|
72
|
-
|
|
73
|
-
... )
|
|
74
|
-
>>> print(tool)
|
|
75
|
-
|
|
76
|
-
>>> # Use it as a tool
|
|
77
|
-
>>> agent = create_agent("vllm:qwen3-4b", tools=[tool], name="agent")
|
|
64
|
+
>>>
|
|
65
|
+
>>> agent = create_agent("vllm:qwen3-4b", tools=[call_time_agent_tool], name="agent")
|
|
78
66
|
|
|
79
67
|
>>> response = agent.invoke({"messages": [HumanMessage(content="What time is it now?")]})
|
|
80
|
-
>>>
|
|
68
|
+
>>> response
|
|
81
69
|
"""
|
|
82
70
|
if agent.name is None:
|
|
83
71
|
raise ValueError("Agent name must not be None")
|