From bbd62ce4fc09c91cde9ad2dc1999d19929ce1e74 Mon Sep 17 00:00:00 2001 From: David Westgate Date: Sun, 21 Apr 2024 13:20:43 -0700 Subject: [PATCH] start with adapting example, and seperating out tooling into file --- hw2/.requirements.txt | 11 +++++++++++ hw2/README.md | 24 +++++++++++++++++++++++ hw2/app.py | 42 +++++++++++++++++++++++++++++++++++++++++ hw2/requirements.txt | 8 ++++++++ hw2/tools.py | 44 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 hw2/.requirements.txt create mode 100644 hw2/README.md create mode 100644 hw2/requirements.txt create mode 100644 hw2/tools.py diff --git a/hw2/.requirements.txt b/hw2/.requirements.txt new file mode 100644 index 0000000..d3647af --- /dev/null +++ b/hw2/.requirements.txt @@ -0,0 +1,11 @@ +langchain-community +langchain +langchain_openai +python-dotenv +firecrawl-py +chromadb +langchainhub +dnspython +validators +google-search-results +langchain-experimental diff --git a/hw2/README.md b/hw2/README.md new file mode 100644 index 0000000..71b47ca --- /dev/null +++ b/hw2/README.md @@ -0,0 +1,24 @@ +## HW2 for gensec + + +### Enviornment +Install python3, then run the following: +``` +pip install -r requirements.txt +cp .env.example .env +``` +After, populate .env with your OPENAI_API_KEY and FIREWALL_API_KEY + + +### Running +``` +python3 app.py +``` + +### Example Queries +``` + + +``` + +Enjoy! \ No newline at end of file diff --git a/hw2/app.py b/hw2/app.py index e69de29..fc986c5 100644 --- a/hw2/app.py +++ b/hw2/app.py @@ -0,0 +1,42 @@ +from langchain import hub +from langchain.agents import AgentExecutor, create_react_agent, load_tools +from langchain.tools import tool +from langchain_openai import ChatOpenAI +from dotenv import load_dotenv +from tools import lookup_ip, lookup_name +from langsmith import Client + +""" +This is the main runner of the custom agent. Agent tools are defined seperatly and imported from tools.py + +So far, wholly adapted from https://github.com/wu4f/cs410g-src/blob/main/04_Agents/07_tools_custom_agent.py + +""" + +load_dotenv() +#os.environ["LANGCHAIN_TRACING_V2"] = "true" +#os.environ["LANGCHAIN_PROJECT"] = f"LangSmith Introduction" +#os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com" +#client = Client() +llm = ChatOpenAI(model_name="gpt-4-turbo", temperature=0) + +tools = load_tools(["serpapi", "terminal"], allow_dangerous_tools=True) +tools.extend([lookup_name, lookup_ip]) + +base_prompt = hub.pull("langchain-ai/react-agent-template") +prompt = base_prompt.partial(instructions="Answer the user's request utilizing at most 8 tool calls") +agent = create_react_agent(llm,tools,prompt) +agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) +print("Welcome to my application. I am configured with these tools:") +for tool in agent_executor.tools: + print(f' Tool: {tool.name} = {tool.description}') +while True: + line = input("llm>> ") + try: + if line: + result = agent_executor.invoke({"input":line}) + print(result) + else: + break + except Exception as e: + print(e) diff --git a/hw2/requirements.txt b/hw2/requirements.txt new file mode 100644 index 0000000..0f037b9 --- /dev/null +++ b/hw2/requirements.txt @@ -0,0 +1,8 @@ +langchain +langchain_openai +langchain-experimental +langchainhub +python-dotenv +dnspython +validators +google-search-results diff --git a/hw2/tools.py b/hw2/tools.py new file mode 100644 index 0000000..e4c710b --- /dev/null +++ b/hw2/tools.py @@ -0,0 +1,44 @@ +from langchain_core.pydantic_v1 import BaseModel, Field, root_validator +from langchain.tools import tool +import dns.resolver, dns.reversename +import validators +import validators + +""" +Tools to be run by my custom agent. + +So far, these are the same tooling provided by the example in https://github.com/wu4f/cs410g-src/blob/main/04_Agents/07_tools_custom_agent.py, +But I will be updating this to build my own tooling +""" + +class LookupNameInput(BaseModel): + hostname: str = Field(description="Should be a hostname such as www.google.com") + @root_validator + def is_dns_address(cls, values: dict[str,any]) -> str: + if validators.domain(values.get("hostname")): + return values + raise ValueError("Malformed hostname") +class LookupIPInput(BaseModel): + address: str = Field(description="Should be an IP address such as 208.91.197.27 or 143.95.239.83") + @root_validator + def is_ip_address(cls, values: dict[str,any]) -> str: + if validators.ip_address.ipv4(values.get("address")): + return values + raise ValueError("Malformed IP address") + + +@tool("lookup_name",args_schema=LookupNameInput, return_direct=False) +def lookup_name(hostname): + """Given a DNS hostname, it will return its IPv4 addresses""" + result = dns.resolver.resolve(hostname, 'A') + res = [ r.to_text() for r in result ] + return res[0] + + +@tool("lookup_ip", args_schema=LookupIPInput, return_direct=False) +def lookup_ip(address): + """Given an IP address, returns names associated with it""" + n = dns.reversename.from_address(address) + result = dns.resolver.resolve(n, 'PTR') + res = [ r.to_text() for r in result ] + return res[0]