├── src └── __init__.py ├── utils ├── __init__.py └── download_from_hf.py ├── .gitignore ├── assets ├── front.png └── modal1.png ├── .env copy ├── llama3 ├── chat_template.jinja └── serve.py ├── README.md ├── pyproject.toml └── Makefile /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *__pycache__/ -------------------------------------------------------------------------------- /assets/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashishpatel26/agentic-design-patterns/master/assets/front.png -------------------------------------------------------------------------------- /assets/modal1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashishpatel26/agentic-design-patterns/master/assets/modal1.png -------------------------------------------------------------------------------- /.env copy: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=<> 2 | LANGCHAIN_TRACING_V2=<> 3 | LANGCHAIN_PROJECT=<> 4 | LANGCHAIN_API_KEY=<> 5 | HF_TOKEN=<> 6 | SERP_API_KEY=<> 7 | TAVILY_API_KEY=<> 8 | GROQ_API_KEY=<> -------------------------------------------------------------------------------- /llama3/chat_template.jinja: -------------------------------------------------------------------------------- 1 | {% set loop_messages = messages %}{% for message in loop_messages %}{% set content = '<|start_header_id|>' + message['role'] + '<|end_header_id|> 2 | 3 | '+ message['content'] | trim + '<|eot_id|>' %}{% if loop.index0 == 0 %}{% set content = bos_token + content %}{% endif %}{{ content }}{% endfor %}{% if add_generation_prompt %}{{ '<|start_header_id|>assistant<|end_header_id|> 4 | 5 | ' }}{% endif %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hands On: Agentic Reasoning Design Patterns 2 | 3 | ![Alt](assets/front.png) 4 | 5 | ## What is in this project? 6 | This project is inspired by the recent [video](https://www.youtube.com/watch?v=sal78ACtGTc) from Sequoia Capital, where Andrew Ng discussed four Agentic Reasoning Design Patterns. The goal of this project is to provide a hands-on approach by building simple examples that represent each of the patterns mentioned in the video. 7 | 8 | | Pattern | Notebook | 9 | | ------- | -------- | 10 | | Reflection | [01.Reflection.ipynb](https://github.com/jjovalle99/agentic-design-patterns/blob/a1a7e3eab50799b5955d1eb1ec296550b0494c34/01.Reflection.ipynb) | 11 | | Tool use | [02.Tools.ipynb](https://github.com/jjovalle99/agentic-design-patterns/blob/1cd0db5848674aeef1952893067b3c0c7429375b/02.Tools.ipynb) | 12 | | Planning | Coming Soon | 13 | | Multi-agent collaboration | Coming Soon | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "Agentic Desings" 3 | version = "0.1.0" 4 | description = "Simple Agentic Desing Examples" 5 | authors = ["jjovalle99 "] 6 | readme = "README.md" 7 | 8 | 9 | [tool.poetry.dependencies] 10 | python = "~3.11" 11 | langchain = "^0.1.16" 12 | langchain-openai = "^0.1.3" 13 | langgraph = "^0.0.37" 14 | tavily-python = "^0.3.3" 15 | google-search-results = "^2.4.2" 16 | arxiv = "^2.1.0" 17 | pyppeteer = "^2.0.0" 18 | langchain-groq = "^0.1.2" 19 | langchainhub = "^0.1.15" 20 | 21 | [tool.poetry.group.dev.dependencies] 22 | ipykernel = "^6.29.4" 23 | ipywidgets = "^8.1.2" 24 | python-dotenv = "^1.0.1" 25 | pygraphviz = "^1.12" 26 | ruff = "^0.4.1" 27 | 28 | 29 | [tool.poetry.group.llama3.dependencies] 30 | transformers = "^4.40.0" 31 | huggingface-hub = "^0.22.2" 32 | modal = "^0.62.98" 33 | 34 | [build-system] 35 | requires = ["poetry-core"] 36 | build-backend = "poetry.core.masonry.api" 37 | 38 | [tool.ruff] 39 | line-length = 120 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | clean-pycache: 2 | find ./ -type d -name '__pycache__' -exec rm -rf {} + 3 | 4 | lint: 5 | poetry run ruff check src/* --fix 6 | poetry run ruff check utils/* --fix 7 | poetry run ruff check llama3/serve.py --fix 8 | 9 | format: 10 | poetry run ruff format src/* 11 | poetry run ruff format utils/* 12 | poetry run ruff format llama3/serve.py 13 | 14 | imports: 15 | poetry run ruff check src/* --select I --fix 16 | poetry run ruff check utils/* --select I --fix 17 | poetry run ruff check llama3/serve.py --select I --fix 18 | 19 | pretty: 20 | $(MAKE) lint 21 | $(MAKE) format 22 | $(MAKE) imports 23 | 24 | llama8-ct: 25 | poetry run python utils/download_from_hf.py \ 26 | --repo_id meta-llama/Meta-Llama-3-8B-Instruct \ 27 | --filename tokenizer_config.json \ 28 | --output_file llama3/chat_template.jinja 29 | 30 | llama70-ct: 31 | poetry run python utils/download_from_hf.py \ 32 | --repo_id meta-llama/Meta-Llama-3-70B-Instruct \ 33 | --filename tokenizer_config.json \ 34 | --output_file llama3/chat_template.jinja 35 | 36 | serve-llama8: 37 | $(MAKE) llama8-ct 38 | poetry run modal serve llama3/serve.py 39 | 40 | serve-llama70: 41 | $(MAKE) llama70-ct 42 | poetry run modal serve llama3/serve.py 43 | 44 | deploy-llama8: 45 | $(MAKE) llama8-ct 46 | poetry run modal deploy llama3/serve.py 47 | 48 | deploy-llama70: 49 | $(MAKE) llama70-ct 50 | poetry run modal deploy llama3/serve.py -------------------------------------------------------------------------------- /utils/download_from_hf.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | 5 | from huggingface_hub import hf_hub_download 6 | 7 | 8 | def parse_args(): 9 | parser = argparse.ArgumentParser(description="Download and extract files from a Hugging Face repository.") 10 | parser.add_argument( 11 | "--repo_id", type=str, required=True, help="The repository ID in the format 'username/repo_name'." 12 | ) 13 | parser.add_argument( 14 | "--filename", type=str, required=True, help="The name of the file to download from the repository." 15 | ) 16 | parser.add_argument("--output_file", type=str, required=True, help="The path to save the file.") 17 | return parser.parse_args() 18 | 19 | 20 | def download_and_extract_chat_template(repo_id: str, filename: str, output_file: str) -> None: 21 | """ 22 | Download a file from a Hugging Face repository and extract the content of the 'chat_template' field. 23 | 24 | Args: 25 | repo_id (str): The repository ID in the format "username/repo_name". 26 | filename (str): The name of the file to download from the repository. 27 | output_file (str): The path to save the extracted chat template. 28 | 29 | Returns: 30 | None 31 | """ 32 | # Download the file from the Hugging Face repository 33 | tokenizer_config_path = hf_hub_download(repo_id, filename, token=os.getenv("HF_TOKEN")) 34 | 35 | # Read the contents of the file 36 | with open(tokenizer_config_path, "r") as file: 37 | tokenizer_config = json.load(file) 38 | 39 | # Extract the content of the 'chat_template' field 40 | chat_template = tokenizer_config["chat_template"] 41 | 42 | # Save the chat template content into a .jinja file 43 | with open(output_file, "w") as file: 44 | file.write(chat_template) 45 | 46 | print(f"Chat template saved as {output_file}") 47 | 48 | 49 | if __name__ == "__main__": 50 | args = parse_args() 51 | download_and_extract_chat_template(repo_id=args.repo_id, filename=args.filename, output_file=args.output_file) 52 | -------------------------------------------------------------------------------- /llama3/serve.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shlex 3 | import subprocess 4 | from pathlib import Path 5 | 6 | from modal import App, Image, Mount, Secret, gpu, web_server 7 | 8 | MODEL_DIR = "/model" 9 | BASE_MODEL = "meta-llama/Meta-Llama-3-70B-Instruct" # "meta-llama/Meta-Llama-3-8B-Instruct" 10 | GPU_CONFIG = gpu.A100(count=2, memory=80) 11 | 12 | 13 | # Download the model 14 | def download_model_to_folder(): 15 | from huggingface_hub import snapshot_download 16 | from transformers.utils import move_cache 17 | 18 | os.makedirs(MODEL_DIR, exist_ok=True) 19 | 20 | snapshot_download( 21 | BASE_MODEL, 22 | local_dir=MODEL_DIR, 23 | ignore_patterns=["*.pt", "*.gguf", "*.bin"], 24 | ) 25 | move_cache() 26 | 27 | 28 | # Image definition 29 | image = ( 30 | Image.from_registry("nvidia/cuda:12.1.1-devel-ubuntu22.04", add_python="3.11") 31 | .pip_install( 32 | "vllm==0.3.2", 33 | "huggingface_hub==0.19.4", 34 | "hf-transfer==0.1.4", 35 | "torch==2.1.2", 36 | ) 37 | .env({"HF_HUB_ENABLE_HF_TRANSFER": "1"}) 38 | .run_function(download_model_to_folder, timeout=60 * 20, secrets=[Secret.from_name("huggingface-secret")]) 39 | ) 40 | 41 | app = App(name="llama3", image=image) 42 | mounts_map = { 43 | "chat_template": { 44 | "local_path": Path(__file__).parent / "chat_template.jinja", 45 | "remote_path": "/model/chat_template.jinja", 46 | }, 47 | } 48 | 49 | 50 | @app.function( 51 | gpu=GPU_CONFIG, 52 | mounts=[Mount.from_local_file(**mounts_map["chat_template"])], 53 | allow_concurrent_inputs=50, 54 | timeout=60 * 60, 55 | keep_warm=1, 56 | secrets=[Secret.from_name("huggingface-secret")], 57 | ) 58 | @web_server(port=8000, startup_timeout=60 * 60) 59 | def serve_model(): 60 | base_model = shlex.quote(str(BASE_MODEL)) 61 | cmd = ( 62 | f"python -m vllm.entrypoints.openai.api_server --model {base_model} " 63 | "--chat-template /model/chat_template.jinja " 64 | "--dtype bfloat16 " 65 | "--tensor-parallel-size 2" 66 | ) 67 | subprocess.Popen(cmd, shell=True) 68 | --------------------------------------------------------------------------------