Skip to content

Commit

Permalink
[Feature] support building tool descriptions automatically (#96)
Browse files Browse the repository at this point in the history
* redundancy reduction

* add `tool_api` to annotate a tool method

* improve json parsing

* enhance parsers

* update README.md

---------

Co-authored-by: wangzy <[email protected]>
  • Loading branch information
braisedpork1964 and wangzy authored Jan 25, 2024
1 parent a470a3e commit 39ac9a0
Show file tree
Hide file tree
Showing 13 changed files with 590 additions and 650 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Below is an example of running ReWOO with GPT-3.5
```python
# Import necessary modules and classes from the "lagent" library.
from lagent.agents import ReWOO
from lagent.actions import ActionExecutor, GoogleSearch, LLMQA
from lagent.actions import ActionExecutor, GoogleSearch
from lagent.llms import GPTAPI

# Initialize the Language Model (llm) and provide your API key.
Expand All @@ -92,14 +92,11 @@ llm = GPTAPI(model_type='gpt-3.5-turbo', key=['Your OPENAI_API_KEY'])
# Initialize the Google Search tool and provide your API key.
search_tool = GoogleSearch(api_key='Your SERPER_API_KEY')

# Initialize the LLMQA tool using the Language Model (llm).
llmqa_tool = LLMQA(llm)

# Create a chatbot by configuring the ReWOO agent.
chatbot = ReWOO(
llm=llm, # Provide the Language Model instance.
action_executor=ActionExecutor(
actions=[search_tool, llmqa_tool] # Specify the actions the chatbot can perform.
actions=[search_tool] # Specify the actions the chatbot can perform.
),
)

Expand Down Expand Up @@ -144,6 +141,7 @@ response = chatbot.chat('若$z=-1+\sqrt{3}i$,则$\frac{z}{{z\overline{z}-1}}=\le
print(response.response) # Output the response generated by the chatbot.
>>> $-\\frac{1}{3}+\\frac{{\\sqrt{3}}}{3}i$
```

### All Thanks To Our Contributors:
<a href="https://github.com/InternLM/lagent/graphs/contributors">
<img src="https://contrib.rocks/image?repo=InternLM/lagent" />
Expand Down
46 changes: 44 additions & 2 deletions lagent/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import Type

from .action_executor import ActionExecutor
from .arxiv_search import ArxivSearch
from .base_action import BaseAction
from .base_action import TOOL_REGISTRY, BaseAction, tool_api
from .bing_map import BINGMap
from .builtin_actions import FinishAction, InvalidAction, NoAction
from .google_scholar_search import GoogleScholar
Expand All @@ -13,5 +15,45 @@
'BaseAction', 'ActionExecutor', 'InvalidAction', 'FinishAction',
'NoAction', 'BINGMap', 'ArxivSearch', 'FinishAction', 'GoogleSearch',
'GoogleScholar', 'PythonInterpreter', 'PPT', 'BaseParser', 'JsonParser',
'TupleParser'
'TupleParser', 'tool_api', 'list_tools', 'get_tool_cls', 'get_tool'
]


def list_tools(with_class: bool = False):
"""List available tools
Args:
with_class (bool): whether to return the action class along
with its name. Defaults to ``False``.
Returns:
list: all action names
"""
return list(TOOL_REGISTRY.items()) if with_class else list(
TOOL_REGISTRY.keys())


def get_tool_cls(specifier: str) -> Type[BaseAction]:
"""Get the action class
Args:
specifier (:class:`str`): tool name
Returns:
Type[BaseAction]: action class
"""
return TOOL_REGISTRY.get_class(specifier)


def get_tool(specifier: str, *args, **kwargs) -> BaseAction:
"""Instantiate an action
Args:
specifier (str): tool name
args: positional arguments passed to the action's ``__init__`` method
kwargs: keyword arguments passed to the action's ``__init__`` method
Returns:
:class:`BaseAction`: action object
"""
return TOOL_REGISTRY.get(specifier, *args, **kwargs)
51 changes: 18 additions & 33 deletions lagent/actions/arxiv_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,40 @@

import arxiv

from lagent.actions.base_action import BaseAction
from lagent.actions.base_action import BaseAction, tool_api
from lagent.actions.parser import BaseParser, JsonParser
from lagent.schema import ActionReturn, ActionStatusCode

DEFAULT_DESCRIPTION = dict(
name='ArxivSearch',
description='Search information from Arxiv.org '
'Useful for when you need to answer questions about Physics, Mathematics, '
'Computer Science, Quantitative Biology, Quantitative Finance, Statistics, '
'Electrical Engineering, and Economics '
'from scientific articles on arxiv.org',
api_list=[
dict(
name='get_arxiv_article_information',
description=
'Run Arxiv search and get the article meta information.',
parameters=[
dict(
name='query',
type='STRING',
description='the content of search query')
],
required=['query'],
return_data=[
dict(
name='content',
description='a list of 3 arxiv search papers'),
],
)
],
)


class ArxivSearch(BaseAction):
"""ArxivSearch action"""
"""Search information from Arxiv.org. \
Useful for when you need to answer questions about Physics, Mathematics, \
Computer Science, Quantitative Biology, Quantitative Finance, Statistics, \
Electrical Engineering, and Economics from scientific articles on arxiv.org.
"""

def __init__(self,
top_k_results: int = 3,
max_query_len: int = 300,
doc_content_chars_max: int = 1500,
description: Optional[dict] = None,
parser: Type[BaseParser] = JsonParser,
enable: bool = True) -> None:
super().__init__(description or DEFAULT_DESCRIPTION, parser, enable)
enable: bool = True):
super().__init__(description, parser, enable)
self.top_k_results = top_k_results
self.max_query_len = max_query_len
self.doc_content_chars_max = doc_content_chars_max

def get_arxiv_article_information(self, query: str):
@tool_api(return_dict=True)
def get_arxiv_article_information(self, query: str) -> dict:
"""Run Arxiv search and get the article meta information.
Args:
query (:class:`str`): the content of search query
Returns:
content (:class:`str`): a list of 3 arxiv search papers
"""
try:
results = arxiv.Search( # type: ignore
query[:self.max_query_len],
Expand Down
Loading

0 comments on commit 39ac9a0

Please sign in to comment.