tool-call
: move usage examples to examples/agent
This commit is contained in:
parent
6610ecf965
commit
0abfa36ca7
7 changed files with 113 additions and 61 deletions
33
examples/agent/README.md
Normal file
33
examples/agent/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Agents / Tool Calling w/ llama.cpp
|
||||
|
||||
- Install prerequisite: [uv](https://docs.astral.sh/uv/) (used to simplify python deps)
|
||||
|
||||
- Run `llama-server` w/ jinja templates:
|
||||
|
||||
```bash
|
||||
make -j LLAMA_CURL=1 llama-server
|
||||
./llama-server \
|
||||
-mu https://huggingface.co/lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF/resolve/main/Meta-Llama-3.1-70B-Instruct-Q4_K_M.gguf \
|
||||
--jinja \
|
||||
-c 8192 -fa
|
||||
```
|
||||
|
||||
- Run some tools inside a docker container (check http://localhost:8088/docs once running):
|
||||
|
||||
```bash
|
||||
docker run -p 8088:8088 -w /src \
|
||||
-v $PWD/examples/agent:/src \
|
||||
--rm -it ghcr.io/astral-sh/uv:python3.12-alpine \
|
||||
uv run fastify.py --port 8088 tools.py
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> The command above gives tools (and your agent) access to the web (and read-only access to `examples/agent/**`. If you're concerned about unleashing a rogue agent on the web, please explore setting up proxies for your docker (and contribute back!)
|
||||
|
||||
- Run the agent with a given goal:
|
||||
|
||||
```bash
|
||||
uv run examples/agent/run.py \
|
||||
--tool-endpoint http://localhost:8088 \
|
||||
--goal "What is the sum of 2535 squared and 32222000403?"
|
||||
```
|
|
@ -22,6 +22,9 @@ import urllib.parse
|
|||
|
||||
class OpenAPIMethod:
|
||||
def __init__(self, url, name, descriptor, catalog):
|
||||
'''
|
||||
Wraps a remote OpenAPI method as a Python function.
|
||||
'''
|
||||
self.url = url
|
||||
self.__name__ = name
|
||||
|
||||
|
@ -96,11 +99,8 @@ def main(
|
|||
goal: Annotated[str, typer.Option()],
|
||||
api_key: Optional[str] = None,
|
||||
tool_endpoint: Optional[list[str]] = None,
|
||||
format: Annotated[Optional[str], typer.Option(help="The output format: either a Python type (e.g. 'float' or a Pydantic model defined in one of the tool files), or a JSON schema, e.g. '{\"format\": \"date\"}'")] = None,
|
||||
max_iterations: Optional[int] = 10,
|
||||
parallel_calls: Optional[bool] = False,
|
||||
verbose: bool = False,
|
||||
# endpoint: Optional[str] = None,
|
||||
endpoint: str = "http://localhost:8080/v1/",
|
||||
):
|
||||
|
||||
|
@ -110,6 +110,7 @@ def main(
|
|||
tool_map = {}
|
||||
tools = []
|
||||
|
||||
# Discover tools using OpenAPI catalogs at the provided endpoints.
|
||||
for url in (tool_endpoint or []):
|
||||
assert url.startswith('http://') or url.startswith('https://'), f'Tools must be URLs, not local files: {url}'
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
# /// script
|
||||
# requires-python = ">=3.10"
|
||||
# dependencies = [
|
||||
# "ipython",
|
||||
# ]
|
||||
# ///
|
||||
import datetime
|
||||
import json
|
||||
from pydantic import BaseModel
|
||||
|
@ -82,32 +88,69 @@ def _is_serializable(obj) -> bool:
|
|||
except Exception as e:
|
||||
return False
|
||||
|
||||
def python(source: str) -> Union[Dict, str]:
|
||||
def python(code: str) -> str:
|
||||
"""
|
||||
Evaluate a Python program and return the globals it declared.
|
||||
Can be used to compute mathematical expressions (e.g. after importing math module).
|
||||
Args:
|
||||
source: contain valid, executable and pure Python code. Should also import any required Python packages.
|
||||
For example: "import math\nresult = math.cos(2) * 10"
|
||||
Executes Python code in a siloed environment using IPython and returns the output.
|
||||
|
||||
Parameters:
|
||||
code (str): The Python code to execute.
|
||||
|
||||
Returns:
|
||||
dict | str: A dictionary containing variables declared, or an error message if an exception occurred.
|
||||
str: The output of the executed code.
|
||||
"""
|
||||
from IPython import InteractiveShell
|
||||
from io import StringIO
|
||||
import sys
|
||||
|
||||
# Create an isolated IPython shell instance
|
||||
shell = InteractiveShell()
|
||||
|
||||
# Redirect stdout to capture output
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = mystdout = StringIO()
|
||||
|
||||
try:
|
||||
namespace = {}
|
||||
sys.stderr.write(f"Executing Python program:\n{source}\n")
|
||||
exec(source, namespace)
|
||||
results = {
|
||||
k: v
|
||||
for k, v in namespace.items()
|
||||
if not k.startswith('_') \
|
||||
and not isinstance(v, type) \
|
||||
and not isinstance(v, types.ModuleType) \
|
||||
and not callable(v) \
|
||||
and _is_serializable(v)
|
||||
}
|
||||
sys.stderr.write(f"Results: {json.dumps(results, indent=2)}\n")
|
||||
return results
|
||||
# Execute the code
|
||||
shell.run_cell(code)
|
||||
except Exception as e:
|
||||
msg = f"Error: {sys.exc_info()[1]}"
|
||||
sys.stderr.write(f"{msg}\n")
|
||||
return msg
|
||||
# Restore stdout before returning
|
||||
sys.stdout = old_stdout
|
||||
return f"An error occurred: {e}"
|
||||
finally:
|
||||
# Always restore stdout
|
||||
sys.stdout = old_stdout
|
||||
|
||||
# Retrieve the output
|
||||
output = mystdout.getvalue()
|
||||
return output
|
||||
|
||||
|
||||
# def python(source: str) -> Union[Dict, str]:
|
||||
# """
|
||||
# Evaluate a Python program and return the globals it declared.
|
||||
# Can be used to compute mathematical expressions (e.g. after importing math module).
|
||||
# Args:
|
||||
# source: contain valid, executable and pure Python code. Should also import any required Python packages.
|
||||
# For example: "import math\nresult = math.cos(2) * 10"
|
||||
# Returns:
|
||||
# dict | str: A dictionary containing variables declared, or an error message if an exception occurred.
|
||||
# """
|
||||
# try:
|
||||
# namespace = {}
|
||||
# sys.stderr.write(f"Executing Python program:\n{source}\n")
|
||||
# exec(source, namespace)
|
||||
# results = {
|
||||
# k: v
|
||||
# for k, v in namespace.items()
|
||||
# if not k.startswith('_') \
|
||||
# and not isinstance(v, type) \
|
||||
# and not isinstance(v, types.ModuleType) \
|
||||
# and not callable(v) \
|
||||
# and _is_serializable(v)
|
||||
# }
|
||||
# sys.stderr.write(f"Results: {json.dumps(results, indent=2)}\n")
|
||||
# return results
|
||||
# except Exception as e:
|
||||
# msg = f"Error: {sys.exc_info()[1]}"
|
||||
# sys.stderr.write(f"{msg}\n")
|
||||
# return msg
|
|
@ -1,33 +0,0 @@
|
|||
# Agents / Tool Calling w/ llama.cpp
|
||||
|
||||
- Install prerequisite: [uv](https://docs.astral.sh/uv/) (used to simplify python deps)
|
||||
|
||||
- Run `llama-server` w/ jinja templates:
|
||||
|
||||
```bash
|
||||
# make -j LLAMA_CURL=1 llama-server
|
||||
./llama-server \
|
||||
-mu https://huggingface.co/lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF/resolve/main/Meta-Llama-3.1-70B-Instruct-Q4_K_M.gguf \
|
||||
--jinja \
|
||||
-c 8192 -fa
|
||||
```
|
||||
|
||||
- Run some tools inside a docker container
|
||||
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-p "8088:8088" \
|
||||
-v $PWD/examples/tool-call:/src \
|
||||
ghcr.io/astral-sh/uv:python3.12-alpine \
|
||||
uv run /src/fastify.py --port 8088 /src/tools.py
|
||||
```
|
||||
|
||||
- Verify which tools have been exposed: http://localhost:8088/docs
|
||||
|
||||
- Run the agent with a given goal:
|
||||
|
||||
```bash
|
||||
uv run examples/tool-call/agent.py \
|
||||
--tool-endpoint http://localhost:8088 \
|
||||
--goal "What is the sum of 2535 squared and 32222000403 then multiplied by one and a half. What's a third of the result?"
|
||||
```
|
|
@ -10,3 +10,5 @@
|
|||
-r ./requirements/requirements-convert_hf_to_gguf_update.txt
|
||||
-r ./requirements/requirements-convert_llama_ggml_to_gguf.txt
|
||||
-r ./requirements/requirements-convert_lora_to_gguf.txt
|
||||
|
||||
-r ./requirements/requirements-agent.txt
|
||||
|
|
6
requirements/requirements-agent.txt
Normal file
6
requirements/requirements-agent.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
fastapi
|
||||
openai
|
||||
pydantic
|
||||
requests
|
||||
typer
|
||||
uvicorn
|
Loading…
Add table
Add a link
Reference in a new issue