You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
following up on #2666 (comment), I would like to propose a design for an abstraction on List[Tool]. That abstraction would be a "tool pool" that makes it possible to add, remove and find tools. It would make it easier to make agents that:
have access to virtually limitless set of tools
dynamically handle the actual set of available tools for a task
use various complex (other agents, LLMs, vector distance search...) to select/elect tools
An example implementation: VectorWorkbench is a workbench that uses vector distance matching on tools description/documentation to find/elect tools.
classVectorWorkbench(Workbench, DynamicWorkbench):
defget_tools_for_context(self, context: Sequence[LLMMessage]) ->List[Tool]:
query="\n".join([msg.contentformsgincontextifisinstance(msg, TextMessage)]).strip()
returnself._get_tools_for_query(query)
def_get_tools_for_query(self, query: str) ->List[str]:
iflen(query) ==0:
return []
logger.info(f"Query: {query}")
# Generate the query embedding.query_embedding=self._embedding_func(query).data[0]["embedding"]
query_embedding=np.array(query_embedding).reshape(1, -1)
# Search for the closest matching tool embeddings.k=min(self._top_k, len(self._tools))
scores, indexes=self._index.search(query_embedding, k=k) # Retrieve top matchesresults= [
{"tool": self._tools[i], "score": scores[0][index]}
forindex, iinenumerate(indexes[0])
ifscores[0][index] <=self._score_threshold# Filter out results below the thresholdandself.tool_is_enabled(self._tools[i].name) # Filter out disabled tools
]
return [result["tool"] forresultinresults]
defget_tool_names_for_query(self, query: str) ->List[str]:
"""Returns a list of tool names that are relevant to the given query."""logger.info(f"getting tool names for query: {query}")
tools=self._get_tools_for_query(query)
return [tool.namefortoolintools]
defget_tool_documentation(self, tool_name: str) ->str:
"""Returns the documentation for the given tool name."""logger.info(f"getting documentation for tool: {tool_name}")
# We assume that all tools have a documentation.iftool_namenotinself._tool_docs:
raiseValueError(f"tool {tool_name} does not exist")
returnself._tool_docs[tool_name]
# the rest is boilerplate...
Then, the following agents can be provided OOB:
classWorkbenchSearchAgent(AssistantAgent):
""" Searches for tools, but does *not* call them. Good for planning for example."""def__init__(
self,
name: str,
model_client: ChatCompletionClient,
workbench: Workbench,
handoffs: List[Handoff|str] |None=None,
description: str="An agent that provides assistance to find relevant tools.",
system_message: str|None="You are a helpful AI assistant to find relevant tools to solve a problem.",
):
super().__init__(
name=name,
model_client=model_client,
handoffs=handoffs,
description=description,
system_message=system_message,
tools=[
workbench.get_tool_names_for_query,
workbench.get_tool_documentation,
],
)
self._workbench=workbench@propertydefproduced_message_types(self) ->List[type[ChatMessage]]:
return [TextMessage]
@propertydefworkbench(self) ->Workbench:
returnself._workbenchclassWorkbenchAgent(AssistantAgent):
"""Find and actually call tools. Good for the plan execution for example."""def__init__(
self,
name: str,
model_client: ChatCompletionClient,
workbench: Workbench,
handoffs: List[Handoff|str] |None=None,
description: str="An agent that provides assistance to find relevant tools.",
system_message: str|None="You are a helpful AI assistant to find relevant tools to solve a problem.",
):
super().__init__(
name=name,
description=description,
model_client=model_client,
system_message=system_message,
# The tools are dynamically set based on the message list using# embedding search.tools=[],
handoffs=handoffs,
)
self._workbench=workbench@propertydefworkbench(self) ->Workbench:
returnself._workbench@propertydefproduced_message_types(self) ->List[type[ChatMessage]]:
return [ToolCallMessage, ToolCallResultMessage]
asyncdefon_messages_stream(
self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken
) ->AsyncGenerator[AgentMessage|Response, None]:
self.remove_all_tools()
tools=self._workbench.get_tools_for_context(messages)
logger.info(f"selected tools: {[tool.namefortoolintools]}")
fortoolintools:
self.add_tool(tool)
asyncformsginsuper().on_messages_stream(messages, cancellation_token):
yieldmsgself.remove_all_tools()
Used like this:
workbench_search_agent=WorkbenchSearchAgent(
name="workbench_search_agent",
model_client=model_client,
workbench=openapi_agent.workbench,
system_message="You are a helpful AI assistant to find tools. When you are done, handoff to planning_agent.",
handoffs=[
Handoff(
target="planning_agent",
message="Here are the tools your are looking for.",
),
],
)
planning_agent=AssistantAgent(
name="planning_agent",
model_client=model_client,
system_message="You are a planning agent. Your task is to create a step-by-step plan for the given task.""In order to plan, you need to know the tools you can use."f"You start by asking {workbench_search_agent.name} to find the relevant tools.""Finally, you create a step-by-step plan for the given task.""When you are done, handoff to coordinator_agent.",
handoffs=[
"coordinator_agent",
Handoff(
target=workbench_search_agent.name,
message="Find the tools to use for the given task.",
),
],
)
Why is this needed?
1. Challenges in Current Tool Management
Static Tool Sets: Current systems rely on pre-defined, fixed tools, limiting flexibility and adaptability to different tasks.
Dynamic Task Requirements: Tasks often need tools tailored to specific contexts, but static systems can’t dynamically adapt.
Scalability Issues: Managing large pools of tools becomes inefficient without dynamic filtering or selection mechanisms.
2. The Role of the Workbench
Centralized Tool Management: The Workbench provides a unified system to add, remove, enable, and filter tools dynamically.
Context-Aware Tool Selection: Uses techniques like vector search to find tools relevant to the current task or query.
Agent Collaboration: Supports modular agents (e.g., Search Agent for finding tools and Execution Agent for using them) to streamline workflows.
3. Advantages for Autogen
Scalability: Handles large, virtually unlimited toolsets dynamically and efficiently.
Flexibility: Adapts tools in real-time to match task-specific needs.
Extensibility: Compatible with various retrieval methods, enabling advanced filtering mechanisms like LLM embeddings or vector matching.
Better Agent Collaboration: Facilitates seamless interactions between agents using a shared tool resource.
The text was updated successfully, but these errors were encountered:
What feature would you like to be added?
Hello,
following up on #2666 (comment), I would like to propose a design for an abstraction on
List[Tool]
. That abstraction would be a "tool pool" that makes it possible to add, remove and find tools. It would make it easier to make agents that:Introducing: the workbench.
An example implementation:
VectorWorkbench
is a workbench that uses vector distance matching on tools description/documentation to find/elect tools.Then, the following agents can be provided OOB:
Used like this:
Why is this needed?
1. Challenges in Current Tool Management
2. The Role of the Workbench
3. Advantages for Autogen
The text was updated successfully, but these errors were encountered: