diff --git a/README.md b/README.md index 7b4af09..93ac660 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,68 @@ -# DeepAgent +# Deep Search Agent – LangChain Implementation -DeepAgent is a minimal example of a deep learning based search agent. -It demonstrates how to combine a neural network with a simple search algorithm -(Monte‑Carlo Tree Search style) without relying on external search libraries. +This repository contains a minimal implementation of a **search agent** built with LangChain, following the “Deep Agents from Scratch” template. +The agent can answer arbitrary questions by performing a web search and reasoning over the results. -## Installation +## Features + +- Uses **OpenAI GPT‑4o‑mini** as the language model. +- Performs web searches via **SerpAPI** (Google/SerpAPI). +- Maintains conversation context with a memory buffer. +- Implements the **Zero‑Shot React** agent pattern. +- Simple command‑line interface for interactive use. + +## Prerequisites + +- Python 3.10+ +- An OpenAI API key. +- A SerpAPI key (free tier available). + +## Setup ```bash -# Create a virtual environment (recommended) -python -m venv .venv -source .venv/bin/activate # On Windows use `.venv\\Scripts\\activate` +# Clone the repository +git clone https://git.brojs.ru/kuzakhmetovartur/8.-samopisnyy-poiskovyy-agent-na-osnove-.git +cd -# Install the package -pip install . +# Create a virtual environment (optional but recommended) +python -m venv .venv +source .venv/bin/activate # On Windows: .venv\\Scripts\\activate + +# Install dependencies +pip install -r requirements.txt +``` + +Create a `.env` file in the project root with your credentials: + +``` +OPENAI_API_KEY=sk-... +SERPAPI_KEY=your-serpapi-key ``` ## Usage -```python -from src.search_agent import SearchAgent, PolicyValueNet - -# Create a policy‑value network -net = PolicyValueNet(input_dim=1, action_space=2) - -# Create the agent -agent = SearchAgent(policy_value_net=net, max_depth=3) - -# Run the agent on a simple state -state = 0 -action = agent.act(state) -print(f"Chosen action: {action}") -``` - -## Running Tests +Run the agent interactively: ```bash -pytest +python -m src.agent ``` +You will be prompted to enter a question. The agent will search the web and return a concise answer. + +## Example + +``` +Enter your question: What is the capital of France? +Processing... + +=== Answer === +The capital of France is Paris. +``` + +## Testing + +The agent can be tested programmatically by importing `create_search_agent` from `src.agent` and calling `agent.run("your question")`. + ## License -MIT License – see the [LICENSE](LICENSE) file for details. \ No newline at end of file +MIT License \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ffcce20..2802346 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ -torch==2.1.0 -pytest==7.4.0 -coverage==7.3.0 \ No newline at end of file +langchain==0.2.0 +langchain-openai==0.1.0 +langchain-community==0.2.0 +openai==1.12.0 +python-dotenv==1.0.0 \ No newline at end of file diff --git a/src/agent.py b/src/agent.py index bf33d7b..685112f 100644 --- a/src/agent.py +++ b/src/agent.py @@ -1,29 +1,177 @@ """ -Base Agent class. +Deep Agents from Scratch – Search Agent Implementation +====================================================== + +This module implements a search agent using LangChain following the +“Deep Agents from Scratch” template. The agent can answer arbitrary +questions by performing a web search and reasoning over the results. + +Prerequisites +------------- +* Python 3.10+ +* The following environment variables must be set: + * OPENAI_API_KEY – OpenAI API key + * SERPAPI_KEY – SerpAPI key (for web search) +* Install dependencies: + pip install -r requirements.txt + +Usage +----- +Run the module directly to start a simple CLI: + + python -m src.agent + +You will be prompted to enter a question. The agent will perform a +search and return a concise answer. + +Author +------ +Artur Kuzakhmetov """ -from abc import ABC, abstractmethod -from typing import Any, List +import os +import sys +from typing import Any, Dict + +from dotenv import load_dotenv +from langchain.agents import AgentExecutor, ZeroShotAgent, Tool +from langchain.agents.agent import AgentOutputParser +from langchain.chat_models import ChatOpenAI +from langchain.memory import ConversationBufferMemory +from langchain.tools import BaseTool +from langchain_community.tools.serpapi import SerpAPIWrapper + +# --------------------------------------------------------------------------- # +# Load environment variables +# --------------------------------------------------------------------------- # +load_dotenv() # Loads .env file if present + +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") +SERPAPI_KEY = os.getenv("SERPAPI_KEY") + +if not OPENAI_API_KEY: + raise RuntimeError("OPENAI_API_KEY environment variable is not set.") +if not SERPAPI_KEY: + raise RuntimeError("SERPAPI_KEY environment variable is not set.") -class Agent(ABC): +# --------------------------------------------------------------------------- # +# Tool definitions +# --------------------------------------------------------------------------- # +def create_serpapi_tool() -> BaseTool: """ - Abstract base class for agents. + Creates a SerpAPI web search tool. + + Returns + ------- + BaseTool + A LangChain tool that performs a web search using SerpAPI. """ + serpapi = SerpAPIWrapper( + serpapi_api_key=SERPAPI_KEY, + # We only need the top 5 results to keep the output concise + num_results=5, + ) + return Tool( + name="WebSearch", + func=serpapi.run, + description=( + "Use this tool to perform a web search. " + "Input should be a concise query. " + "Return the top results as a short summary." + ), + ) - @abstractmethod - def act(self, state: Any) -> Any: - """ - Choose an action given a state. - Parameters - ---------- - state : Any - Current state. +# --------------------------------------------------------------------------- # +# Agent construction +# --------------------------------------------------------------------------- # +def create_search_agent() -> AgentExecutor: + """ + Builds a search agent following the Deep Agents from Scratch template. - Returns - ------- - Any - Selected action. - """ - pass \ No newline at end of file + Returns + ------- + AgentExecutor + An executable agent that can answer arbitrary questions by + searching the web and reasoning over the results. + """ + # LLM configuration + llm = ChatOpenAI( + model_name="gpt-4o-mini", + temperature=0.2, + openai_api_key=OPENAI_API_KEY, + ) + + # Memory to keep conversation context + memory = ConversationBufferMemory( + memory_key="chat_history", + return_messages=True, + ) + + # Tools available to the agent + tools = [create_serpapi_tool()] + + # Prompt template for the zero-shot-react agent + # The template is derived from LangChain's ZeroShotAgent + prompt = ZeroShotAgent.create_prompt( + tools=tools, + llm=llm, + prefix="You are a helpful assistant that can search the web to answer questions.", + suffix=( + "When you need to search the web, use the following tool:\n" + "Tool: {tool_name}\n" + "Input: {tool_input}\n" + "When you have the answer, respond with the final answer." + ), + input_variables=["input", "intermediate_steps"], + ) + + # Agent + agent = ZeroShotAgent( + llm=llm, + tools=tools, + prompt=prompt, + ) + + # Agent executor + executor = AgentExecutor.from_agent_and_tools( + agent=agent, + tools=tools, + memory=memory, + verbose=True, + handle_parsing_errors=True, + ) + + return executor + + +# --------------------------------------------------------------------------- # +# CLI entry point +# --------------------------------------------------------------------------- # +def main() -> None: + """ + Simple command‑line interface that prompts the user for a question + and prints the agent's answer. + """ + agent = create_search_agent() + + print("Deep Search Agent (press Ctrl+C to exit)") + while True: + try: + query = input("\nEnter your question: ").strip() + if not query: + continue + print("\nProcessing...\n") + result = agent.run(query) + print("\n=== Answer ===") + print(result) + except KeyboardInterrupt: + print("\nExiting.") + sys.exit(0) + except Exception as exc: + print(f"\nError: {exc}") + + +if __name__ == "__main__": + main() \ No newline at end of file