# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= from typing import Optional from camel.agents.chat_agent import ChatAgent from camel.messages import BaseMessage from camel.models import BaseModelBackend from camel.prompts import TextPrompt from camel.types import RoleType from camel.utils import create_chunks # AgentOps decorator setting try: import os if os.getenv("AGENTOPS_API_KEY") is not None: from agentops import track_agent else: raise ImportError except (ImportError, AttributeError): from camel.utils import track_agent @track_agent(name="SearchAgent") class SearchAgent(ChatAgent): r"""An agent that summarizes text based on a query and evaluates the relevance of an answer. Args: model (BaseModelBackend, optional): The model backend to use for generating responses. (default: :obj:`OpenAIModel` with `GPT_4O_MINI`) """ def __init__( self, model: Optional[BaseModelBackend] = None, ) -> None: system_message = BaseMessage( role_name="Assistant", role_type=RoleType.ASSISTANT, meta_dict=None, content="You are a helpful assistant.", ) super().__init__(system_message, model=model) def summarize_text(self, text: str, query: str) -> str: r"""Summarize the information from the text, base on the query. Args: text (str): Text to summarize. query (str): What information you want. Returns: str: Strings with information. """ self.reset() summary_prompt = TextPrompt( '''Gather information from this text that relative to the question, but do not directly answer the question.\nquestion: {query}\ntext ''' ) summary_prompt = summary_prompt.format(query=query) # Max length of each chunk max_len = 3000 results = "" chunks = create_chunks(text, max_len) # Summarize for i, chunk in enumerate(chunks, start=1): prompt = summary_prompt + str(i) + ": " + chunk user_msg = BaseMessage.make_user_message( role_name="User", content=prompt, ) result = self.step(user_msg).msg.content results += result + "\n" # Final summarization final_prompt = TextPrompt( '''Here are some summarized texts which split from one text. Using the information to answer the question. If can't find the answer, you must answer "I can not find the answer to the query" and explain why.\n Query:\n{query}.\n\nText:\n''' ) final_prompt = final_prompt.format(query=query) prompt = final_prompt + results user_msg = BaseMessage.make_user_message( role_name="User", content=prompt, ) response = self.step(user_msg).msg.content return response def continue_search(self, query: str, answer: str) -> bool: r"""Ask whether to continue search or not based on the provided answer. Args: query (str): The question. answer (str): The answer to the question. Returns: bool: `True` if the user want to continue search, `False` otherwise. """ prompt = TextPrompt( "Do you think the ANSWER can answer the QUERY? " "Use only 'yes' or 'no' to answer.\n" "===== QUERY =====\n{query}\n\n" "===== ANSWER =====\n{answer}" ) prompt = prompt.format(query=query, answer=answer) user_msg = BaseMessage.make_user_message( role_name="User", content=prompt, ) response = self.step(user_msg).msg.content if "yes" in str(response).lower(): return False return True