-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Autogen latency v2 [do not merge] #492
Conversation
WalkthroughThis update introduces several enhancements and optimizations across the AgentOps project. The autogen check has been relocated within the initialization process to streamline module loading. Connection pooling has been implemented in the HTTP client to improve performance, reducing request time by 0.5 seconds. A new utility function for formatting durations has been added. Additionally, the server has been updated to include a new endpoint for autogen completion, featuring detailed logging and time tracking for session operations. These changes collectively enhance the efficiency and functionality of the system. Changes
Files selected (5)
Files ignored (0)InstructionsEmoji Descriptions:
Interact with the Bot:
Available Commands:
Tips for Using @Entelligence.AI Effectively:
Need More Help?
|
result.status = Response.get_status(e.response.status_code) | ||
result.body = {"error": str(e)} | ||
raise ApiServerException(f"HTTPError: {e}") | ||
|
||
except requests.exceptions.RequestException as e: | ||
result.body = {"error": str(e)} | ||
raise ApiServerException(f"RequestException: {e}") | ||
|
||
# Handle error status codes | ||
if result.code == 401: | ||
raise ApiServerException( | ||
f"API server: invalid API key: {api_key}. Find your API key at https://app.agentops.ai/settings/projects" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Error Handling
Enhanced Error Handling for HTTP Requests
The error handling for HTTP requests has been improved by catching specific exceptions like Timeout
, HTTPError
, and RequestException
. This ensures that the application can gracefully handle network issues and provide meaningful error messages.
(i.e. Crew determining when tasks are complete and ending the session) | ||
Attributes: | ||
""" | ||
|
||
if "autogen" in sys.modules: | ||
Client().configure(instrument_llm_calls=False) | ||
Client()._initialize_autogen_logger() | ||
Client().add_default_tags(["autogen"]) | ||
|
||
Client().unsuppress_logs() | ||
t = threading.Thread(target=check_agentops_update) | ||
t.start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Performance Improvement
Implement Connection Pooling for HTTP Requests
The introduction of connection pooling in the HTTP client significantly reduces the time taken for HTTP requests by reusing existing connections. This change enhances performance by minimizing the overhead of establishing new connections for each request, saving approximately 0.5 seconds per request.
agentops/http_client.py
Outdated
header=None, | ||
) -> Response: | ||
result = Response() | ||
try: | ||
# Create request session with retries configured | ||
request_session = requests.Session() | ||
request_session.mount(url, HTTPAdapter(max_retries=retry_config)) | ||
|
||
if api_key is not None: | ||
JSON_HEADER["X-Agentops-Api-Key"] = api_key | ||
|
||
if parent_key is not None: | ||
JSON_HEADER["X-Agentops-Parent-Key"] = parent_key | ||
session = cls.get_session() | ||
|
||
if jwt is not None: | ||
JSON_HEADER["Authorization"] = f"Bearer {jwt}" | ||
|
||
res = request_session.post( | ||
url, data=payload, headers=JSON_HEADER, timeout=20 | ||
) | ||
# Update headers for this request | ||
headers = dict(session.headers) | ||
if api_key: | ||
headers["X-Agentops-Api-Key"] = api_key | ||
if parent_key: | ||
headers["X-Agentops-Parent-Key"] = parent_key | ||
if jwt: | ||
headers["Authorization"] = f"Bearer {jwt}" | ||
|
||
try: | ||
res = session.post(url, data=payload, headers=headers, timeout=20) | ||
result.parse(res) | ||
|
||
except requests.exceptions.Timeout: | ||
result.code = 408 | ||
result.status = HttpStatus.TIMEOUT | ||
raise ApiServerException( | ||
"Could not reach API server - connection timed out" | ||
) | ||
raise ApiServerException("Could not reach API server - connection timed out") | ||
|
||
except requests.exceptions.HTTPError as e: | ||
try: | ||
result.parse(e.response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security Suggestion
Secure Handling of Sensitive Headers
Ensure that sensitive headers such as API keys and JWT tokens are not logged or exposed in error messages. Consider using environment variables or secure vaults to manage these credentials.
agentops/http_client.py
Outdated
# Configure session defaults | ||
adapter = HTTPAdapter( | ||
max_retries=retry_config, | ||
pool_connections=1, # Assuming api.agentops.ai is the only host | ||
pool_maxsize=100, # Maximum number of connections to save in the pool | ||
) | ||
cls._session.mount('http://', adapter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Performance Improvement
Re-evaluate Connection Pool Configuration for Scalability
The change reduces the number of connection pools from 10 to 1, assuming that api.agentops.ai
is the only host. While this might be suitable for a single-host scenario, it could lead to performance bottlenecks if multiple hosts are accessed in the future. Consider maintaining a higher number of connection pools to accommodate potential future scalability needs.
Commitable Code Suggestion:
# Configure session defaults | |
adapter = HTTPAdapter( | |
max_retries=retry_config, | |
pool_connections=1, # Assuming api.agentops.ai is the only host | |
pool_maxsize=100, # Maximum number of connections to save in the pool | |
) | |
cls._session.mount('http://', adapter) | |
- pool_connections=1, # Assuming api.agentops.ai is the only host | |
+ pool_connections=10, # Maintain higher pool for scalability |
agentops/http_client.py
Outdated
|
||
|
||
class HttpClient: | ||
|
||
@staticmethod | ||
_session = None # Class-level session object | ||
|
||
@classmethod | ||
def get_session(cls) -> requests.Session: | ||
if cls._session is None: | ||
cls._session = requests.Session() | ||
# Configure session defaults | ||
adapter = HTTPAdapter( | ||
max_retries=retry_config, | ||
pool_connections=1, # Assuming api.agentops.ai is the only host | ||
pool_maxsize=100, # Maximum number of connections to save in the pool | ||
) | ||
cls._session.mount('http://', adapter) | ||
cls._session.mount('https://', adapter) | ||
cls._session.headers.update({ | ||
'Content-Type': 'application/json; charset=UTF-8', | ||
'Accept': '*/*', | ||
'User-Agent': 'AgentOps-Client' | ||
}) | ||
return cls._session | ||
|
||
@classmethod | ||
def post( | ||
cls, | ||
url: str, | ||
payload: bytes, | ||
api_key: Optional[str] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Performance Improvement
Implement Connection Pooling for Improved Performance
The introduction of a class-level session object for connection pooling significantly improves performance by reusing connections, reducing the overhead of establishing new connections for each request. This change is crucial for high-throughput applications.
Commitable Code Suggestion:
class HttpClient: | |
@staticmethod | |
_session = None # Class-level session object | |
@classmethod | |
def get_session(cls) -> requests.Session: | |
if cls._session is None: | |
cls._session = requests.Session() | |
# Configure session defaults | |
adapter = HTTPAdapter( | |
max_retries=retry_config, | |
pool_connections=1, # Assuming api.agentops.ai is the only host | |
pool_maxsize=100, # Maximum number of connections to save in the pool | |
) | |
cls._session.mount('http://', adapter) | |
cls._session.mount('https://', adapter) | |
cls._session.headers.update({ | |
'Content-Type': 'application/json; charset=UTF-8', | |
'Accept': '*/*', | |
'User-Agent': 'AgentOps-Client' | |
}) | |
return cls._session | |
@classmethod | |
def post( | |
cls, | |
url: str, | |
payload: bytes, | |
api_key: Optional[str] = None, | |
class HttpClient: | |
_session = None # Class-level session object | |
@classmethod | |
def get_session(cls) -> requests.Session: | |
if cls._session is None: | |
cls._session = requests.Session() | |
# Configure session defaults | |
adapter = HTTPAdapter( | |
max_retries=retry_config, | |
pool_connections=10, # Number of connection pools to cache | |
pool_maxsize=100, # Maximum number of connections to save in the pool | |
) | |
cls._session.mount('http://', adapter) | |
cls._session.mount('https://', adapter) | |
cls._session.headers.update({ | |
'Content-Type': 'application/json; charset=UTF-8', | |
'Accept': '*/*', | |
'User-Agent': 'AgentOps-Client' | |
}) | |
return cls._session | |
@classmethod | |
def post( | |
cls, | |
url: str, | |
payload: bytes, | |
api_key: Optional[str] = None, |
agentops/http_client.py
Outdated
|
||
return result | ||
|
||
@staticmethod | ||
@classmethod | ||
def get( | ||
cls, | ||
url: str, | ||
api_key: Optional[str] = None, | ||
jwt: Optional[str] = None, | ||
header=None, | ||
) -> Response: | ||
result = Response() | ||
try: | ||
# Create request session with retries configured | ||
request_session = requests.Session() | ||
request_session.mount(url, HTTPAdapter(max_retries=retry_config)) | ||
|
||
if api_key is not None: | ||
JSON_HEADER["X-Agentops-Api-Key"] = api_key | ||
|
||
if jwt is not None: | ||
JSON_HEADER["Authorization"] = f"Bearer {jwt}" | ||
session = cls.get_session() | ||
|
||
res = request_session.get(url, headers=JSON_HEADER, timeout=20) | ||
# Update headers for this request | ||
headers = dict(session.headers) | ||
if api_key: | ||
headers["X-Agentops-Api-Key"] = api_key | ||
if jwt: | ||
headers["Authorization"] = f"Bearer {jwt}" | ||
|
||
try: | ||
res = session.get(url, headers=headers, timeout=20) | ||
result.parse(res) | ||
|
||
except requests.exceptions.Timeout: | ||
result.code = 408 | ||
result.status = HttpStatus.TIMEOUT | ||
raise ApiServerException( | ||
"Could not reach API server - connection timed out" | ||
) | ||
raise ApiServerException("Could not reach API server - connection timed out") | ||
|
||
except requests.exceptions.HTTPError as e: | ||
try: | ||
result.parse(e.response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💻 Code Refactoring
Refactor HTTP Methods to Use Shared Session
Refactoring the post
and get
methods to use a shared session object reduces code duplication and improves maintainability. This change also ensures consistent configuration across all HTTP requests.
Commitable Code Suggestion:
return result | |
@staticmethod | |
@classmethod | |
def get( | |
cls, | |
url: str, | |
api_key: Optional[str] = None, | |
jwt: Optional[str] = None, | |
header=None, | |
) -> Response: | |
result = Response() | |
try: | |
# Create request session with retries configured | |
request_session = requests.Session() | |
request_session.mount(url, HTTPAdapter(max_retries=retry_config)) | |
if api_key is not None: | |
JSON_HEADER["X-Agentops-Api-Key"] = api_key | |
if jwt is not None: | |
JSON_HEADER["Authorization"] = f"Bearer {jwt}" | |
session = cls.get_session() | |
res = request_session.get(url, headers=JSON_HEADER, timeout=20) | |
# Update headers for this request | |
headers = dict(session.headers) | |
if api_key: | |
headers["X-Agentops-Api-Key"] = api_key | |
if jwt: | |
headers["Authorization"] = f"Bearer {jwt}" | |
try: | |
res = session.get(url, headers=headers, timeout=20) | |
result.parse(res) | |
except requests.exceptions.Timeout: | |
result.code = 408 | |
result.status = HttpStatus.TIMEOUT | |
raise ApiServerException( | |
"Could not reach API server - connection timed out" | |
) | |
raise ApiServerException("Could not reach API server - connection timed out") | |
except requests.exceptions.HTTPError as e: | |
try: | |
result.parse(e.response) | |
def post( | |
return result | |
@classmethod | |
def get( | |
cls, | |
url: str, | |
api_key: Optional[str] = None, | |
jwt: Optional[str] = None, | |
header=None, | |
) -> Response: | |
result = Response() | |
session = cls.get_session() | |
# Update headers for this request | |
headers = dict(session.headers) | |
if api_key: | |
headers["X-Agentops-Api-Key"] = api_key | |
if jwt: | |
headers["Authorization"] = f"Bearer {jwt}" | |
try: | |
res = session.get(url, headers=headers, timeout=20) | |
result.parse(res) | |
except requests.exceptions.Timeout: | |
result.code = 408 | |
result.status = HttpStatus.TIMEOUT | |
raise ApiServerException("Could not reach API server - connection timed out") | |
except requests.exceptions.HTTPError as e: | |
try: | |
result.parse(e.response) |
end_start = time.time() | ||
session.end_session(end_state="Success") | ||
end_time = time.time() - end_start | ||
print(f"Ending session took {end_time:.2f} seconds") | ||
|
||
total_time = time.time() - start_time | ||
print(f"Total completion time: {total_time:.2f} seconds") | ||
|
||
return {"response": response} | ||
|
||
|
||
uvicorn.run(app, host="0.0.0.0", port=9696) | ||
@app.get("/autogen_completion") | ||
def autogen_completion(): | ||
# Add time tracking | ||
start_time = time.time() | ||
# Record start time for session initialization | ||
session_start = time.time() | ||
session = agentops.start_session(tags=["api-server-test", "fastapi", "autogen"]) | ||
session_time = time.time() - session_start | ||
print(f"Session initialization took {session_time:.2f} seconds") | ||
|
||
# Define model, openai api key, tags, etc in the agent configuration | ||
config_list = [ | ||
{ | ||
"model": "gpt-4o-mini", | ||
"api_key": os.getenv("OPENAI_API_KEY"), | ||
"tags": ["mathagent-example", "tool"], | ||
} | ||
] | ||
|
||
Operator = Literal["+", "-", "*", "/"] | ||
|
||
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int: | ||
if operator == "+": | ||
return a + b | ||
elif operator == "-": | ||
return a - b | ||
elif operator == "*": | ||
return a * b | ||
elif operator == "/": | ||
return int(a / b) | ||
else: | ||
raise ValueError("Invalid operator") | ||
|
||
# Create the agent that uses the LLM | ||
assistant = ConversableAgent( | ||
name="Assistant", | ||
system_message="You are a helpful AI assistant. " | ||
"You can help with simple calculations. " | ||
"Return 'TERMINATE' when the task is done.", | ||
llm_config={"config_list": config_list}, | ||
) | ||
|
||
# Create the user proxy agent | ||
user_proxy = ConversableAgent( | ||
name="User", | ||
llm_config=False, | ||
is_termination_msg=lambda msg: msg.get("content") is not None | ||
and "TERMINATE" in msg["content"], | ||
human_input_mode="NEVER", | ||
) | ||
|
||
# Register the calculator function | ||
assistant.register_for_llm(name="calculator", description="A simple calculator")(calculator) | ||
user_proxy.register_for_execution(name="calculator")(calculator) | ||
|
||
register_function( | ||
calculator, | ||
caller=assistant, | ||
executor=user_proxy, | ||
name="calculator", | ||
description="A simple calculator", | ||
) | ||
|
||
response = None | ||
try: | ||
response = user_proxy.initiate_chat( | ||
assistant, message="What is (1423 - 123) / 3 + (32 + 23) * 5?" | ||
) | ||
except StdinNotImplementedError: | ||
print("Stdin not implemented. Skipping initiate_chat") | ||
session.end_session("Indeterminate") | ||
return {"response": "Chat initiation skipped - stdin not implemented"} | ||
|
||
# Close your AgentOps session to indicate that it completed | ||
end_start = time.time() | ||
session.end_session("Success") | ||
end_duration = time.time() - end_start | ||
print(f"Session ended in {end_duration:.2f}s. Visit your AgentOps dashboard to see the replay") | ||
|
||
# Calculate duration at the end | ||
duration = time.time() - start_time | ||
print(f"Total duration: {duration:.2f} seconds") | ||
|
||
return {"response": response, "duration": duration} | ||
|
||
|
||
if __name__ == "__main__": | ||
uvicorn.run("server:app", host="0.0.0.0", port=9696, reload=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security Suggestion
Handle Division by Zero in Calculator Function
The calculator
function currently performs division without handling division by zero, which could lead to runtime errors. Implement error handling to manage this scenario gracefully.
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int:
if operator == "+":
return a + b
elif operator == "-":
return a - b
elif operator == "*":
return a * b
elif operator == "/":
+ if b == 0:
+ raise ValueError("Division by zero is not allowed")
return int(a / b)
else:
raise ValueError("Invalid operator")
Commitable Code Suggestion:
returns=str(response.choices[0].message.content), | |
), | |
) | |
record_time = time.time() - record_start | |
print(f"Recording event took {record_time:.2f} seconds") | |
end_start = time.time() | |
session.end_session(end_state="Success") | |
end_time = time.time() - end_start | |
print(f"Ending session took {end_time:.2f} seconds") | |
total_time = time.time() - start_time | |
print(f"Total completion time: {total_time:.2f} seconds") | |
return {"response": response} | |
uvicorn.run(app, host="0.0.0.0", port=9696) | |
@app.get("/autogen_completion") | |
def autogen_completion(): | |
# Add time tracking | |
start_time = time.time() | |
# Record start time for session initialization | |
session_start = time.time() | |
session = agentops.start_session(tags=["api-server-test", "fastapi", "autogen"]) | |
session_time = time.time() - session_start | |
print(f"Session initialization took {session_time:.2f} seconds") | |
# Define model, openai api key, tags, etc in the agent configuration | |
config_list = [ | |
{ | |
"model": "gpt-4o-mini", | |
"api_key": os.getenv("OPENAI_API_KEY"), | |
"tags": ["mathagent-example", "tool"], | |
} | |
] | |
Operator = Literal["+", "-", "*", "/"] | |
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int: | |
if operator == "+": | |
return a + b | |
elif operator == "-": | |
return a - b | |
elif operator == "*": | |
return a * b | |
elif operator == "/": | |
return int(a / b) | |
else: | |
raise ValueError("Invalid operator") | |
# Create the agent that uses the LLM | |
assistant = ConversableAgent( | |
name="Assistant", | |
system_message="You are a helpful AI assistant. " | |
"You can help with simple calculations. " | |
"Return 'TERMINATE' when the task is done.", | |
llm_config={"config_list": config_list}, | |
) | |
# Create the user proxy agent | |
user_proxy = ConversableAgent( | |
name="User", | |
llm_config=False, | |
is_termination_msg=lambda msg: msg.get("content") is not None | |
and "TERMINATE" in msg["content"], | |
human_input_mode="NEVER", | |
) | |
# Register the calculator function | |
assistant.register_for_llm(name="calculator", description="A simple calculator")(calculator) | |
user_proxy.register_for_execution(name="calculator")(calculator) | |
register_function( | |
calculator, | |
caller=assistant, | |
executor=user_proxy, | |
name="calculator", | |
description="A simple calculator", | |
) | |
response = None | |
try: | |
response = user_proxy.initiate_chat( | |
assistant, message="What is (1423 - 123) / 3 + (32 + 23) * 5?" | |
) | |
except StdinNotImplementedError: | |
print("Stdin not implemented. Skipping initiate_chat") | |
session.end_session("Indeterminate") | |
return {"response": "Chat initiation skipped - stdin not implemented"} | |
# Close your AgentOps session to indicate that it completed | |
end_start = time.time() | |
session.end_session("Success") | |
end_duration = time.time() - end_start | |
print(f"Session ended in {end_duration:.2f}s. Visit your AgentOps dashboard to see the replay") | |
# Calculate duration at the end | |
duration = time.time() - start_time | |
print(f"Total duration: {duration:.2f} seconds") | |
return {"response": response, "duration": duration} | |
if __name__ == "__main__": | |
uvicorn.run("server:app", host="0.0.0.0", port=9696, reload=True) | |
def calculator(a: int, b: int, operator: Annotated[Operator, "operator"]) -> int: | |
if operator == "+": | |
return a + b | |
elif operator == "-": | |
return a - b | |
elif operator == "*": | |
return a * b | |
elif operator == "/": | |
if b == 0: | |
raise ValueError("Division by zero is not allowed") | |
return int(a / b) | |
else: | |
raise ValueError("Invalid operator") |
return datetime.now(timezone.utc).isoformat() | ||
|
||
|
||
def format_duration(start_time, end_time): | ||
start = datetime.fromisoformat(start_time.replace("Z", "+00:00")) | ||
end = datetime.fromisoformat(end_time.replace("Z", "+00:00")) | ||
duration = end - start | ||
|
||
hours, remainder = divmod(duration.total_seconds(), 3600) | ||
minutes, seconds = divmod(remainder, 60) | ||
|
||
parts = [] | ||
if hours > 0: | ||
parts.append(f"{int(hours)}h") | ||
if minutes > 0: | ||
parts.append(f"{int(minutes)}m") | ||
parts.append(f"{seconds:.1f}s") | ||
|
||
return " ".join(parts) | ||
|
||
|
||
def is_jsonable(x): | ||
try: | ||
json.dumps(x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Logic Error
Handle Durations Exceeding 24 Hours
The format_duration
function currently assumes that the duration will not exceed 24 hours. If the duration can be longer, consider adding logic to handle days as well. This will ensure accurate representation of longer durations.
+def format_duration(start_time, end_time):
+ start = datetime.fromisoformat(start_time.replace("Z", "+00:00"))
+ end = datetime.fromisoformat(end_time.replace("Z", "+00:00"))
+ duration = end - start
+
+ days = duration.days
+ hours, remainder = divmod(duration.seconds, 3600)
+ minutes, seconds = divmod(remainder, 60)
+
+ parts = []
+ if days > 0:
+ parts.append(f"{days}d")
+ if hours > 0:
+ parts.append(f"{int(hours)}h")
+ if minutes > 0:
+ parts.append(f"{int(minutes)}m")
+ parts.append(f"{seconds:.1f}s")
+
+ return " ".join(parts)
Commitable Code Suggestion:
return datetime.now(timezone.utc).isoformat() | |
def format_duration(start_time, end_time): | |
start = datetime.fromisoformat(start_time.replace("Z", "+00:00")) | |
end = datetime.fromisoformat(end_time.replace("Z", "+00:00")) | |
duration = end - start | |
hours, remainder = divmod(duration.total_seconds(), 3600) | |
minutes, seconds = divmod(remainder, 60) | |
parts = [] | |
if hours > 0: | |
parts.append(f"{int(hours)}h") | |
if minutes > 0: | |
parts.append(f"{int(minutes)}m") | |
parts.append(f"{seconds:.1f}s") | |
return " ".join(parts) | |
def is_jsonable(x): | |
try: | |
json.dumps(x) | |
def format_duration(start_time, end_time): | |
start = datetime.fromisoformat(start_time.replace("Z", "+00:00")) | |
end = datetime.fromisoformat(end_time.replace("Z", "+00:00")) | |
duration = end - start | |
days = duration.days | |
hours, remainder = divmod(duration.seconds, 3600) | |
minutes, seconds = divmod(remainder, 60) | |
parts = [] | |
if days > 0: | |
parts.append(f"{days}d") | |
if hours > 0: | |
parts.append(f"{int(hours)}h") | |
if minutes > 0: | |
parts.append(f"{int(minutes)}m") | |
parts.append(f"{seconds:.1f}s") | |
return " ".join(parts) |
import autogen | ||
import agentops | ||
from fastapi import FastAPI | ||
import uvicorn | ||
from dotenv import load_dotenv | ||
from agentops import ActionEvent | ||
from openai import OpenAI | ||
import os | ||
from autogen import ConversableAgent, UserProxyAgent | ||
import os | ||
from dotenv import load_dotenv | ||
from IPython.core.error import ( | ||
StdinNotImplementedError, | ||
) # only needed by AgentOps testing automation | ||
from typing import Annotated, Literal | ||
from autogen import register_function | ||
import time | ||
import litellm | ||
|
||
load_dotenv() | ||
|
||
openai = OpenAI() | ||
agentops.init() | ||
agentops.init(auto_start_session=False) | ||
client = OpenAI() | ||
app = FastAPI() | ||
|
||
|
||
@app.get("/completion") | ||
def completion(): | ||
start_time = time.time() | ||
|
||
session = agentops.start_session(tags=["api-server-test"]) | ||
session_start = time.time() | ||
session = agentops.start_session(tags=["api-server-test", "fastapi"]) | ||
session_time = time.time() - session_start | ||
print(f"Session initialization took {session_time:.2f} seconds") | ||
|
||
messages = [{"role": "user", "content": "Hello"}] | ||
response = session.patch(openai.chat.completions.create)( | ||
model="gpt-3.5-turbo", | ||
|
||
llm_start = time.time() | ||
response = litellm.completion( | ||
model="gpt-4o", | ||
messages=messages, | ||
temperature=0.5, | ||
) | ||
print(response) | ||
llm_time = time.time() - llm_start | ||
print(f"LLM call took {llm_time:.2f} seconds") | ||
|
||
record_start = time.time() | ||
session.record( | ||
ActionEvent( | ||
action_type="Agent says hello", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Performance Improvement
Use Logging Library for Time Tracking
The introduction of time tracking for various operations (session initialization, LLM call, recording, and session ending) is a valuable addition for performance monitoring. However, consider using a dedicated logging library instead of print statements for better control over log levels and outputs.
+ import logging
+ logging.basicConfig(level=logging.INFO)
start_time = time.time()
session_start = time.time()
session = agentops.start_session(tags=["api-server-test", "fastapi"])
session_time = time.time() - session_start
- print(f"Session initialization took {session_time:.2f} seconds")
+ logging.info(f"Session initialization took {session_time:.2f} seconds")
messages = [{"role": "user", "content": "Hello"}]
llm_start = time.time()
response = litellm.completion(
model="gpt-4o",
messages=messages,
temperature=0.5,
)
- print(response)
llm_time = time.time() - llm_start
- print(f"LLM call took {llm_time:.2f} seconds")
+ logging.info(f"LLM call took {llm_time:.2f} seconds")
record_start = time.time()
session.record(
ActionEvent(
action_type="Agent says hello",
returns=str(response.choices[0].message.content),
),
)
record_time = time.time() - record_start
- print(f"Recording event took {record_time:.2f} seconds")
+ logging.info(f"Recording event took {record_time:.2f} seconds")
end_start = time.time()
session.end_session(end_state="Success")
end_time = time.time() - end_start
- print(f"Ending session took {end_time:.2f} seconds")
+ logging.info(f"Ending session took {end_time:.2f} seconds")
total_time = time.time() - start_time
- print(f"Total completion time: {total_time:.2f} seconds")
+ logging.info(f"Total completion time: {total_time:.2f} seconds")
Commitable Code Suggestion:
import autogen | |
import agentops | |
from fastapi import FastAPI | |
import uvicorn | |
from dotenv import load_dotenv | |
from agentops import ActionEvent | |
from openai import OpenAI | |
import os | |
from autogen import ConversableAgent, UserProxyAgent | |
import os | |
from dotenv import load_dotenv | |
from IPython.core.error import ( | |
StdinNotImplementedError, | |
) # only needed by AgentOps testing automation | |
from typing import Annotated, Literal | |
from autogen import register_function | |
import time | |
import litellm | |
load_dotenv() | |
openai = OpenAI() | |
agentops.init() | |
agentops.init(auto_start_session=False) | |
client = OpenAI() | |
app = FastAPI() | |
@app.get("/completion") | |
def completion(): | |
start_time = time.time() | |
session = agentops.start_session(tags=["api-server-test"]) | |
session_start = time.time() | |
session = agentops.start_session(tags=["api-server-test", "fastapi"]) | |
session_time = time.time() - session_start | |
print(f"Session initialization took {session_time:.2f} seconds") | |
messages = [{"role": "user", "content": "Hello"}] | |
response = session.patch(openai.chat.completions.create)( | |
model="gpt-3.5-turbo", | |
llm_start = time.time() | |
response = litellm.completion( | |
model="gpt-4o", | |
messages=messages, | |
temperature=0.5, | |
) | |
print(response) | |
llm_time = time.time() - llm_start | |
print(f"LLM call took {llm_time:.2f} seconds") | |
record_start = time.time() | |
session.record( | |
ActionEvent( | |
action_type="Agent says hello", | |
import logging | |
logging.basicConfig(level=logging.INFO) | |
start_time = time.time() | |
session_start = time.time() | |
session = agentops.start_session(tags=["api-server-test", "fastapi"]) | |
session_time = time.time() - session_start | |
logging.info(f"Session initialization took {session_time:.2f} seconds") | |
messages = [{"role": "user", "content": "Hello"}] | |
llm_start = time.time() | |
response = litellm.completion( | |
model="gpt-4o", | |
messages=messages, | |
temperature=0.5, | |
) | |
llm_time = time.time() - llm_start | |
logging.info(f"LLM call took {llm_time:.2f} seconds") | |
record_start = time.time() | |
session.record( | |
ActionEvent( | |
action_type="Agent says hello", | |
returns=str(response.choices[0].message.content), | |
), | |
) | |
record_time = time.time() - record_start | |
logging.info(f"Recording event took {record_time:.2f} seconds") | |
end_start = time.time() | |
session.end_session(end_state="Success") | |
end_time = time.time() - end_start | |
logging.info(f"Ending session took {end_time:.2f} seconds") | |
total_time = time.time() - start_time | |
logging.info(f"Total completion time: {total_time:.2f} seconds") |
Files selected (1)
Files ignored (0)InstructionsEmoji Descriptions:
Interact with the Bot:
Available Commands:
Tips for Using @Entelligence.AI Effectively:
Need More Help?
|
adapter = HTTPAdapter( | ||
max_retries=retry_config, | ||
pool_connections=1, # Assuming api.agentops.ai is the only host | ||
pool_maxsize=100, # Maximum number of connections to save in the pool | ||
) | ||
cls._session.mount("http://", adapter) | ||
cls._session.mount("https://", adapter) | ||
cls._session.headers.update( | ||
{ | ||
"Content-Type": "application/json; charset=UTF-8", | ||
"Accept": "*/*", | ||
"User-Agent": "AgentOps-Client", | ||
} | ||
) | ||
return cls._session | ||
|
||
@staticmethod | ||
@classmethod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Performance Improvement
Ensure Consistent Protocol Handling with HTTP Adapter
The refactoring of the HTTP adapter configuration ensures that the session mounts for both HTTP and HTTPS protocols are correctly set up. This change improves the reliability of the HTTP client by ensuring that all requests are handled consistently, regardless of the protocol used.
Commitable Code Suggestion:
adapter = HTTPAdapter( | |
max_retries=retry_config, | |
pool_connections=1, # Assuming api.agentops.ai is the only host | |
pool_maxsize=100, # Maximum number of connections to save in the pool | |
) | |
cls._session.mount("http://", adapter) | |
cls._session.mount("https://", adapter) | |
cls._session.headers.update( | |
{ | |
"Content-Type": "application/json; charset=UTF-8", | |
"Accept": "*/*", | |
"User-Agent": "AgentOps-Client", | |
} | |
) | |
return cls._session | |
@staticmethod | |
@classmethod | |
def get_session(cls) -> requests.Session: | |
adapter = HTTPAdapter( | |
max_retries=retry_config, | |
pool_connections=1, # Assuming api.agentops.ai is the only host | |
pool_maxsize=100, # Maximum number of connections to save in the pool | |
) | |
cls._session.mount("http://", adapter) | |
cls._session.mount("https://", adapter) | |
cls._session.headers.update( | |
{ | |
"Content-Type": "application/json; charset=UTF-8", | |
"Accept": "*/*", | |
"User-Agent": "AgentOps-Client", | |
} | |
) | |
return cls._session |
Files selected (1)
Files ignored (0)InstructionsEmoji Descriptions:
Interact with the Bot:
Available Commands:
Tips for Using @Entelligence.AI Effectively:
Need More Help?
|
Closing until I get this under control |
🔍 Review Summary
Purpose:
Streamline module loading and improve HTTP request performance.
Key Changes:
format_duration
function for duration calculation and formatting./autogen_completion
endpoint to server with detailed logging and time tracking.Impact:
Improves system efficiency and functionality by reducing request time, optimizing module loading, and providing detailed logging and time tracking for session operations.
Original Description
No existing description found