Doc Update (#129)

* init update

* Update terminology.rst

* fix the branch to create an index.html, and fix pre-commit issues

* Doc update

* made several changes to the docs after Shuguang's revision

* fixing pre-commit issues

* fixed the reference file to the final prompt config file

* added google analytics

---------

Co-authored-by: Salman Paracha <salmanparacha@MacBook-Pro-261.local>
This commit is contained in:
Shuguang Chen 2024-10-06 16:54:34 -07:00 committed by GitHub
parent 2a7b95582c
commit 5c7567584d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 1185 additions and 609 deletions

View file

@ -0,0 +1,47 @@
version: "0.1-beta"
listen:
address: 127.0.0.1 | 0.0.0.0
port_value: 8080 #If you configure port 443, you'll need to update the listener with tls_certificates
system_prompt: |
You are a network assistant that just offers facts; not advice on manufacturers or purchasing decisions.
llm_providers:
- name: "OpenAI"
provider: "openai"
access_key: OPENAI_API_KEY
model: gpt-4o
stream: true
prompt_targets:
- name: reboot_devices
description: >
This prompt target handles user requests to reboot devices.
It ensures that when users request to reboot specific devices or device groups, the system processes the reboot commands accurately.
**Examples of user prompts:**
- "Please reboot device 12345."
- "Restart all devices in tenant group tenant-XYZ
- "I need to reboot devices A, B, and C."
path: /agent/device_reboot
parameters:
- name: "device_ids"
type: list # Options: integer | float | list | dictionary | set
description: "A list of device identifiers (IDs) to reboot."
required: false
- name: "device_group"
type: string # Options: string | integer | float | list | dictionary | set
description: "The name of the device group to reboot."
required: false
# Arch creates a round-robin load balancing between different endpoints, managed via the cluster subsystem.
endpoints:
app_server:
# value could be ip address or a hostname with port
# this could also be a list of endpoints for load balancing
# for example endpoint: [ ip1:port, ip2:port ]
endpoint: "127.0.0.1:80"
# max time to wait for a connection to be established
connect_timeout: 0.005s

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

View file

@ -0,0 +1,41 @@
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/agent/device_summary', methods=['POST'])
def get_device_summary():
"""
Endpoint to retrieve device statistics based on device IDs and an optional time range.
"""
data = request.get_json()
# Validate 'device_ids' parameter
device_ids = data.get('device_ids')
if not device_ids or not isinstance(device_ids, list):
return jsonify({'error': "'device_ids' parameter is required and must be a list"}), 400
# Validate 'time_range' parameter (optional, defaults to 7)
time_range = data.get('time_range', 7)
if not isinstance(time_range, int):
return jsonify({'error': "'time_range' must be an integer"}), 400
# Simulate retrieving statistics for the given device IDs and time range
# In a real application, you would query your database or external service here
statistics = []
for device_id in device_ids:
# Placeholder for actual data retrieval
stats = {
'device_id': device_id,
'time_range': f'Last {time_range} days',
'data': f'Statistics data for device {device_id} over the last {time_range} days.'
}
statistics.append(stats)
response = {
'statistics': statistics
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)

View file

@ -0,0 +1,152 @@
from flask import Flask, request, jsonify
from datetime import datetime
import uuid
from langchain.memory import ConversationBufferMemory
from langchain.schema import AIMessage, HumanMessage
from langchain import OpenAI
app = Flask(__name__)
# Global dictionary to keep track of user memories
user_memories = {}
def get_user_conversation(user_id):
"""
Retrieve the user's conversation memory using LangChain.
If the user does not exist, initialize their conversation memory.
"""
if user_id not in user_memories:
user_memories[user_id] = ConversationBufferMemory(return_messages=True)
return user_memories[user_id]
def update_user_conversation(user_id, client_messages, intent_changed):
"""
Update the user's conversation memory with new messages using LangChain.
Each message is augmented with a UUID, timestamp, and intent change marker.
Only new messages are added to avoid duplication.
"""
memory = get_user_conversation(user_id)
stored_messages = memory.chat_memory.messages
# Determine the number of stored messages
num_stored_messages = len(stored_messages)
new_messages = client_messages[num_stored_messages:]
# Process each new message
for index, message in enumerate(new_messages):
role = message.get('role')
content = message.get('content')
metadata = {
'uuid': str(uuid.uuid4()),
'timestamp': datetime.utcnow().isoformat(),
'intent_changed': False # Default value
}
# Mark the intent change on the last message if detected
if intent_changed and index == len(new_messages) - 1:
metadata['intent_changed'] = True
# Create a new message with metadata
if role == 'user':
memory.chat_memory.add_message(
HumanMessage(content=content, additional_kwargs={'metadata': metadata})
)
elif role == 'assistant':
memory.chat_memory.add_message(
AIMessage(content=content, additional_kwargs={'metadata': metadata})
)
else:
# Handle other roles if necessary
pass
return memory
def get_messages_since_last_intent(messages):
"""
Retrieve messages from the last intent change onwards using LangChain.
"""
messages_since_intent = []
for message in reversed(messages):
# Insert message at the beginning to maintain correct order
messages_since_intent.insert(0, message)
metadata = message.additional_kwargs.get('metadata', {})
# Break if intent_changed is True
if metadata.get('intent_changed', False) == True:
break
return messages_since_intent
def forward_to_llm(messages):
"""
Forward messages to an upstream LLM using LangChain.
"""
# Convert messages to a conversation string
conversation = ""
for message in messages:
role = 'User' if isinstance(message, HumanMessage) else 'Assistant'
content = message.content
conversation += f"{role}: {content}\n"
# Use LangChain's LLM to get a response. This call is proxied through Arch for end-to-end observability and traffic management
llm = OpenAI()
# Create a prompt that includes the conversation
prompt = f"{conversation}Assistant:"
response = llm(prompt)
return response
@app.route('/process_rag', methods=['POST'])
def process_rag():
# Extract JSON data from the request
data = request.get_json()
user_id = data.get('user_id')
if not user_id:
return jsonify({'error': 'User ID is required'}), 400
client_messages = data.get('messages')
if not client_messages or not isinstance(client_messages, list):
return jsonify({'error': 'Messages array is required'}), 400
# Extract the intent change marker from Arch's headers if present for the current prompt
intent_changed_header = request.headers.get('x-arch-intent-marker', '').lower()
if intent_changed_header in ['', 'false']:
intent_changed = False
elif intent_changed_header == 'true':
intent_changed = True
else:
# Invalid value provided
return jsonify({'error': 'Invalid value for x-arch-prompt-intent-change header'}), 400
# Update user conversation based on intent change
memory = update_user_conversation(user_id, client_messages, intent_changed)
# Retrieve messages since last intent change for LLM
messages_for_llm = get_messages_since_last_intent(memory.chat_memory.messages)
# Forward messages to upstream LLM
llm_response = forward_to_llm(messages_for_llm)
# Prepare the messages to return
messages_to_return = []
for message in memory.chat_memory.messages:
role = 'user' if isinstance(message, HumanMessage) else 'assistant'
content = message.content
metadata = message.additional_kwargs.get('metadata', {})
message_entry = {
'uuid': metadata.get('uuid'),
'timestamp': metadata.get('timestamp'),
'role': role,
'content': content,
'intent_changed': metadata.get('intent_changed', False)
}
messages_to_return.append(message_entry)
# Prepare the response
response = {
'user_id': user_id,
'messages': messages_to_return,
'llm_response': llm_response
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)

View file

@ -0,0 +1,41 @@
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/agent/device_summary', methods=['POST'])
def get_device_summary():
"""
Endpoint to retrieve device statistics based on device IDs and an optional time range.
"""
data = request.get_json()
# Validate 'device_ids' parameter
device_ids = data.get('device_ids')
if not device_ids or not isinstance(device_ids, list):
return jsonify({'error': "'device_ids' parameter is required and must be a list"}), 400
# Validate 'time_range' parameter (optional, defaults to 7)
time_range = data.get('time_range', 7)
if not isinstance(time_range, int):
return jsonify({'error': "'time_range' must be an integer"}), 400
# Simulate retrieving statistics for the given device IDs and time range
# In a real application, you would query your database or external service here
statistics = []
for device_id in device_ids:
# Placeholder for actual data retrieval
stats = {
'device_id': device_id,
'time_range': f'Last {time_range} days',
'data': f'Statistics data for device {device_id} over the last {time_range} days.'
}
statistics.append(stats)
response = {
'statistics': statistics
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)

View file

@ -0,0 +1,21 @@
prompt_targets:
- name: get_device_statistics
description: >
This prompt target ensures that when users request device-related statistics, the system accurately retrieves and presents the relevant data
based on the specified devices and time range. Examples of user prompts, include:
- "Show me the performance stats for device 12345 over the past week."
- "What are the error rates for my devices in the last 24 hours?"
- "I need statistics on device 789 over the last 10 days."
path: /agent/device_summary
parameters:
- name: "device_ids"
type: list # Options: integer | float | list | dictionary | set
description: "A list of device identifiers (IDs) for which the statistics are requested."
required: true
- name: "time_range"
type: integer # Options: integer | float | list | dictionary | set
description: "The number of days in the past over which to retrieve device statistics. Defaults to 7 days if not specified."
required: false
default: 7